forked from M-Labs/nac3
analyzer: implement firmware part
This commit is contained in:
parent
b62fbce826
commit
2e10922715
104
src/runtime/src/analyzer.rs
Normal file
104
src/runtime/src/analyzer.rs
Normal file
@ -0,0 +1,104 @@
|
||||
use libasync::{smoltcp::TcpStream, task};
|
||||
use libboard_zynq::smoltcp::Error;
|
||||
use libcortex_a9::cache;
|
||||
use log::{debug, info, warn};
|
||||
|
||||
use crate::proto_async::*;
|
||||
use crate::pl;
|
||||
|
||||
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() {
|
||||
debug!("arming RTIO analyzer");
|
||||
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;
|
||||
pl::csr::rtio_analyzer::message_encoder_overflow_reset_write(1);
|
||||
pl::csr::rtio_analyzer::dma_base_address_write(base_addr as u32);
|
||||
pl::csr::rtio_analyzer::dma_last_address_write(last_addr as u32);
|
||||
pl::csr::rtio_analyzer::dma_reset_write(1);
|
||||
pl::csr::rtio_analyzer::enable_write(1);
|
||||
}
|
||||
}
|
||||
|
||||
fn disarm() {
|
||||
debug!("disarming RTIO analyzer");
|
||||
unsafe {
|
||||
pl::csr::rtio_analyzer::enable_write(0);
|
||||
while pl::csr::rtio_analyzer::busy_read() != 0 {}
|
||||
cache::dcci_slice(&BUFFER.data);
|
||||
}
|
||||
debug!("RTIO analyzer disarmed");
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Header {
|
||||
sent_bytes: u32,
|
||||
total_byte_count: u64,
|
||||
overflow_occurred: bool,
|
||||
log_channel: u8,
|
||||
dds_onehot_sel: bool
|
||||
}
|
||||
|
||||
async fn write_header(stream: &mut TcpStream, header: &Header) -> Result<(), Error> {
|
||||
write_i32(stream, header.sent_bytes as i32).await?;
|
||||
write_i64(stream, header.total_byte_count as i64).await?;
|
||||
write_i8(stream, header.overflow_occurred as i8).await?;
|
||||
write_i8(stream, header.log_channel as i8).await?;
|
||||
write_i8(stream, header.dds_onehot_sel as i8).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn handle_connection(stream: &mut TcpStream) -> Result<(), Error> {
|
||||
info!("received connection");
|
||||
|
||||
let data = unsafe { &BUFFER.data[..] };
|
||||
let overflow_occurred = unsafe { pl::csr::rtio_analyzer::message_encoder_overflow_read() != 0 };
|
||||
let total_byte_count = unsafe { pl::csr::rtio_analyzer::dma_byte_count_read() as u64 };
|
||||
let pointer = (total_byte_count % BUFFER_SIZE as u64) as usize;
|
||||
let wraparound = total_byte_count >= BUFFER_SIZE as u64;
|
||||
|
||||
let header = Header {
|
||||
total_byte_count: total_byte_count,
|
||||
sent_bytes: if wraparound { BUFFER_SIZE as u32 } else { total_byte_count as u32 },
|
||||
overflow_occurred: overflow_occurred,
|
||||
log_channel: 255,
|
||||
dds_onehot_sel: true // kept for backward compatibility of analyzer dumps
|
||||
};
|
||||
debug!("{:?}", header);
|
||||
debug!("{:?}", &data[..256]);
|
||||
|
||||
write_header(stream, &header).await?;
|
||||
if wraparound {
|
||||
stream.send(data[pointer..].iter().copied()).await?;
|
||||
stream.send(data[..pointer].iter().copied()).await?;
|
||||
} else {
|
||||
stream.send(data[..pointer].iter().copied()).await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn start() {
|
||||
task::spawn(async move {
|
||||
loop {
|
||||
arm();
|
||||
let mut stream = TcpStream::accept(1382, 2048, 2048).await.unwrap();
|
||||
disarm();
|
||||
let _ = handle_connection(&mut stream)
|
||||
.await
|
||||
.map_err(|e| warn!("connection terminated: {:?}", e));
|
||||
let _ = stream.flush().await;
|
||||
let _ = stream.abort().await;
|
||||
}
|
||||
});
|
||||
}
|
@ -28,6 +28,7 @@ use crate::kernel;
|
||||
use crate::rpc;
|
||||
use crate::moninj;
|
||||
use crate::mgmt;
|
||||
use crate::analyzer;
|
||||
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
@ -331,6 +332,10 @@ pub fn main(timer: GlobalTimer, cfg: &config::Config) {
|
||||
|
||||
Sockets::init(32);
|
||||
|
||||
mgmt::start();
|
||||
analyzer::start();
|
||||
moninj::start(timer);
|
||||
|
||||
let control: Rc<RefCell<kernel::Control>> = Rc::new(RefCell::new(kernel::Control::start()));
|
||||
if let Ok(buffer) = cfg.read("startup") {
|
||||
info!("Loading startup kernel...");
|
||||
@ -357,9 +362,6 @@ pub fn main(timer: GlobalTimer, cfg: &config::Config) {
|
||||
}
|
||||
});
|
||||
|
||||
mgmt::start();
|
||||
moninj::start(timer);
|
||||
|
||||
Sockets::run(&mut iface, || {
|
||||
Instant::from_millis(timer.get_time().0 as i32)
|
||||
});
|
||||
|
@ -35,6 +35,7 @@ mod eh_artiq;
|
||||
mod panic;
|
||||
mod logger;
|
||||
mod mgmt;
|
||||
mod analyzer;
|
||||
|
||||
fn init_gateware() {
|
||||
// Set up PS->PL clocks
|
||||
|
Loading…
Reference in New Issue
Block a user