1
0
Fork 0

Compare commits

..

8 Commits

Author SHA1 Message Date
Simon Renblad 15f9d1a9e5 fix warnings 2024-10-18 14:19:06 +08:00
Simon Renblad ee03879620 fix satman error traits 2024-10-18 14:16:48 +08:00
Simon Renblad 79d965d551 up flake 2024-10-17 14:35:55 +08:00
Simon Renblad fb013c2c5a added eh_rust 2024-10-17 14:35:55 +08:00
Simon Renblad c7387441f3 fix misc errors 2024-10-17 14:35:37 +08:00
Simon Renblad f13a554596 removing core_io dependency 2024-10-17 14:34:24 +08:00
newell 030247be18 add pre-commit hooks for code formatting
Co-authored-by: newell <newell.jensen@gmail.com>
Co-committed-by: newell <newell.jensen@gmail.com>
2024-10-08 15:19:07 +08:00
newell 61df939c87 ebaz4205: add variant and hydra job
Co-authored-by: newell <newell.jensen@gmail.com>
Co-committed-by: newell <newell.jensen@gmail.com>
2024-10-08 11:35:31 +08:00
21 changed files with 338 additions and 150 deletions

View File

@ -59,6 +59,16 @@ Notes:
- Firmware type must be either ``runtime`` for DRTIO-less or DRTIO master variants, or ``satman`` for DRTIO satellite. - Firmware type must be either ``runtime`` for DRTIO-less or DRTIO master variants, or ``satman`` for DRTIO satellite.
- If the board is connected to the local machine, use the ``local_run.sh`` script. - If the board is connected to the local machine, use the ``local_run.sh`` script.
Pre-Commit Hooks
----------------
You are strongly recommended to use the provided pre-commit hooks to automatically reformat files and check for non-optimal Rust/C/C++ practices. Run `pre-commit install` to install the hook and `pre-commit` will automatically run `cargo fmt`, `cargo clippy`, and `clang-format` for you.
Several things to note:
- If `cargo fmt`, `cargo clippy`, or `clang-format` returns an error, the pre-commit hook will fail. You should fix all errors before trying to commit again.
- If `cargo fmt` or `clang-format` reformats some files, the pre-commit hook will also fail. You should review the changes and, if satisfied, try to commit again.
License License
------- -------

View File

@ -364,7 +364,8 @@
(board-package-set { target = "zc706"; variant = "acpki_nist_qc2_satellite_100mhz"; }) // (board-package-set { target = "zc706"; variant = "acpki_nist_qc2_satellite_100mhz"; }) //
(board-package-set { target = "kasli_soc"; variant = "demo"; json = ./demo.json; }) // (board-package-set { target = "kasli_soc"; variant = "demo"; json = ./demo.json; }) //
(board-package-set { target = "kasli_soc"; variant = "master"; json = ./kasli-soc-master.json; }) // (board-package-set { target = "kasli_soc"; variant = "master"; json = ./kasli-soc-master.json; }) //
(board-package-set { target = "kasli_soc"; variant = "satellite"; json = ./kasli-soc-satellite.json; }); (board-package-set { target = "kasli_soc"; variant = "satellite"; json = ./kasli-soc-satellite.json; }) //
(board-package-set { target = "ebaz4205"; variant = "base"; });
hydraJobs = packages.x86_64-linux // { inherit zc706-hitl-tests; inherit gateware-sim; inherit fmt-check; }; hydraJobs = packages.x86_64-linux // { inherit zc706-hitl-tests; inherit gateware-sim; inherit fmt-check; };
@ -384,6 +385,7 @@
artiqpkgs.artiq artiqpkgs.artiq
artiqpkgs.vivado artiqpkgs.vivado
binutils-arm binutils-arm
pre-commit
]; ];
XARGO_RUST_SRC = "${rust}/lib/rustlib/src/rust/library"; XARGO_RUST_SRC = "${rust}/lib/rustlib/src/rust/library";
CLANG_EXTRA_INCLUDE_DIR = "${llvmPackages_11.clang-unwrapped.lib}/lib/clang/11.1.0/include"; CLANG_EXTRA_INCLUDE_DIR = "${llvmPackages_11.clang-unwrapped.lib}/lib/clang/11.1.0/include";

32
src/.clang-format Normal file
View File

@ -0,0 +1,32 @@
BasedOnStyle: LLVM
Language: Cpp
Standard: Cpp11
AccessModifierOffset: -1
AlignEscapedNewlines: Left
AlwaysBreakAfterReturnType: None
AlwaysBreakTemplateDeclarations: Yes
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortFunctionsOnASingleLine: Inline
BinPackParameters: false
BreakBeforeBinaryOperators: NonAssignment
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: AfterColon
BreakInheritanceList: AfterColon
ColumnLimit: 120
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ContinuationIndentWidth: 4
DerivePointerAlignment: false
IndentCaseLabels: true
IndentPPDirectives: None
IndentWidth: 4
MaxEmptyLinesToKeep: 1
PointerAlignment: Left
ReflowComments: true
SortIncludes: false
SortUsingDeclarations: true
SpaceAfterTemplateKeyword: false
SpacesBeforeTrailingComments: 2
TabWidth: 4
UseTab: Never

1
src/.clippy.toml Normal file
View File

@ -0,0 +1 @@
doc-valid-idents = ["CPython", "NumPy", ".."]

View File

