forked from M-Labs/nac3
move kernel-related code to separate library
This commit is contained in:
parent
c696fd826f
commit
6885c618b5
|
@ -218,6 +218,33 @@ dependencies = [
|
||||||
"libsupport_zynq",
|
"libsupport_zynq",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "kernel"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"build_zynq",
|
||||||
|
"byteorder",
|
||||||
|
"core_io",
|
||||||
|
"cslice",
|
||||||
|
"dwarf",
|
||||||
|
"dyld",
|
||||||
|
"io",
|
||||||
|
"libasync",
|
||||||
|
"libboard_artiq",
|
||||||
|
"libboard_zynq",
|
||||||
|
"libc",
|
||||||
|
"libconfig",
|
||||||
|
"libcortex_a9",
|
||||||
|
"libm",
|
||||||
|
"libregister",
|
||||||
|
"libsupport_zynq",
|
||||||
|
"log",
|
||||||
|
"log_buffer",
|
||||||
|
"nb 0.1.3",
|
||||||
|
"unwind",
|
||||||
|
"void",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libasync"
|
name = "libasync"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
|
@ -438,18 +465,17 @@ dependencies = [
|
||||||
"embedded-hal",
|
"embedded-hal",
|
||||||
"futures",
|
"futures",
|
||||||
"io",
|
"io",
|
||||||
|
"kernel",
|
||||||
"libasync",
|
"libasync",
|
||||||
"libboard_artiq",
|
"libboard_artiq",
|
||||||
"libboard_zynq",
|
"libboard_zynq",
|
||||||
"libc",
|
"libc",
|
||||||
"libconfig",
|
"libconfig",
|
||||||
"libcortex_a9",
|
"libcortex_a9",
|
||||||
"libm",
|
|
||||||
"libregister",
|
"libregister",
|
||||||
"libsupport_zynq",
|
"libsupport_zynq",
|
||||||
"log",
|
"log",
|
||||||
"log_buffer",
|
"log_buffer",
|
||||||
"nb 0.1.3",
|
|
||||||
"num-derive",
|
"num-derive",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"unwind",
|
"unwind",
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
[package]
|
||||||
|
name = "kernel"
|
||||||
|
description = "Kernel support for Zynq-based platforms"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["M-Labs"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
build_zynq = { path = "../libbuild_zynq" }
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
cslice = "0.3"
|
||||||
|
log = "0.4"
|
||||||
|
nb = "0.1"
|
||||||
|
core_io = { version = "0.1", features = ["collections"] }
|
||||||
|
byteorder = { version = "1.3", default-features = false }
|
||||||
|
void = { version = "1", default-features = false }
|
||||||
|
log_buffer = { version = "1.2" }
|
||||||
|
libm = { version = "0.2", features = ["unstable"] }
|
||||||
|
|
||||||
|
libboard_zynq = { git = "https://git.m-labs.hk/M-Labs/zynq-rs.git", features = ["ipv6"]}
|
||||||
|
libsupport_zynq = { default-features = false, features = ["alloc_core"], git = "https://git.m-labs.hk/M-Labs/zynq-rs.git" }
|
||||||
|
libcortex_a9 = { git = "https://git.m-labs.hk/M-Labs/zynq-rs.git" }
|
||||||
|
libasync = { git = "https://git.m-labs.hk/M-Labs/zynq-rs.git" }
|
||||||
|
libregister = { git = "https://git.m-labs.hk/M-Labs/zynq-rs.git" }
|
||||||
|
libconfig = { git = "https://git.m-labs.hk/M-Labs/zynq-rs.git", features = ["fat_lfn", "ipv6"] }
|
||||||
|
|
||||||
|
dyld = { path = "../libdyld" }
|
||||||
|
dwarf = { path = "../libdwarf" }
|
||||||
|
unwind = { path = "../libunwind" }
|
||||||
|
libc = { path = "../libc" }
|
||||||
|
io = { path = "../libio" }
|
||||||
|
libboard_artiq = { path = "../libboard_artiq" }
|
|
@ -0,0 +1,5 @@
|
||||||
|
extern crate build_zynq;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
build_zynq::cfg();
|
||||||
|
}
|
|
@ -5,6 +5,8 @@ use libc::{c_char, c_int, size_t};
|
||||||
use libm;
|
use libm;
|
||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
|
|
||||||
|
#[cfg(has_drtio)]
|
||||||
|
use super::subkernel;
|
||||||
use super::{cache,
|
use super::{cache,
|
||||||
core1::rtio_get_destination_status,
|
core1::rtio_get_destination_status,
|
||||||
dma,
|
dma,
|
|
@ -3,8 +3,8 @@ use core::mem::{forget, replace};
|
||||||
use libcortex_a9::sync_channel::{Receiver, Sender};
|
use libcortex_a9::sync_channel::{Receiver, Sender};
|
||||||
use libsupport_zynq::boot::Core1;
|
use libsupport_zynq::boot::Core1;
|
||||||
|
|
||||||
use super::{Message, CHANNEL_0TO1, CHANNEL_1TO0, CHANNEL_SEM, INIT_LOCK};
|
use super::{CHANNEL_0TO1, CHANNEL_1TO0, CHANNEL_SEM, INIT_LOCK};
|
||||||
use crate::irq::restart_core1;
|
use crate::{irq::restart_core1, Message};
|
||||||
|
|
||||||
pub struct Control {
|
pub struct Control {
|
||||||
pub tx: Sender<'static, Message>,
|
pub tx: Sender<'static, Message>,
|
|
@ -0,0 +1,27 @@
|
||||||
|
use core::ptr;
|
||||||
|
|
||||||
|
use libcortex_a9::{mutex::Mutex, semaphore::Semaphore, sync_channel};
|
||||||
|
|
||||||
|
use crate::Message;
|
||||||
|
|
||||||
|
mod control;
|
||||||
|
pub use control::Control;
|
||||||
|
mod api;
|
||||||
|
pub mod core1;
|
||||||
|
mod dma;
|
||||||
|
mod rpc;
|
||||||
|
pub use dma::DmaRecorder;
|
||||||
|
mod cache;
|
||||||
|
#[cfg(has_drtio)]
|
||||||
|
mod subkernel;
|
||||||
|
|
||||||
|
static CHANNEL_0TO1: Mutex<Option<sync_channel::Sender<'static, Message>>> = Mutex::new(None);
|
||||||
|
static CHANNEL_1TO0: Mutex<Option<sync_channel::Receiver<'static, Message>>> = Mutex::new(None);
|
||||||
|
static CHANNEL_SEM: Semaphore = Semaphore::new(0, 1);
|
||||||
|
|
||||||
|
static mut KERNEL_CHANNEL_0TO1: Option<sync_channel::Receiver<'static, Message>> = None;
|
||||||
|
static mut KERNEL_CHANNEL_1TO0: Option<sync_channel::Sender<'static, Message>> = None;
|
||||||
|
|
||||||
|
pub static mut KERNEL_IMAGE: *const core1::KernelImage = ptr::null();
|
||||||
|
|
||||||
|
static INIT_LOCK: Mutex<()> = Mutex::new(());
|
|
@ -2,8 +2,8 @@ use alloc::vec::Vec;
|
||||||
|
|
||||||
use cslice::CSlice;
|
use cslice::CSlice;
|
||||||
|
|
||||||
use super::{Message, SubkernelStatus, KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0};
|
use super::{KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0};
|
||||||
use crate::{artiq_raise, rpc::send_args};
|
use crate::{artiq_raise, rpc::send_args, Message, SubkernelStatus};
|
||||||
|
|
||||||
pub extern "C" fn load_run(id: u32, run: bool) {
|
pub extern "C" fn load_run(id: u32, run: bool) {
|
||||||
unsafe {
|
unsafe {
|
|
@ -0,0 +1,243 @@
|
||||||
|
#![no_std]
|
||||||
|
#![feature(c_variadic)]
|
||||||
|
#![feature(const_btree_new)]
|
||||||
|
#![feature(const_in_array_repeat_expressions)]
|
||||||
|
#![feature(naked_functions)]
|
||||||
|
#![feature(asm)]
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
|
use alloc::{collections::BTreeMap, string::String, vec::Vec};
|
||||||
|
|
||||||
|
use io::{Cursor, ProtoRead};
|
||||||
|
pub use kernel::{Control, DmaRecorder};
|
||||||
|
use libasync::block_async;
|
||||||
|
use libconfig::Config;
|
||||||
|
use log::{error, warn};
|
||||||
|
use void::Void;
|
||||||
|
|
||||||
|
pub mod eh_artiq;
|
||||||
|
pub mod i2c;
|
||||||
|
pub mod irq;
|
||||||
|
pub mod kernel;
|
||||||
|
pub mod rpc;
|
||||||
|
#[cfg(ki_impl = "csr")]
|
||||||
|
#[path = "rtio_csr.rs"]
|
||||||
|
pub mod rtio;
|
||||||
|
#[cfg(ki_impl = "acp")]
|
||||||
|
#[path = "rtio_acp.rs"]
|
||||||
|
pub mod rtio;
|
||||||
|
#[rustfmt::skip]
|
||||||
|
#[path = "../../../build/pl.rs"]
|
||||||
|
pub mod pl;
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct RPCException {
|
||||||
|
pub id: u32,
|
||||||
|
pub message: u32,
|
||||||
|
pub param: [i64; 3],
|
||||||
|
pub file: u32,
|
||||||
|
pub line: i32,
|
||||||
|
pub column: i32,
|
||||||
|
pub function: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(has_drtio)]
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum SubkernelStatus {
|
||||||
|
NoError,
|
||||||
|
Timeout,
|
||||||
|
IncorrectState,
|
||||||
|
CommLost,
|
||||||
|
OtherError,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Message {
|
||||||
|
LoadRequest(Vec<u8>),
|
||||||
|
LoadCompleted,
|
||||||
|
LoadFailed,
|
||||||
|
StartRequest,
|
||||||
|
KernelFinished(u8),
|
||||||
|
KernelException(
|
||||||
|
&'static [Option<eh_artiq::Exception<'static>>],
|
||||||
|
&'static [eh_artiq::StackPointerBacktrace],
|
||||||
|
&'static [(usize, usize)],
|
||||||
|
u8,
|
||||||
|
),
|
||||||
|
RpcSend {
|
||||||
|
is_async: bool,
|
||||||
|
data: Vec<u8>,
|
||||||
|
},
|
||||||
|
RpcRecvRequest(*mut ()),
|
||||||
|
RpcRecvReply(Result<usize, RPCException>),
|
||||||
|
|
||||||
|
CacheGetRequest(String),
|
||||||
|
CacheGetReply(Vec<i32>),
|
||||||
|
CachePutRequest(String, Vec<i32>),
|
||||||
|
|
||||||
|
DmaPutRequest(DmaRecorder),
|
||||||
|
DmaEraseRequest(String),
|
||||||
|
DmaGetRequest(String),
|
||||||
|
DmaGetReply(Option<(i32, i64, bool)>),
|
||||||
|
#[cfg(has_drtio)]
|
||||||
|
DmaStartRemoteRequest {
|
||||||
|
id: i32,
|
||||||
|
timestamp: i64,
|
||||||
|
},
|
||||||
|
#[cfg(has_drtio)]
|
||||||
|
DmaAwaitRemoteRequest(i32),
|
||||||
|
#[cfg(has_drtio)]
|
||||||
|
DmaAwaitRemoteReply {
|
||||||
|
timeout: bool,
|
||||||
|
error: u8,
|
||||||
|
channel: u32,
|
||||||
|
timestamp: u64,
|
||||||
|
},
|
||||||
|
|
||||||
|
#[cfg(has_drtio)]
|
||||||
|
UpDestinationsRequest(i32),
|
||||||
|
#[cfg(has_drtio)]
|
||||||
|
UpDestinationsReply(bool),
|
||||||
|
|
||||||
|
#[cfg(has_drtio)]
|
||||||
|
SubkernelLoadRunRequest {
|
||||||
|
id: u32,
|
||||||
|
run: bool,
|
||||||
|
},
|
||||||
|
#[cfg(has_drtio)]
|
||||||
|
SubkernelLoadRunReply {
|
||||||
|
succeeded: bool,
|
||||||
|
},
|
||||||
|
#[cfg(has_drtio)]
|
||||||
|
SubkernelAwaitFinishRequest {
|
||||||
|
id: u32,
|
||||||
|
timeout: u64,
|
||||||
|
},
|
||||||
|
#[cfg(has_drtio)]
|
||||||
|
SubkernelAwaitFinishReply {
|
||||||
|
status: SubkernelStatus,
|
||||||
|
},
|
||||||
|
#[cfg(has_drtio)]
|
||||||
|
SubkernelMsgSend {
|
||||||
|
id: u32,
|
||||||
|
data: Vec<u8>,
|
||||||
|
},
|
||||||
|
#[cfg(has_drtio)]
|
||||||
|
SubkernelMsgRecvRequest {
|
||||||
|
id: u32,
|
||||||
|
timeout: u64,
|
||||||
|
},
|
||||||
|
#[cfg(has_drtio)]
|
||||||
|
SubkernelMsgRecvReply {
|
||||||
|
status: SubkernelStatus,
|
||||||
|
count: u8,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
pub static mut SEEN_ASYNC_ERRORS: u8 = 0;
|
||||||
|
|
||||||
|
pub const ASYNC_ERROR_COLLISION: u8 = 1 << 0;
|
||||||
|
pub const ASYNC_ERROR_BUSY: u8 = 1 << 1;
|
||||||
|
pub const ASYNC_ERROR_SEQUENCE_ERROR: u8 = 1 << 2;
|
||||||
|
|
||||||
|
pub unsafe fn get_async_errors() -> u8 {
|
||||||
|
let errors = SEEN_ASYNC_ERRORS;
|
||||||
|
SEEN_ASYNC_ERRORS = 0;
|
||||||
|
errors
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wait_for_async_rtio_error() -> nb::Result<(), Void> {
|
||||||
|
unsafe {
|
||||||
|
if pl::csr::rtio_core::async_error_read() != 0 {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(nb::Error::WouldBlock)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn report_async_rtio_errors() {
|
||||||
|
loop {
|
||||||
|
let _ = block_async!(wait_for_async_rtio_error()).await;
|
||||||
|
unsafe {
|
||||||
|
let errors = pl::csr::rtio_core::async_error_read();
|
||||||
|
if errors & ASYNC_ERROR_COLLISION != 0 {
|
||||||
|
let channel = pl::csr::rtio_core::collision_channel_read();
|
||||||
|
error!(
|
||||||
|
"RTIO collision involving channel 0x{:04x}:{}",
|
||||||
|
channel,
|
||||||
|
resolve_channel_name(channel as u32)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if errors & ASYNC_ERROR_BUSY != 0 {
|
||||||
|
let channel = pl::csr::rtio_core::busy_channel_read();
|
||||||
|
error!(
|
||||||
|
"RTIO busy error involving channel 0x{:04x}:{}",
|
||||||
|
channel,
|
||||||
|
resolve_channel_name(channel as u32)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if errors & ASYNC_ERROR_SEQUENCE_ERROR != 0 {
|
||||||
|
let channel = pl::csr::rtio_core::sequence_error_channel_read();
|
||||||
|
error!(
|
||||||
|
"RTIO sequence error involving channel 0x{:04x}:{}",
|
||||||
|
channel,
|
||||||
|
resolve_channel_name(channel as u32)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
SEEN_ASYNC_ERRORS = errors;
|
||||||
|
pl::csr::rtio_core::async_error_write(errors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static mut RTIO_DEVICE_MAP: BTreeMap<u32, String> = BTreeMap::new();
|
||||||
|
|
||||||
|
fn read_device_map(cfg: &Config) -> BTreeMap<u32, String> {
|
||||||
|
let mut device_map: BTreeMap<u32, String> = BTreeMap::new();
|
||||||
|
let _ = cfg
|
||||||
|
.read("device_map")
|
||||||
|
.and_then(|raw_bytes| {
|
||||||
|
let mut bytes_cr = Cursor::new(raw_bytes);
|
||||||
|
let size = bytes_cr.read_u32().unwrap();
|
||||||
|
for _ in 0..size {
|
||||||
|
let channel = bytes_cr.read_u32().unwrap();
|
||||||
|
let device_name = bytes_cr.read_string().unwrap();
|
||||||
|
if let Some(old_entry) = device_map.insert(channel, device_name.clone()) {
|
||||||
|
warn!(
|
||||||
|
"conflicting device map entries for RTIO channel {}: '{}' and '{}'",
|
||||||
|
channel, old_entry, device_name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
.or_else(|err| {
|
||||||
|
warn!(
|
||||||
|
"error reading device map ({}), device names will not be available in RTIO error messages",
|
||||||
|
err
|
||||||
|
);
|
||||||
|
Err(err)
|
||||||
|
});
|
||||||
|
device_map
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _resolve_channel_name(channel: u32, device_map: &BTreeMap<u32, String>) -> String {
|
||||||
|
match device_map.get(&channel) {
|
||||||
|
Some(val) => val.clone(),
|
||||||
|
None => String::from("unknown"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resolve_channel_name(channel: u32) -> String {
|
||||||
|
_resolve_channel_name(channel, unsafe { &RTIO_DEVICE_MAP })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setup_device_map(cfg: &Config) {
|
||||||
|
unsafe {
|
||||||
|
RTIO_DEVICE_MAP = read_device_map(cfg);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,75 +1,62 @@
|
||||||
use alloc::boxed::Box;
|
use core::str;
|
||||||
#[cfg(has_drtio)]
|
|
||||||
use alloc::vec::Vec;
|
|
||||||
use core::{future::Future, str};
|
|
||||||
|
|
||||||
use async_recursion::async_recursion;
|
|
||||||
use byteorder::{ByteOrder, NativeEndian};
|
use byteorder::{ByteOrder, NativeEndian};
|
||||||
use core_io::{Error, Write};
|
use core_io::{Error, Read, Write};
|
||||||
use cslice::{CMutSlice, CSlice};
|
use cslice::{CMutSlice, CSlice};
|
||||||
#[cfg(has_drtio)]
|
use io::{ProtoRead, ProtoWrite};
|
||||||
use io::{Cursor, ProtoRead};
|
|
||||||
use io::ProtoWrite;
|
|
||||||
use libasync::smoltcp::TcpStream;
|
|
||||||
use libboard_zynq::smoltcp;
|
|
||||||
use log::trace;
|
use log::trace;
|
||||||
|
|
||||||
use self::tag::{split_tag, Tag, TagIterator};
|
use self::tag::{split_tag, Tag, TagIterator};
|
||||||
use crate::proto_async;
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn round_up(val: usize, power_of_two: usize) -> usize {
|
pub fn round_up(val: usize, power_of_two: usize) -> usize {
|
||||||
assert!(power_of_two.is_power_of_two());
|
assert!(power_of_two.is_power_of_two());
|
||||||
let max_rem = power_of_two - 1;
|
let max_rem = power_of_two - 1;
|
||||||
(val + max_rem) & (!max_rem)
|
(val + max_rem) & (!max_rem)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn round_up_mut<T>(ptr: *mut T, power_of_two: usize) -> *mut T {
|
pub unsafe fn round_up_mut<T>(ptr: *mut T, power_of_two: usize) -> *mut T {
|
||||||
round_up(ptr as usize, power_of_two) as *mut T
|
round_up(ptr as usize, power_of_two) as *mut T
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn round_up_const<T>(ptr: *const T, power_of_two: usize) -> *const T {
|
pub unsafe fn round_up_const<T>(ptr: *const T, power_of_two: usize) -> *const T {
|
||||||
round_up(ptr as usize, power_of_two) as *const T
|
round_up(ptr as usize, power_of_two) as *const T
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn align_ptr<T>(ptr: *const ()) -> *const T {
|
pub unsafe fn align_ptr<T>(ptr: *const ()) -> *const T {
|
||||||
round_up_const(ptr, core::mem::align_of::<T>()) as *const T
|
round_up_const(ptr, core::mem::align_of::<T>()) as *const T
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn align_ptr_mut<T>(ptr: *mut ()) -> *mut T {
|
pub unsafe fn align_ptr_mut<T>(ptr: *mut ()) -> *mut T {
|
||||||
round_up_mut(ptr, core::mem::align_of::<T>()) as *mut T
|
round_up_mut(ptr, core::mem::align_of::<T>()) as *mut T
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads (deserializes) `length` array or list elements of type `tag` from `stream`,
|
// versions for reader rather than TcpStream
|
||||||
/// writing them into the buffer given by `storage`.
|
// they will be made into sync for satellite subkernels later
|
||||||
///
|
unsafe fn recv_elements<F, R>(
|
||||||
/// `alloc` is used for nested allocations (if elements themselves contain
|
reader: &mut R,
|
||||||
/// lists/arrays), see [recv_value].
|
elt_tag: Tag,
|
||||||
#[async_recursion(?Send)]
|
|
||||||
async unsafe fn recv_elements<F>(
|
|
||||||
stream: &TcpStream,
|
|
||||||
elt_tag: Tag<'async_recursion>,
|
|
||||||
length: usize,
|
length: usize,
|
||||||
storage: *mut (),
|
storage: *mut (),
|
||||||
alloc: &(impl Fn(usize) -> F + 'async_recursion),
|
alloc: &F,
|
||||||
) -> Result<(), smoltcp::Error>
|
) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
F: Future<Output = *mut ()>,
|
F: Fn(usize) -> *mut (),
|
||||||
|
R: Read + ?Sized,
|
||||||
{
|
{
|
||||||
// List of simple types are special-cased in the protocol for performance.
|
|
||||||
match elt_tag {
|
match elt_tag {
|
||||||
Tag::Bool => {
|
Tag::Bool => {
|
||||||
let dest = core::slice::from_raw_parts_mut(storage as *mut u8, length);
|
let dest = core::slice::from_raw_parts_mut(storage as *mut u8, length);
|
||||||
proto_async::read_chunk(stream, dest).await?;
|
reader.read_exact(dest)?;
|
||||||
}
|
}
|
||||||
Tag::Int32 => {
|
Tag::Int32 => {
|
||||||
let ptr = storage as *mut u32;
|
let ptr = storage as *mut u32;
|
||||||
let dest = core::slice::from_raw_parts_mut(ptr as *mut u8, length * 4);
|
let dest = core::slice::from_raw_parts_mut(ptr as *mut u8, length * 4);
|
||||||
proto_async::read_chunk(stream, dest).await?;
|
reader.read_exact(dest)?;
|
||||||
drop(dest);
|
drop(dest);
|
||||||
let dest = core::slice::from_raw_parts_mut(ptr, length);
|
let dest = core::slice::from_raw_parts_mut(ptr, length);
|
||||||
NativeEndian::from_slice_u32(dest);
|
NativeEndian::from_slice_u32(dest);
|
||||||
|
@ -77,7 +64,7 @@ where
|
||||||
Tag::Int64 | Tag::Float64 => {
|
Tag::Int64 | Tag::Float64 => {
|
||||||
let ptr = storage as *mut u64;
|
let ptr = storage as *mut u64;
|
||||||
let dest = core::slice::from_raw_parts_mut(ptr as *mut u8, length * 8);
|
let dest = core::slice::from_raw_parts_mut(ptr as *mut u8, length * 8);
|
||||||
proto_async::read_chunk(stream, dest).await?;
|
reader.read_exact(dest)?;
|
||||||
drop(dest);
|
drop(dest);
|
||||||
let dest = core::slice::from_raw_parts_mut(ptr, length);
|
let dest = core::slice::from_raw_parts_mut(ptr, length);
|
||||||
NativeEndian::from_slice_u64(dest);
|
NativeEndian::from_slice_u64(dest);
|
||||||
|
@ -85,27 +72,17 @@ where
|
||||||
_ => {
|
_ => {
|
||||||
let mut data = storage;
|
let mut data = storage;
|
||||||
for _ in 0..length {
|
for _ in 0..length {
|
||||||
recv_value(stream, elt_tag, &mut data, alloc).await?
|
recv_value(reader, elt_tag, &mut data, alloc)?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads (deserializes) a value of type `tag` from `stream`, writing the results to
|
unsafe fn recv_value<F, R>(reader: &mut R, tag: Tag, data: &mut *mut (), alloc: &F) -> Result<(), Error>
|
||||||
/// the kernel-side buffer `data` (the passed pointer to which is incremented to point
|
|
||||||
/// past the just-received data). For nested allocations (lists/arrays), `alloc` is
|
|
||||||
/// invoked any number of times with the size of the required allocation as a parameter
|
|
||||||
/// (which is assumed to be correctly aligned for all payload types).
|
|
||||||
#[async_recursion(?Send)]
|
|
||||||
async unsafe fn recv_value<F>(
|
|
||||||
stream: &TcpStream,
|
|
||||||
tag: Tag<'async_recursion>,
|
|
||||||
data: &mut *mut (),
|
|
||||||
alloc: &(impl Fn(usize) -> F + 'async_recursion),
|
|
||||||
) -> Result<(), smoltcp::Error>
|
|
||||||
where
|
where
|
||||||
F: Future<Output = *mut ()>,
|
F: Fn(usize) -> *mut (),
|
||||||
|
R: Read + ?Sized,
|
||||||
{
|
{
|
||||||
macro_rules! consume_value {
|
macro_rules! consume_value {
|
||||||
($ty:ty, | $ptr:ident | $map:expr) => {{
|
($ty:ty, | $ptr:ident | $map:expr) => {{
|
||||||
|
@ -118,22 +95,22 @@ where
|
||||||
match tag {
|
match tag {
|
||||||
Tag::None => Ok(()),
|
Tag::None => Ok(()),
|
||||||
Tag::Bool => consume_value!(i8, |ptr| {
|
Tag::Bool => consume_value!(i8, |ptr| {
|
||||||
*ptr = proto_async::read_i8(stream).await?;
|
*ptr = reader.read_u8()? as i8;
|
||||||
Ok(())
|
Ok(())
|
||||||
}),
|
}),
|
||||||
Tag::Int32 => consume_value!(i32, |ptr| {
|
Tag::Int32 => consume_value!(i32, |ptr| {
|
||||||
*ptr = proto_async::read_i32(stream).await?;
|
*ptr = reader.read_u32()? as i32;
|
||||||
Ok(())
|
Ok(())
|
||||||
}),
|
}),
|
||||||
Tag::Int64 | Tag::Float64 => consume_value!(i64, |ptr| {
|
Tag::Int64 | Tag::Float64 => consume_value!(i64, |ptr| {
|
||||||
*ptr = proto_async::read_i64(stream).await?;
|
*ptr = reader.read_u64()? as i64;
|
||||||
Ok(())
|
Ok(())
|
||||||
}),
|
}),
|
||||||
Tag::String | Tag::Bytes | Tag::ByteArray => {
|
Tag::String | Tag::Bytes | Tag::ByteArray => {
|
||||||
consume_value!(CMutSlice<u8>, |ptr| {
|
consume_value!(CMutSlice<u8>, |ptr| {
|
||||||
let length = proto_async::read_i32(stream).await? as usize;
|
let length = reader.read_u32()? as usize;
|
||||||
*ptr = CMutSlice::new(alloc(length).await as *mut u8, length);
|
*ptr = CMutSlice::new(alloc(length) as *mut u8, length);
|
||||||
proto_async::read_chunk(stream, (*ptr).as_mut()).await?;
|
reader.read_exact((*ptr).as_mut())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -143,10 +120,8 @@ where
|
||||||
let mut it = it.clone();
|
let mut it = it.clone();
|
||||||
for _ in 0..arity {
|
for _ in 0..arity {
|
||||||
let tag = it.next().expect("truncated tag");
|
let tag = it.next().expect("truncated tag");
|
||||||
recv_value(stream, tag, data, alloc).await?
|
recv_value(reader, tag, data, alloc)?
|
||||||
}
|
}
|
||||||
// Take into account any tail padding (if element(s) with largest alignment
|
|
||||||
// are not at the end).
|
|
||||||
*data = round_up_mut(*data, alignment);
|
*data = round_up_mut(*data, alignment);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -158,50 +133,41 @@ where
|
||||||
}
|
}
|
||||||
consume_value!(*mut List, |ptr_to_list| {
|
consume_value!(*mut List, |ptr_to_list| {
|
||||||
let tag = it.clone().next().expect("truncated tag");
|
let tag = it.clone().next().expect("truncated tag");
|
||||||
let length = proto_async::read_i32(stream).await? as usize;
|
let length = reader.read_u32()? as usize;
|
||||||
|
|
||||||
// To avoid multiple kernel CPU roundtrips, use a single allocation for
|
|
||||||
// both the pointer/length List (slice) and the backing storage for the
|
|
||||||
// elements. We can assume that alloc() is aligned suitably, so just
|
|
||||||
// need to take into account any extra padding required.
|
|
||||||
// (Note: At the time of writing, there will never actually be any types
|
|
||||||
// with alignment larger than 8 bytes, so storage_offset == 0 always.)
|
|
||||||
let list_size = 4 + 4;
|
let list_size = 4 + 4;
|
||||||
let storage_offset = round_up(list_size, tag.alignment());
|
let storage_offset = round_up(list_size, tag.alignment());
|
||||||
let storage_size = tag.size() * length;
|
let storage_size = tag.size() * length;
|
||||||
|
|
||||||
let allocation = alloc(storage_offset + storage_size).await as *mut u8;
|
let allocation = alloc(storage_offset + storage_size) as *mut u8;
|
||||||
*ptr_to_list = allocation as *mut List;
|
*ptr_to_list = allocation as *mut List;
|
||||||
let storage = allocation.offset(storage_offset as isize) as *mut ();
|
let storage = allocation.offset(storage_offset as isize) as *mut ();
|
||||||
|
|
||||||
(**ptr_to_list).length = length;
|
(**ptr_to_list).length = length;
|
||||||
(**ptr_to_list).elements = storage;
|
(**ptr_to_list).elements = storage;
|
||||||
recv_elements(stream, tag, length, storage, alloc).await
|
recv_elements(reader, tag, length, storage, alloc)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Tag::Array(it, num_dims) => {
|
Tag::Array(it, num_dims) => {
|
||||||
consume_value!(*mut (), |buffer| {
|
consume_value!(*mut (), |buffer| {
|
||||||
// Deserialize length along each dimension and compute total number of
|
|
||||||
// elements.
|
|
||||||
let mut total_len: usize = 1;
|
let mut total_len: usize = 1;
|
||||||
for _ in 0..num_dims {
|
for _ in 0..num_dims {
|
||||||
let len = proto_async::read_i32(stream).await? as usize;
|
let len = reader.read_u32()? as usize;
|
||||||
total_len *= len;
|
total_len *= len;
|
||||||
consume_value!(usize, |ptr| *ptr = len)
|
consume_value!(usize, |ptr| *ptr = len)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate backing storage for elements; deserialize them.
|
|
||||||
let elt_tag = it.clone().next().expect("truncated tag");
|
let elt_tag = it.clone().next().expect("truncated tag");
|
||||||
*buffer = alloc(elt_tag.size() * total_len).await;
|
*buffer = alloc(elt_tag.size() * total_len);
|
||||||
recv_elements(stream, elt_tag, total_len, *buffer, alloc).await
|
recv_elements(reader, elt_tag, total_len, *buffer, alloc)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Tag::Range(it) => {
|
Tag::Range(it) => {
|
||||||
*data = round_up_mut(*data, tag.alignment());
|
*data = round_up_mut(*data, tag.alignment());
|
||||||
let tag = it.clone().next().expect("truncated tag");
|
let tag = it.clone().next().expect("truncated tag");
|
||||||
recv_value(stream, tag, data, alloc).await?;
|
recv_value(reader, tag, data, alloc)?;
|
||||||
recv_value(stream, tag, data, alloc).await?;
|
recv_value(reader, tag, data, alloc)?;
|
||||||
recv_value(stream, tag, data, alloc).await?;
|
recv_value(reader, tag, data, alloc)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Tag::Keyword(_) => unreachable!(),
|
Tag::Keyword(_) => unreachable!(),
|
||||||
|
@ -209,21 +175,17 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn recv_return<F>(
|
pub fn recv_return<F, R>(reader: &mut R, tag_bytes: &[u8], data: *mut (), alloc: &F) -> Result<(), Error>
|
||||||
stream: &TcpStream,
|
|
||||||
tag_bytes: &[u8],
|
|
||||||
data: *mut (),
|
|
||||||
alloc: &impl Fn(usize) -> F,
|
|
||||||
) -> Result<(), smoltcp::Error>
|
|
||||||
where
|
where
|
||||||
F: Future<Output = *mut ()>,
|
F: Fn(usize) -> *mut (),
|
||||||
|
R: Read + ?Sized,
|
||||||
{
|
{
|
||||||
let mut it = TagIterator::new(tag_bytes);
|
let mut it = TagIterator::new(tag_bytes);
|
||||||
trace!("recv ...->{}", it);
|
trace!("recv ...->{}", it);
|
||||||
|
|
||||||
let tag = it.next().expect("truncated tag");
|
let tag = it.next().expect("truncated tag");
|
||||||
let mut data = data;
|
let mut data = data;
|
||||||
unsafe { recv_value(stream, tag, &mut data, alloc).await? };
|
unsafe { recv_value(reader, tag, &mut data, alloc)? };
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -538,7 +500,7 @@ where W: Write + ?Sized {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
mod tag {
|
pub mod tag {
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
||||||
pub fn split_tag(tag_bytes: &[u8]) -> (&[u8], &[u8]) {
|
pub fn split_tag(tag_bytes: &[u8]) -> (&[u8], &[u8]) {
|
|
@ -4,7 +4,7 @@ use cslice::CSlice;
|
||||||
use libcortex_a9::asm;
|
use libcortex_a9::asm;
|
||||||
use vcell::VolatileCell;
|
use vcell::VolatileCell;
|
||||||
|
|
||||||
use crate::{artiq_raise, pl::csr, rtio_mgt::resolve_channel_name};
|
use crate::{artiq_raise, pl::csr, resolve_channel_name};
|
||||||
|
|
||||||
pub const RTIO_O_STATUS_WAIT: i32 = 1;
|
pub const RTIO_O_STATUS_WAIT: i32 = 1;
|
||||||
pub const RTIO_O_STATUS_UNDERFLOW: i32 = 2;
|
pub const RTIO_O_STATUS_UNDERFLOW: i32 = 2;
|
|
@ -2,7 +2,7 @@ use core::ptr::{read_volatile, write_volatile};
|
||||||
|
|
||||||
use cslice::CSlice;
|
use cslice::CSlice;
|
||||||
|
|
||||||
use crate::{artiq_raise, pl::csr, rtio_mgt::resolve_channel_name};
|
use crate::{artiq_raise, pl::csr, resolve_channel_name};
|
||||||
|
|
||||||
pub const RTIO_O_STATUS_WAIT: u8 = 1;
|
pub const RTIO_O_STATUS_WAIT: u8 = 1;
|
||||||
pub const RTIO_O_STATUS_UNDERFLOW: u8 = 2;
|
pub const RTIO_O_STATUS_UNDERFLOW: u8 = 2;
|
|
@ -18,7 +18,6 @@ num-traits = { version = "0.2", default-features = false }
|
||||||
num-derive = "0.3"
|
num-derive = "0.3"
|
||||||
cslice = "0.3"
|
cslice = "0.3"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
nb = "0.1"
|
|
||||||
embedded-hal = "0.2"
|
embedded-hal = "0.2"
|
||||||
core_io = { version = "0.1", features = ["collections"] }
|
core_io = { version = "0.1", features = ["collections"] }
|
||||||
byteorder = { version = "1.3", default-features = false }
|
byteorder = { version = "1.3", default-features = false }
|
||||||
|
@ -26,7 +25,6 @@ void = { version = "1", default-features = false }
|
||||||
futures = { version = "0.3", default-features = false, features = ["async-await"] }
|
futures = { version = "0.3", default-features = false, features = ["async-await"] }
|
||||||
async-recursion = "0.3"
|
async-recursion = "0.3"
|
||||||
log_buffer = { version = "1.2" }
|
log_buffer = { version = "1.2" }
|
||||||
libm = { version = "0.2", features = ["unstable"] }
|
|
||||||
vcell = "0.1"
|
vcell = "0.1"
|
||||||
|
|
||||||
libboard_zynq = { git = "https://git.m-labs.hk/M-Labs/zynq-rs.git", features = ["ipv6"]}
|
libboard_zynq = { git = "https://git.m-labs.hk/M-Labs/zynq-rs.git", features = ["ipv6"]}
|
||||||
|
@ -41,4 +39,5 @@ dwarf = { path = "../libdwarf" }
|
||||||
unwind = { path = "../libunwind" }
|
unwind = { path = "../libunwind" }
|
||||||
libc = { path = "../libc" }
|
libc = { path = "../libc" }
|
||||||
io = { path = "../libio" }
|
io = { path = "../libio" }
|
||||||
|
kernel = { path = "../libkernel" }
|
||||||
libboard_artiq = { path = "../libboard_artiq" }
|
libboard_artiq = { path = "../libboard_artiq" }
|
|
@ -6,6 +6,9 @@ use cslice::CSlice;
|
||||||
use futures::{future::FutureExt, select_biased};
|
use futures::{future::FutureExt, select_biased};
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
use io::{Cursor, ProtoRead};
|
use io::{Cursor, ProtoRead};
|
||||||
|
use kernel::resolve_channel_name;
|
||||||
|
#[cfg(has_drtio)]
|
||||||
|
use kernel::rpc;
|
||||||
use libasync::{smoltcp::{Sockets, TcpStream},
|
use libasync::{smoltcp::{Sockets, TcpStream},
|
||||||
task};
|
task};
|
||||||
use libboard_artiq::drtio_routing;
|
use libboard_artiq::drtio_routing;
|
||||||
|
@ -27,10 +30,7 @@ use num_traits::{FromPrimitive, ToPrimitive};
|
||||||
|
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
use crate::pl;
|
use crate::pl;
|
||||||
use crate::{analyzer, kernel, mgmt, moninj,
|
use crate::{analyzer, mgmt, moninj, proto_async::*, rpc_async, rtio_dma, rtio_mgt};
|
||||||
proto_async::*,
|
|
||||||
rpc, rtio_dma,
|
|
||||||
rtio_mgt::{self, resolve_channel_name}};
|
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
use crate::{subkernel, subkernel::Error as SubkernelError};
|
use crate::{subkernel, subkernel::Error as SubkernelError};
|
||||||
|
|
||||||
|
@ -207,7 +207,7 @@ async fn handle_run_kernel(
|
||||||
kernel::Message::RpcRecvRequest(slot) => slot,
|
kernel::Message::RpcRecvRequest(slot) => slot,
|
||||||
other => panic!("expected root value slot from core1, not {:?}", other),
|
other => panic!("expected root value slot from core1, not {:?}", other),
|
||||||
};
|
};
|
||||||
rpc::recv_return(stream, &tag, slot, &|size| {
|
rpc_async::recv_return(stream, &tag, slot, &|size| {
|
||||||
let control = control.clone();
|
let control = control.clone();
|
||||||
async move {
|
async move {
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
|
@ -471,24 +471,20 @@ async fn handle_run_kernel(
|
||||||
kernel::Message::RpcRecvRequest(slot) => slot,
|
kernel::Message::RpcRecvRequest(slot) => slot,
|
||||||
other => panic!("expected root value slot from core1, not {:?}", other),
|
other => panic!("expected root value slot from core1, not {:?}", other),
|
||||||
};
|
};
|
||||||
rpc::recv_return_cursor(&mut reader, &tag, slot, &|size| {
|
rpc::recv_return(&mut reader, &tag, slot, &|size| {
|
||||||
let control = control.clone();
|
if size == 0 {
|
||||||
async move {
|
0 as *mut ()
|
||||||
if size == 0 {
|
} else {
|
||||||
0 as *mut ()
|
let mut control = control.borrow_mut();
|
||||||
} else {
|
control.tx.send(kernel::Message::RpcRecvReply(Ok(size)));
|
||||||
let mut control = control.borrow_mut();
|
match control.rx.recv() {
|
||||||
fast_send(&mut control.tx, kernel::Message::RpcRecvReply(Ok(size))).await;
|
kernel::Message::RpcRecvRequest(slot) => slot,
|
||||||
match fast_recv(&mut control.rx).await {
|
other => {
|
||||||
kernel::Message::RpcRecvRequest(slot) => slot,
|
panic!("expected nested value slot from kernel CPU, not {:?}", other)
|
||||||
other => {
|
|
||||||
panic!("expected nested value slot from kernel CPU, not {:?}", other)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})?;
|
||||||
.await?;
|
|
||||||
control
|
control
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.tx
|
.tx
|
||||||
|
@ -619,7 +615,7 @@ async fn handle_connection(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(not(has_drtio))]
|
#[cfg(not(has_drtio))]
|
||||||
{
|
{
|
||||||
write_header(stream, Reply::LoadFailed).await?;
|
write_header(stream, Reply::LoadFailed).await?;
|
||||||
write_chunk(stream, b"No DRTIO on this system, subkernels are not supported").await?;
|
write_chunk(stream, b"No DRTIO on this system, subkernels are not supported").await?;
|
||||||
|
@ -688,7 +684,8 @@ pub fn main(timer: GlobalTimer, cfg: Config) {
|
||||||
#[cfg(has_drtio_routing)]
|
#[cfg(has_drtio_routing)]
|
||||||
drtio_routing::interconnect_disable_all();
|
drtio_routing::interconnect_disable_all();
|
||||||
|
|
||||||
rtio_mgt::startup(&aux_mutex, &drtio_routing_table, &up_destinations, timer, &cfg);
|
rtio_mgt::startup(&aux_mutex, &drtio_routing_table, &up_destinations, timer);
|
||||||
|
kernel::setup_device_map(&cfg);
|
||||||
|
|
||||||
analyzer::start(&aux_mutex, &drtio_routing_table, &up_destinations, timer);
|
analyzer::start(&aux_mutex, &drtio_routing_table, &up_destinations, timer);
|
||||||
moninj::start(timer, &aux_mutex, &drtio_routing_table);
|
moninj::start(timer, &aux_mutex, &drtio_routing_table);
|
||||||
|
|
|
@ -1,132 +0,0 @@
|
||||||
use alloc::{string::String, vec::Vec};
|
|
||||||
use core::ptr;
|
|
||||||
|
|
||||||
use libcortex_a9::{mutex::Mutex, semaphore::Semaphore, sync_channel};
|
|
||||||
|
|
||||||
use crate::eh_artiq;
|
|
||||||
|
|
||||||
mod control;
|
|
||||||
pub use control::Control;
|
|
||||||
mod api;
|
|
||||||
pub mod core1;
|
|
||||||
mod dma;
|
|
||||||
mod rpc;
|
|
||||||
pub use dma::DmaRecorder;
|
|
||||||
mod cache;
|
|
||||||
#[cfg(has_drtio)]
|
|
||||||
mod subkernel;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct RPCException {
|
|
||||||
pub id: u32,
|
|
||||||
pub message: u32,
|
|
||||||
pub param: [i64; 3],
|
|
||||||
pub file: u32,
|
|
||||||
pub line: i32,
|
|
||||||
pub column: i32,
|
|
||||||
pub function: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(has_drtio)]
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum SubkernelStatus {
|
|
||||||
NoError,
|
|
||||||
Timeout,
|
|
||||||
IncorrectState,
|
|
||||||
CommLost,
|
|
||||||
OtherError,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum Message {
|
|
||||||
LoadRequest(Vec<u8>),
|
|
||||||
LoadCompleted,
|
|
||||||
LoadFailed,
|
|
||||||
StartRequest,
|
|
||||||
KernelFinished(u8),
|
|
||||||
KernelException(
|
|
||||||
&'static [Option<eh_artiq::Exception<'static>>],
|
|
||||||
&'static [eh_artiq::StackPointerBacktrace],
|
|
||||||
&'static [(usize, usize)],
|
|
||||||
u8,
|
|
||||||
),
|
|
||||||
RpcSend {
|
|
||||||
is_async: bool,
|
|
||||||
data: Vec<u8>,
|
|
||||||
},
|
|
||||||
RpcRecvRequest(*mut ()),
|
|
||||||
RpcRecvReply(Result<usize, RPCException>),
|
|
||||||
|
|
||||||
CacheGetRequest(String),
|
|
||||||
CacheGetReply(Vec<i32>),
|
|
||||||
CachePutRequest(String, Vec<i32>),
|
|
||||||
|
|
||||||
DmaPutRequest(DmaRecorder),
|
|
||||||
DmaEraseRequest(String),
|
|
||||||
DmaGetRequest(String),
|
|
||||||
DmaGetReply(Option<(i32, i64, bool)>),
|
|
||||||
#[cfg(has_drtio)]
|
|
||||||
DmaStartRemoteRequest {
|
|
||||||
id: i32,
|
|
||||||
timestamp: i64,
|
|
||||||
},
|
|
||||||
#[cfg(has_drtio)]
|
|
||||||
DmaAwaitRemoteRequest(i32),
|
|
||||||
#[cfg(has_drtio)]
|
|
||||||
DmaAwaitRemoteReply {
|
|
||||||
timeout: bool,
|
|
||||||
error: u8,
|
|
||||||
channel: u32,
|
|
||||||
timestamp: u64,
|
|
||||||
},
|
|
||||||
|
|
||||||
#[cfg(has_drtio)]
|
|
||||||
UpDestinationsRequest(i32),
|
|
||||||
#[cfg(has_drtio)]
|
|
||||||
UpDestinationsReply(bool),
|
|
||||||
|
|
||||||
#[cfg(has_drtio)]
|
|
||||||
SubkernelLoadRunRequest {
|
|
||||||
id: u32,
|
|
||||||
run: bool,
|
|
||||||
},
|
|
||||||
#[cfg(has_drtio)]
|
|
||||||
SubkernelLoadRunReply {
|
|
||||||
succeeded: bool,
|
|
||||||
},
|
|
||||||
#[cfg(has_drtio)]
|
|
||||||
SubkernelAwaitFinishRequest {
|
|
||||||
id: u32,
|
|
||||||
timeout: u64,
|
|
||||||
},
|
|
||||||
#[cfg(has_drtio)]
|
|
||||||
SubkernelAwaitFinishReply {
|
|
||||||
status: SubkernelStatus,
|
|
||||||
},
|
|
||||||
#[cfg(has_drtio)]
|
|
||||||
SubkernelMsgSend {
|
|
||||||
id: u32,
|
|
||||||
data: Vec<u8>,
|
|
||||||
},
|
|
||||||
#[cfg(has_drtio)]
|
|
||||||
SubkernelMsgRecvRequest {
|
|
||||||
id: u32,
|
|
||||||
timeout: u64,
|
|
||||||
},
|
|
||||||
#[cfg(has_drtio)]
|
|
||||||
SubkernelMsgRecvReply {
|
|
||||||
status: SubkernelStatus,
|
|
||||||
count: u8,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
static CHANNEL_0TO1: Mutex<Option<sync_channel::Sender<'static, Message>>> = Mutex::new(None);
|
|
||||||
static CHANNEL_1TO0: Mutex<Option<sync_channel::Receiver<'static, Message>>> = Mutex::new(None);
|
|
||||||
static CHANNEL_SEM: Semaphore = Semaphore::new(0, 1);
|
|
||||||
|
|
||||||
static mut KERNEL_CHANNEL_0TO1: Option<sync_channel::Receiver<'static, Message>> = None;
|
|
||||||
static mut KERNEL_CHANNEL_1TO0: Option<sync_channel::Sender<'static, Message>> = None;
|
|
||||||
|
|
||||||
pub static mut KERNEL_IMAGE: *const core1::KernelImage = ptr::null();
|
|
||||||
|
|
||||||
static INIT_LOCK: Mutex<()> = Mutex::new(());
|
|
|
@ -2,12 +2,8 @@
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![recursion_limit = "1024"] // for futures_util::select!
|
#![recursion_limit = "1024"] // for futures_util::select!
|
||||||
#![feature(alloc_error_handler)]
|
#![feature(alloc_error_handler)]
|
||||||
#![feature(panic_info_message)]
|
|
||||||
#![feature(c_variadic)]
|
|
||||||
#![feature(const_btree_new)]
|
#![feature(const_btree_new)]
|
||||||
#![feature(const_in_array_repeat_expressions)]
|
#![feature(panic_info_message)]
|
||||||
#![feature(naked_functions)]
|
|
||||||
#![feature(asm)]
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
@ -15,7 +11,8 @@ extern crate alloc;
|
||||||
#[cfg(feature = "target_kasli_soc")]
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
use core::cell::RefCell;
|
use core::cell::RefCell;
|
||||||
|
|
||||||
use libasync::{block_async, task};
|
use kernel;
|
||||||
|
use libasync::task;
|
||||||
#[cfg(feature = "target_kasli_soc")]
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
use libboard_artiq::io_expander;
|
use libboard_artiq::io_expander;
|
||||||
use libboard_artiq::{identifier_read, logger, pl};
|
use libboard_artiq::{identifier_read, logger, pl};
|
||||||
|
@ -23,90 +20,22 @@ use libboard_zynq::{gic, mpcore, timer::GlobalTimer};
|
||||||
use libconfig::Config;
|
use libconfig::Config;
|
||||||
use libcortex_a9::l2c::enable_l2_cache;
|
use libcortex_a9::l2c::enable_l2_cache;
|
||||||
use libsupport_zynq::ram;
|
use libsupport_zynq::ram;
|
||||||
use log::{error, info, warn};
|
use log::{info, warn};
|
||||||
use nb;
|
|
||||||
use void::Void;
|
|
||||||
|
|
||||||
const ASYNC_ERROR_COLLISION: u8 = 1 << 0;
|
|
||||||
const ASYNC_ERROR_BUSY: u8 = 1 << 1;
|
|
||||||
const ASYNC_ERROR_SEQUENCE_ERROR: u8 = 1 << 2;
|
|
||||||
|
|
||||||
mod analyzer;
|
mod analyzer;
|
||||||
mod comms;
|
mod comms;
|
||||||
mod eh_artiq;
|
|
||||||
mod i2c;
|
|
||||||
mod irq;
|
|
||||||
mod kernel;
|
|
||||||
mod mgmt;
|
mod mgmt;
|
||||||
mod moninj;
|
mod moninj;
|
||||||
mod panic;
|
mod panic;
|
||||||
mod proto_async;
|
mod proto_async;
|
||||||
mod rpc;
|
mod rpc_async;
|
||||||
#[cfg(ki_impl = "csr")]
|
|
||||||
#[path = "rtio_csr.rs"]
|
|
||||||
mod rtio;
|
|
||||||
#[cfg(ki_impl = "acp")]
|
|
||||||
#[path = "rtio_acp.rs"]
|
|
||||||
mod rtio;
|
|
||||||
mod rtio_clocking;
|
mod rtio_clocking;
|
||||||
mod rtio_dma;
|
mod rtio_dma;
|
||||||
mod rtio_mgt;
|
mod rtio_mgt;
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
mod subkernel;
|
mod subkernel;
|
||||||
|
|
||||||
static mut SEEN_ASYNC_ERRORS: u8 = 0;
|
|
||||||
|
|
||||||
pub unsafe fn get_async_errors() -> u8 {
|
|
||||||
let errors = SEEN_ASYNC_ERRORS;
|
|
||||||
SEEN_ASYNC_ERRORS = 0;
|
|
||||||
errors
|
|
||||||
}
|
|
||||||
|
|
||||||
fn wait_for_async_rtio_error() -> nb::Result<(), Void> {
|
|
||||||
unsafe {
|
|
||||||
if pl::csr::rtio_core::async_error_read() != 0 {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(nb::Error::WouldBlock)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn report_async_rtio_errors() {
|
|
||||||
loop {
|
|
||||||
let _ = block_async!(wait_for_async_rtio_error()).await;
|
|
||||||
unsafe {
|
|
||||||
let errors = pl::csr::rtio_core::async_error_read();
|
|
||||||
if errors & ASYNC_ERROR_COLLISION != 0 {
|
|
||||||
let channel = pl::csr::rtio_core::collision_channel_read();
|
|
||||||
error!(
|
|
||||||
"RTIO collision involving channel 0x{:04x}:{}",
|
|
||||||
channel,
|
|
||||||
rtio_mgt::resolve_channel_name(channel as u32)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if errors & ASYNC_ERROR_BUSY != 0 {
|
|
||||||
let channel = pl::csr::rtio_core::busy_channel_read();
|
|
||||||
error!(
|
|
||||||
"RTIO busy error involving channel 0x{:04x}:{}",
|
|
||||||
channel,
|
|
||||||
rtio_mgt::resolve_channel_name(channel as u32)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if errors & ASYNC_ERROR_SEQUENCE_ERROR != 0 {
|
|
||||||
let channel = pl::csr::rtio_core::sequence_error_channel_read();
|
|
||||||
error!(
|
|
||||||
"RTIO sequence error involving channel 0x{:04x}:{}",
|
|
||||||
channel,
|
|
||||||
rtio_mgt::resolve_channel_name(channel as u32)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
SEEN_ASYNC_ERRORS = errors;
|
|
||||||
pl::csr::rtio_core::async_error_write(errors);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "target_kasli_soc")]
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
async fn io_expanders_service(
|
async fn io_expanders_service(
|
||||||
i2c_bus: RefCell<&mut libboard_zynq::i2c::I2c>,
|
i2c_bus: RefCell<&mut libboard_zynq::i2c::I2c>,
|
||||||
|
@ -145,9 +74,9 @@ pub fn main_core0() {
|
||||||
|
|
||||||
info!("gateware ident: {}", identifier_read(&mut [0; 64]));
|
info!("gateware ident: {}", identifier_read(&mut [0; 64]));
|
||||||
|
|
||||||
i2c::init();
|
kernel::i2c::init();
|
||||||
#[cfg(feature = "target_kasli_soc")]
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
let i2c_bus = unsafe { (i2c::I2C_BUS).as_mut().unwrap() };
|
let i2c_bus = unsafe { (kernel::i2c::I2C_BUS).as_mut().unwrap() };
|
||||||
|
|
||||||
#[cfg(feature = "target_kasli_soc")]
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
let (mut io_expander0, mut io_expander1);
|
let (mut io_expander0, mut io_expander1);
|
||||||
|
@ -180,7 +109,7 @@ pub fn main_core0() {
|
||||||
|
|
||||||
rtio_clocking::init(&mut timer, &cfg);
|
rtio_clocking::init(&mut timer, &cfg);
|
||||||
|
|
||||||
task::spawn(report_async_rtio_errors());
|
task::spawn(kernel::report_async_rtio_errors());
|
||||||
|
|
||||||
#[cfg(feature = "target_kasli_soc")]
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
task::spawn(io_expanders_service(
|
task::spawn(io_expanders_service(
|
||||||
|
|
|
@ -0,0 +1,197 @@
|
||||||
|
use alloc::boxed::Box;
|
||||||
|
use core::future::Future;
|
||||||
|
|
||||||
|
use async_recursion::async_recursion;
|
||||||
|
use byteorder::{ByteOrder, NativeEndian};
|
||||||
|
use cslice::CMutSlice;
|
||||||
|
use kernel::rpc::{tag::{Tag, TagIterator},
|
||||||
|
*};
|
||||||
|
use libasync::smoltcp::TcpStream;
|
||||||
|
use libboard_zynq::smoltcp;
|
||||||
|
use log::trace;
|
||||||
|
|
||||||
|
use crate::proto_async;
|
||||||
|
|
||||||
|
/// Reads (deserializes) `length` array or list elements of type `tag` from `stream`,
|
||||||
|
/// writing them into the buffer given by `storage`.
|
||||||
|
///
|
||||||
|
/// `alloc` is used for nested allocations (if elements themselves contain
|
||||||
|
/// lists/arrays), see [recv_value].
|
||||||
|
#[async_recursion(?Send)]
|
||||||
|
async unsafe fn recv_elements<F>(
|
||||||
|
stream: &TcpStream,
|
||||||
|
elt_tag: Tag<'async_recursion>,
|
||||||
|
length: usize,
|
||||||
|
storage: *mut (),
|
||||||
|
alloc: &(impl Fn(usize) -> F + 'async_recursion),
|
||||||
|
) -> Result<(), smoltcp::Error>
|
||||||
|
where
|
||||||
|
F: Future<Output = *mut ()>,
|
||||||
|
{
|
||||||
|
// List of simple types are special-cased in the protocol for performance.
|
||||||
|
match elt_tag {
|
||||||
|
Tag::Bool => {
|
||||||
|
let dest = core::slice::from_raw_parts_mut(storage as *mut u8, length);
|
||||||
|
proto_async::read_chunk(stream, dest).await?;
|
||||||
|
}
|
||||||
|
Tag::Int32 => {
|
||||||
|
let ptr = storage as *mut u32;
|
||||||
|
let dest = core::slice::from_raw_parts_mut(ptr as *mut u8, length * 4);
|
||||||
|
proto_async::read_chunk(stream, dest).await?;
|
||||||
|
drop(dest);
|
||||||
|
let dest = core::slice::from_raw_parts_mut(ptr, length);
|
||||||
|
NativeEndian::from_slice_u32(dest);
|
||||||
|
}
|
||||||
|
Tag::Int64 | Tag::Float64 => {
|
||||||
|
let ptr = storage as *mut u64;
|
||||||
|
let dest = core::slice::from_raw_parts_mut(ptr as *mut u8, length * 8);
|
||||||
|
proto_async::read_chunk(stream, dest).await?;
|
||||||
|
drop(dest);
|
||||||
|
let dest = core::slice::from_raw_parts_mut(ptr, length);
|
||||||
|
NativeEndian::from_slice_u64(dest);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let mut data = storage;
|
||||||
|
for _ in 0..length {
|
||||||
|
recv_value(stream, elt_tag, &mut data, alloc).await?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reads (deserializes) a value of type `tag` from `stream`, writing the results to
|
||||||
|
/// the kernel-side buffer `data` (the passed pointer to which is incremented to point
|
||||||
|
/// past the just-received data). For nested allocations (lists/arrays), `alloc` is
|
||||||
|
/// invoked any number of times with the size of the required allocation as a parameter
|
||||||
|
/// (which is assumed to be correctly aligned for all payload types).
|
||||||
|
#[async_recursion(?Send)]
|
||||||
|
async unsafe fn recv_value<F>(
|
||||||
|
stream: &TcpStream,
|
||||||
|
tag: Tag<'async_recursion>,
|
||||||
|
data: &mut *mut (),
|
||||||
|
alloc: &(impl Fn(usize) -> F + 'async_recursion),
|
||||||
|
) -> Result<(), smoltcp::Error>
|
||||||
|
where
|
||||||
|
F: Future<Output = *mut ()>,
|
||||||
|
{
|
||||||
|
macro_rules! consume_value {
|
||||||
|
($ty:ty, | $ptr:ident | $map:expr) => {{
|
||||||
|
let $ptr = align_ptr_mut::<$ty>(*data);
|
||||||
|
*data = $ptr.offset(1) as *mut ();
|
||||||
|
$map
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
match tag {
|
||||||
|
Tag::None => Ok(()),
|
||||||
|
Tag::Bool => consume_value!(i8, |ptr| {
|
||||||
|
*ptr = proto_async::read_i8(stream).await?;
|
||||||
|
Ok(())
|
||||||
|
}),
|
||||||
|
Tag::Int32 => consume_value!(i32, |ptr| {
|
||||||
|
*ptr = proto_async::read_i32(stream).await?;
|
||||||
|
Ok(())
|
||||||
|
}),
|
||||||
|
Tag::Int64 | Tag::Float64 => consume_value!(i64, |ptr| {
|
||||||
|
*ptr = proto_async::read_i64(stream).await?;
|
||||||
|
Ok(())
|
||||||
|
}),
|
||||||
|
Tag::String | Tag::Bytes | Tag::ByteArray => {
|
||||||
|
consume_value!(CMutSlice<u8>, |ptr| {
|
||||||
|
let length = proto_async::read_i32(stream).await? as usize;
|
||||||
|
*ptr = CMutSlice::new(alloc(length).await as *mut u8, length);
|
||||||
|
proto_async::read_chunk(stream, (*ptr).as_mut()).await?;
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Tag::Tuple(it, arity) => {
|
||||||
|
let alignment = tag.alignment();
|
||||||
|
*data = round_up_mut(*data, alignment);
|
||||||
|
let mut it = it.clone();
|
||||||
|
for _ in 0..arity {
|
||||||
|
let tag = it.next().expect("truncated tag");
|
||||||
|
recv_value(stream, tag, data, alloc).await?
|
||||||
|
}
|
||||||
|
// Take into account any tail padding (if element(s) with largest alignment
|
||||||
|
// are not at the end).
|
||||||
|
*data = round_up_mut(*data, alignment);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Tag::List(it) => {
|
||||||
|
#[repr(C)]
|
||||||
|
struct List {
|
||||||
|
elements: *mut (),
|
||||||
|
length: usize,
|
||||||
|
}
|
||||||
|
consume_value!(*mut List, |ptr_to_list| {
|
||||||
|
let tag = it.clone().next().expect("truncated tag");
|
||||||
|
let length = proto_async::read_i32(stream).await? as usize;
|
||||||
|
|
||||||
|
// To avoid multiple kernel CPU roundtrips, use a single allocation for
|
||||||
|
// both the pointer/length List (slice) and the backing storage for the
|
||||||
|
// elements. We can assume that alloc() is aligned suitably, so just
|
||||||
|
// need to take into account any extra padding required.
|
||||||
|
// (Note: At the time of writing, there will never actually be any types
|
||||||
|
// with alignment larger than 8 bytes, so storage_offset == 0 always.)
|
||||||
|
let list_size = 4 + 4;
|
||||||
|
let storage_offset = round_up(list_size, tag.alignment());
|
||||||
|
let storage_size = tag.size() * length;
|
||||||
|
|
||||||
|
let allocation = alloc(storage_offset + storage_size).await as *mut u8;
|
||||||
|
*ptr_to_list = allocation as *mut List;
|
||||||
|
let storage = allocation.offset(storage_offset as isize) as *mut ();
|
||||||
|
|
||||||
|
(**ptr_to_list).length = length;
|
||||||
|
(**ptr_to_list).elements = storage;
|
||||||
|
recv_elements(stream, tag, length, storage, alloc).await
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Tag::Array(it, num_dims) => {
|
||||||
|
consume_value!(*mut (), |buffer| {
|
||||||
|
// Deserialize length along each dimension and compute total number of
|
||||||
|
// elements.
|
||||||
|
let mut total_len: usize = 1;
|
||||||
|
for _ in 0..num_dims {
|
||||||
|
let len = proto_async::read_i32(stream).await? as usize;
|
||||||
|
total_len *= len;
|
||||||
|
consume_value!(usize, |ptr| *ptr = len)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate backing storage for elements; deserialize them.
|
||||||
|
let elt_tag = it.clone().next().expect("truncated tag");
|
||||||
|
*buffer = alloc(elt_tag.size() * total_len).await;
|
||||||
|
recv_elements(stream, elt_tag, total_len, *buffer, alloc).await
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Tag::Range(it) => {
|
||||||
|
*data = round_up_mut(*data, tag.alignment());
|
||||||
|
let tag = it.clone().next().expect("truncated tag");
|
||||||
|
recv_value(stream, tag, data, alloc).await?;
|
||||||
|
recv_value(stream, tag, data, alloc).await?;
|
||||||
|
recv_value(stream, tag, data, alloc).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Tag::Keyword(_) => unreachable!(),
|
||||||
|
Tag::Object => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn recv_return<F>(
|
||||||
|
stream: &TcpStream,
|
||||||
|
tag_bytes: &[u8],
|
||||||
|
data: *mut (),
|
||||||
|
alloc: &impl Fn(usize) -> F,
|
||||||
|
) -> Result<(), smoltcp::Error>
|
||||||
|
where
|
||||||
|
F: Future<Output = *mut ()>,
|
||||||
|
{
|
||||||
|
let mut it = TagIterator::new(tag_bytes);
|
||||||
|
trace!("recv ...->{}", it);
|
||||||
|
|
||||||
|
let tag = it.next().expect("truncated tag");
|
||||||
|
let mut data = data;
|
||||||
|
unsafe { recv_value(stream, tag, &mut data, alloc).await? };
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -1,4 +1,6 @@
|
||||||
use embedded_hal::blocking::delay::DelayMs;
|
use embedded_hal::blocking::delay::DelayMs;
|
||||||
|
#[cfg(has_si5324)]
|
||||||
|
use kernel::i2c;
|
||||||
use libboard_artiq::pl;
|
use libboard_artiq::pl;
|
||||||
#[cfg(has_si5324)]
|
#[cfg(has_si5324)]
|
||||||
use libboard_artiq::si5324;
|
use libboard_artiq::si5324;
|
||||||
|
@ -8,9 +10,6 @@ use libboard_zynq::timer::GlobalTimer;
|
||||||
use libconfig::Config;
|
use libconfig::Config;
|
||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
|
|
||||||
#[cfg(has_si5324)]
|
|
||||||
use crate::i2c;
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Copy, Clone)]
|
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
pub enum RtioClock {
|
pub enum RtioClock {
|
||||||
|
|
|
@ -2,14 +2,13 @@ use alloc::{collections::BTreeMap, rc::Rc, string::String, vec::Vec};
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
use core::mem;
|
use core::mem;
|
||||||
|
|
||||||
|
use kernel::DmaRecorder;
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
use libasync::task;
|
use libasync::task;
|
||||||
use libboard_artiq::drtio_routing::RoutingTable;
|
use libboard_artiq::drtio_routing::RoutingTable;
|
||||||
use libboard_zynq::timer::GlobalTimer;
|
use libboard_zynq::timer::GlobalTimer;
|
||||||
use libcortex_a9::{cache::dcci_slice, mutex::Mutex};
|
use libcortex_a9::{cache::dcci_slice, mutex::Mutex};
|
||||||
|
|
||||||
use crate::kernel::DmaRecorder;
|
|
||||||
|
|
||||||
const ALIGNMENT: usize = 16 * 8;
|
const ALIGNMENT: usize = 16 * 8;
|
||||||
|
|
||||||
static DMA_RECORD_STORE: Mutex<BTreeMap<String, (u32, Vec<u8>, i64)>> = Mutex::new(BTreeMap::new());
|
static DMA_RECORD_STORE: Mutex<BTreeMap<String, (u32, Vec<u8>, i64)>> = Mutex::new(BTreeMap::new());
|
||||||
|
|
|
@ -1,20 +1,16 @@
|
||||||
use alloc::{collections::BTreeMap, rc::Rc, string::String};
|
use alloc::rc::Rc;
|
||||||
use core::cell::RefCell;
|
use core::cell::RefCell;
|
||||||
|
|
||||||
use io::{Cursor, ProtoRead};
|
|
||||||
use libboard_artiq::{drtio_routing, pl::csr};
|
use libboard_artiq::{drtio_routing, pl::csr};
|
||||||
use libboard_zynq::timer::GlobalTimer;
|
use libboard_zynq::timer::GlobalTimer;
|
||||||
use libconfig::Config;
|
|
||||||
use libcortex_a9::mutex::Mutex;
|
use libcortex_a9::mutex::Mutex;
|
||||||
use log::warn;
|
|
||||||
|
|
||||||
static mut RTIO_DEVICE_MAP: BTreeMap<u32, String> = BTreeMap::new();
|
|
||||||
|
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
pub mod drtio {
|
pub mod drtio {
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
use embedded_hal::blocking::delay::DelayMs;
|
use embedded_hal::blocking::delay::DelayMs;
|
||||||
|
use kernel::{ASYNC_ERROR_BUSY, ASYNC_ERROR_COLLISION, ASYNC_ERROR_SEQUENCE_ERROR, SEEN_ASYNC_ERRORS};
|
||||||
use libasync::{delay, task};
|
use libasync::{delay, task};
|
||||||
use libboard_artiq::{drtioaux::Error, drtioaux_async, drtioaux_async::Packet,
|
use libboard_artiq::{drtioaux::Error, drtioaux_async, drtioaux_async::Packet,
|
||||||
drtioaux_proto::MASTER_PAYLOAD_MAX_SIZE};
|
drtioaux_proto::MASTER_PAYLOAD_MAX_SIZE};
|
||||||
|
@ -22,8 +18,7 @@ pub mod drtio {
|
||||||
use log::{error, info, warn};
|
use log::{error, info, warn};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{analyzer::remote_analyzer::RemoteBuffer, rtio_dma::remote_dma, subkernel, ASYNC_ERROR_BUSY,
|
use crate::{analyzer::remote_analyzer::RemoteBuffer, rtio_dma::remote_dma, subkernel};
|
||||||
ASYNC_ERROR_COLLISION, ASYNC_ERROR_SEQUENCE_ERROR, SEEN_ASYNC_ERRORS};
|
|
||||||
|
|
||||||
pub fn startup(
|
pub fn startup(
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
aux_mutex: &Rc<Mutex<bool>>,
|
||||||
|
@ -756,46 +751,6 @@ pub mod drtio {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_device_map(cfg: &Config) -> BTreeMap<u32, String> {
|
|
||||||
let mut device_map: BTreeMap<u32, String> = BTreeMap::new();
|
|
||||||
let _ = cfg
|
|
||||||
.read("device_map")
|
|
||||||
.and_then(|raw_bytes| {
|
|
||||||
let mut bytes_cr = Cursor::new(raw_bytes);
|
|
||||||
let size = bytes_cr.read_u32().unwrap();
|
|
||||||
for _ in 0..size {
|
|
||||||
let channel = bytes_cr.read_u32().unwrap();
|
|
||||||
let device_name = bytes_cr.read_string().unwrap();
|
|
||||||
if let Some(old_entry) = device_map.insert(channel, device_name.clone()) {
|
|
||||||
warn!(
|
|
||||||
"conflicting device map entries for RTIO channel {}: '{}' and '{}'",
|
|
||||||
channel, old_entry, device_name
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
.or_else(|err| {
|
|
||||||
warn!(
|
|
||||||
"error reading device map ({}), device names will not be available in RTIO error messages",
|
|
||||||
err
|
|
||||||
);
|
|
||||||
Err(err)
|
|
||||||
});
|
|
||||||
device_map
|
|
||||||
}
|
|
||||||
|
|
||||||
fn _resolve_channel_name(channel: u32, device_map: &BTreeMap<u32, String>) -> String {
|
|
||||||
match device_map.get(&channel) {
|
|
||||||
Some(val) => val.clone(),
|
|
||||||
None => String::from("unknown"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn resolve_channel_name(channel: u32) -> String {
|
|
||||||
_resolve_channel_name(channel, unsafe { &RTIO_DEVICE_MAP })
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(has_drtio))]
|
#[cfg(not(has_drtio))]
|
||||||
pub mod drtio {
|
pub mod drtio {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -817,11 +772,7 @@ pub fn startup(
|
||||||
routing_table: &Rc<RefCell<drtio_routing::RoutingTable>>,
|
routing_table: &Rc<RefCell<drtio_routing::RoutingTable>>,
|
||||||
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
|
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
|
||||||
timer: GlobalTimer,
|
timer: GlobalTimer,
|
||||||
cfg: &Config,
|
|
||||||
) {
|
) {
|
||||||
unsafe {
|
|
||||||
RTIO_DEVICE_MAP = read_device_map(cfg);
|
|
||||||
}
|
|
||||||
drtio::startup(aux_mutex, routing_table, up_destinations, timer);
|
drtio::startup(aux_mutex, routing_table, up_destinations, timer);
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::rtio_core::reset_phy_write(1);
|
csr::rtio_core::reset_phy_write(1);
|
||||||
|
|
Loading…
Reference in New Issue