Compare commits

...

18 Commits

Author SHA1 Message Date
abdul124 118f096c5a flake: update dependencies 2024-08-23 17:39:05 +08:00
abdul124 953e60b4d2 firmware: restore exception id order 2024-08-23 14:12:50 +08:00
Sebastien Bourdeauducq 0e48524999 flake: update dependencies 2024-08-21 18:57:20 +08:00
abdul124 e9a8c3fe10 firmware: add unit tests for exception sync 2024-08-21 18:45:33 +08:00
abdul124 84bcdec2d2 firmware: sync exception names and ids 2024-08-21 18:44:50 +08:00
Sebastien Bourdeauducq 367061aab8 cargo fmt 2024-08-05 19:37:39 +08:00
Simon Renblad f348ea140a comms: remove idle kernel DRTIO error case 2024-08-05 19:28:43 +08:00
Simon Renblad 6e5cbf8abf comms: run idle kernel on start-up 2024-08-05 19:28:43 +08:00
mwojcik a67e45a2bc subkernels: support exceptions from subkernels 2024-07-31 17:23:56 +08:00
mwojcik a9b43e8ae2 subkernels: raise exceptions to kernel 2024-07-31 17:23:56 +08:00
Sebastien Bourdeauducq 8e72f28f24 flake: update dependencies 2024-07-31 17:22:46 +08:00
mwojcik 4248d71555 repeater: handle async messages 2024-07-09 17:05:16 +02:00
mwojcik 836e266a36 allow toggling SED spread with flash config key 2024-07-09 17:00:09 +02:00
Sebastien Bourdeauducq c58256fdd4 flake: update dependencies 2024-07-09 16:59:33 +02:00
abdul124 25e858f2e9 kernel/api: add rint api 2024-07-05 08:55:13 +02:00
mwojcik 50c63b2c93 repeater: clear buffer after ping 2024-07-04 13:40:32 +02:00
Sebastien Bourdeauducq f87adab53f flake: update dependencies 2024-06-06 13:55:46 +08:00
Sebastien Bourdeauducq cae316fe10 flake: follow ARTIQ release-8 2024-06-06 10:19:58 +08:00
15 changed files with 790 additions and 215 deletions

View File

@ -11,15 +11,16 @@
"src-pythonparser": "src-pythonparser" "src-pythonparser": "src-pythonparser"
}, },
"locked": { "locked": {
"lastModified": 1717638354, "lastModified": 1724402779,
"narHash": "sha256-eyI8OsOrn/j8ChbCpyFpS5VXBW8xSNGGIboFGQj/d4I=", "narHash": "sha256-mWaCa1AMsUbL+1rIfPB359LUAMQea8Krtctbu901rdY=",
"ref": "refs/heads/master", "ref": "release-8",
"rev": "ebc1e3fb767d6c0eac6eac20c3afeaba2ab70d1a", "rev": "4235309ab75519aee98d06f942c8cb90fba94af7",
"revCount": 8833, "revCount": 8954,
"type": "git", "type": "git",
"url": "https://github.com/m-labs/artiq.git" "url": "https://github.com/m-labs/artiq.git"
}, },
"original": { "original": {
"ref": "release-8",
"type": "git", "type": "git",
"url": "https://github.com/m-labs/artiq.git" "url": "https://github.com/m-labs/artiq.git"
} }
@ -37,11 +38,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1717637438, "lastModified": 1720768567,
"narHash": "sha256-BXFidNm3Em8iChPGu1L0s2bY+f2yQ0VVid4MuOoTehw=", "narHash": "sha256-3VoK7o5MtHtbHLrc6Pv+eQWFtaz5Gd/YWyV5TD3c5Ss=",
"owner": "m-labs", "owner": "m-labs",
"repo": "artiq-comtools", "repo": "artiq-comtools",
"rev": "78d27026efe76a13f7b4698a554f55811369ec4d", "rev": "f93570d8f2ed5a3cfb3e1c16ab00f2540551e994",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -118,11 +119,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1717281328, "lastModified": 1722987190,
"narHash": "sha256-evZPzpf59oNcDUXxh2GHcxHkTEG4fjae2ytWP85jXRo=", "narHash": "sha256-68hmex5efCiM2aZlAAEcQgmFI4ZwWt8a80vOeB/5w3A=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "b3b2b28c1daa04fe2ae47c21bb76fd226eac4ca1", "rev": "21cc704b5e918c5fbf4f9fff22b4ac2681706d90",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -163,11 +164,11 @@
"src-migen": { "src-migen": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1715484909, "lastModified": 1721561053,
"narHash": "sha256-4DCHBUBfc/VA+7NW2Hr0+JP4NnKPru2uVJyZjCCk0Ws=", "narHash": "sha256-z3LRhNmKZrjr6rFD0yxtccSa/SWvFIYmb+G/D5d2Jd8=",
"owner": "m-labs", "owner": "m-labs",
"repo": "migen", "repo": "migen",
"rev": "4790bb577681a8c3a8d226bc196a4e5deb39e4df", "rev": "9279e8623f8433bc4f23ac51e5e2331bfe544417",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -234,11 +235,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1716889070, "lastModified": 1720537402,
"narHash": "sha256-w+M5NfukmcMTt73+u6Cmltjn4qpQH8bcoTGskB2IzBE=", "narHash": "sha256-ybvaQ48SVBqYVqgYmGUdefGZkni7PJ90qYQPHnFOwDs=",
"ref": "refs/heads/master", "ref": "refs/heads/master",
"rev": "51b8111e799ebe90ca231ae4d02f84ede32632d5", "rev": "b2b3e5c933cbc4b7cb14adde480d7561a3ae71ee",
"revCount": 646, "revCount": 648,
"type": "git", "type": "git",
"url": "https://git.m-labs.hk/m-labs/zynq-rs" "url": "https://git.m-labs.hk/m-labs/zynq-rs"
}, },

View File