@ -0,0 +1,32 @@
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
default_stages: [commit]
repos:
- repo: local
hooks:
- id: cargo-fmt
name: artiq-zynq cargo format
entry: nix
language: system
types: [file, rust]
pass_filenames: false
description: Runs cargo fmt on the codebase.
args: [develop, -c, cargo, fmt, --manifest-path, src/Cargo.toml, --all]
- id: cargo-clippy
name: artiq-zynq cargo clippy
entry: nix
language: system
types: [file, rust]
pass_filenames: false
description: Runs cargo clippy on the codebase.
args: [develop, -c, cargo, clippy, --manifest-path, src/Cargo.toml, --tests]
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: v19.1.0
hooks:
- id: clang-format
name: artiq-zynq clang-format
description: Runs clang-format on the codebase.
files: \.(cpp|h|hpp|c)$
args: [-style=file, -fallback-style=none, -assume-filename=src/.clang-format]

View File

@ -212,6 +212,14 @@ class EBAZ4205(SoCCore):
self.csr_devices.append("rtio_analyzer") self.csr_devices.append("rtio_analyzer")
class BASE(EBAZ4205):
def __init__(self, rtio_clk, acpki):
EBAZ4205.__init__(self, rtio_clk, acpki)
VARIANTS = {cls.__name__.lower(): cls for cls in [BASE]}
def main(): def main():
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description="ARTIQ port to the EBAZ4205 control card of Ebit E9+ BTC miner" description="ARTIQ port to the EBAZ4205 control card of Ebit E9+ BTC miner"
@ -232,11 +240,25 @@ def main():
) )
parser.add_argument("--rtio-clk", default=125e6, help="RTIO Clock Frequency (Hz)") parser.add_argument("--rtio-clk", default=125e6, help="RTIO Clock Frequency (Hz)")
parser.add_argument( parser.add_argument(
"--acpki", default=False, action="store_true", help="enable ACPKI" "-V",
"--variant",
default="base",
help="variant: " "[acpki_]base" "(default: %(default)s)",
) )
args = parser.parse_args() args = parser.parse_args()
soc = EBAZ4205(rtio_clk=int(args.rtio_clk), acpki=args.acpki) rtio_clk = int(args.rtio_clk)
variant = args.variant.lower()
acpki = variant.startswith("acpki_")
if acpki:
variant = variant[6:]
try:
cls = VARIANTS[variant]
except KeyError:
raise SystemExit("Invalid variant (-V/--variant)")
soc = cls(rtio_clk=rtio_clk, acpki=acpki)
soc.finalize() soc.finalize()
if args.r is not None: if args.r is not None:

View File

