forked from M-Labs/artiq
subkernels: add support for (d)dma
This commit is contained in:
parent
c876acd5a5
commit
c9e3771cd5
|
@ -453,12 +453,39 @@ extern fn dma_playback(timestamp: i64, ptr: i32, _uses_ddma: bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(kernel_has_rtio_dma))]
|
#[cfg(all(not(kernel_has_rtio_dma), not(has_rtio_dma)))]
|
||||||
#[unwind(allowed)]
|
#[unwind(allowed)]
|
||||||
extern fn dma_playback(_timestamp: i64, _ptr: i32, _uses_ddma: bool) {
|
extern fn dma_playback(_timestamp: i64, _ptr: i32, _uses_ddma: bool) {
|
||||||
unimplemented!("not(kernel_has_rtio_dma)")
|
unimplemented!("not(kernel_has_rtio_dma)")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for satellite (has_rtio_dma but not in kernel)
|
||||||
|
#[cfg(all(not(kernel_has_rtio_dma), has_rtio_dma))]
|
||||||
|
#[unwind(allowed)]
|
||||||
|
extern fn dma_playback(timestamp: i64, ptr: i32, _uses_ddma: bool) {
|
||||||
|
// DDMA is always used on satellites, so the `uses_ddma` setting is ignored
|
||||||
|
// StartRemoteRequest reused as "normal" start request
|
||||||
|
send(&DmaStartRemoteRequest { id: ptr as i32, timestamp: timestamp });
|
||||||
|
// skip awaitremoterequest - it's a given
|
||||||
|
recv!(&DmaAwaitRemoteReply { timeout, error, channel, timestamp } => {
|
||||||
|
if timeout {
|
||||||
|
raise!("DMAError",
|
||||||
|
"Error running DMA on satellite device, timed out waiting for results");
|
||||||
|
}
|
||||||
|
if error & 1 != 0 {
|
||||||
|
raise!("RTIOUnderflow",
|
||||||
|
"RTIO underflow at channel {rtio_channel_info:0}, {1} mu",
|
||||||
|
channel as i64, timestamp as i64, 0);
|
||||||
|
}
|
||||||
|
if error & 2 != 0 {
|
||||||
|
raise!("RTIODestinationUnreachable",
|
||||||
|
"RTIO destination unreachable, output, at channel {rtio_channel_info:0}, {1} mu",
|
||||||
|
channel as i64, timestamp as i64, 0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[unwind(allowed)]
|
#[unwind(allowed)]
|
||||||
extern fn subkernel_load_run(id: u32, destination: u8, run: bool) {
|
extern fn subkernel_load_run(id: u32, destination: u8, run: bool) {
|
||||||
send(&SubkernelLoadRunRequest { id: id, destination: destination, run: run });
|
send(&SubkernelLoadRunRequest { id: id, destination: destination, run: run });
|
||||||
|
|
|
@ -113,7 +113,7 @@ pub enum Packet {
|
||||||
id: u32, status: PayloadStatus,
|
id: u32, status: PayloadStatus,
|
||||||
length: u16, trace: [u8; MASTER_PAYLOAD_MAX_SIZE]
|
length: u16, trace: [u8; MASTER_PAYLOAD_MAX_SIZE]
|
||||||
},
|
},
|
||||||
DmaAddTraceReply { destination: u8, succeeded: bool },
|
DmaAddTraceReply { source: u8, destination: u8, id: u32, succeeded: bool },
|
||||||
DmaRemoveTraceRequest { source: u8, destination: u8, id: u32 },
|
DmaRemoveTraceRequest { source: u8, destination: u8, id: u32 },
|
||||||
DmaRemoveTraceReply { destination: u8, succeeded: bool },
|
DmaRemoveTraceReply { destination: u8, succeeded: bool },
|
||||||
DmaPlaybackRequest { source: u8, destination: u8, id: u32, timestamp: u64 },
|
DmaPlaybackRequest { source: u8, destination: u8, id: u32, timestamp: u64 },
|
||||||
|
@ -303,7 +303,9 @@ impl Packet {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
0xb1 => Packet::DmaAddTraceReply {
|
0xb1 => Packet::DmaAddTraceReply {
|
||||||
|
source: reader.read_u8()?,
|
||||||
destination: reader.read_u8()?,
|
destination: reader.read_u8()?,
|
||||||
|
id: reader.read_u32()?,
|
||||||
succeeded: reader.read_bool()?
|
succeeded: reader.read_bool()?
|
||||||
},
|
},
|
||||||
0xb2 => Packet::DmaRemoveTraceRequest {
|
0xb2 => Packet::DmaRemoveTraceRequest {
|
||||||
|
@ -598,9 +600,11 @@ impl Packet {
|
||||||
writer.write_u16(length)?;
|
writer.write_u16(length)?;
|
||||||
writer.write_all(&trace[0..length as usize])?;
|
writer.write_all(&trace[0..length as usize])?;
|
||||||
},
|
},
|
||||||
Packet::DmaAddTraceReply { destination, succeeded } => {
|
Packet::DmaAddTraceReply { source, destination, id, succeeded } => {
|
||||||
writer.write_u8(0xb1)?;
|
writer.write_u8(0xb1)?;
|
||||||
|
writer.write_u8(source)?;
|
||||||
writer.write_u8(destination)?;
|
writer.write_u8(destination)?;
|
||||||
|
writer.write_u32(id)?;
|
||||||
writer.write_bool(succeeded)?;
|
writer.write_bool(succeeded)?;
|
||||||
},
|
},
|
||||||
Packet::DmaRemoveTraceRequest { source, destination, id } => {
|
Packet::DmaRemoveTraceRequest { source, destination, id } => {
|
||||||
|
|
|
@ -167,10 +167,10 @@ pub mod remote_dma {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn playback_done(io: &Io, ddma_mutex: &Mutex,
|
pub fn playback_done(io: &Io, ddma_mutex: &Mutex,
|
||||||
id: u32, destination: u8, error: u8, channel: u32, timestamp: u64) {
|
id: u32, source: u8, error: u8, channel: u32, timestamp: u64) {
|
||||||
// called upon receiving PlaybackDone aux packet
|
// called upon receiving PlaybackDone aux packet
|
||||||
let _lock = ddma_mutex.lock(io).unwrap();
|
let _lock = ddma_mutex.lock(io).unwrap();
|
||||||
let mut trace = unsafe { TRACES.get_mut(&id).unwrap().get_mut(&destination).unwrap() };
|
let mut trace = unsafe { TRACES.get_mut(&id).unwrap().get_mut(&source).unwrap() };
|
||||||
trace.state = RemoteState::PlaybackEnded {
|
trace.state = RemoteState::PlaybackEnded {
|
||||||
error: error,
|
error: error,
|
||||||
channel: channel,
|
channel: channel,
|
||||||
|
|
|
@ -491,8 +491,8 @@ pub mod drtio {
|
||||||
&drtioaux::Packet::DmaAddTraceRequest {
|
&drtioaux::Packet::DmaAddTraceRequest {
|
||||||
id: id, source: 0, destination: destination, status: status, length: len as u16, trace: *slice})?;
|
id: id, source: 0, destination: destination, status: status, length: len as u16, trace: *slice})?;
|
||||||
match reply {
|
match reply {
|
||||||
drtioaux::Packet::DmaAddTraceReply { destination: 0, succeeded: true } => Ok(()),
|
drtioaux::Packet::DmaAddTraceReply { destination: 0, succeeded: true, .. } => Ok(()),
|
||||||
drtioaux::Packet::DmaAddTraceReply { destination: 0, succeeded: false } => Err(Error::DmaAddTraceFail(destination)),
|
drtioaux::Packet::DmaAddTraceReply { destination: 0, succeeded: false, .. } => Err(Error::DmaAddTraceFail(destination)),
|
||||||
packet => Err(Error::UnexpectedPacket(packet)),
|
packet => Err(Error::UnexpectedPacket(packet)),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
|
use alloc::{vec::Vec, collections::btree_map::BTreeMap, string::String};
|
||||||
|
use core::mem;
|
||||||
|
use board_artiq::{drtioaux, drtio_routing::RoutingTable};
|
||||||
use board_misoc::{csr, cache::flush_l2_cache};
|
use board_misoc::{csr, cache::flush_l2_cache};
|
||||||
use proto_artiq::drtioaux_proto::PayloadStatus;
|
use proto_artiq::drtioaux_proto::PayloadStatus;
|
||||||
use alloc::{vec::Vec, collections::btree_map::BTreeMap};
|
use routing::{Router, Sliceable};
|
||||||
use ::{cricon_select, RtioMaster};
|
use kernel::Manager as KernelManager;
|
||||||
|
use ::{cricon_select, RtioMaster, MASTER_PAYLOAD_MAX_SIZE};
|
||||||
|
|
||||||
const ALIGNMENT: usize = 64;
|
const ALIGNMENT: usize = 64;
|
||||||
|
|
||||||
|
@ -19,17 +23,158 @@ pub struct RtioStatus {
|
||||||
pub timestamp: u64
|
pub timestamp: u64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
IdNotFound,
|
IdNotFound,
|
||||||
PlaybackInProgress,
|
PlaybackInProgress,
|
||||||
EntryNotComplete
|
EntryNotComplete,
|
||||||
|
MasterDmaFound,
|
||||||
|
UploadFail,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Entry {
|
struct Entry {
|
||||||
trace: Vec<u8>,
|
trace: Vec<u8>,
|
||||||
padding_len: usize,
|
padding_len: usize,
|
||||||
complete: bool
|
complete: bool,
|
||||||
|
duration: u64, // relevant for locally ran DMA
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Entry {
|
||||||
|
pub fn from_vec(data: Vec<u8>, duration: u64) -> Entry {
|
||||||
|
let mut entry = Entry {
|
||||||
|
trace: data,
|
||||||
|
padding_len: 0,
|
||||||
|
complete: true,
|
||||||
|
duration: duration,
|
||||||
|
};
|
||||||
|
entry.realign();
|
||||||
|
entry
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn id(&self) -> u32 {
|
||||||
|
self.trace[self.padding_len..].as_ptr() as u32
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn realign(&mut self) {
|
||||||
|
self.trace.push(0);
|
||||||
|
let data_len = self.trace.len();
|
||||||
|
|
||||||
|
self.trace.reserve(ALIGNMENT - 1);
|
||||||
|
let padding = ALIGNMENT - self.trace.as_ptr() as usize % ALIGNMENT;
|
||||||
|
let padding = if padding == ALIGNMENT { 0 } else { padding };
|
||||||
|
for _ in 0..padding {
|
||||||
|
// Vec guarantees that this will not reallocate
|
||||||
|
self.trace.push(0)
|
||||||
|
}
|
||||||
|
for i in 1..data_len + 1 {
|
||||||
|
self.trace[data_len + padding - i] = self.trace[data_len - i]
|
||||||
|
}
|
||||||
|
self.complete = true;
|
||||||
|
self.padding_len = padding;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum RemoteTraceState {
|
||||||
|
Unsent,
|
||||||
|
Sending(usize),
|
||||||
|
Ready,
|
||||||
|
Running(usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct RemoteTraces {
|
||||||
|
remote_traces: BTreeMap<u8, Sliceable>,
|
||||||
|
state: RemoteTraceState,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RemoteTraces {
|
||||||
|
pub fn new(traces: BTreeMap<u8, Sliceable>) -> RemoteTraces {
|
||||||
|
RemoteTraces {
|
||||||
|
remote_traces: traces,
|
||||||
|
state: RemoteTraceState::Unsent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// on subkernel request
|
||||||
|
pub fn upload_traces(&mut self, id: u32, router: &mut Router, rank: u8, self_destination: u8, routing_table: &RoutingTable) -> usize {
|
||||||
|
let len = self.remote_traces.len();
|
||||||
|
if len > 0 {
|
||||||
|
self.state = RemoteTraceState::Sending(self.remote_traces.len());
|
||||||
|
for (dest, trace) in self.remote_traces.iter_mut() {
|
||||||
|
// queue up the first packet for all destinations, rest will be sent after first ACK
|
||||||
|
let mut data_slice: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
|
||||||
|
let meta = trace.get_slice_master(&mut data_slice);
|
||||||
|
router.route(drtioaux::Packet::DmaAddTraceRequest {
|
||||||
|
source: self_destination, destination: *dest, id: id,
|
||||||
|
status: meta.status, length: meta.len, trace: data_slice
|
||||||
|
}, routing_table, rank, self_destination);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
len
|
||||||
|
}
|
||||||
|
|
||||||
|
// on incoming Packet::DmaAddTraceReply
|
||||||
|
pub fn ack_upload(&mut self, kernel_manager: &mut KernelManager, source: u8, id: u32, succeeded: bool, router: &mut Router, rank: u8, self_destination: u8, routing_table: &RoutingTable) {
|
||||||
|
if let RemoteTraceState::Sending(count) = self.state {
|
||||||
|
if let Some(trace) = self.remote_traces.get_mut(&source) {
|
||||||
|
if trace.at_end() {
|
||||||
|
if count - 1 == 0 {
|
||||||
|
self.state = RemoteTraceState::Ready;
|
||||||
|
kernel_manager.ddma_remote_uploaded(succeeded);
|
||||||
|
} else {
|
||||||
|
self.state = RemoteTraceState::Sending(count - 1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// send next slice
|
||||||
|
let mut data_slice: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
|
||||||
|
let meta = trace.get_slice_master(&mut data_slice);
|
||||||
|
router.route(drtioaux::Packet::DmaAddTraceRequest {
|
||||||
|
source: self_destination, destination: meta.destination, id: id,
|
||||||
|
status: meta.status, length: meta.len, trace: data_slice
|
||||||
|
}, routing_table, rank, self_destination);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// on subkernel request
|
||||||
|
pub fn playback(&mut self, id: u32, timestamp: u64, router: &mut Router, rank: u8, self_destination: u8, routing_table: &RoutingTable) {
|
||||||
|
// route all the playback requests
|
||||||
|
// remote traces + local trace
|
||||||
|
self.state = RemoteTraceState::Running(self.remote_traces.len() + 1);
|
||||||
|
for (dest, _) in self.remote_traces.iter() {
|
||||||
|
router.route(drtioaux::Packet::DmaPlaybackRequest {
|
||||||
|
source: self_destination, destination: *dest, id: id, timestamp: timestamp
|
||||||
|
}, routing_table, rank, self_destination);
|
||||||
|
// response will be ignored (succeeded = false handled by the main thread)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// on incoming Packet::DmaPlaybackDone
|
||||||
|
pub fn remote_finished(&mut self, kernel_manager: &mut KernelManager, error: u8, channel: u32, timestamp: u64) {
|
||||||
|
if let RemoteTraceState::Running(count) = self.state {
|
||||||
|
if error != 0 || count - 1 == 0 {
|
||||||
|
// notify the kernel about a DDMA error or finish
|
||||||
|
kernel_manager.ddma_finished(error, channel, timestamp);
|
||||||
|
self.state = RemoteTraceState::Ready;
|
||||||
|
// further messages will be ignored (if there was an error)
|
||||||
|
} else { // no error and not the last one awaited
|
||||||
|
self.state = RemoteTraceState::Running(count - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn erase(&mut self, id: u32, router: &mut Router, rank: u8, self_destination: u8, routing_table: &RoutingTable) {
|
||||||
|
for (dest, _) in self.remote_traces.iter() {
|
||||||
|
router.route(drtioaux::Packet::DmaRemoveTraceRequest {
|
||||||
|
source: self_destination, destination: *dest, id: id
|
||||||
|
}, routing_table, rank, self_destination);
|
||||||
|
// response will be ignored as this object will stop existing too
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -37,7 +182,12 @@ pub struct Manager {
|
||||||
entries: BTreeMap<(u8, u32), Entry>,
|
entries: BTreeMap<(u8, u32), Entry>,
|
||||||
state: ManagerState,
|
state: ManagerState,
|
||||||
current_id: u32,
|
current_id: u32,
|
||||||
current_source: u8
|
current_source: u8,
|
||||||
|
|
||||||
|
remote_entries: BTreeMap<u32, RemoteTraces>,
|
||||||
|
name_map: BTreeMap<String, u32>,
|
||||||
|
recording_trace: Vec<u8>,
|
||||||
|
recording_name: String
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Manager {
|
impl Manager {
|
||||||
|
@ -52,6 +202,10 @@ impl Manager {
|
||||||
current_id: 0,
|
current_id: 0,
|
||||||
current_source: 0,
|
current_source: 0,
|
||||||
state: ManagerState::Idle,
|
state: ManagerState::Idle,
|
||||||
|
remote_entries: BTreeMap::new(),
|
||||||
|
name_map: BTreeMap::new(),
|
||||||
|
recording_trace: Vec::new(),
|
||||||
|
recording_name: String::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +221,9 @@ impl Manager {
|
||||||
self.entries.insert((source, id), Entry {
|
self.entries.insert((source, id), Entry {
|
||||||
trace: Vec::new(),
|
trace: Vec::new(),
|
||||||
padding_len: 0,
|
padding_len: 0,
|
||||||
complete: false });
|
complete: false,
|
||||||
|
duration: 0
|
||||||
|
});
|
||||||
self.entries.get_mut(&(source, id)).unwrap()
|
self.entries.get_mut(&(source, id)).unwrap()
|
||||||
} else {
|
} else {
|
||||||
entry
|
entry
|
||||||
|
@ -77,34 +233,122 @@ impl Manager {
|
||||||
self.entries.insert((source, id), Entry {
|
self.entries.insert((source, id), Entry {
|
||||||
trace: Vec::new(),
|
trace: Vec::new(),
|
||||||
padding_len: 0,
|
padding_len: 0,
|
||||||
complete: false });
|
complete: false,
|
||||||
|
duration: 0,
|
||||||
|
});
|
||||||
self.entries.get_mut(&(source, id)).unwrap()
|
self.entries.get_mut(&(source, id)).unwrap()
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
entry.trace.extend(&trace[0..trace_len]);
|
entry.trace.extend(&trace[0..trace_len]);
|
||||||
|
|
||||||
if status.is_last() {
|
if status.is_last() {
|
||||||
entry.trace.push(0);
|
entry.realign();
|
||||||
let data_len = entry.trace.len();
|
|
||||||
|
|
||||||
// Realign.
|
|
||||||
entry.trace.reserve(ALIGNMENT - 1);
|
|
||||||
let padding = ALIGNMENT - entry.trace.as_ptr() as usize % ALIGNMENT;
|
|
||||||
let padding = if padding == ALIGNMENT { 0 } else { padding };
|
|
||||||
for _ in 0..padding {
|
|
||||||
// Vec guarantees that this will not reallocate
|
|
||||||
entry.trace.push(0)
|
|
||||||
}
|
|
||||||
for i in 1..data_len + 1 {
|
|
||||||
entry.trace[data_len + padding - i] = entry.trace[data_len - i]
|
|
||||||
}
|
|
||||||
entry.complete = true;
|
|
||||||
entry.padding_len = padding;
|
|
||||||
flush_l2_cache();
|
flush_l2_cache();
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
// API for subkernel
|
||||||
|
pub fn record_start(&mut self, name: &str) {
|
||||||
|
self.recording_name = String::from(name);
|
||||||
|
self.recording_trace = Vec::new();
|
||||||
|
}
|
||||||
|
|
||||||
|
// API for subkernel
|
||||||
|
pub fn record_append(&mut self, data: &[u8]) {
|
||||||
|
self.recording_trace.extend_from_slice(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// API for subkernel
|
||||||
|
pub fn record_stop(&mut self, duration: u64, self_destination: u8) -> Result<u32, Error> {
|
||||||
|
let mut trace = Vec::new();
|
||||||
|
mem::swap(&mut self.recording_trace, &mut trace);
|
||||||
|
trace.push(0);
|
||||||
|
let mut local_trace = Vec::new();
|
||||||
|
let mut remote_traces: BTreeMap<u8, Sliceable> = BTreeMap::new();
|
||||||
|
// analyze each entry and put in proper buckets, as the kernel core
|
||||||
|
// sends whole chunks, to limit comms/kernel CPU communication,
|
||||||
|
// and as only comms core has access to varios DMA buffers.
|
||||||
|
let mut ptr = 0;
|
||||||
|
while trace[ptr] != 0 {
|
||||||
|
// ptr + 3 = tgt >> 24 (destination)
|
||||||
|
let len = trace[ptr] as usize;
|
||||||
|
let destination = trace[ptr+3];
|
||||||
|
if destination == 0 {
|
||||||
|
return Err(Error::MasterDmaFound);
|
||||||
|
} else if destination == self_destination {
|
||||||
|
local_trace.extend(&trace[ptr..ptr+len]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if let Some(remote_trace) = remote_traces.get_mut(&destination) {
|
||||||
|
remote_trace.extend(&trace[ptr..ptr+len]);
|
||||||
|
} else {
|
||||||
|
remote_traces.insert(destination, Sliceable::new(destination, trace[ptr..ptr+len].to_vec()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// and jump to the next event
|
||||||
|
ptr += len;
|
||||||
|
}
|
||||||
|
let local_entry = Entry::from_vec(local_trace, duration);
|
||||||
|
let id = local_entry.id();
|
||||||
|
|
||||||
|
self.entries.insert((self_destination, id), local_entry);
|
||||||
|
self.remote_entries.insert(id, RemoteTraces::new(remote_traces));
|
||||||
|
let mut name = String::new();
|
||||||
|
mem::swap(&mut self.recording_name, &mut name);
|
||||||
|
self.name_map.insert(name, id);
|
||||||
|
|
||||||
|
flush_l2_cache();
|
||||||
|
|
||||||
|
Ok(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn upload_traces(&mut self, id: u32, router: &mut Router, rank: u8, self_destination: u8,
|
||||||
|
routing_table: &RoutingTable) -> Result<usize, Error> {
|
||||||
|
let remote_traces = self.remote_entries.get_mut(&id);
|
||||||
|
let mut len = 0;
|
||||||
|
if let Some(traces) = remote_traces {
|
||||||
|
len = traces.upload_traces(id, router, rank, self_destination, routing_table);
|
||||||
|
}
|
||||||
|
Ok(len)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_trace<F, R>(&self, self_destination: u8, name: &str, f: F) -> R
|
||||||
|
where F: FnOnce(Option<&[u8]>, u64) -> R {
|
||||||
|
if let Some(ptr) = self.name_map.get(name) {
|
||||||
|
match self.entries.get(&(self_destination, *ptr)) {
|
||||||
|
Some(entry) => f(Some(&entry.trace[entry.padding_len..]), entry.duration),
|
||||||
|
None => f(None, 0)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
f(None, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// API for subkernel
|
||||||
|
pub fn playback_remote(&mut self, id: u32, timestamp: u64,
|
||||||
|
router: &mut Router, rank: u8, self_destination: u8, routing_table: &RoutingTable
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
if let Some(traces) = self.remote_entries.get_mut(&id) {
|
||||||
|
traces.playback(id, timestamp, router, rank, self_destination, routing_table);
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(Error::IdNotFound)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// API for subkernel
|
||||||
|
pub fn erase_name(&mut self, name: &str, router: &mut Router, rank: u8, self_destination: u8, routing_table: &RoutingTable) {
|
||||||
|
if let Some(id) = self.name_map.get(name) {
|
||||||
|
if let Some(traces) = self.remote_entries.get_mut(&id) {
|
||||||
|
traces.erase(*id, router, rank, self_destination, routing_table);
|
||||||
|
self.remote_entries.remove(&id);
|
||||||
|
}
|
||||||
|
self.entries.remove(&(self_destination, *id));
|
||||||
|
self.name_map.remove(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// API for incoming DDMA (drtio)
|
||||||
pub fn erase(&mut self, source: u8, id: u32) -> Result<(), Error> {
|
pub fn erase(&mut self, source: u8, id: u32) -> Result<(), Error> {
|
||||||
match self.entries.remove(&(source, id)) {
|
match self.entries.remove(&(source, id)) {
|
||||||
Some(_) => Ok(()),
|
Some(_) => Ok(()),
|
||||||
|
@ -112,6 +356,33 @@ impl Manager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn remote_finished(&mut self, kernel_manager: &mut KernelManager,
|
||||||
|
id: u32, error: u8, channel: u32, timestamp: u64) {
|
||||||
|
if let Some(entry) = self.remote_entries.get_mut(&id) {
|
||||||
|
entry.remote_finished(kernel_manager, error, channel, timestamp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ack_upload(&mut self, kernel_manager: &mut KernelManager, source: u8, id: u32, succeeded: bool,
|
||||||
|
router: &mut Router, rank: u8, self_destination: u8, routing_table: &RoutingTable) {
|
||||||
|
if let Some(entry) = self.remote_entries.get_mut(&id) {
|
||||||
|
entry.ack_upload(kernel_manager, source, id, succeeded, router, rank, self_destination, routing_table);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cleanup(&mut self, router: &mut Router, rank: u8, self_destination: u8, routing_table: &RoutingTable) {
|
||||||
|
// after subkernel ends, remove all self-generated traces
|
||||||
|
for (_, id) in self.name_map.iter_mut() {
|
||||||
|
if let Some(traces) = self.remote_entries.get_mut(&id) {
|
||||||
|
traces.erase(*id, router, rank, self_destination, routing_table);
|
||||||
|
self.remote_entries.remove(&id);
|
||||||
|
}
|
||||||
|
self.entries.remove(&(self_destination, *id));
|
||||||
|
}
|
||||||
|
self.name_map.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// API for both incoming DDMA (drtio) and subkernel
|
||||||
pub fn playback(&mut self, source: u8, id: u32, timestamp: u64) -> Result<(), Error> {
|
pub fn playback(&mut self, source: u8, id: u32, timestamp: u64) -> Result<(), Error> {
|
||||||
if self.state != ManagerState::Idle {
|
if self.state != ManagerState::Idle {
|
||||||
return Err(Error::PlaybackInProgress);
|
return Err(Error::PlaybackInProgress);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use core::{mem, option::NoneError, cmp::min};
|
use core::{mem, option::NoneError};
|
||||||
use alloc::{string::String, format, vec::Vec, collections::{btree_map::BTreeMap, vec_deque::VecDeque}};
|
use alloc::{string::String, format, vec::Vec, collections::{btree_map::BTreeMap, vec_deque::VecDeque}};
|
||||||
use cslice::AsCSlice;
|
use cslice::AsCSlice;
|
||||||
|
|
||||||
|
@ -15,7 +15,8 @@ use kernel::eh_artiq::StackPointerBacktrace;
|
||||||
|
|
||||||
use ::{cricon_select, RtioMaster};
|
use ::{cricon_select, RtioMaster};
|
||||||
use cache::Cache;
|
use cache::Cache;
|
||||||
use routing::Router;
|
use dma::{Manager as DmaManager, Error as DmaError};
|
||||||
|
use routing::{Router, Sliceable, SliceMeta};
|
||||||
use SAT_PAYLOAD_MAX_SIZE;
|
use SAT_PAYLOAD_MAX_SIZE;
|
||||||
use MASTER_PAYLOAD_MAX_SIZE;
|
use MASTER_PAYLOAD_MAX_SIZE;
|
||||||
|
|
||||||
|
@ -65,7 +66,9 @@ enum KernelState {
|
||||||
MsgAwait { max_time: u64, tags: Vec<u8> },
|
MsgAwait { max_time: u64, tags: Vec<u8> },
|
||||||
MsgSending,
|
MsgSending,
|
||||||
SubkernelAwaitLoad,
|
SubkernelAwaitLoad,
|
||||||
SubkernelAwaitFinish { max_time: u64, id: u32 }
|
SubkernelAwaitFinish { max_time: u64, id: u32 },
|
||||||
|
DmaUploading { max_time: u64 },
|
||||||
|
DmaAwait { max_time: u64 },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -78,7 +81,8 @@ pub enum Error {
|
||||||
AwaitingMessage,
|
AwaitingMessage,
|
||||||
SubkernelIoError,
|
SubkernelIoError,
|
||||||
DrtioError,
|
DrtioError,
|
||||||
KernelException(Sliceable)
|
KernelException(Sliceable),
|
||||||
|
DmaError(DmaError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<NoneError> for Error {
|
impl From<NoneError> for Error {
|
||||||
|
@ -99,16 +103,14 @@ impl From<drtioaux::Error<!>> for Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! unexpected {
|
impl From<DmaError> for Error {
|
||||||
($($arg:tt)*) => (return Err(Error::Unexpected(format!($($arg)*))));
|
fn from(value: DmaError) -> Error {
|
||||||
|
Error::DmaError(value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* represents data that has to be sent to Master */
|
macro_rules! unexpected {
|
||||||
#[derive(Debug)]
|
($($arg:tt)*) => (return Err(Error::Unexpected(format!($($arg)*))));
|
||||||
pub struct Sliceable {
|
|
||||||
it: usize,
|
|
||||||
data: Vec<u8>,
|
|
||||||
destination: u8
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* represents interkernel messages */
|
/* represents interkernel messages */
|
||||||
|
@ -164,44 +166,6 @@ pub struct SubkernelFinished {
|
||||||
pub source: u8
|
pub source: u8
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SliceMeta {
|
|
||||||
pub destination: u8,
|
|
||||||
pub len: u16,
|
|
||||||
pub status: PayloadStatus
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! get_slice_fn {
|
|
||||||
( $name:tt, $size:expr ) => {
|
|
||||||
pub fn $name(&mut self, data_slice: &mut [u8; $size]) -> SliceMeta {
|
|
||||||
let first = self.it == 0;
|
|
||||||
let len = min($size, self.data.len() - self.it);
|
|
||||||
let last = self.it + len == self.data.len();
|
|
||||||
let status = PayloadStatus::from_status(first, last);
|
|
||||||
data_slice[..len].clone_from_slice(&self.data[self.it..self.it+len]);
|
|
||||||
self.it += len;
|
|
||||||
|
|
||||||
SliceMeta {
|
|
||||||
destination: self.destination,
|
|
||||||
len: len as u16,
|
|
||||||
status: status
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Sliceable {
|
|
||||||
pub fn new(destination: u8, data: Vec<u8>) -> Sliceable {
|
|
||||||
Sliceable {
|
|
||||||
it: 0,
|
|
||||||
data: data,
|
|
||||||
destination: destination
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get_slice_fn!(get_slice_sat, SAT_PAYLOAD_MAX_SIZE);
|
|
||||||
get_slice_fn!(get_slice_master, MASTER_PAYLOAD_MAX_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MessageManager {
|
impl MessageManager {
|
||||||
pub fn new() -> MessageManager {
|
pub fn new() -> MessageManager {
|
||||||
MessageManager {
|
MessageManager {
|
||||||
|
@ -313,9 +277,7 @@ impl Session {
|
||||||
fn running(&self) -> bool {
|
fn running(&self) -> bool {
|
||||||
match self.kernel_state {
|
match self.kernel_state {
|
||||||
KernelState::Absent | KernelState::Loaded => false,
|
KernelState::Absent | KernelState::Loaded => false,
|
||||||
KernelState::Running | KernelState::MsgAwait { .. } |
|
_ => true
|
||||||
KernelState::MsgSending | KernelState::SubkernelAwaitLoad |
|
|
||||||
KernelState::SubkernelAwaitFinish { .. } => true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -490,7 +452,39 @@ impl Manager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_kern_requests(&mut self, router: &mut Router, routing_table: &RoutingTable, rank: u8, destination: u8) {
|
pub fn ddma_finished(&mut self, error: u8, channel: u32, timestamp: u64) {
|
||||||
|
if let KernelState::DmaAwait { .. } = self.session.kernel_state {
|
||||||
|
kern_send(&kern::DmaAwaitRemoteReply {
|
||||||
|
timeout: false, error: error, channel: channel, timestamp: timestamp
|
||||||
|
}).unwrap();
|
||||||
|
self.session.kernel_state = KernelState::Running;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ddma_nack(&mut self) {
|
||||||
|
// for simplicity treat it as a timeout for now...
|
||||||
|
if let KernelState::DmaAwait { .. } = self.session.kernel_state {
|
||||||
|
kern_send(&kern::DmaAwaitRemoteReply {
|
||||||
|
timeout: true, error: 0, channel: 0, timestamp: 0
|
||||||
|
}).unwrap();
|
||||||
|
self.session.kernel_state = KernelState::Running;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ddma_remote_uploaded(&mut self, succeeded: bool) {
|
||||||
|
if let KernelState::DmaUploading { .. } = self.session.kernel_state {
|
||||||
|
if succeeded {
|
||||||
|
self.session.kernel_state = KernelState::Running;
|
||||||
|
kern_acknowledge().unwrap();
|
||||||
|
} else {
|
||||||
|
self.stop();
|
||||||
|
self.runtime_exception(Error::DmaError(DmaError::UploadFail));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn process_kern_requests(&mut self, router: &mut Router, routing_table: &RoutingTable, rank: u8, destination: u8, dma_manager: &mut DmaManager) {
|
||||||
macro_rules! finished {
|
macro_rules! finished {
|
||||||
($with_exception:expr) => {{ Some(SubkernelFinished {
|
($with_exception:expr) => {{ Some(SubkernelFinished {
|
||||||
source: self.session.source, id: self.current_id,
|
source: self.session.source, id: self.current_id,
|
||||||
|
@ -504,6 +498,7 @@ impl Manager {
|
||||||
destination: subkernel_finished.source, id: subkernel_finished.id,
|
destination: subkernel_finished.source, id: subkernel_finished.id,
|
||||||
with_exception: subkernel_finished.with_exception, exception_src: subkernel_finished.exception_source
|
with_exception: subkernel_finished.with_exception, exception_src: subkernel_finished.exception_source
|
||||||
}, &routing_table, rank, destination);
|
}, &routing_table, rank, destination);
|
||||||
|
dma_manager.cleanup(router, rank, destination, routing_table);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.is_running() {
|
if !self.is_running() {
|
||||||
|
@ -528,7 +523,7 @@ impl Manager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.process_kern_message(router, routing_table, rank, destination) {
|
match self.process_kern_message(router, routing_table, rank, destination, dma_manager) {
|
||||||
Ok(Some(with_exception)) => {
|
Ok(Some(with_exception)) => {
|
||||||
self.last_finished = finished!(with_exception)
|
self.last_finished = finished!(with_exception)
|
||||||
},
|
},
|
||||||
|
@ -585,6 +580,20 @@ impl Manager {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
KernelState::DmaAwait { max_time } => {
|
||||||
|
if clock::get_ms() > *max_time {
|
||||||
|
kern_send(&kern::DmaAwaitRemoteReply { timeout: true, error: 0, channel: 0, timestamp: 0 })?;
|
||||||
|
self.session.kernel_state = KernelState::Running;
|
||||||
|
}
|
||||||
|
// ddma_finished() and nack() covers the other case
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
KernelState::DmaUploading { max_time } => {
|
||||||
|
if clock::get_ms() > *max_time {
|
||||||
|
unexpected!("DMAError: Timed out sending traces to remote");
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
_ => Ok(())
|
_ => Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -622,13 +631,19 @@ impl Manager {
|
||||||
|
|
||||||
fn process_kern_message(&mut self, router: &mut Router,
|
fn process_kern_message(&mut self, router: &mut Router,
|
||||||
routing_table: &RoutingTable,
|
routing_table: &RoutingTable,
|
||||||
rank: u8, destination: u8
|
rank: u8, destination: u8,
|
||||||
|
dma_manager: &mut DmaManager
|
||||||
) -> Result<Option<bool>, Error> {
|
) -> Result<Option<bool>, Error> {
|
||||||
// returns Ok(with_exception) on finish
|
// returns Ok(with_exception) on finish
|
||||||
// None if the kernel is still running
|
// None if the kernel is still running
|
||||||
kern_recv(|request| {
|
kern_recv(|request| {
|
||||||
match (request, &self.session.kernel_state) {
|
match (request, &self.session.kernel_state) {
|
||||||
(&kern::LoadReply(_), KernelState::Loaded) => {
|
(&kern::LoadReply(_), KernelState::Loaded) |
|
||||||
|
(_, KernelState::DmaUploading { .. }) |
|
||||||
|
(_, KernelState::DmaAwait { .. }) |
|
||||||
|
(_, KernelState::MsgSending) |
|
||||||
|
(_, KernelState::SubkernelAwaitLoad) |
|
||||||
|
(_, KernelState::SubkernelAwaitFinish { .. }) => {
|
||||||
// We're standing by; ignore the message.
|
// We're standing by; ignore the message.
|
||||||
return Ok(None)
|
return Ok(None)
|
||||||
}
|
}
|
||||||
|
@ -693,6 +708,50 @@ impl Manager {
|
||||||
return Ok(Some(true))
|
return Ok(Some(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&kern::DmaRecordStart(name) => {
|
||||||
|
dma_manager.record_start(name);
|
||||||
|
kern_acknowledge()
|
||||||
|
}
|
||||||
|
&kern::DmaRecordAppend(data) => {
|
||||||
|
dma_manager.record_append(data);
|
||||||
|
kern_acknowledge()
|
||||||
|
}
|
||||||
|
&kern::DmaRecordStop { duration, enable_ddma: _ } => {
|
||||||
|
// ddma is always used on satellites
|
||||||
|
if let Ok(id) = dma_manager.record_stop(duration, destination) {
|
||||||
|
let remote_count = dma_manager.upload_traces(id, router, rank, destination, routing_table)?;
|
||||||
|
if remote_count > 0 {
|
||||||
|
let max_time = clock::get_ms() + 10_000 as u64;
|
||||||
|
self.session.kernel_state = KernelState::DmaUploading { max_time: max_time };
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
kern_acknowledge()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unexpected!("DMAError: found an unsupported call to RTIO devices on master")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&kern::DmaEraseRequest { name } => {
|
||||||
|
dma_manager.erase_name(name, router, rank, destination, routing_table);
|
||||||
|
kern_acknowledge()
|
||||||
|
}
|
||||||
|
&kern::DmaRetrieveRequest { name } => {
|
||||||
|
dma_manager.with_trace(destination, name, |trace, duration| {
|
||||||
|
kern_send(&kern::DmaRetrieveReply {
|
||||||
|
trace: trace,
|
||||||
|
duration: duration,
|
||||||
|
uses_ddma: true,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
&kern::DmaStartRemoteRequest { id, timestamp } => {
|
||||||
|
let max_time = clock::get_ms() + 10_000 as u64;
|
||||||
|
self.session.kernel_state = KernelState::DmaAwait { max_time: max_time };
|
||||||
|
dma_manager.playback_remote(id as u32, timestamp as u64, router, rank, destination, routing_table)?;
|
||||||
|
dma_manager.playback(destination, id as u32, timestamp as u64)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
&kern::SubkernelMsgSend { id: _, destination: msg_dest, count, tag, data } => {
|
&kern::SubkernelMsgSend { id: _, destination: msg_dest, count, tag, data } => {
|
||||||
let dest = match msg_dest {
|
let dest = match msg_dest {
|
||||||
Some(dest) => dest,
|
Some(dest) => dest,
|
||||||
|
@ -717,13 +776,13 @@ impl Manager {
|
||||||
router.route(drtioaux::Packet::SubkernelLoadRunRequest {
|
router.route(drtioaux::Packet::SubkernelLoadRunRequest {
|
||||||
source: destination, destination: sk_destination, id: id, run: run
|
source: destination, destination: sk_destination, id: id, run: run
|
||||||
}, routing_table, rank, destination);
|
}, routing_table, rank, destination);
|
||||||
kern_acknowledge()
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
&kern::SubkernelAwaitFinishRequest{ id, timeout } => {
|
&kern::SubkernelAwaitFinishRequest{ id, timeout } => {
|
||||||
let max_time = clock::get_ms() + timeout as u64;
|
let max_time = clock::get_ms() + timeout as u64;
|
||||||
self.session.kernel_state = KernelState::SubkernelAwaitFinish { max_time: max_time, id: id };
|
self.session.kernel_state = KernelState::SubkernelAwaitFinish { max_time: max_time, id: id };
|
||||||
kern_acknowledge()
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
request => unexpected!("unexpected request {:?} from kernel CPU", request)
|
request => unexpected!("unexpected request {:?} from kernel CPU", request)
|
||||||
|
|
|
@ -377,9 +377,14 @@ fn process_aux_packet(dmamgr: &mut DmaManager, analyzer: &mut Analyzer, kernelmg
|
||||||
*self_destination = destination;
|
*self_destination = destination;
|
||||||
let succeeded = dmamgr.add(source, id, status, &trace, length as usize).is_ok();
|
let succeeded = dmamgr.add(source, id, status, &trace, length as usize).is_ok();
|
||||||
router.send(drtioaux::Packet::DmaAddTraceReply {
|
router.send(drtioaux::Packet::DmaAddTraceReply {
|
||||||
destination: source, succeeded: succeeded
|
source: *self_destination, destination: source, id: id, succeeded: succeeded
|
||||||
}, _routing_table, *rank, *self_destination)
|
}, _routing_table, *rank, *self_destination)
|
||||||
}
|
}
|
||||||
|
drtioaux::Packet::DmaAddTraceReply { source, destination: _destination, id, succeeded } => {
|
||||||
|
forward!(_routing_table, _destination, *rank, _repeaters, &packet);
|
||||||
|
dmamgr.ack_upload(kernelmgr, source, id, succeeded, router, *rank, *self_destination, _routing_table);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
drtioaux::Packet::DmaRemoveTraceRequest { source, destination: _destination, id } => {
|
drtioaux::Packet::DmaRemoveTraceRequest { source, destination: _destination, id } => {
|
||||||
forward!(_routing_table, _destination, *rank, _repeaters, &packet);
|
forward!(_routing_table, _destination, *rank, _repeaters, &packet);
|
||||||
let succeeded = dmamgr.erase(source, id).is_ok();
|
let succeeded = dmamgr.erase(source, id).is_ok();
|
||||||
|
@ -395,6 +400,18 @@ fn process_aux_packet(dmamgr: &mut DmaManager, analyzer: &mut Analyzer, kernelmg
|
||||||
destination: source, succeeded: succeeded
|
destination: source, succeeded: succeeded
|
||||||
}, _routing_table, *rank, *self_destination)
|
}, _routing_table, *rank, *self_destination)
|
||||||
}
|
}
|
||||||
|
drtioaux::Packet::DmaPlaybackReply { destination: _destination, succeeded } => {
|
||||||
|
forward!(_routing_table, _destination, *rank, _repeaters, &packet);
|
||||||
|
if !succeeded {
|
||||||
|
kernelmgr.ddma_nack();
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
drtioaux::Packet::DmaPlaybackStatus { source: _, destination: _destination, id, error, channel, timestamp } => {
|
||||||
|
forward!(_routing_table, _destination, *rank, _repeaters, &packet);
|
||||||
|
dmamgr.remote_finished(kernelmgr, id, error, channel, timestamp);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
drtioaux::Packet::SubkernelAddDataRequest { destination, id, status, length, data } => {
|
drtioaux::Packet::SubkernelAddDataRequest { destination, id, status, length, data } => {
|
||||||
forward!(_routing_table, destination, *rank, _repeaters, &packet);
|
forward!(_routing_table, destination, *rank, _repeaters, &packet);
|
||||||
|
@ -426,7 +443,6 @@ fn process_aux_packet(dmamgr: &mut DmaManager, analyzer: &mut Analyzer, kernelmg
|
||||||
kernelmgr.subkernel_load_run_reply(succeeded, *self_destination);
|
kernelmgr.subkernel_load_run_reply(succeeded, *self_destination);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
// { destination: u8, id: u32, with_exception: bool, exception_src: u8 },
|
|
||||||
drtioaux::Packet::SubkernelFinished { destination: _destination, id, with_exception, exception_src } => {
|
drtioaux::Packet::SubkernelFinished { destination: _destination, id, with_exception, exception_src } => {
|
||||||
forward!(_routing_table, _destination, *rank, _repeaters, &packet);
|
forward!(_routing_table, _destination, *rank, _repeaters, &packet);
|
||||||
kernelmgr.remote_subkernel_finished(id, with_exception, exception_src);
|
kernelmgr.remote_subkernel_finished(id, with_exception, exception_src);
|
||||||
|
@ -772,7 +788,7 @@ pub extern fn main() -> i32 {
|
||||||
}, &routing_table, rank, destination);
|
}, &routing_table, rank, destination);
|
||||||
}
|
}
|
||||||
|
|
||||||
kernelmgr.process_kern_requests(&mut router, &routing_table, rank, destination);
|
kernelmgr.process_kern_requests(&mut router, &routing_table, rank, destination, &mut dma_manager);
|
||||||
|
|
||||||
if let Some((repno, packet)) = router.get_downstream_packet() {
|
if let Some((repno, packet)) = router.get_downstream_packet() {
|
||||||
if let Err(e) = repeaters[repno].aux_send(&packet) {
|
if let Err(e) = repeaters[repno].aux_send(&packet) {
|
||||||
|
|
|
@ -1,6 +1,64 @@
|
||||||
use alloc::collections::vec_deque::VecDeque;
|
use alloc::{vec::Vec, collections::vec_deque::VecDeque};
|
||||||
use board_artiq::{drtioaux, drtio_routing};
|
use board_artiq::{drtioaux, drtio_routing};
|
||||||
use board_misoc::csr;
|
use board_misoc::csr;
|
||||||
|
use core::cmp::min;
|
||||||
|
use proto_artiq::drtioaux_proto::PayloadStatus;
|
||||||
|
use SAT_PAYLOAD_MAX_SIZE;
|
||||||
|
use MASTER_PAYLOAD_MAX_SIZE;
|
||||||
|
|
||||||
|
/* represents data that has to be sent with the aux protocol */
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Sliceable {
|
||||||
|
it: usize,
|
||||||
|
data: Vec<u8>,
|
||||||
|
destination: u8
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SliceMeta {
|
||||||
|
pub destination: u8,
|
||||||
|
pub len: u16,
|
||||||
|
pub status: PayloadStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! get_slice_fn {
|
||||||
|
( $name:tt, $size:expr ) => {
|
||||||
|
pub fn $name(&mut self, data_slice: &mut [u8; $size]) -> SliceMeta {
|
||||||
|
let first = self.it == 0;
|
||||||
|
let len = min($size, self.data.len() - self.it);
|
||||||
|
let last = self.it + len == self.data.len();
|
||||||
|
let status = PayloadStatus::from_status(first, last);
|
||||||
|
data_slice[..len].clone_from_slice(&self.data[self.it..self.it+len]);
|
||||||
|
self.it += len;
|
||||||
|
|
||||||
|
SliceMeta {
|
||||||
|
destination: self.destination,
|
||||||
|
len: len as u16,
|
||||||
|
status: status
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sliceable {
|
||||||
|
pub fn new(destination: u8, data: Vec<u8>) -> Sliceable {
|
||||||
|
Sliceable {
|
||||||
|
it: 0,
|
||||||
|
data: data,
|
||||||
|
destination: destination
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn at_end(&self) -> bool {
|
||||||
|
self.it == self.data.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn extend(&mut self, data: &[u8]) {
|
||||||
|
self.data.extend(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
get_slice_fn!(get_slice_sat, SAT_PAYLOAD_MAX_SIZE);
|
||||||
|
get_slice_fn!(get_slice_master, MASTER_PAYLOAD_MAX_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
// Packets from downstream (further satellites) are received and routed appropriately.
|
// Packets from downstream (further satellites) are received and routed appropriately.
|
||||||
// they're passed as soon as possible downstream (within the subtree), or sent upstream,
|
// they're passed as soon as possible downstream (within the subtree), or sent upstream,
|
||||||
|
|
Loading…
Reference in New Issue