@ -1,7 +1,7 @@
{ {
description = "ARTIQ port to the Zynq-7000 platform"; description = "ARTIQ port to the Zynq-7000 platform";
inputs.artiq.url = git+https://github.com/m-labs/artiq.git; inputs.artiq.url = git+https://github.com/m-labs/artiq.git?ref=release-8;
inputs.mozilla-overlay = { url = github:mozilla/nixpkgs-mozilla; flake = false; }; inputs.mozilla-overlay = { url = github:mozilla/nixpkgs-mozilla; flake = false; };
inputs.zynq-rs.url = git+https://git.m-labs.hk/m-labs/zynq-rs; inputs.zynq-rs.url = git+https://git.m-labs.hk/m-labs/zynq-rs;
inputs.zynq-rs.inputs.nixpkgs.follows = "artiq/nixpkgs"; inputs.zynq-rs.inputs.nixpkgs.follows = "artiq/nixpkgs";

View File

@ -560,7 +560,10 @@ class GenericSatellite(SoCCore):
self.submodules.local_io = SyncRTIO( self.submodules.local_io = SyncRTIO(
self.rtio_tsc, self.rtio_channels, lane_count=description["sed_lanes"] self.rtio_tsc, self.rtio_channels, lane_count=description["sed_lanes"]
) )
self.comb += self.drtiosat.async_errors.eq(self.local_io.async_errors) self.comb += [
self.drtiosat.async_errors.eq(self.local_io.async_errors),
self.local_io.sed_spread_enable.eq(self.drtiosat.sed_spread_enable.storage)
]
self.submodules.cri_con = rtio.CRIInterconnectShared( self.submodules.cri_con = rtio.CRIInterconnectShared(
[self.drtiosat.cri, self.rtio_dma.cri, self.rtio.cri], [self.drtiosat.cri, self.rtio_dma.cri, self.rtio.cri],

View File

@ -487,6 +487,10 @@ class _SatelliteBase(SoCCore):
self.csr_devices.append("rtio_dma") self.csr_devices.append("rtio_dma")
self.submodules.local_io = SyncRTIO(self.rtio_tsc, rtio_channels) self.submodules.local_io = SyncRTIO(self.rtio_tsc, rtio_channels)
self.comb += [
self.drtiosat.async_errors.eq(self.local_io.async_errors),
self.local_io.sed_spread_enable.eq(self.drtiosat.sed_spread_enable.storage)
]
self.submodules.cri_con = rtio.CRIInterconnectShared( self.submodules.cri_con = rtio.CRIInterconnectShared(
[self.drtiosat.cri, self.rtio_dma.cri, self.rtio.cri], [self.drtiosat.cri, self.rtio_dma.cri, self.rtio.cri],
[self.local_io.cri] + self.drtio_cri, [self.local_io.cri] + self.drtio_cri,

View File

@ -267,12 +267,14 @@ pub enum Packet {
exception_src: u8, exception_src: u8,
}, },
SubkernelExceptionRequest { SubkernelExceptionRequest {
source: u8,
destination: u8, destination: u8,
}, },
SubkernelException { SubkernelException {
destination: u8,
last: bool, last: bool,
length: u16, length: u16,
data: [u8; SAT_PAYLOAD_MAX_SIZE], data: [u8; MASTER_PAYLOAD_MAX_SIZE],
}, },
SubkernelMessage { SubkernelMessage {
source: u8, source: u8,
@ -524,14 +526,17 @@ impl Packet {
exception_src: reader.read_u8()?, exception_src: reader.read_u8()?,
}, },
0xc9 => Packet::SubkernelExceptionRequest { 0xc9 => Packet::SubkernelExceptionRequest {
source: reader.read_u8()?,
destination: reader.read_u8()?, destination: reader.read_u8()?,
}, },
0xca => { 0xca => {
let destination = reader.read_u8()?;
let last = reader.read_bool()?; let last = reader.read_bool()?;
let length = reader.read_u16()?; let length = reader.read_u16()?;
let mut data: [u8; SAT_PAYLOAD_MAX_SIZE] = [0; SAT_PAYLOAD_MAX_SIZE]; let mut data: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
reader.read_exact(&mut data[0..length as usize])?; reader.read_exact(&mut data[0..length as usize])?;
Packet::SubkernelException { Packet::SubkernelException {
destination: destination,
last: last, last: last,
length: length, length: length,
data: data, data: data,
@ -896,12 +901,19 @@ impl Packet {
writer.write_bool(with_exception)?; writer.write_bool(with_exception)?;
writer.write_u8(exception_src)?; writer.write_u8(exception_src)?;
} }
Packet::SubkernelExceptionRequest { destination } => { Packet::SubkernelExceptionRequest { source, destination } => {
writer.write_u8(0xc9)?; writer.write_u8(0xc9)?;
writer.write_u8(source)?;
writer.write_u8(destination)?; writer.write_u8(destination)?;
} }
Packet::SubkernelException { last, length, data } => { Packet::SubkernelException {
destination,
last,
length,
data,
} => {
writer.write_u8(0xca)?; writer.write_u8(0xca)?;
writer.write_u8(destination)?;
writer.write_bool(last)?; writer.write_bool(last)?;
writer.write_u16(length)?; writer.write_u16(length)?;
writer.write_all(&data[0..length as usize])?; writer.write_all(&data[0..length as usize])?;
@ -943,6 +955,8 @@ impl Packet {
Packet::SubkernelLoadRunReply { destination, .. } => Some(*destination), Packet::SubkernelLoadRunReply { destination, .. } => Some(*destination),
Packet::SubkernelMessage { destination, .. } => Some(*destination), Packet::SubkernelMessage { destination, .. } => Some(*destination),
Packet::SubkernelMessageAck { destination } => Some(*destination), Packet::SubkernelMessageAck { destination } => Some(*destination),
Packet::SubkernelExceptionRequest { destination, .. } => Some(*destination),
Packet::SubkernelException { destination, .. } => Some(*destination),
Packet::DmaPlaybackStatus { destination, .. } => Some(*destination), Packet::DmaPlaybackStatus { destination, .. } => Some(*destination),
Packet::SubkernelFinished { destination, .. } => Some(*destination), Packet::SubkernelFinished { destination, .. } => Some(*destination),
_ => None, _ => None,

View File

@ -14,8 +14,10 @@
use core::mem; use core::mem;
use cslice::CSlice; use core_io::Error as ReadError;
use cslice::{AsCSlice, CSlice};
use dwarf::eh::{self, EHAction, EHContext}; use dwarf::eh::{self, EHAction, EHContext};
use io::{Cursor, ProtoRead};
use libc::{c_int, c_void, uintptr_t}; use libc::{c_int, c_void, uintptr_t};
use log::{error, trace}; use log::{error, trace};
use unwind as uw; use unwind as uw;
@ -220,8 +222,6 @@ pub unsafe fn artiq_personality(
} }
pub unsafe extern "C" fn raise(exception: *const Exception) -> ! { pub unsafe extern "C" fn raise(exception: *const Exception) -> ! {
use cslice::AsCSlice;
let count = EXCEPTION_BUFFER.exception_count; let count = EXCEPTION_BUFFER.exception_count;
let stack = &mut EXCEPTION_BUFFER.exception_stack; let stack = &mut EXCEPTION_BUFFER.exception_stack;
let diff = exception as isize - EXCEPTION_BUFFER.exceptions.as_ptr() as isize; let diff = exception as isize - EXCEPTION_BUFFER.exceptions.as_ptr() as isize;
@ -295,6 +295,60 @@ pub unsafe extern "C" fn raise(exception: *const Exception) -> ! {
unreachable!(); unreachable!();
} }
fn read_exception_string<'a>(reader: &mut Cursor<&[u8]>) -> Result<CSlice<'a, u8>, ReadError> {
let len = reader.read_u32()? as usize;
if len == usize::MAX {
let data = reader.read_u32()?;
Ok(unsafe { CSlice::new(data as *const u8, len) })
} else {
let pos = reader.position();
let slice = unsafe {
let ptr = reader.get_ref().as_ptr().offset(pos as isize);
CSlice::new(ptr, len)
};
reader.set_position(pos + len);
Ok(slice)
}
}
fn read_exception(raw_exception: &[u8]) -> Result<Exception, ReadError> {
let mut reader = Cursor::new(raw_exception);
let mut byte = reader.read_u8()?;
// to sync
while byte != 0x5a {
byte = reader.read_u8()?;
}
// skip sync bytes, 0x09 indicates exception
while byte != 0x09 {
byte = reader.read_u8()?;
}
let _len = reader.read_u32()?;
// ignore the remaining exceptions, stack traces etc. - unwinding from another device would be unwise anyway
Ok(Exception {
id: reader.read_u32()?,
message: read_exception_string(&mut reader)?,
param: [
reader.read_u64()? as i64,
reader.read_u64()? as i64,
reader.read_u64()? as i64,
],
file: read_exception_string(&mut reader)?,
line: reader.read_u32()?,
column: reader.read_u32()?,
function: read_exception_string(&mut reader)?,
})
}
pub fn raise_raw(raw_exception: &[u8]) -> ! {
use crate::artiq_raise;
if let Ok(exception) = read_exception(raw_exception) {
unsafe { raise(&exception) };
} else {
artiq_raise!("SubkernelError", "Error passing exception");
}
}
pub unsafe extern "C" fn resume() -> ! { pub unsafe extern "C" fn resume() -> ! {
trace!("resume"); trace!("resume");
assert!(EXCEPTION_BUFFER.exception_count != 0); assert!(EXCEPTION_BUFFER.exception_count != 0);
@ -421,7 +475,7 @@ extern "C" fn stop_fn(
} }
} }
// Must be kept in sync with preallocate_runtime_exception_names() in artiq/language/embedding_map.py // Must be kept in sync with preallocate_runtime_exception_names() in `artiq.compiler.embedding`
static EXCEPTION_ID_LOOKUP: [(&str, u32); 12] = [ static EXCEPTION_ID_LOOKUP: [(&str, u32); 12] = [
("RuntimeError", 0), ("RuntimeError", 0),
("RTIOUnderflow", 1), ("RTIOUnderflow", 1),
@ -469,3 +523,29 @@ macro_rules! artiq_raise {
}}; }};
($name:expr, $message:expr) => {{ artiq_raise!($name, $message, 0, 0, 0) }}; ($name:expr, $message:expr) => {{ artiq_raise!($name, $message, 0, 0, 0) }};
} }
/// Takes as input exception id from host
/// Generates a new exception with:
/// * `id` set to `exn_id`
/// * `message` set to corresponding exception name from `EXCEPTION_ID_LOOKUP`
///
/// The message is matched on host to ensure correct exception is being referred
/// This test checks the synchronization of exception ids for runtime errors
#[no_mangle]
pub extern "C" fn test_exception_id_sync(exn_id: u32) {
let message = EXCEPTION_ID_LOOKUP
.iter()
.find_map(|&(name, id)| if id == exn_id { Some(name) } else { None })
.unwrap_or("unallocated internal exception id");
let exn = Exception {
id: exn_id,
file: file!().as_c_slice(),
line: 0,
column: 0,
function: "test_exception_id_sync".as_c_slice(),
message: message.as_c_slice(),
param: [0, 0, 0],
};
unsafe { raise(&exn) };
}

View File

@ -303,6 +303,7 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
api_libm_f64f64f64!(nextafter), api_libm_f64f64f64!(nextafter),
api_libm_f64f64f64!(pow), api_libm_f64f64f64!(pow),
api_libm_f64f64!(round), api_libm_f64f64!(round),
api_libm_f64f64!(rint),
api_libm_f64f64!(sin), api_libm_f64f64!(sin),
api_libm_f64f64!(sinh), api_libm_f64f64!(sinh),
api_libm_f64f64!(sqrt), api_libm_f64f64!(sqrt),
@ -318,6 +319,13 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
} }
api!(yn = yn) api!(yn = yn)
}, },
/*
* syscall for unit tests
* Used in `artiq.tests.coredevice.test_exceptions.ExceptionTest.test_raise_exceptions_kernel`
* This syscall checks that the exception IDs used in the Python `EmbeddingMap` (in `artiq.language.embedding`)
* match the `EXCEPTION_ID_LOOKUP` defined in the firmware (`libksupport::src::eh_artiq`)
*/
api!(test_exception_id_sync = eh_artiq::test_exception_id_sync)
]; ];
api.iter() api.iter()
.find(|&&(exported, _)| exported.as_bytes() == required) .find(|&&(exported, _)| exported.as_bytes() == required)

View File

@ -23,6 +23,7 @@ pub enum SubkernelStatus {
Timeout, Timeout,
IncorrectState, IncorrectState,
CommLost, CommLost,
Exception(Vec<u8>),
OtherError, OtherError,
} }
@ -90,9 +91,7 @@ pub enum Message {
timeout: i64, timeout: i64,
}, },
#[cfg(has_drtio)] #[cfg(has_drtio)]
SubkernelAwaitFinishReply { SubkernelAwaitFinishReply,
status: SubkernelStatus,
},
#[cfg(has_drtio)] #[cfg(has_drtio)]
SubkernelMsgSend { SubkernelMsgSend {
id: u32, id: u32,
@ -109,9 +108,10 @@ pub enum Message {
}, },
#[cfg(has_drtio)] #[cfg(has_drtio)]
SubkernelMsgRecvReply { SubkernelMsgRecvReply {
status: SubkernelStatus,
count: u8, count: u8,
}, },
#[cfg(has_drtio)]
SubkernelError(SubkernelStatus),
} }
static CHANNEL_0TO1: Mutex<Option<sync_channel::Sender<'static, Message>>> = Mutex::new(None); static CHANNEL_0TO1: Mutex<Option<sync_channel::Sender<'static, Message>>> = Mutex::new(None);