@ -9,7 +9,7 @@ pub use crate::drtioaux_proto::Packet;
use crate::{drtioaux_proto::Error as ProtocolError, mem::mem::DRTIOAUX_MEM, pl::csr::DRTIOAUX}; use crate::{drtioaux_proto::Error as ProtocolError, mem::mem::DRTIOAUX_MEM, pl::csr::DRTIOAUX};
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error<T> {
GatewareError, GatewareError,
CorruptedPacket, CorruptedPacket,
@ -19,17 +19,17 @@ pub enum Error {
RoutingError, RoutingError,
Protocol(ProtocolError), Protocol(ProtocolError<T>),
} }
impl From<ProtocolError> for Error { impl<T> From<ProtocolError<T>> for Error<T> {
fn from(value: ProtocolError) -> Error { fn from(value: ProtocolError<T>) -> Error<T> {
Error::Protocol(value) Error::Protocol(value)
} }
} }
impl From<IoError> for Error { impl<T> From<IoError<T>> for Error<T> {
fn from(value: IoError) -> Error { fn from(value: IoError<T>) -> Error<T> {
Error::Protocol(ProtocolError::Io(value)) Error::Protocol(ProtocolError::Io(value))
} }
} }
@ -56,8 +56,8 @@ pub fn has_rx_error(linkno: u8) -> bool {
} }
} }
fn receive<F, T>(linkno: u8, f: F) -> Result<Option<T>, Error> fn receive<F, T>(linkno: u8, f: F) -> Result<Option<T>, Error<!>>
where F: FnOnce(&[u8]) -> Result<T, Error> { where F: FnOnce(&[u8]) -> Result<T, Error<!>> {
let linkidx = linkno as usize; let linkidx = linkno as usize;
unsafe { unsafe {
if (DRTIOAUX[linkidx].aux_rx_present_read)() == 1 { if (DRTIOAUX[linkidx].aux_rx_present_read)() == 1 {
@ -72,14 +72,14 @@ where F: FnOnce(&[u8]) -> Result<T, Error> {
} }
} }
pub fn recv(linkno: u8) -> Result<Option<Packet>, Error> { pub fn recv(linkno: u8) -> Result<Option<Packet>, Error<!>> {
if has_rx_error(linkno) { if has_rx_error(linkno) {
return Err(Error::GatewareError); return Err(Error::GatewareError);
} }
receive(linkno, |buffer| { receive(linkno, |buffer| {
if buffer.len() < 8 { if buffer.len() < 8 {
return Err(IoError::UnexpectedEnd).into()); return Err(IoError::UnexpectedEnd.into());
} }
let mut reader = Cursor::new(buffer); let mut reader = Cursor::new(buffer);
@ -96,7 +96,7 @@ pub fn recv(linkno: u8) -> Result<Option<Packet>, Error> {
}) })
} }
pub fn recv_timeout(linkno: u8, timeout_ms: Option<u64>, timer: GlobalTimer) -> Result<Packet, Error> { pub fn recv_timeout(linkno: u8, timeout_ms: Option<u64>, timer: GlobalTimer) -> Result<Packet, Error<!>> {
let timeout_ms = Milliseconds(timeout_ms.unwrap_or(10)); let timeout_ms = Milliseconds(timeout_ms.unwrap_or(10));
let limit = timer.get_time() + timeout_ms; let limit = timer.get_time() + timeout_ms;
while timer.get_time() < limit { while timer.get_time() < limit {
@ -108,8 +108,8 @@ pub fn recv_timeout(linkno: u8, timeout_ms: Option<u64>, timer: GlobalTimer) ->
Err(Error::TimedOut) Err(Error::TimedOut)
} }
fn transmit<F>(linkno: u8, f: F) -> Result<(), Error> fn transmit<F>(linkno: u8, f: F) -> Result<(), Error<!>>
where F: FnOnce(&mut [u8]) -> Result<usize, Error> { where F: FnOnce(&mut [u8]) -> Result<usize, Error<!>> {
let linkno = linkno as usize; let linkno = linkno as usize;
unsafe { unsafe {
while (DRTIOAUX[linkno].aux_tx_read)() != 0 {} while (DRTIOAUX[linkno].aux_tx_read)() != 0 {}
@ -121,7 +121,7 @@ where F: FnOnce(&mut [u8]) -> Result<usize, Error> {
} }
} }
pub fn send(linkno: u8, packet: &Packet) -> Result<(), Error> { pub fn send(linkno: u8, packet: &Packet) -> Result<(), Error<!>> {
transmit(linkno, |buffer| { transmit(linkno, |buffer| {
let mut writer = Cursor::new(buffer); let mut writer = Cursor::new(buffer);

View File

@ -34,8 +34,8 @@ fn tx_ready(linkno: usize) -> nb::Result<(), Void> {
} }
} }
async fn receive<F, T>(linkno: u8, f: F) -> Result<Option<T>, Error> async fn receive<F, T>(linkno: u8, f: F) -> Result<Option<T>, Error<!>>
where F: FnOnce(&[u8]) -> Result<T, Error> { where F: FnOnce(&[u8]) -> Result<T, Error<!>> {
let linkidx = linkno as usize; let linkidx = linkno as usize;
unsafe { unsafe {
if (DRTIOAUX[linkidx].aux_rx_present_read)() == 1 { if (DRTIOAUX[linkidx].aux_rx_present_read)() == 1 {
@ -50,14 +50,14 @@ where F: FnOnce(&[u8]) -> Result<T, Error> {
} }
} }
pub async fn recv(linkno: u8) -> Result<Option<Packet>, Error> { pub async fn recv(linkno: u8) -> Result<Option<Packet>, Error<!>> {
if has_rx_error(linkno) { if has_rx_error(linkno) {
return Err(Error::GatewareError); return Err(Error::GatewareError);
} }
receive(linkno, |buffer| { receive(linkno, |buffer| {
if buffer.len() < 8 { if buffer.len() < 8 {
return Err(IoError::UnexpectedEnd).into()); return Err(IoError::UnexpectedEnd.into());
} }
let mut reader = Cursor::new(buffer); let mut reader = Cursor::new(buffer);
@ -75,7 +75,7 @@ pub async fn recv(linkno: u8) -> Result<Option<Packet>, Error> {
.await .await
} }
pub async fn recv_timeout(linkno: u8, timeout_ms: Option<u64>, timer: GlobalTimer) -> Result<Packet, Error> { pub async fn recv_timeout(linkno: u8, timeout_ms: Option<u64>, timer: GlobalTimer) -> Result<Packet, Error<!>> {
let timeout_ms = Milliseconds(timeout_ms.unwrap_or(10)); let timeout_ms = Milliseconds(timeout_ms.unwrap_or(10));
let limit = timer.get_time() + timeout_ms; let limit = timer.get_time() + timeout_ms;
let mut would_block = false; let mut would_block = false;
@ -95,8 +95,8 @@ pub async fn recv_timeout(linkno: u8, timeout_ms: Option<u64>, timer: GlobalTime
Err(Error::TimedOut) Err(Error::TimedOut)
} }
async fn transmit<F>(linkno: u8, f: F) -> Result<(), Error> async fn transmit<F>(linkno: u8, f: F) -> Result<(), Error<!>>
where F: FnOnce(&mut [u8]) -> Result<usize, Error> { where F: FnOnce(&mut [u8]) -> Result<usize, Error<!>> {
let linkno = linkno as usize; let linkno = linkno as usize;
unsafe { unsafe {
let _ = block_async!(tx_ready(linkno)).await; let _ = block_async!(tx_ready(linkno)).await;
@ -108,7 +108,7 @@ where F: FnOnce(&mut [u8]) -> Result<usize, Error> {
} }
} }
pub async fn send(linkno: u8, packet: &Packet) -> Result<(), Error> { pub async fn send(linkno: u8, packet: &Packet) -> Result<(), Error<!>> {
transmit(linkno, |buffer| { transmit(linkno, |buffer| {
let mut writer = Cursor::new(buffer); let mut writer = Cursor::new(buffer);

View File

@ -1,7 +1,7 @@
#![no_std] #![no_std]
#![feature(never_type)] #![feature(never_type)]
#![feature(naked_functions)] #![feature(naked_functions)]
#![feature(asm)] #![allow(unexpected_cfgs)]
extern crate crc; extern crate crc;
extern crate embedded_hal; extern crate embedded_hal;

View File

@ -1,3 +1,5 @@
#![allow(unexpected_cfgs)]
use std::{env, use std::{env,
fs::File, fs::File,
io::{BufRead, BufReader, Write}, io::{BufRead, BufReader, Write},

View File

@ -1,5 +1,6 @@
#![no_std] #![no_std]
#![feature(never_type)] #![feature(never_type)]
#![allow(unexpected_cfgs)]
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
extern crate alloc; extern crate alloc;

View File

@ -15,9 +15,9 @@
// By design, this personality function is only ever called in the search phase, although // By design, this personality function is only ever called in the search phase, although
// to keep things simple and close to upstream, it is not modified // to keep things simple and close to upstream, it is not modified
use unwind as uw; use unwind as uw;
use libc::{c_int, uintptr_t}; use libc::c_int;
use dwarf::eh::{self, EHAction, EHContext}; use dwarf::eh::{EHAction, EHContext};
// Register ids were lifted from LLVM's TargetLowering::getExceptionPointerRegister() // Register ids were lifted from LLVM's TargetLowering::getExceptionPointerRegister()
// and TargetLowering::getExceptionSelectorRegister() for each architecture, // and TargetLowering::getExceptionSelectorRegister() for each architecture,

View File

@ -2,9 +2,8 @@
#![feature(c_variadic)] #![feature(c_variadic)]
#![feature(const_btree_len)] #![feature(const_btree_len)]
#![feature(lang_items)] #![feature(lang_items)]
#![feature(generic_const_exprs)]
#![feature(naked_functions)] #![feature(naked_functions)]
#![feature(asm)] #![allow(unexpected_cfgs)]
#[macro_use] #[macro_use]
extern crate alloc; extern crate alloc;

View File

@ -44,7 +44,7 @@ unsafe fn recv_elements<F, R, E>(
alloc: &mut F, alloc: &mut F,
) -> Result<(), E> ) -> Result<(), E>
where where
F: FnMut(usize) -> *mut (), F: FnMut(usize) -> Result<*mut (), E>,
R: Read + ?Sized, R: Read + ?Sized,
E: From<Error<R::ReadError>>, E: From<Error<R::ReadError>>,
{ {
@ -57,7 +57,6 @@ where
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);
reader.read_exact(dest)?; reader.read_exact(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);
} }
@ -65,7 +64,6 @@ where
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);
reader.read_exact(dest)?; reader.read_exact(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);
} }
@ -81,7 +79,7 @@ where
unsafe fn recv_value<F, R, E>(reader: &mut R, tag: Tag, data: &mut *mut (), alloc: &mut F) -> Result<(), E> unsafe fn recv_value<F, R, E>(reader: &mut R, tag: Tag, data: &mut *mut (), alloc: &mut F) -> Result<(), E>
where where
F: FnMut(usize) -> *mut (), F: FnMut(usize) -> Result<*mut (), E>,
R: Read + ?Sized, R: Read + ?Sized,
E: From<Error<R::ReadError>>, E: From<Error<R::ReadError>>,
{ {
@ -110,7 +108,7 @@ where
Tag::String | Tag::Bytes | Tag::ByteArray => { Tag::String | Tag::Bytes | Tag::ByteArray => {
consume_value!(CMutSlice<u8>, |ptr| { consume_value!(CMutSlice<u8>, |ptr| {
let length = reader.read_u32()? as usize; let length = reader.read_u32()? as usize;
*ptr = CMutSlice::new(alloc(length) as *mut u8, length); *ptr = CMutSlice::new(alloc(length)? as *mut u8, length);
reader.read_exact((*ptr).as_mut())?; reader.read_exact((*ptr).as_mut())?;
Ok(()) Ok(())
}) })
@ -140,7 +138,7 @@ where
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) 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 ();
@ -159,7 +157,7 @@ where
} }
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); *buffer = alloc(elt_tag.size() * total_len)?;
recv_elements(reader, elt_tag, total_len, *buffer, alloc) recv_elements(reader, elt_tag, total_len, *buffer, alloc)
}) })
} }
@ -183,7 +181,7 @@ pub fn recv_return<'a, F, R, E>(
alloc: &mut F, alloc: &mut F,
) -> Result<&'a [u8], E> ) -> Result<&'a [u8], E>
where where
F: FnMut(usize) -> *mut (), F: FnMut(usize) -> Result<*mut (), E>,
R: Read + ?Sized, R: Read + ?Sized,
E: From<Error<R::ReadError>>, E: From<Error<R::ReadError>>,
{ {

View File

@ -1,3 +1,4 @@
#![allow(unexpected_cfgs)]
extern crate build_zynq; extern crate build_zynq;
fn main() { fn main() {

View File

@ -1,9 +1,9 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
#![recursion_limit = "1024"] // for futures_util::select! #![recursion_limit = "1024"] // for futures_util::select!
#![allow(unexpected_cfgs)]
#![feature(alloc_error_handler)] #![feature(alloc_error_handler)]
#![feature(const_btree_new)] #![feature(const_btree_len)]
#![feature(panic_info_message)]
#[macro_use] #[macro_use]
extern crate alloc; extern crate alloc;

View File

@ -38,7 +38,6 @@ where
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?; proto_async::read_chunk(stream, dest).await?;
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);
} }
@ -46,7 +45,6 @@ where
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?; proto_async::read_chunk(stream, dest).await?;
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);
} }

View File

@ -1,6 +1,7 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
#![feature(alloc_error_handler, try_trait, never_type, panic_info_message)] #![feature(alloc_error_handler, never_type)]
#![allow(unexpected_cfgs)]
#[macro_use] #[macro_use]
extern crate log; extern crate log;
@ -149,7 +150,7 @@ fn process_aux_packet(
analyzer: &mut Analyzer, analyzer: &mut Analyzer,
kernel_manager: &mut KernelManager, kernel_manager: &mut KernelManager,
router: &mut Router, router: &mut Router,
) -> Result<(), drtioaux::Error> { ) -> Result<(), drtioaux::Error<!>> {
// In the code below, *_chan_sel_write takes an u8 if there are fewer than 256 channels, // In the code below, *_chan_sel_write takes an u8 if there are fewer than 256 channels,
// and u16 otherwise; hence the `as _` conversion. // and u16 otherwise; hence the `as _` conversion.
match packet { match packet {
@ -1457,7 +1458,7 @@ pub fn panic_fmt(info: &core::panic::PanicInfo) -> ! {
} else { } else {
print!("unknown location"); print!("unknown location");
} }
if let Some(message) = info.message() { if let Some(message) = info.message().as_str() {
println!(": {}", message); println!(": {}", message);
} else { } else {
println!(""); println!("");

View File

@ -191,7 +191,7 @@ impl Repeater {
} }
} }
fn recv_aux_timeout(&self, timeout: u32, timer: &mut GlobalTimer) -> Result<drtioaux::Packet, drtioaux::Error> { fn recv_aux_timeout(&self, timeout: u32, timer: &mut GlobalTimer) -> Result<drtioaux::Packet, drtioaux::Error<!>> {
let max_time = timer.get_time() + Milliseconds(timeout.into()); let max_time = timer.get_time() + Milliseconds(timeout.into());
loop { loop {
if !rep_link_rx_up(self.repno) { if !rep_link_rx_up(self.repno) {
@ -216,7 +216,7 @@ impl Repeater {
rank: u8, rank: u8,
self_destination: u8, self_destination: u8,
timer: &mut GlobalTimer, timer: &mut GlobalTimer,
) -> Result<(), drtioaux::Error> { ) -> Result<(), drtioaux::Error<!>> {
self.aux_send(request)?; self.aux_send(request)?;
loop { loop {
let reply = self.recv_aux_timeout(200, timer)?; let reply = self.recv_aux_timeout(200, timer)?;
@ -242,14 +242,14 @@ impl Repeater {
Ok(()) Ok(())
} }
pub fn aux_send(&self, request: &drtioaux::Packet) -> Result<(), drtioaux::Error> { pub fn aux_send(&self, request: &drtioaux::Packet) -> Result<(), drtioaux::Error<!>> {
if self.state != RepeaterState::Up { if self.state != RepeaterState::Up {
return Err(drtioaux::Error::LinkDown); return Err(drtioaux::Error::LinkDown);
} }
drtioaux::send(self.auxno, request) drtioaux::send(self.auxno, request)
} }
pub fn sync_tsc(&self, timer: &mut GlobalTimer) -> Result<(), drtioaux::Error> { pub fn sync_tsc(&self, timer: &mut GlobalTimer) -> Result<(), drtioaux::Error<!>> {
if self.state != RepeaterState::Up { if self.state != RepeaterState::Up {
return Ok(()); return Ok(());
} }
@ -275,7 +275,7 @@ impl Repeater {
destination: u8, destination: u8,
hops: &[u8; drtio_routing::MAX_HOPS], hops: &[u8; drtio_routing::MAX_HOPS],
timer: &mut GlobalTimer, timer: &mut GlobalTimer,
) -> Result<(), drtioaux::Error> { ) -> Result<(), drtioaux::Error<!>> {
if self.state != RepeaterState::Up { if self.state != RepeaterState::Up {
return Ok(()); return Ok(());
} }
@ -299,14 +299,14 @@ impl Repeater {
&self, &self,
routing_table: &drtio_routing::RoutingTable, routing_table: &drtio_routing::RoutingTable,
timer: &mut GlobalTimer, timer: &mut GlobalTimer,
) -> Result<(), drtioaux::Error> { ) -> Result<(), drtioaux::Error<!>> {
for i in 0..drtio_routing::DEST_COUNT { for i in 0..drtio_routing::DEST_COUNT {
self.set_path(i as u8, &routing_table.0[i], timer)?; self.set_path(i as u8, &routing_table.0[i], timer)?;
} }
Ok(()) Ok(())
} }
pub fn set_rank(&self, rank: u8, timer: &mut GlobalTimer) -> Result<(), drtioaux::Error> { pub fn set_rank(&self, rank: u8, timer: &mut GlobalTimer) -> Result<(), drtioaux::Error<!>> {
if self.state != RepeaterState::Up { if self.state != RepeaterState::Up {
return Ok(()); return Ok(());
} }
@ -318,7 +318,7 @@ impl Repeater {
Ok(()) Ok(())
} }
pub fn rtio_reset(&self, timer: &mut GlobalTimer) -> Result<(), drtioaux::Error> { pub fn rtio_reset(&self, timer: &mut GlobalTimer) -> Result<(), drtioaux::Error<!>> {
let repno = self.repno as usize; let repno = self.repno as usize;
unsafe { unsafe {
(csr::DRTIOREP[repno].reset_write)(1); (csr::DRTIOREP[repno].reset_write)(1);
@ -361,11 +361,11 @@ impl Repeater {
) { ) {
} }
pub fn sync_tsc(&self, _timer: &mut GlobalTimer) -> Result<(), drtioaux::Error> { pub fn sync_tsc(&self, _timer: &mut GlobalTimer) -> Result<(), drtioaux::Error<!>> {
Ok(()) Ok(())
} }
pub fn rtio_reset(&self, _timer: &mut GlobalTimer) -> Result<(), drtioaux::Error> { pub fn rtio_reset(&self, _timer: &mut GlobalTimer) -> Result<(), drtioaux::Error<!>> {
Ok(()) Ok(())
} }
} }

View File

@ -129,7 +129,7 @@ impl Router {
_routing_table: &drtio_routing::RoutingTable, _routing_table: &drtio_routing::RoutingTable,
_rank: u8, _rank: u8,
_destination: u8, _destination: u8,
) -> Result<(), drtioaux::Error> { ) -> Result<(), drtioaux::Error<!>> {
#[cfg(has_drtio_routing)] #[cfg(has_drtio_routing)]
{ {
let destination = packet.routable_destination(); let destination = packet.routable_destination();

View File

@ -1,17 +1,21 @@
use alloc::{collections::BTreeMap, use alloc::{
format, collections::BTreeMap,
string::{String, ToString}, format,
vec::Vec}; string::{String, ToString},
use core::{option::NoneError, slice, str}; vec::Vec,
};
use core::{slice, str};
use cslice::AsCSlice; use cslice::AsCSlice;
use dma::{Error as DmaError, Manager as DmaManager}; use dma::{Error as DmaError, Manager as DmaManager};
use io::{Cursor, Error as IoError, ProtoWrite, Write}; use io::{Cursor, Error as IoError, ProtoWrite, Write};
use ksupport::{eh_artiq, kernel, rpc}; use ksupport::{eh_artiq, kernel, rpc};
use libboard_artiq::{drtio_routing::RoutingTable, use libboard_artiq::{
drtioaux, drtio_routing::RoutingTable,
drtioaux_proto::{PayloadStatus, MASTER_PAYLOAD_MAX_SIZE}, drtioaux,
pl::csr}; drtioaux_proto::{PayloadStatus, MASTER_PAYLOAD_MAX_SIZE},
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;
use log::warn; use log::warn;
@ -51,6 +55,7 @@ enum KernelState {
}, },
} }
#[allow(dead_code)]
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
Load(String), Load(String),
@ -64,14 +69,8 @@ pub enum Error {
DmaError(DmaError), DmaError(DmaError),
} }
impl From<NoneError> for Error { impl<T> From<IoError<T>> for Error {
fn from(_: NoneError) -> Error { fn from(_value: IoError<T>) -> Error {
Error::KernelNotFound
}
}
impl From<IoError> for Error {
fn from(_value: IoError) -> Error {
Error::SubkernelIoError Error::SubkernelIoError
} }
} }
@ -88,8 +87,8 @@ impl From<()> for Error {
} }
} }
impl From<drtioaux::Error> for Error { impl<T> From<drtioaux::Error<T>> for Error {
fn from(_value: drtioaux::Error) -> Error { fn from(_value: drtioaux::Error<T>) -> Error {
Error::DrtioError Error::DrtioError
} }
} }
@ -125,7 +124,7 @@ struct MessageManager {
struct Session { struct Session {
id: u32, id: u32,
kernel_state: KernelState, kernel_state: KernelState,
last_exception: Option<Sliceable>, // exceptions raised locally last_exception: Option<Sliceable>, // exceptions raised locally
external_exception: Option<Vec<u8>>, // exceptions from sub-subkernels 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
@ -221,7 +220,10 @@ impl MessageManager {
} }
} }
pub fn get_outgoing_slice(&mut self, data_slice: &mut [u8; MASTER_PAYLOAD_MAX_SIZE]) -> Option<SliceMeta> { pub fn get_outgoing_slice(
&mut self,
data_slice: &mut [u8; MASTER_PAYLOAD_MAX_SIZE],
) -> Option<SliceMeta> {
if self.out_state != OutMessageState::MessageBeingSent { if self.out_state != OutMessageState::MessageBeingSent {
return None; return None;
} }
@ -302,7 +304,13 @@ impl<'a> Manager<'_> {
} }
} }
pub fn add(&mut self, id: u32, status: PayloadStatus, data: &[u8], data_len: usize) -> Result<(), Error> { pub fn add(
&mut self,
id: u32,
status: PayloadStatus,
data: &[u8],
data_len: usize,
) -> Result<(), Error> {
let kernel = match self.kernels.get_mut(&id) { let kernel = match self.kernels.get_mut(&id) {
Some(kernel) => { Some(kernel) => {
if kernel.complete || status.is_first() { if kernel.complete || status.is_first() {
@ -315,7 +323,7 @@ impl<'a> Manager<'_> {
complete: false, complete: false,
}, },
); );
self.kernels.get_mut(&id)? self.kernels.get_mut(&id).ok_or(Error::KernelNotFound)?
} else { } else {
kernel kernel
} }
@ -328,7 +336,7 @@ impl<'a> Manager<'_> {
complete: false, complete: false,
}, },
); );
self.kernels.get_mut(&id)? self.kernels.get_mut(&id).ok_or(Error::KernelNotFound)?
} }
}; };
kernel.library.extend(&data[0..data_len]); kernel.library.extend(&data[0..data_len]);
@ -372,10 +380,15 @@ impl<'a> Manager<'_> {
if !self.running() { if !self.running() {
return; return;
} }
self.session.messages.handle_incoming(status, id, length, slice); self.session
.messages
.handle_incoming(status, id, length, slice);
} }
pub fn message_get_slice(&mut self, slice: &mut [u8; MASTER_PAYLOAD_MAX_SIZE]) -> Option<SliceMeta> { pub fn message_get_slice(
&mut self,
slice: &mut [u8; MASTER_PAYLOAD_MAX_SIZE],
) -> Option<SliceMeta> {
if !self.running() { if !self.running() {
return None; return None;
} }
@ -394,15 +407,19 @@ impl<'a> Manager<'_> {
if self.session.id == id && self.session.kernel_state == KernelState::Loaded { if self.session.id == id && self.session.kernel_state == KernelState::Loaded {
return Ok(()); return Ok(());
} }
if !self.kernels.get(&id)?.complete { if !self.kernels.get(&id).ok_or(Error::KernelNotFound)?.complete {
return Err(Error::KernelNotFound); return Err(Error::KernelNotFound);
} }
self.session = Session::new(id); self.session = Session::new(id);
self.control.restart(); self.control.restart();
self.control self.control.tx.send(kernel::Message::LoadRequest(
.tx self.kernels
.send(kernel::Message::LoadRequest(self.kernels.get(&id)?.library.clone())); .get(&id)
.ok_or(Error::KernelNotFound)?
.library
.clone(),
));
let reply = self.control.rx.recv(); let reply = self.control.rx.recv();
match reply { match reply {
kernel::Message::LoadCompleted => Ok(()), kernel::Message::LoadCompleted => Ok(()),
@ -414,7 +431,10 @@ impl<'a> Manager<'_> {
} }
} }
pub fn exception_get_slice(&mut self, data_slice: &mut [u8; MASTER_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_master(data_slice), Some(exception) => exception.get_slice_master(data_slice),
None => SliceMeta { None => SliceMeta {
@ -568,7 +588,14 @@ impl<'a> Manager<'_> {
} }
} }
match self.process_kern_message(router, routing_table, rank, destination, dma_manager, timer) { match self.process_kern_message(
router,
routing_table,
rank,
destination,
dma_manager,
timer,
) {
Ok(true) => { Ok(true) => {
self.last_finished = Some(SubkernelFinished { self.last_finished = Some(SubkernelFinished {
id: self.session.id, id: self.session.id,
@ -611,7 +638,9 @@ impl<'a> Manager<'_> {
for (i, (status, exception_source)) in self.session.subkernels_finished.iter().enumerate() { for (i, (status, exception_source)) in self.session.subkernels_finished.iter().enumerate() {
if *status == id { if *status == id {
if exception_source.is_none() { if exception_source.is_none() {
self.control.tx.send(kernel::Message::SubkernelAwaitFinishReply); self.control
.tx
.send(kernel::Message::SubkernelAwaitFinishReply);
self.session.kernel_state = KernelState::Running; self.session.kernel_state = KernelState::Running;
self.session.subkernels_finished.swap_remove(i); self.session.subkernels_finished.swap_remove(i);
} else { } else {
@ -639,15 +668,26 @@ impl<'a> Manager<'_> {
if self.session.kernel_state == KernelState::SubkernelAwaitLoad { if self.session.kernel_state == KernelState::SubkernelAwaitLoad {
self.control self.control
.tx .tx
.send(kernel::Message::SubkernelLoadRunReply { succeeded: succeeded }); .send(kernel::Message::SubkernelLoadRunReply {
succeeded: succeeded,
});
self.session.kernel_state = KernelState::Running; self.session.kernel_state = KernelState::Running;
} else { } else {
warn!("received unsolicited SubkernelLoadRunReply"); warn!("received unsolicited SubkernelLoadRunReply");
} }
} }
pub fn remote_subkernel_finished(&mut self, id: u32, with_exception: bool, exception_source: u8) { pub fn remote_subkernel_finished(
let exception_src = if with_exception { Some(exception_source) } else { None }; &mut self,
id: u32,
with_exception: bool,
exception_source: u8,
) {
let exception_src = if with_exception {
Some(exception_source)
} else {
None
};
self.session.subkernels_finished.push((id, exception_src)); self.session.subkernels_finished.push((id, exception_src));
} }
@ -660,18 +700,19 @@ impl<'a> Manager<'_> {
rank: u8, rank: u8,
self_destination: u8, self_destination: u8,
) { ) {
if let KernelState::SubkernelRetrievingException { destination } = self.session.kernel_state { if let KernelState::SubkernelRetrievingException { destination } = self.session.kernel_state
{
self.session self.session
.external_exception .external_exception
.as_mut() .as_mut()
.unwrap() .unwrap()
.extend_from_slice(exception_data); .extend_from_slice(exception_data);
if last { if last {
self.control self.control.tx.send(kernel::Message::SubkernelError(
.tx kernel::SubkernelStatus::Exception(
.send(kernel::Message::SubkernelError(kernel::SubkernelStatus::Exception(
self.session.external_exception.take().unwrap(), self.session.external_exception.take().unwrap(),
))); ),
));
self.session.kernel_state = KernelState::Running; self.session.kernel_state = KernelState::Running;
} else { } else {
/* fetch another slice */ /* fetch another slice */
@ -706,7 +747,12 @@ impl<'a> Manager<'_> {
dma_manager.cleanup(router, rank, self_destination, routing_table); dma_manager.cleanup(router, rank, self_destination, routing_table);
return Ok(true); return Ok(true);
} }
kernel::Message::KernelException(exceptions, stack_pointers, backtrace, async_errors) => { kernel::Message::KernelException(
exceptions,
stack_pointers,
backtrace,
async_errors,
) => {
error!("exception in kernel"); error!("exception in kernel");
for exception in exceptions { for exception in exceptions {
error!("{:?}", exception.unwrap()); error!("{:?}", exception.unwrap());
@ -715,12 +761,21 @@ impl<'a> Manager<'_> {
error!("backtrace: {:?}", backtrace); error!("backtrace: {:?}", backtrace);
let buf: Vec<u8> = Vec::new(); let buf: Vec<u8> = Vec::new();
let mut writer = Cursor::new(buf); let mut writer = Cursor::new(buf);
match write_exception(&mut writer, exceptions, stack_pointers, backtrace, async_errors) { match write_exception(
&mut writer,
exceptions,
stack_pointers,
backtrace,
async_errors,
) {
Ok(()) => (), Ok(()) => (),
Err(_) => error!("Error writing exception data"), Err(_) => error!("Error writing exception data"),
} }
self.kernel_stop(); self.kernel_stop();
return Err(Error::KernelException(Sliceable::new(0, writer.into_inner()))); return Err(Error::KernelException(Sliceable::new(
0,
writer.into_inner(),
)));
} }
kernel::Message::CachePutRequest(key, value) => { kernel::Message::CachePutRequest(key, value) => {
self.cache.insert(key, value); self.cache.insert(key, value);
@ -768,11 +823,13 @@ impl<'a> Manager<'_> {
let max_time = timer.get_time() + Milliseconds(10000); let max_time = timer.get_time() + Milliseconds(10000);
self.session.kernel_state = match self.session.kernel_state { self.session.kernel_state = match self.session.kernel_state {
// if we are still waiting for the traces to be uploaded, extend the state by timeout // if we are still waiting for the traces to be uploaded, extend the state by timeout
KernelState::DmaPendingPlayback { id, timestamp } => KernelState::DmaPendingAwait { KernelState::DmaPendingPlayback { id, timestamp } => {
id: id, KernelState::DmaPendingAwait {
timestamp: timestamp, id: id,
max_time: max_time, timestamp: timestamp,
}, max_time: max_time,
}
}
_ => KernelState::DmaAwait { max_time: max_time }, _ => KernelState::DmaAwait { max_time: max_time },
}; };
} }
@ -843,7 +900,10 @@ impl<'a> Manager<'_> {
)); ));
} }
_ => { _ => {
unexpected!("unexpected message from core1 while kernel was running: {:?}", reply); unexpected!(
"unexpected message from core1 while kernel was running: {:?}",
reply
);
} }
} }
Ok(false) Ok(false)
@ -861,9 +921,9 @@ impl<'a> Manager<'_> {
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 self.control.tx.send(kernel::Message::SubkernelError(
.tx kernel::SubkernelStatus::Timeout,
.send(kernel::Message::SubkernelError(kernel::SubkernelStatus::Timeout)); ));
self.session.kernel_state = KernelState::Running; self.session.kernel_state = KernelState::Running;
return Ok(()); return Ok(());
} }
@ -871,7 +931,9 @@ impl<'a> Manager<'_> {
if let Some(message) = self.session.messages.get_incoming(*id) { if let Some(message) = self.session.messages.get_incoming(*id) {
self.control self.control
.tx .tx
.send(kernel::Message::SubkernelMsgRecvReply { 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)
@ -893,9 +955,9 @@ 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 self.control.tx.send(kernel::Message::SubkernelError(
.tx kernel::SubkernelStatus::Timeout,
.send(kernel::Message::SubkernelError(kernel::SubkernelStatus::Timeout)); ));
self.session.kernel_state = KernelState::Running; self.session.kernel_state = KernelState::Running;
return Ok(()); return Ok(());
} }
@ -921,7 +983,12 @@ impl<'a> Manager<'_> {
} }
} }
fn pass_message_to_kernel(&mut self, message: &Message, tags: Vec<u8>, timer: &GlobalTimer) -> Result<(), Error> { fn pass_message_to_kernel(
&mut self,
message: &Message,
tags: Vec<u8>,
timer: &GlobalTimer,
) -> Result<(), Error> {
let mut reader = Cursor::new(&message.data); let mut reader = Cursor::new(&message.data);
let mut current_tags: &[u8] = &tags; let mut current_tags: &[u8] = &tags;
let mut i = message.count; let mut i = message.count;
@ -932,33 +999,54 @@ impl<'a> Manager<'_> {
}; };
let mut exception: Option<Sliceable> = None; let mut exception: Option<Sliceable> = None;
let mut unexpected: Option<String> = None; let mut unexpected: Option<String> = None;
let remaining_tags = rpc::recv_return(&mut reader, current_tags, slot, &mut |size| { let remaining_tags =
if size == 0 { rpc::recv_return(&mut reader, current_tags, slot, &mut |size| -> Result<
0 as *mut () _,
} else { Error,
self.control.tx.send(kernel::Message::RpcRecvReply(Ok(size))); > {
match recv_w_timeout(&mut self.control.rx, timer, 100) { if size == 0 {
Ok(kernel::Message::RpcRecvRequest(slot)) => slot, Ok(0 as *mut ())
Ok(kernel::Message::KernelException(exceptions, stack_pointers, backtrace, async_errors)) => { } else {
let buf: Vec<u8> = Vec::new(); self.control
let mut writer = Cursor::new(buf); .tx
match write_exception(&mut writer, exceptions, stack_pointers, backtrace, async_errors) { .send(kernel::Message::RpcRecvReply(Ok(size)));
Ok(()) => { match recv_w_timeout(&mut self.control.rx, timer, 100) {
exception = Some(Sliceable::new(0, writer.into_inner())); Ok(kernel::Message::RpcRecvRequest(slot)) => Ok(slot),
} Ok(kernel::Message::KernelException(
Err(_) => { exceptions,
unexpected = Some("Error writing exception data".to_string()); stack_pointers,
} backtrace,
}; async_errors,
0 as *mut () )) => {
} let buf: Vec<u8> = Vec::new();
other => { let mut writer = Cursor::new(buf);
unexpected = Some(format!("expected nested value slot from kernel CPU, not {:?}", other)); match write_exception(
0 as *mut () &mut writer,
exceptions,
stack_pointers,
backtrace,
async_errors,
) {
Ok(()) => {
exception = Some(Sliceable::new(0, writer.into_inner()));
}
Err(_) => {
unexpected =
Some("Error writing exception data".to_string());
}
};
Ok(0 as *mut ())
}
other => {
unexpected = Some(format!(
"expected nested value slot from kernel CPU, not {:?}",
other
));
Ok(0 as *mut ())
}
} }
} }
} })?;
})?;
if let Some(exception) = exception { if let Some(exception) = exception {
self.kernel_stop(); self.kernel_stop();
return Err(Error::KernelException(exception)); return Err(Error::KernelException(exception));
@ -1000,17 +1088,18 @@ where
writer.write_u32(u32::MAX)?; writer.write_u32(u32::MAX)?;
writer.write_u32(exception.message.as_ptr() as u32)?; writer.write_u32(exception.message.as_ptr() as u32)?;
} else { } else {
let msg = let msg = str::from_utf8(unsafe {
str::from_utf8(unsafe { slice::from_raw_parts(exception.message.as_ptr(), exception.message.len()) }) slice::from_raw_parts(exception.message.as_ptr(), exception.message.len())
.unwrap() })
.replace( .unwrap()
"{rtio_channel_info:0}", .replace(
&format!( "{rtio_channel_info:0}",
"0x{:04x}:{}", &format!(
exception.param[0], "0x{:04x}:{}",
ksupport::resolve_channel_name(exception.param[0] as u32) exception.param[0],
), ksupport::resolve_channel_name(exception.param[0] as u32)
); ),
);
writer.write_string(&msg)?; writer.write_string(&msg)?;
} }
writer.write_u64(exception.param[0] as u64)?; writer.write_u64(exception.param[0] as u64)?;