diff --git a/src/libboard_artiq/src/drtioaux_proto.rs b/src/libboard_artiq/src/drtioaux_proto.rs index 85b6411..39f87b6 100644 --- a/src/libboard_artiq/src/drtioaux_proto.rs +++ b/src/libboard_artiq/src/drtioaux_proto.rs @@ -1,8 +1,8 @@ use core_io::{Error as IoError, Read, Write}; use io::proto::{ProtoRead, ProtoWrite}; -/* 512 (max size) - 4 (CRC) - 1 (packet ID) - 1 (destination) - 4 (trace ID) - 1 (last) - 2 (length) */ -pub const DMA_TRACE_MAX_SIZE: usize = 499; +pub const DMA_TRACE_MAX_SIZE: usize = /*max size*/512 - /*CRC*/4 - /*packet ID*/1 - /*trace ID*/4 - /*last*/1 -/*length*/2; +pub const ANALYZER_MAX_SIZE: usize = /*max size*/512 - /*CRC*/4 - /*packet ID*/1 - /*last*/1 - /*length*/2; #[derive(Debug)] pub enum Error { @@ -136,6 +136,23 @@ pub enum Packet { succeeded: bool, }, + AnalyzerHeaderRequest { + destination: u8 + }, + AnalyzerHeader { + sent_bytes: u32, + total_byte_count: u64, + overflow_occurred: bool, + }, + AnalyzerDataRequest { + destination: u8, + }, + AnalyzerData { + last: bool, + length: u16, + data: [u8; ANALYZER_MAX_SIZE], + }, + DmaAddTraceRequest { destination: u8, id: u32, @@ -298,6 +315,29 @@ impl Packet { succeeded: reader.read_bool()?, }, + 0xa0 => Packet::AnalyzerHeaderRequest { + destination: reader.read_u8()? + }, + 0xa1 => Packet::AnalyzerHeader { + sent_bytes: reader.read_u32()?, + total_byte_count: reader.read_u64()?, + overflow_occurred: reader.read_bool()?, + }, + 0xa2 => Packet::AnalyzerDataRequest { + destination: reader.read_u8()? + }, + 0xa3 => { + let last = reader.read_bool()?; + let length = reader.read_u16()?; + let mut data: [u8; ANALYZER_MAX_SIZE] = [0; ANALYZER_MAX_SIZE]; + reader.read_exact(&mut data[0..length as usize])?; + Packet::AnalyzerData { + last: last, + length: length, + data: data + } + }, + 0xb0 => { let destination = reader.read_u8()?; let id = reader.read_u32()?; @@ -526,6 +566,35 @@ impl Packet { writer.write_bool(succeeded)?; } + Packet::AnalyzerHeaderRequest { destination } => { + writer.write_u8(0xa0)?; + writer.write_u8(destination)?; + } + Packet::AnalyzerHeader { + sent_bytes, + total_byte_count, + overflow_occurred + } => { + writer.write_u8(0xa1)?; + writer.write_u32(sent_bytes)?; + writer.write_u64(total_byte_count)?; + writer.write_bool(overflow_occurred)?; + } + Packet::AnalyzerDataRequest { destination } => { + writer.write_u8(0xa2)?; + writer.write_u8(destination)?; + } + Packet::AnalyzerData { + last, + length, + data + } => { + writer.write_u8(0xa3)?; + writer.write_bool(last)?; + writer.write_u16(length)?; + writer.write_all(&data[0..length as usize])?; + } + Packet::DmaAddTraceRequest { destination, id, diff --git a/src/satman/src/analyzer.rs b/src/satman/src/analyzer.rs new file mode 100644 index 0000000..d0b4a6d --- /dev/null +++ b/src/satman/src/analyzer.rs @@ -0,0 +1,106 @@ +use libboard_artiq::pl::csr; +use libcortex_a9::cache; +use libboard_artiq::drtioaux_proto::ANALYZER_MAX_SIZE; + +const BUFFER_SIZE: usize = 512 * 1024; + +#[repr(align(64))] +struct Buffer { + data: [u8; BUFFER_SIZE], +} + +static mut BUFFER: Buffer = Buffer { + data: [0; BUFFER_SIZE] +}; + +fn arm() { + unsafe { + let base_addr = &mut BUFFER.data[0] as *mut _ as usize; + let last_addr = &mut BUFFER.data[BUFFER_SIZE - 1] as *mut _ as usize; + csr::rtio_analyzer::dma_base_address_write(base_addr as u32); + csr::rtio_analyzer::message_encoder_overflow_reset_write(1); + csr::rtio_analyzer::dma_last_address_write(last_addr as u32); + csr::rtio_analyzer::dma_reset_write(1); + csr::rtio_analyzer::enable_write(1); + } +} + +fn disarm() { + unsafe { + csr::rtio_analyzer::enable_write(0); + while csr::rtio_analyzer::busy_read() != 0 {} + cache::dcci_slice(&BUFFER.data); + } +} + +pub struct Analyzer { + // necessary for keeping track of sent data + sent_bytes: usize, + data_iter: usize +} + +pub struct Header { + pub total_byte_count: u64, + pub sent_bytes: u32, + pub error: bool +} + +pub struct AnalyzerSliceMeta { + pub len: u16, + pub last: bool +} + +impl Analyzer { + pub fn new() -> Analyzer { + // create and arm new Analyzer + arm(); + Analyzer { + sent_bytes: 0, + data_iter: 0 + } + } + + fn drop(&mut self) { + disarm(); + } + + pub fn get_header(&mut self) -> Header { + disarm(); + + let overflow = unsafe { csr::rtio_analyzer::message_encoder_overflow_read() != 0 }; + let bus_err = unsafe { csr::rtio_analyzer::dma_bus_error_read() != 0 }; + let total_byte_count = unsafe { csr::rtio_analyzer::dma_byte_count_read() as u64 }; + let wraparound = total_byte_count >= BUFFER_SIZE as u64; + self.sent_bytes = if wraparound { BUFFER_SIZE } else { total_byte_count as usize }; + self.data_iter = if wraparound { (total_byte_count % BUFFER_SIZE as u64) as usize } else { 0 }; + + Header { + total_byte_count: total_byte_count, + sent_bytes: self.sent_bytes as u32, + error: overflow | bus_err + } + } + + pub fn get_data(&mut self, data_slice: &mut [u8; ANALYZER_MAX_SIZE]) -> AnalyzerSliceMeta { + let data = unsafe { &BUFFER.data[..] }; + let i = self.data_iter; + let len = if i + ANALYZER_MAX_SIZE < self.sent_bytes { ANALYZER_MAX_SIZE } else { self.sent_bytes - i }; + let last = i + len == self.sent_bytes; + if i + len >= BUFFER_SIZE { + data_slice[..len].clone_from_slice(&data[i..BUFFER_SIZE]); + data_slice[..len].clone_from_slice(&data[..(i+len) % BUFFER_SIZE]); + } else { + data_slice[..len].clone_from_slice(&data[i..i+len]); + } + self.data_iter += len; + + if last { + arm(); + } + + AnalyzerSliceMeta { + len: len as u16, + last: last + } + } +} diff --git a/src/satman/src/main.rs b/src/satman/src/main.rs index 0a05a72..6eb33cd 100644 --- a/src/satman/src/main.rs +++ b/src/satman/src/main.rs @@ -20,6 +20,7 @@ extern crate alloc; use core::sync::atomic::{AtomicBool, Ordering}; +use analyzer::Analyzer as Analyzer; use dma::Manager as DmaManager; use embedded_hal::blocking::delay::DelayUs; #[cfg(feature = "target_kasli_soc")] @@ -40,6 +41,7 @@ use libsupport_zynq::ram; mod dma; mod repeater; +mod analyzer; fn drtiosat_reset(reset: bool) { unsafe { @@ -95,6 +97,7 @@ fn process_aux_packet( timer: &mut GlobalTimer, i2c: &mut I2c, dma_manager: &mut DmaManager, + analyzer: &mut Analyzer, ) -> Result<(), drtioaux::Error> { // In the code below, *_chan_sel_write takes an u8 if there are fewer than 256 channels, // and u16 otherwise; hence the `as _` conversion. @@ -412,6 +415,26 @@ fn process_aux_packet( ) } + drtioaux::Packet::AnalyzerHeaderRequest { destination: _destination } => { + forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer); + let header = analyzer.get_header(); + drtioaux::send(0, &drtioaux::Packet::AnalyzerHeader { + total_byte_count: header.total_byte_count, + sent_bytes: header.sent_bytes, + overflow_occurred: header.overflow, + }) + } + drtioaux::Packet::AnalyzerDataRequest { destination: _destination } => { + forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer); + let mut data_slice: [u8; ANALYZER_MAX_SIZE] = [0; ANALYZER_MAX_SIZE]; + let meta = analyzer.get_data(&mut data_slice); + drtioaux::send(0, &drtioaux::Packet::AnalyzerData { + last: meta.last, + length: meta.len, + data: data_slice, + }) + } + drtioaux::Packet::DmaAddTraceRequest { destination: _destination, id, @@ -455,10 +478,11 @@ fn process_aux_packets( timer: &mut GlobalTimer, i2c: &mut I2c, dma_manager: &mut DmaManager, + analyzer: &mut Analyzer, ) { let result = drtioaux::recv(0).and_then(|packet| { if let Some(packet) = packet { - process_aux_packet(repeaters, routing_table, rank, packet, timer, i2c, dma_manager) + process_aux_packet(repeaters, routing_table, rank, packet, timer, i2c, dma_manager, analyzer) } else { Ok(()) } @@ -635,6 +659,8 @@ pub extern "C" fn main_core0() -> i32 { // are cleared out for a clean slate on subsequent connections, // without a manual intervention. let mut dma_manager = DmaManager::new(); + // same for RTIO Analyzer + let mut analyzer = Analyzer::new(); drtioaux::reset(0); drtiosat_reset(false); @@ -649,6 +675,7 @@ pub extern "C" fn main_core0() -> i32 { &mut timer, &mut i2c, &mut dma_manager, + &mut analyzer, ); #[allow(unused_mut)] for mut rep in repeaters.iter_mut() {