View File

@ -3,7 +3,7 @@ use alloc::vec::Vec;
use cslice::CSlice; use cslice::CSlice;
use super::{Message, SubkernelStatus, KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0}; use super::{Message, SubkernelStatus, KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0};
use crate::{artiq_raise, rpc::send_args}; use crate::{artiq_raise, eh_artiq, rpc::send_args};
pub extern "C" fn load_run(id: u32, destination: u8, run: bool) { pub extern "C" fn load_run(id: u32, destination: u8, run: bool) {
unsafe { unsafe {
@ -36,21 +36,18 @@ pub extern "C" fn await_finish(id: u32, timeout: i64) {
}); });
} }
match unsafe { KERNEL_CHANNEL_0TO1.as_mut().unwrap() }.recv() { match unsafe { KERNEL_CHANNEL_0TO1.as_mut().unwrap() }.recv() {
Message::SubkernelAwaitFinishReply { Message::SubkernelAwaitFinishReply => (),
status: SubkernelStatus::NoError, Message::SubkernelError(SubkernelStatus::IncorrectState) => {
} => (), artiq_raise!("SubkernelError", "Subkernel not running")
Message::SubkernelAwaitFinishReply { }
status: SubkernelStatus::IncorrectState, Message::SubkernelError(SubkernelStatus::Timeout) => artiq_raise!("SubkernelError", "Subkernel timed out"),
} => artiq_raise!("SubkernelError", "Subkernel not running"), Message::SubkernelError(SubkernelStatus::CommLost) => {
Message::SubkernelAwaitFinishReply { artiq_raise!("SubkernelError", "Lost communication with satellite")
status: SubkernelStatus::Timeout, }
} => artiq_raise!("SubkernelError", "Subkernel timed out"), Message::SubkernelError(SubkernelStatus::OtherError) => {
Message::SubkernelAwaitFinishReply { artiq_raise!("SubkernelError", "An error occurred during subkernel operation")
status: SubkernelStatus::CommLost, }
} => artiq_raise!("SubkernelError", "Lost communication with satellite"), Message::SubkernelError(SubkernelStatus::Exception(raw_exception)) => eh_artiq::raise_raw(&raw_exception),
Message::SubkernelAwaitFinishReply {
status: SubkernelStatus::OtherError,
} => artiq_raise!("SubkernelError", "An error occurred during subkernel operation"),
_ => panic!("expected SubkernelAwaitFinishReply after SubkernelAwaitFinishRequest"), _ => panic!("expected SubkernelAwaitFinishReply after SubkernelAwaitFinishRequest"),
} }
} }
@ -92,30 +89,22 @@ pub extern "C" fn await_message(id: i32, timeout: i64, tags: &CSlice<u8>, min: u
}); });
} }
match unsafe { KERNEL_CHANNEL_0TO1.as_mut().unwrap() }.recv() { match unsafe { KERNEL_CHANNEL_0TO1.as_mut().unwrap() }.recv() {
Message::SubkernelMsgRecvReply { Message::SubkernelMsgRecvReply { count } => {
status: SubkernelStatus::NoError,
count,
} => {
if min > count || count > max { if min > count || count > max {
artiq_raise!("SubkernelError", "Received more or less arguments than required") artiq_raise!("SubkernelError", "Received more or less arguments than required")
} }
} }
Message::SubkernelMsgRecvReply { Message::SubkernelError(SubkernelStatus::IncorrectState) => {
status: SubkernelStatus::IncorrectState, artiq_raise!("SubkernelError", "Subkernel not running")
.. }
} => artiq_raise!("SubkernelError", "Subkernel not running"), Message::SubkernelError(SubkernelStatus::Timeout) => artiq_raise!("SubkernelError", "Subkernel timed out"),
Message::SubkernelMsgRecvReply { Message::SubkernelError(SubkernelStatus::CommLost) => {
status: SubkernelStatus::Timeout, artiq_raise!("SubkernelError", "Lost communication with satellite")
.. }
} => artiq_raise!("SubkernelError", "Subkernel timed out"), Message::SubkernelError(SubkernelStatus::OtherError) => {
Message::SubkernelMsgRecvReply { artiq_raise!("SubkernelError", "An error occurred during subkernel operation")
status: SubkernelStatus::CommLost, }
.. Message::SubkernelError(SubkernelStatus::Exception(raw_exception)) => eh_artiq::raise_raw(&raw_exception),
} => artiq_raise!("SubkernelError", "Lost communication with satellite"),
Message::SubkernelMsgRecvReply {
status: SubkernelStatus::OtherError,
..
} => artiq_raise!("SubkernelError", "An error occurred during subkernel operation"),
_ => panic!("expected SubkernelMsgRecvReply after SubkernelMsgRecvRequest"), _ => panic!("expected SubkernelMsgRecvReply after SubkernelMsgRecvRequest"),
} }
// RpcRecvRequest should be called after this to receive message data // RpcRecvRequest should be called after this to receive message data

View File

