forked from M-Labs/nac3
satellite: port analyzer, drtio packets
This commit is contained in:
parent
c5aac198f2
commit
259b0ba1b7
|
@ -1,8 +1,8 @@
|
||||||
use core_io::{Error as IoError, Read, Write};
|
use core_io::{Error as IoError, Read, Write};
|
||||||
use io::proto::{ProtoRead, ProtoWrite};
|
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 = /*max size*/512 - /*CRC*/4 - /*packet ID*/1 - /*trace ID*/4 - /*last*/1 -/*length*/2;
|
||||||
pub const DMA_TRACE_MAX_SIZE: usize = 499;
|
pub const ANALYZER_MAX_SIZE: usize = /*max size*/512 - /*CRC*/4 - /*packet ID*/1 - /*last*/1 - /*length*/2;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
@ -136,6 +136,23 @@ pub enum Packet {
|
||||||
succeeded: bool,
|
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 {
|
DmaAddTraceRequest {
|
||||||
destination: u8,
|
destination: u8,
|
||||||
id: u32,
|
id: u32,
|
||||||
|
@ -298,6 +315,29 @@ impl Packet {
|
||||||
succeeded: reader.read_bool()?,
|
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 => {
|
0xb0 => {
|
||||||
let destination = reader.read_u8()?;
|
let destination = reader.read_u8()?;
|
||||||
let id = reader.read_u32()?;
|
let id = reader.read_u32()?;
|
||||||
|
@ -526,6 +566,35 @@ impl Packet {
|
||||||
writer.write_bool(succeeded)?;
|
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 {
|
Packet::DmaAddTraceRequest {
|
||||||
destination,
|
destination,
|
||||||
id,
|
id,
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,6 +20,7 @@ extern crate alloc;
|
||||||
|
|
||||||
use core::sync::atomic::{AtomicBool, Ordering};
|
use core::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
|
||||||
|
use analyzer::Analyzer as Analyzer;
|
||||||
use dma::Manager as DmaManager;
|
use dma::Manager as DmaManager;
|
||||||
use embedded_hal::blocking::delay::DelayUs;
|
use embedded_hal::blocking::delay::DelayUs;
|
||||||
#[cfg(feature = "target_kasli_soc")]
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
|
@ -40,6 +41,7 @@ use libsupport_zynq::ram;
|
||||||
|
|
||||||
mod dma;
|
mod dma;
|
||||||
mod repeater;
|
mod repeater;
|
||||||
|
mod analyzer;
|
||||||
|
|
||||||
fn drtiosat_reset(reset: bool) {
|
fn drtiosat_reset(reset: bool) {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -95,6 +97,7 @@ fn process_aux_packet(
|
||||||
timer: &mut GlobalTimer,
|
timer: &mut GlobalTimer,
|
||||||
i2c: &mut I2c,
|
i2c: &mut I2c,
|
||||||
dma_manager: &mut DmaManager,
|
dma_manager: &mut DmaManager,
|
||||||
|
analyzer: &mut Analyzer,
|
||||||
) -> Result<(), drtioaux::Error> {
|
) -> Result<(), drtioaux::Error> {
|
||||||
// In the code below, *_chan_sel_write takes an u8 if there are fewer than 256 channels,
|
// In the code below, *_chan_sel_write takes an u8 if there are fewer than 256 channels,
|
||||||
// and u16 otherwise; hence the `as _` conversion.
|
// 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 {
|
drtioaux::Packet::DmaAddTraceRequest {
|
||||||
destination: _destination,
|
destination: _destination,
|
||||||
id,
|
id,
|
||||||
|
@ -455,10 +478,11 @@ fn process_aux_packets(
|
||||||
timer: &mut GlobalTimer,
|
timer: &mut GlobalTimer,
|
||||||
i2c: &mut I2c,
|
i2c: &mut I2c,
|
||||||
dma_manager: &mut DmaManager,
|
dma_manager: &mut DmaManager,
|
||||||
|
analyzer: &mut Analyzer,
|
||||||
) {
|
) {
|
||||||
let result = drtioaux::recv(0).and_then(|packet| {
|
let result = drtioaux::recv(0).and_then(|packet| {
|
||||||
if let Some(packet) = 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 {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -635,6 +659,8 @@ pub extern "C" fn main_core0() -> i32 {
|
||||||
// are cleared out for a clean slate on subsequent connections,
|
// are cleared out for a clean slate on subsequent connections,
|
||||||
// without a manual intervention.
|
// without a manual intervention.
|
||||||
let mut dma_manager = DmaManager::new();
|
let mut dma_manager = DmaManager::new();
|
||||||
|
// same for RTIO Analyzer
|
||||||
|
let mut analyzer = Analyzer::new();
|
||||||
|
|
||||||
drtioaux::reset(0);
|
drtioaux::reset(0);
|
||||||
drtiosat_reset(false);
|
drtiosat_reset(false);
|
||||||
|
@ -649,6 +675,7 @@ pub extern "C" fn main_core0() -> i32 {
|
||||||
&mut timer,
|
&mut timer,
|
||||||
&mut i2c,
|
&mut i2c,
|
||||||
&mut dma_manager,
|
&mut dma_manager,
|
||||||
|
&mut analyzer,
|
||||||
);
|
);
|
||||||
#[allow(unused_mut)]
|
#[allow(unused_mut)]
|
||||||
for mut rep in repeaters.iter_mut() {
|
for mut rep in repeaters.iter_mut() {
|
||||||
|
|
Loading…
Reference in New Issue