diff --git a/src/Cargo.lock b/src/Cargo.lock index 2a908988..4e655fb9 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -280,6 +280,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "log_buffer" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f033173c9486b7fe97a79c895c0a3483ae395ab6744c985d10078950e2492419" + [[package]] name = "managed" version = "0.7.2" @@ -400,6 +406,7 @@ dependencies = [ "libregister", "libsupport_zynq", "log", + "log_buffer", "nb", "num-derive", "num-traits", diff --git a/src/runtime/Cargo.toml b/src/runtime/Cargo.toml index 56f08e53..91173f01 100644 --- a/src/runtime/Cargo.toml +++ b/src/runtime/Cargo.toml @@ -22,6 +22,7 @@ void = { version = "1", default-features = false } futures = { version = "0.3", default-features = false, features = ["async-await"] } async-recursion = "0.3" fatfs = { version = "0.3", features = ["core_io"], default-features = false } +log_buffer = { version = "1.2" } libboard_zynq = { git = "https://git.m-labs.hk/M-Labs/zc706.git" } libsupport_zynq = { default-features = false, git = "https://git.m-labs.hk/M-Labs/zc706.git" } diff --git a/src/runtime/src/logger.rs b/src/runtime/src/logger.rs new file mode 100644 index 00000000..9862bf35 --- /dev/null +++ b/src/runtime/src/logger.rs @@ -0,0 +1,113 @@ +use core::cell::{Cell, RefCell, RefMut}; +use core::fmt::Write; +use log::{Log, LevelFilter}; +use log_buffer::LogBuffer; +use libboard_zynq::{println, timer::GlobalTimer}; + +pub struct LogBufferRef<'a> { + buffer: RefMut<'a, LogBuffer<&'static mut [u8]>>, + old_log_level: LevelFilter +} + +impl<'a> LogBufferRef<'a> { + fn new(buffer: RefMut<'a, LogBuffer<&'static mut [u8]>>) -> LogBufferRef<'a> { + let old_log_level = log::max_level(); + log::set_max_level(LevelFilter::Off); + LogBufferRef { buffer, old_log_level } + } + + pub fn is_empty(&self) -> bool { + self.buffer.is_empty() + } + + pub fn clear(&mut self) { + self.buffer.clear() + } + + pub fn extract(&mut self) -> &str { + self.buffer.extract() + } +} + +impl<'a> Drop for LogBufferRef<'a> { + fn drop(&mut self) { + log::set_max_level(self.old_log_level) + } +} + +pub struct BufferLogger { + buffer: RefCell>, + uart_filter: Cell +} + +static mut LOGGER: *const BufferLogger = 0 as *const _; + +impl BufferLogger { + pub fn new(buffer: &'static mut [u8]) -> BufferLogger { + BufferLogger { + buffer: RefCell::new(LogBuffer::new(buffer)), + uart_filter: Cell::new(LevelFilter::Info), + } + } + + pub fn register(&self, f: F) { + unsafe { + LOGGER = self; + log::set_logger(&*LOGGER) + .expect("global logger can only be initialized once"); + } + log::set_max_level(LevelFilter::Info); + f(); + } + + pub fn with R>(f: F) -> R { + f(unsafe { &*LOGGER }) + } + + pub fn buffer<'a>(&'a self) -> Result, ()> { + self.buffer + .try_borrow_mut() + .map(LogBufferRef::new) + .map_err(|_| ()) + } + + pub fn uart_log_level(&self) -> LevelFilter { + self.uart_filter.get() + } + + pub fn set_uart_log_level(&self, max_level: LevelFilter) { + self.uart_filter.set(max_level) + } +} + +// required for impl Log +unsafe impl Sync for BufferLogger {} + +impl Log for BufferLogger { + fn enabled(&self, _metadata: &log::Metadata) -> bool { + true + } + + fn log(&self, record: &log::Record) { + if self.enabled(record.metadata()) { + let timestamp = unsafe { + GlobalTimer::get() + }.get_us(); + let seconds = timestamp / 1_000_000; + let micros = timestamp % 1_000_000; + + if let Ok(mut buffer) = self.buffer.try_borrow_mut() { + writeln!(buffer, "[{:6}.{:06}s] {:>5}({}): {}", seconds, micros, + record.level(), record.target(), record.args()).unwrap(); + } + + if record.level() <= self.uart_filter.get() { + println!("[{:6}.{:06}s] {:>5}({}): {}", seconds, micros, + record.level(), record.target(), record.args()); + } + } + } + + fn flush(&self) { + } +} diff --git a/src/runtime/src/main.rs b/src/runtime/src/main.rs index 4c0c4189..49f56a21 100644 --- a/src/runtime/src/main.rs +++ b/src/runtime/src/main.rs @@ -9,7 +9,7 @@ extern crate alloc; use core::{cmp, str}; use log::{info, warn}; -use libboard_zynq::{timer::GlobalTimer, time::Milliseconds, logger, devc, slcr}; +use libboard_zynq::{timer::GlobalTimer, time::Milliseconds, devc, slcr, println}; use libsupport_zynq::ram; use libregister::RegisterW; use nb::block; @@ -30,6 +30,7 @@ mod moninj; mod load_pl; mod eh_artiq; mod panic; +mod logger; fn init_gateware() { // Set up PS->PL clocks @@ -124,10 +125,16 @@ fn init_rtio(timer: GlobalTimer, cfg: &config::Config) { } } +static mut LOG_BUFFER: [u8; 1<<17] = [0; 1<<17]; + #[no_mangle] pub fn main_core0() { let timer = GlobalTimer::start(); - let _ = logger::init(); + unsafe { + println!("BUFFER ADDR = {:p}", LOG_BUFFER.as_ptr()); + println!("BUFFER LEN = {}", LOG_BUFFER.len()); + logger::BufferLogger::new(&mut LOG_BUFFER[..]).register(|| {}); + } log::set_max_level(log::LevelFilter::Debug); info!("NAR3/Zynq7000 starting...");