@ -422,33 +422,23 @@ async fn handle_run_kernel(
#[cfg(has_drtio)] #[cfg(has_drtio)]
kernel::Message::SubkernelAwaitFinishRequest { id, timeout } => { kernel::Message::SubkernelAwaitFinishRequest { id, timeout } => {
let res = subkernel::await_finish(aux_mutex, routing_table, timer, id, timeout).await; let res = subkernel::await_finish(aux_mutex, routing_table, timer, id, timeout).await;
let status = match res { let response = match res {
Ok(ref res) => { Ok(res) => {
if res.status == subkernel::FinishStatus::CommLost { if res.status == subkernel::FinishStatus::CommLost {
kernel::SubkernelStatus::CommLost kernel::Message::SubkernelError(kernel::SubkernelStatus::CommLost)
} else if let Some(exception) = &res.exception { } else if let Some(exception) = res.exception {
error!("Exception in subkernel"); kernel::Message::SubkernelError(kernel::SubkernelStatus::Exception(exception))
match stream {
None => (),
Some(stream) => {
write_chunk(stream, exception).await?;
}
}
// will not be called after exception is served
kernel::SubkernelStatus::OtherError
} else { } else {
kernel::SubkernelStatus::NoError kernel::Message::SubkernelAwaitFinishReply
} }
} }
Err(SubkernelError::Timeout) => kernel::SubkernelStatus::Timeout, Err(SubkernelError::Timeout) => kernel::Message::SubkernelError(kernel::SubkernelStatus::Timeout),
Err(SubkernelError::IncorrectState) => kernel::SubkernelStatus::IncorrectState, Err(SubkernelError::IncorrectState) => {
Err(_) => kernel::SubkernelStatus::OtherError, kernel::Message::SubkernelError(kernel::SubkernelStatus::IncorrectState)
}
Err(_) => kernel::Message::SubkernelError(kernel::SubkernelStatus::OtherError),
}; };
control control.borrow_mut().tx.async_send(response).await;
.borrow_mut()
.tx
.async_send(kernel::Message::SubkernelAwaitFinishReply { status: status })
.await;
} }
#[cfg(has_drtio)] #[cfg(has_drtio)]
kernel::Message::SubkernelMsgSend { id, destination, data } => { kernel::Message::SubkernelMsgSend { id, destination, data } => {
@ -469,35 +459,23 @@ async fn handle_run_kernel(
#[cfg(has_drtio)] #[cfg(has_drtio)]
kernel::Message::SubkernelMsgRecvRequest { id, timeout, tags } => { kernel::Message::SubkernelMsgRecvRequest { id, timeout, tags } => {
let message_received = subkernel::message_await(id as u32, timeout, timer).await; let message_received = subkernel::message_await(id as u32, timeout, timer).await;
let (status, count) = match message_received { let response = match message_received {
Ok(ref message) => (kernel::SubkernelStatus::NoError, message.count), Ok(ref message) => kernel::Message::SubkernelMsgRecvReply { count: message.count },
Err(SubkernelError::Timeout) => (kernel::SubkernelStatus::Timeout, 0), Err(SubkernelError::Timeout) => kernel::Message::SubkernelError(kernel::SubkernelStatus::Timeout),
Err(SubkernelError::IncorrectState) => (kernel::SubkernelStatus::IncorrectState, 0), Err(SubkernelError::IncorrectState) => {
Err(SubkernelError::CommLost) => (kernel::SubkernelStatus::CommLost, 0), kernel::Message::SubkernelError(kernel::SubkernelStatus::IncorrectState)
}
Err(SubkernelError::CommLost) => kernel::Message::SubkernelError(kernel::SubkernelStatus::CommLost),
Err(SubkernelError::SubkernelException) => { Err(SubkernelError::SubkernelException) => {
error!("Exception in subkernel");
// just retrieve the exception // just retrieve the exception
let status = subkernel::await_finish(aux_mutex, routing_table, timer, id as u32, timeout) let status = subkernel::await_finish(aux_mutex, routing_table, timer, id as u32, timeout)
.await .await
.unwrap(); .unwrap();
match stream { kernel::Message::SubkernelError(kernel::SubkernelStatus::Exception(status.exception.unwrap()))
None => (),
Some(stream) => {
write_chunk(stream, &status.exception.unwrap()).await?;
}
}
(kernel::SubkernelStatus::OtherError, 0)
} }
Err(_) => (kernel::SubkernelStatus::OtherError, 0), Err(_) => kernel::Message::SubkernelError(kernel::SubkernelStatus::OtherError),
}; };
control control.borrow_mut().tx.async_send(response).await;
.borrow_mut()
.tx
.async_send(kernel::Message::SubkernelMsgRecvReply {
status: status,
count: count,
})
.await;
if let Ok(message) = message_received { if let Ok(message) = message_received {
// receive code almost identical to RPC recv, except we are not reading from a stream // receive code almost identical to RPC recv, except we are not reading from a stream
let mut reader = Cursor::new(message.data); let mut reader = Cursor::new(message.data);
@ -529,7 +507,7 @@ async fn handle_run_kernel(
.async_send(kernel::Message::RpcRecvReply(Ok(0))) .async_send(kernel::Message::RpcRecvReply(Ok(0)))
.await; .await;
i += 1; i += 1;
if i < count { if i < message.count {
current_tags = remaining_tags; current_tags = remaining_tags;
} else { } else {
break; break;
@ -718,6 +696,27 @@ async fn handle_connection(
} }
} }
async fn load_and_run_idle_kernel(
buffer: &Vec<u8>,
control: &Rc<RefCell<kernel::Control>>,
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &drtio_routing::RoutingTable,
timer: GlobalTimer,
) {
info!("Loading idle kernel");
let res = handle_flash_kernel(buffer, control, up_destinations, aux_mutex, routing_table, timer).await;
match res {
Err(_) => warn!("error loading idle kernel"),
_ => (),
}
info!("Running idle kernel");
let _ = handle_run_kernel(None, control, up_destinations, aux_mutex, routing_table, timer)
.await
.map_err(|_| warn!("error running idle kernel"));
info!("Idle kernel terminated");
}
pub fn main(timer: GlobalTimer, cfg: Config) { pub fn main(timer: GlobalTimer, cfg: Config) {
let net_addresses = net_settings::get_addresses(&cfg); let net_addresses = net_settings::get_addresses(&cfg);
info!("network addresses: {}", net_addresses); info!("network addresses: {}", net_addresses);
@ -771,7 +770,7 @@ 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); rtio_mgt::startup(&aux_mutex, &drtio_routing_table, &up_destinations, &cfg, timer);
ksupport::setup_device_map(&cfg); ksupport::setup_device_map(&cfg);
analyzer::start(&aux_mutex, &drtio_routing_table, &up_destinations, timer); analyzer::start(&aux_mutex, &drtio_routing_table, &up_destinations, timer);
@ -808,8 +807,30 @@ pub fn main(timer: GlobalTimer, cfg: Config) {
mgmt::start(cfg); mgmt::start(cfg);
task::spawn(async move { task::spawn(async move {
let connection = Rc::new(Semaphore::new(1, 1)); let connection = Rc::new(Semaphore::new(0, 1));
let terminate = Rc::new(Semaphore::new(0, 1)); let terminate = Rc::new(Semaphore::new(0, 1));
{
let control = control.clone();
let idle_kernel = idle_kernel.clone();
let connection = connection.clone();
let terminate = terminate.clone();
let up_destinations = up_destinations.clone();
let aux_mutex = aux_mutex.clone();
let routing_table = drtio_routing_table.clone();
task::spawn(async move {
let routing_table = routing_table.borrow();
select_biased! {
_ = (async {
if let Some(buffer) = &*idle_kernel {
load_and_run_idle_kernel(&buffer, &control, &up_destinations, &aux_mutex, &routing_table, timer).await;
}
}).fuse() => (),
_ = terminate.async_wait().fuse() => ()
}
connection.signal();
});
}
loop { loop {
let mut stream = TcpStream::accept(1381, 0x10_000, 0x10_000).await.unwrap(); let mut stream = TcpStream::accept(1381, 0x10_000, 0x10_000).await.unwrap();
@ -837,22 +858,7 @@ pub fn main(timer: GlobalTimer, cfg: Config) {
.await .await
.map_err(|e| warn!("connection terminated: {}", e)); .map_err(|e| warn!("connection terminated: {}", e));
if let Some(buffer) = &*idle_kernel { if let Some(buffer) = &*idle_kernel {
info!("Loading idle kernel"); load_and_run_idle_kernel(&buffer, &control, &up_destinations, &aux_mutex, &routing_table, timer).await;
let res = handle_flash_kernel(&buffer, &control, &up_destinations, &aux_mutex, &routing_table, timer)
.await;
match res {
#[cfg(has_drtio)]
Err(Error::DestinationDown) => {
let mut countdown = timer.countdown();
delay(&mut countdown, Milliseconds(500)).await;
}
Err(_) => warn!("error loading idle kernel"),
_ => (),
}
info!("Running idle kernel");
let _ = handle_run_kernel(None, &control, &up_destinations, &aux_mutex, &routing_table, timer)
.await.map_err(|_| warn!("error running idle kernel"));
info!("Idle kernel terminated");
} }
}).fuse() => (), }).fuse() => (),
_ = terminate.async_wait().fuse() => () _ = terminate.async_wait().fuse() => ()

View File

@ -3,7 +3,9 @@ use core::cell::RefCell;
use libboard_artiq::{drtio_routing, drtio_routing::RoutingTable, pl::csr}; use libboard_artiq::{drtio_routing, drtio_routing::RoutingTable, 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::{info, warn};
#[cfg(has_drtio)] #[cfg(has_drtio)]
pub mod drtio { pub mod drtio {
@ -127,6 +129,8 @@ pub mod drtio {
| Packet::SubkernelLoadRunReply { destination, .. } | Packet::SubkernelLoadRunReply { destination, .. }
| Packet::SubkernelMessage { destination, .. } | Packet::SubkernelMessage { destination, .. }
| Packet::SubkernelMessageAck { destination, .. } | Packet::SubkernelMessageAck { destination, .. }
| Packet::SubkernelException { destination, .. }
| Packet::SubkernelExceptionRequest { destination, .. }
| Packet::DmaPlaybackStatus { destination, .. } | Packet::DmaPlaybackStatus { destination, .. }
| Packet::SubkernelFinished { destination, .. } => { | Packet::SubkernelFinished { destination, .. } => {
if destination == 0 { if destination == 0 {
@ -181,10 +185,7 @@ pub mod drtio {
async fn drain_buffer(linkno: u8, draining_time: Milliseconds, timer: GlobalTimer) { async fn drain_buffer(linkno: u8, draining_time: Milliseconds, timer: GlobalTimer) {
let max_time = timer.get_time() + draining_time; let max_time = timer.get_time() + draining_time;
loop { while timer.get_time() < max_time {
if timer.get_time() > max_time {
return;
}
let _ = drtioaux_async::recv(linkno).await; let _ = drtioaux_async::recv(linkno).await;
} }
} }
@ -833,13 +834,19 @@ pub mod drtio {
linkno, linkno,
routing_table, routing_table,
&Packet::SubkernelExceptionRequest { &Packet::SubkernelExceptionRequest {
source: 0,
destination: destination, destination: destination,
}, },
timer, timer,
) )
.await?; .await?;
match reply { match reply {
Packet::SubkernelException { last, length, data } => { Packet::SubkernelException {
destination: 0,
last,
length,
data,
} => {
remote_data.extend(&data[0..length as usize]); remote_data.extend(&data[0..length as usize]);
if last { if last {
return Ok(remote_data); return Ok(remote_data);
@ -898,12 +905,36 @@ pub mod drtio {
pub fn reset(_aux_mutex: Rc<Mutex<bool>>, _routing_table: &RoutingTable, mut _timer: GlobalTimer) {} pub fn reset(_aux_mutex: Rc<Mutex<bool>>, _routing_table: &RoutingTable, mut _timer: GlobalTimer) {}
} }
fn toggle_sed_spread(val: u8) {
unsafe {
csr::rtio_core::sed_spread_enable_write(val);
}
}
fn setup_sed_spread(cfg: &Config) {
if let Ok(spread_enable) = cfg.read_str("sed_spread_enable") {
match spread_enable.as_ref() {
"1" => toggle_sed_spread(1),
"0" => toggle_sed_spread(0),
_ => {
warn!("sed_spread_enable value not supported (only 1, 0 allowed), disabling by default");
toggle_sed_spread(0)
}
};
} else {
info!("SED spreading disabled by default");
toggle_sed_spread(0);
}
}
pub fn startup( pub fn startup(
aux_mutex: &Rc<Mutex<bool>>, aux_mutex: &Rc<Mutex<bool>>,
routing_table: &Rc<RefCell<RoutingTable>>, routing_table: &Rc<RefCell<RoutingTable>>,
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>, up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
cfg: &Config,
timer: GlobalTimer, timer: GlobalTimer,
) { ) {
setup_sed_spread(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);

View File

@ -12,6 +12,7 @@ extern crate io;
extern crate ksupport; extern crate ksupport;
extern crate libboard_artiq; extern crate libboard_artiq;
extern crate libboard_zynq; extern crate libboard_zynq;
extern crate libconfig;
extern crate libcortex_a9; extern crate libcortex_a9;
extern crate libregister; extern crate libregister;
extern crate libsupport_zynq; extern crate libsupport_zynq;
@ -38,6 +39,7 @@ use libboard_artiq::{drtio_routing, drtioaux,
#[cfg(feature = "target_kasli_soc")] #[cfg(feature = "target_kasli_soc")]
use libboard_zynq::error_led::ErrorLED; use libboard_zynq::error_led::ErrorLED;
use libboard_zynq::{i2c::I2c, print, println, time::Milliseconds, timer::GlobalTimer}; use libboard_zynq::{i2c::I2c, print, println, time::Milliseconds, timer::GlobalTimer};
use libconfig::Config;
use libcortex_a9::{l2c::enable_l2_cache, regs::MPIDR}; use libcortex_a9::{l2c::enable_l2_cache, regs::MPIDR};
use libregister::RegisterR; use libregister::RegisterR;
use libsupport_zynq::{exception_vectors, ram}; use libsupport_zynq::{exception_vectors, ram};
@ -81,15 +83,37 @@ fn drtiosat_tsc_loaded() -> bool {
} }
} }
fn toggle_sed_spread(val: u8) {
unsafe {
csr::drtiosat::sed_spread_enable_write(val);
}
}
#[cfg(has_drtio_routing)] #[cfg(has_drtio_routing)]
macro_rules! forward { macro_rules! forward {
($routing_table:expr, $destination:expr, $rank:expr, $repeaters:expr, $packet:expr, $timer:expr) => {{ (
$router:expr,
$routing_table:expr,
$destination:expr,
$rank:expr,
$self_destination:expr,
$repeaters:expr,
$packet:expr,
$timer:expr
) => {{
let hop = $routing_table.0[$destination as usize][$rank as usize]; let hop = $routing_table.0[$destination as usize][$rank as usize];
if hop != 0 { if hop != 0 {
let repno = (hop - 1) as usize; let repno = (hop - 1) as usize;
if repno < $repeaters.len() { if repno < $repeaters.len() {
if $packet.expects_response() { if $packet.expects_response() {
return $repeaters[repno].aux_forward($packet, $timer); return $repeaters[repno].aux_forward(
$packet,
$router,
$routing_table,
$rank,
$self_destination,
$timer,
);
} else { } else {
return $repeaters[repno].aux_send($packet); return $repeaters[repno].aux_send($packet);
} }
@ -102,7 +126,16 @@ macro_rules! forward {
#[cfg(not(has_drtio_routing))] #[cfg(not(has_drtio_routing))]
macro_rules! forward { macro_rules! forward {
($routing_table:expr, $destination:expr, $rank:expr, $repeaters:expr, $packet:expr, $timer:expr) => {}; (
$router:expr,
$routing_table:expr,
$destination:expr,
$rank:expr,
$self_destination:expr,
$repeaters:expr,
$packet:expr,
$timer:expr
) => {};
} }
fn process_aux_packet( fn process_aux_packet(
@ -183,6 +216,10 @@ fn process_aux_packet(
&drtioaux::Packet::DestinationStatusRequest { &drtioaux::Packet::DestinationStatusRequest {
destination: destination, destination: destination,
}, },
router,
_routing_table,
*rank,
*self_destination,
timer, timer,
) { ) {
Ok(()) => (), Ok(()) => (),
@ -244,7 +281,16 @@ fn process_aux_packet(
channel, channel,
probe, probe,
} => { } => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer); forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
let value; let value;
#[cfg(has_rtio_moninj)] #[cfg(has_rtio_moninj)]
unsafe { unsafe {
@ -266,7 +312,16 @@ fn process_aux_packet(
overrd, overrd,
value, value,
} => { } => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer); forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
#[cfg(has_rtio_moninj)] #[cfg(has_rtio_moninj)]
unsafe { unsafe {
csr::rtio_moninj::inj_chan_sel_write(channel as _); csr::rtio_moninj::inj_chan_sel_write(channel as _);
@ -280,7 +335,16 @@ fn process_aux_packet(
channel, channel,
overrd, overrd,
} => { } => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer); forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
let value; let value;
#[cfg(has_rtio_moninj)] #[cfg(has_rtio_moninj)]
unsafe { unsafe {
@ -299,7 +363,16 @@ fn process_aux_packet(
destination: _destination, destination: _destination,
busno: _busno, busno: _busno,
} => { } => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer); forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
let succeeded = i2c.start().is_ok(); let succeeded = i2c.start().is_ok();
drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded })
} }
@ -307,7 +380,16 @@ fn process_aux_packet(
destination: _destination, destination: _destination,
busno: _busno, busno: _busno,
} => { } => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer); forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
let succeeded = i2c.restart().is_ok(); let succeeded = i2c.restart().is_ok();
drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded })
} }
@ -315,7 +397,16 @@ fn process_aux_packet(
destination: _destination, destination: _destination,
busno: _busno, busno: _busno,
} => { } => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer); forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
let succeeded = i2c.stop().is_ok(); let succeeded = i2c.stop().is_ok();
drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded })
} }
@ -324,7 +415,16 @@ fn process_aux_packet(
busno: _busno, busno: _busno,
data, data,
} => { } => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer); forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
match i2c.write(data) { match i2c.write(data) {
Ok(ack) => drtioaux::send( Ok(ack) => drtioaux::send(
0, 0,
@ -347,7 +447,16 @@ fn process_aux_packet(
busno: _busno, busno: _busno,
ack, ack,
} => { } => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer); forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
match i2c.read(ack) { match i2c.read(ack) {
Ok(data) => drtioaux::send( Ok(data) => drtioaux::send(
0, 0,
@ -371,7 +480,16 @@ fn process_aux_packet(
address, address,
mask, mask,
} => { } => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer); forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
let ch = match mask { let ch = match mask {
//decode from mainline, PCA9548-centric API //decode from mainline, PCA9548-centric API
0x00 => None, 0x00 => None,
@ -397,7 +515,16 @@ fn process_aux_packet(
div: _div, div: _div,
cs: _cs, cs: _cs,
} => { } => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer); forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
// todo: reimplement when/if SPI is available // todo: reimplement when/if SPI is available
//let succeeded = spi::set_config(busno, flags, length, div, cs).is_ok(); //let succeeded = spi::set_config(busno, flags, length, div, cs).is_ok();
drtioaux::send(0, &drtioaux::Packet::SpiBasicReply { succeeded: false }) drtioaux::send(0, &drtioaux::Packet::SpiBasicReply { succeeded: false })
@ -407,7 +534,16 @@ fn process_aux_packet(
busno: _busno, busno: _busno,
data: _data, data: _data,
} => { } => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer); forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
// todo: reimplement when/if SPI is available // todo: reimplement when/if SPI is available
//let succeeded = spi::write(busno, data).is_ok(); //let succeeded = spi::write(busno, data).is_ok();
drtioaux::send(0, &drtioaux::Packet::SpiBasicReply { succeeded: false }) drtioaux::send(0, &drtioaux::Packet::SpiBasicReply { succeeded: false })
@ -416,7 +552,16 @@ fn process_aux_packet(
destination: _destination, destination: _destination,
busno: _busno, busno: _busno,
} => { } => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer); forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
// todo: reimplement when/if SPI is available // todo: reimplement when/if SPI is available
// match spi::read(busno) { // match spi::read(busno) {
// Ok(data) => drtioaux::send(0, // Ok(data) => drtioaux::send(0,
@ -436,7 +581,16 @@ fn process_aux_packet(
drtioaux::Packet::AnalyzerHeaderRequest { drtioaux::Packet::AnalyzerHeaderRequest {
destination: _destination, destination: _destination,
} => { } => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer); forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
let header = analyzer.get_header(); let header = analyzer.get_header();
drtioaux::send( drtioaux::send(
0, 0,
@ -450,7 +604,16 @@ fn process_aux_packet(
drtioaux::Packet::AnalyzerDataRequest { drtioaux::Packet::AnalyzerDataRequest {
destination: _destination, destination: _destination,
} => { } => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer); forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
let mut data_slice: [u8; SAT_PAYLOAD_MAX_SIZE] = [0; SAT_PAYLOAD_MAX_SIZE]; let mut data_slice: [u8; SAT_PAYLOAD_MAX_SIZE] = [0; SAT_PAYLOAD_MAX_SIZE];
let meta = analyzer.get_data(&mut data_slice); let meta = analyzer.get_data(&mut data_slice);
drtioaux::send( drtioaux::send(
@ -471,7 +634,16 @@ fn process_aux_packet(
length, length,
trace, trace,
} => { } => {
forward!(_routing_table, destination, *rank, _repeaters, &packet, timer); forward!(
router,
_routing_table,
destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
*self_destination = destination; *self_destination = destination;
let succeeded = dma_manager.add(source, id, status, &trace, length as usize).is_ok(); let succeeded = dma_manager.add(source, id, status, &trace, length as usize).is_ok();
router.send( router.send(
@ -492,7 +664,16 @@ fn process_aux_packet(
id, id,
succeeded, succeeded,
} => { } => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer); forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
dma_manager.ack_upload( dma_manager.ack_upload(
kernel_manager, kernel_manager,
source, source,
@ -510,7 +691,16 @@ fn process_aux_packet(
destination: _destination, destination: _destination,
id, id,
} => { } => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer); forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
let succeeded = dma_manager.erase(source, id).is_ok(); let succeeded = dma_manager.erase(source, id).is_ok();
router.send( router.send(
drtioaux::Packet::DmaRemoveTraceReply { drtioaux::Packet::DmaRemoveTraceReply {
@ -526,7 +716,16 @@ fn process_aux_packet(
destination: _destination, destination: _destination,
succeeded: _, succeeded: _,
} => { } => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer); forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
Ok(()) Ok(())
} }
drtioaux::Packet::DmaPlaybackRequest { drtioaux::Packet::DmaPlaybackRequest {
@ -535,7 +734,16 @@ fn process_aux_packet(
id, id,
timestamp, timestamp,
} => { } => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer); forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
let succeeded = if !kernel_manager.running() { let succeeded = if !kernel_manager.running() {
dma_manager.playback(source, id, timestamp).is_ok() dma_manager.playback(source, id, timestamp).is_ok()
} else { } else {
@ -555,7 +763,16 @@ fn process_aux_packet(
destination: _destination, destination: _destination,
succeeded, succeeded,
} => { } => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer); forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
if !succeeded { if !succeeded {
kernel_manager.ddma_nack(); kernel_manager.ddma_nack();
} }
@ -569,7 +786,16 @@ fn process_aux_packet(
channel, channel,
timestamp, timestamp,
} => { } => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer); forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
dma_manager.remote_finished(kernel_manager, id, error, channel, timestamp); dma_manager.remote_finished(kernel_manager, id, error, channel, timestamp);
Ok(()) Ok(())
} }
@ -581,7 +807,16 @@ fn process_aux_packet(
length, length,
data, data,
} => { } => {
forward!(_routing_table, destination, *rank, _repeaters, &packet, timer); forward!(
router,
_routing_table,
destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
*self_destination = destination; *self_destination = destination;
let succeeded = kernel_manager.add(id, status, &data, length as usize).is_ok(); let succeeded = kernel_manager.add(id, status, &data, length as usize).is_ok();
drtioaux::send(0, &drtioaux::Packet::SubkernelAddDataReply { succeeded: succeeded }) drtioaux::send(0, &drtioaux::Packet::SubkernelAddDataReply { succeeded: succeeded })
@ -592,7 +827,16 @@ fn process_aux_packet(
id, id,
run, run,
} => { } => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer); forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
let mut succeeded = kernel_manager.load(id).is_ok(); let mut succeeded = kernel_manager.load(id).is_ok();
// allow preloading a kernel with delayed run // allow preloading a kernel with delayed run
if run { if run {
@ -617,7 +861,16 @@ fn process_aux_packet(
destination: _destination, destination: _destination,
succeeded, succeeded,
} => { } => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer); forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
// received if local subkernel started another, remote subkernel // received if local subkernel started another, remote subkernel
kernel_manager.subkernel_load_run_reply(succeeded); kernel_manager.subkernel_load_run_reply(succeeded);
Ok(()) Ok(())
@ -628,25 +881,73 @@ fn process_aux_packet(
with_exception, with_exception,
exception_src, exception_src,
} => { } => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer); forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
kernel_manager.remote_subkernel_finished(id, with_exception, exception_src); kernel_manager.remote_subkernel_finished(id, with_exception, exception_src);
Ok(()) Ok(())
} }
drtioaux::Packet::SubkernelExceptionRequest { drtioaux::Packet::SubkernelExceptionRequest {
source,
destination: _destination, destination: _destination,
} => { } => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer); forward!(
let mut data_slice: [u8; SAT_PAYLOAD_MAX_SIZE] = [0; SAT_PAYLOAD_MAX_SIZE]; router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
let mut data_slice: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
let meta = kernel_manager.exception_get_slice(&mut data_slice); let meta = kernel_manager.exception_get_slice(&mut data_slice);
drtioaux::send( router.send(
0, drtioaux::Packet::SubkernelException {
&drtioaux::Packet::SubkernelException { destination: source,
last: meta.status.is_last(), last: meta.status.is_last(),
length: meta.len, length: meta.len,
data: data_slice, data: data_slice,
}, },
_routing_table,
*rank,
*self_destination,
) )
} }
drtioaux::Packet::SubkernelException {
destination: _destination,
last,
length,
data,
} => {
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
kernel_manager.received_exception(
&data[..length as usize],
last,
router,
_routing_table,
*rank,
*self_destination,
);
Ok(())
}
drtioaux::Packet::SubkernelMessage { drtioaux::Packet::SubkernelMessage {
source, source,
destination: _destination, destination: _destination,
@ -655,7 +956,16 @@ fn process_aux_packet(
length, length,
data, data,
} => { } => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer); forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
kernel_manager.message_handle_incoming(status, id, length as usize, &data); kernel_manager.message_handle_incoming(status, id, length as usize, &data);
router.send( router.send(
drtioaux::Packet::SubkernelMessageAck { destination: source }, drtioaux::Packet::SubkernelMessageAck { destination: source },
@ -667,7 +977,16 @@ fn process_aux_packet(
drtioaux::Packet::SubkernelMessageAck { drtioaux::Packet::SubkernelMessageAck {
destination: _destination, destination: _destination,
} => { } => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer); forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
if kernel_manager.message_ack_slice() { if kernel_manager.message_ack_slice() {
let mut data_slice: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE]; let mut data_slice: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
if let Some(meta) = kernel_manager.message_get_slice(&mut data_slice) { if let Some(meta) = kernel_manager.message_get_slice(&mut data_slice) {
@ -920,6 +1239,28 @@ pub extern "C" fn main_core0() -> i32 {
#[cfg(has_si549)] #[cfg(has_si549)]
si549::helper_setup(&mut timer, &SI549_SETTINGS).expect("cannot initialize helper Si549"); si549::helper_setup(&mut timer, &SI549_SETTINGS).expect("cannot initialize helper Si549");
let cfg = match Config::new() {
Ok(cfg) => cfg,
Err(err) => {
warn!("config initialization failed: {}", err);
Config::new_dummy()
}
};
if let Ok(spread_enable) = cfg.read_str("sed_spread_enable") {
match spread_enable.as_ref() {
"1" => toggle_sed_spread(1),
"0" => toggle_sed_spread(0),
_ => {
warn!("sed_spread_enable value not supported (only 1, 0 allowed), disabling by default");
toggle_sed_spread(0)
}
};
} else {
info!("SED spreading disabled by default");
toggle_sed_spread(0);
}
#[cfg(has_drtio_routing)] #[cfg(has_drtio_routing)]
let mut repeaters = [repeater::Repeater::default(); csr::DRTIOREP.len()]; let mut repeaters = [repeater::Repeater::default(); csr::DRTIOREP.len()];
#[cfg(not(has_drtio_routing))] #[cfg(not(has_drtio_routing))]

View File

@ -87,6 +87,10 @@ impl Repeater {
if rep_link_rx_up(self.repno) { if rep_link_rx_up(self.repno) {
if let Ok(Some(drtioaux::Packet::EchoReply)) = drtioaux::recv(self.auxno) { if let Ok(Some(drtioaux::Packet::EchoReply)) = drtioaux::recv(self.auxno) {
info!("[REP#{}] remote replied after {} packets", self.repno, ping_count); info!("[REP#{}] remote replied after {} packets", self.repno, ping_count);
let max_time = timer.get_time() + Milliseconds(200);
while timer.get_time() < max_time {
let _ = drtioaux::recv(self.auxno);
}
self.state = RepeaterState::Up; self.state = RepeaterState::Up;
if let Err(e) = self.sync_tsc(timer) { if let Err(e) = self.sync_tsc(timer) {
error!("[REP#{}] failed to sync TSC ({:?})", self.repno, e); error!("[REP#{}] failed to sync TSC ({:?})", self.repno, e);
@ -204,10 +208,37 @@ impl Repeater {
} }
} }
pub fn aux_forward(&self, request: &drtioaux::Packet, timer: &mut GlobalTimer) -> Result<(), drtioaux::Error> { pub fn aux_forward(
&self,
request: &drtioaux::Packet,
router: &mut Router,
routing_table: &drtio_routing::RoutingTable,
rank: u8,
self_destination: u8,
timer: &mut GlobalTimer,
) -> Result<(), drtioaux::Error> {
self.aux_send(request)?; self.aux_send(request)?;
let reply = self.recv_aux_timeout(200, timer)?; loop {
drtioaux::send(0, &reply).unwrap(); let reply = self.recv_aux_timeout(200, timer)?;
match reply {
// async/locally requested packets to be consumed or routed
// these may come while a packet would be forwarded
drtioaux::Packet::DmaPlaybackStatus { .. }
| drtioaux::Packet::SubkernelFinished { .. }
| drtioaux::Packet::SubkernelMessage { .. }
| drtioaux::Packet::SubkernelMessageAck { .. }
| drtioaux::Packet::SubkernelLoadRunReply { .. }
| drtioaux::Packet::SubkernelException { .. }
| drtioaux::Packet::DmaAddTraceReply { .. }
| drtioaux::Packet::DmaPlaybackReply { .. } => {
router.route(reply, routing_table, rank, self_destination);
}
_ => {
drtioaux::send(0, &reply).unwrap();
break;
}
}
}
Ok(()) Ok(())
} }

View File

@ -4,7 +4,7 @@ use core::cmp::min;
#[cfg(has_drtio_routing)] #[cfg(has_drtio_routing)]
use libboard_artiq::pl::csr; use libboard_artiq::pl::csr;
use libboard_artiq::{drtio_routing, drtioaux, use libboard_artiq::{drtio_routing, drtioaux,
drtioaux_proto::{PayloadStatus, MASTER_PAYLOAD_MAX_SIZE, SAT_PAYLOAD_MAX_SIZE}}; drtioaux_proto::{PayloadStatus, MASTER_PAYLOAD_MAX_SIZE}};
pub struct SliceMeta { pub struct SliceMeta {
pub destination: u8, pub destination: u8,
@ -57,7 +57,6 @@ impl Sliceable {
self.data.extend(data); self.data.extend(data);
} }
get_slice_fn!(get_slice_sat, SAT_PAYLOAD_MAX_SIZE);
get_slice_fn!(get_slice_master, MASTER_PAYLOAD_MAX_SIZE); get_slice_fn!(get_slice_master, MASTER_PAYLOAD_MAX_SIZE);
} }

View File

@ -11,7 +11,7 @@ use io::{Cursor, ProtoWrite};
use ksupport::{eh_artiq, kernel, rpc}; use ksupport::{eh_artiq, kernel, rpc};
use libboard_artiq::{drtio_routing::RoutingTable, use libboard_artiq::{drtio_routing::RoutingTable,
drtioaux, drtioaux,
drtioaux_proto::{PayloadStatus, MASTER_PAYLOAD_MAX_SIZE, SAT_PAYLOAD_MAX_SIZE}, drtioaux_proto::{PayloadStatus, MASTER_PAYLOAD_MAX_SIZE},
pl::csr}; pl::csr};
use libboard_zynq::{time::Milliseconds, timer::GlobalTimer}; use libboard_zynq::{time::Milliseconds, timer::GlobalTimer};
use libcortex_a9::sync_channel::Receiver; use libcortex_a9::sync_channel::Receiver;
@ -47,6 +47,9 @@ enum KernelState {
DmaAwait { DmaAwait {
max_time: Milliseconds, max_time: Milliseconds,
}, },
SubkernelRetrievingException {
destination: u8,
},
} }
#[derive(Debug)] #[derive(Debug)]
@ -123,10 +126,11 @@ struct MessageManager {
struct Session { struct Session {
id: u32, id: u32,
kernel_state: KernelState, kernel_state: KernelState,
last_exception: Option<Sliceable>, last_exception: Option<Sliceable>, // exceptions raised locally
external_exception: Option<Vec<u8>>, // exceptions from sub-subkernels
messages: MessageManager, messages: MessageManager,
source: u8, // which destination requested running the kernel source: u8, // which destination requested running the kernel
subkernels_finished: Vec<u32>, subkernels_finished: Vec<(u32, Option<u8>)>,
} }
impl Session { impl Session {
@ -135,6 +139,7 @@ impl Session {
id: id, id: id,
kernel_state: KernelState::Absent, kernel_state: KernelState::Absent,
last_exception: None, last_exception: None,
external_exception: None,
messages: MessageManager::new(), messages: MessageManager::new(),
source: 0, source: 0,
subkernels_finished: Vec::new(), subkernels_finished: Vec::new(),
@ -410,9 +415,9 @@ impl<'a> Manager<'_> {
} }
} }
pub fn exception_get_slice(&mut self, data_slice: &mut [u8; SAT_PAYLOAD_MAX_SIZE]) -> SliceMeta { pub fn exception_get_slice(&mut self, data_slice: &mut [u8; MASTER_PAYLOAD_MAX_SIZE]) -> SliceMeta {
match self.session.last_exception.as_mut() { match self.session.last_exception.as_mut() {
Some(exception) => exception.get_slice_sat(data_slice), Some(exception) => exception.get_slice_master(data_slice),
None => SliceMeta { None => SliceMeta {
destination: 0, destination: 0,
len: 0, len: 0,
@ -540,7 +545,7 @@ impl<'a> Manager<'_> {
return; return;
} }
match self.process_external_messages(timer) { match self.process_external_messages(router, routing_table, rank, destination, timer) {
Ok(()) => (), Ok(()) => (),
Err(Error::AwaitingMessage) => return, // kernel still waiting, do not process kernel messages Err(Error::AwaitingMessage) => return, // kernel still waiting, do not process kernel messages
Err(Error::KernelException(exception)) => { Err(Error::KernelException(exception)) => {
@ -596,6 +601,41 @@ impl<'a> Manager<'_> {
} }
} }
fn check_finished_kernels(
&mut self,
id: u32,
router: &mut Router,
routing_table: &RoutingTable,
rank: u8,
self_destination: u8,
) {
for (i, (status, exception_source)) in self.session.subkernels_finished.iter().enumerate() {
if *status == id {
if exception_source.is_none() {
self.control.tx.send(kernel::Message::SubkernelAwaitFinishReply);
self.session.kernel_state = KernelState::Running;
self.session.subkernels_finished.swap_remove(i);
} else {
let destination = exception_source.unwrap();
self.session.external_exception = Some(Vec::new());
self.session.kernel_state = KernelState::SubkernelRetrievingException {
destination: destination,
};
router.route(
drtioaux::Packet::SubkernelExceptionRequest {
source: self_destination,
destination: destination,
},
&routing_table,
rank,
self_destination,
);
}
break;
}
}
}
pub fn subkernel_load_run_reply(&mut self, succeeded: bool) { pub fn subkernel_load_run_reply(&mut self, succeeded: bool) {
if self.session.kernel_state == KernelState::SubkernelAwaitLoad { if self.session.kernel_state == KernelState::SubkernelAwaitLoad {
self.control self.control
@ -608,16 +648,46 @@ impl<'a> Manager<'_> {
} }
pub fn remote_subkernel_finished(&mut self, id: u32, with_exception: bool, exception_source: u8) { pub fn remote_subkernel_finished(&mut self, id: u32, with_exception: bool, exception_source: u8) {
if with_exception { let exception_src = if with_exception { Some(exception_source) } else { None };
self.kernel_stop(); self.session.subkernels_finished.push((id, exception_src));
self.last_finished = Some(SubkernelFinished { }
source: self.session.source,
id: self.session.id, pub fn received_exception(
with_exception: true, &mut self,
exception_source: exception_source, exception_data: &[u8],
}) last: bool,
router: &mut Router,
routing_table: &RoutingTable,
rank: u8,
self_destination: u8,
) {
if let KernelState::SubkernelRetrievingException { destination } = self.session.kernel_state {
self.session
.external_exception
.as_mut()
.unwrap()
.extend_from_slice(exception_data);
if last {
self.control
.tx
.send(kernel::Message::SubkernelError(kernel::SubkernelStatus::Exception(
self.session.external_exception.take().unwrap(),
)));
self.session.kernel_state = KernelState::Running;
} else {
/* fetch another slice */
router.route(
drtioaux::Packet::SubkernelExceptionRequest {
source: self_destination,
destination: destination,
},
routing_table,
rank,
self_destination,
);
}
} else { } else {
self.session.subkernels_finished.push(id); warn!("Received unsolicited exception data");
} }
} }
@ -780,28 +850,35 @@ impl<'a> Manager<'_> {
Ok(false) Ok(false)
} }
fn process_external_messages(&mut self, timer: &GlobalTimer) -> Result<(), Error> { fn process_external_messages(
&mut self,
router: &mut Router,
routing_table: &RoutingTable,
rank: u8,
self_destination: u8,
timer: &GlobalTimer,
) -> Result<(), Error> {
match &self.session.kernel_state { match &self.session.kernel_state {
KernelState::MsgAwait { max_time, id, tags } => { KernelState::MsgAwait { max_time, id, tags } => {
if let Some(max_time) = *max_time { if let Some(max_time) = *max_time {
if timer.get_time() > max_time { if timer.get_time() > max_time {
self.control.tx.send(kernel::Message::SubkernelMsgRecvReply { self.control
status: kernel::SubkernelStatus::Timeout, .tx
count: 0, .send(kernel::Message::SubkernelError(kernel::SubkernelStatus::Timeout));
});
self.session.kernel_state = KernelState::Running; self.session.kernel_state = KernelState::Running;
return Ok(()); return Ok(());
} }
} }
if let Some(message) = self.session.messages.get_incoming(*id) { if let Some(message) = self.session.messages.get_incoming(*id) {
self.control.tx.send(kernel::Message::SubkernelMsgRecvReply { self.control
status: kernel::SubkernelStatus::NoError, .tx
count: message.count, .send(kernel::Message::SubkernelMsgRecvReply { count: message.count });
});
let tags = tags.clone(); let tags = tags.clone();
self.session.kernel_state = KernelState::Running; self.session.kernel_state = KernelState::Running;
self.pass_message_to_kernel(&message, tags, timer) self.pass_message_to_kernel(&message, tags, timer)
} else { } else {
let id = *id;
self.check_finished_kernels(id, router, routing_table, rank, self_destination);
Err(Error::AwaitingMessage) Err(Error::AwaitingMessage)
} }
} }
@ -817,27 +894,18 @@ impl<'a> Manager<'_> {
KernelState::SubkernelAwaitFinish { max_time, id } => { KernelState::SubkernelAwaitFinish { max_time, id } => {
if let Some(max_time) = *max_time { if let Some(max_time) = *max_time {
if timer.get_time() > max_time { if timer.get_time() > max_time {
self.control.tx.send(kernel::Message::SubkernelAwaitFinishReply { self.control
status: kernel::SubkernelStatus::Timeout, .tx
}); .send(kernel::Message::SubkernelError(kernel::SubkernelStatus::Timeout));
self.session.kernel_state = KernelState::Running; self.session.kernel_state = KernelState::Running;
return Ok(()); return Ok(());
} }
} }
let mut i = 0; let id = *id;
for status in &self.session.subkernels_finished { self.check_finished_kernels(id, router, routing_table, rank, self_destination);
if *status == *id {
self.control.tx.send(kernel::Message::SubkernelAwaitFinishReply {
status: kernel::SubkernelStatus::NoError,
});
self.session.kernel_state = KernelState::Running;
self.session.subkernels_finished.swap_remove(i);
break;
}
i += 1;
}
Ok(()) Ok(())
} }
KernelState::SubkernelRetrievingException { .. } => Err(Error::AwaitingMessage),
KernelState::DmaAwait { max_time } | KernelState::DmaPendingAwait { max_time, .. } => { KernelState::DmaAwait { max_time } | KernelState::DmaPendingAwait { max_time, .. } => {
if timer.get_time() > *max_time { if timer.get_time() > *max_time {
self.control.tx.send(kernel::Message::DmaAwaitRemoteReply { self.control.tx.send(kernel::Message::DmaAwaitRemoteReply {