From ce6c89e3439c16857191f70fdbcf48237c37912b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 12 Apr 2020 20:15:01 +0800 Subject: [PATCH] add RTIO syscalls --- Cargo.lock | 7 ++ runtime/Cargo.toml | 1 + runtime/src/main.rs | 1 + runtime/src/rtio.rs | 173 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 182 insertions(+) create mode 100644 runtime/src/rtio.rs diff --git a/Cargo.lock b/Cargo.lock index 822a0ce..23cb5a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -30,6 +30,12 @@ version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "036b035e9ebcd705affece16319223d19f229e2358be6e3b7b094e57193312e6" +[[package]] +name = "cslice" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f8cb7306107e4b10e64994de6d3274bd08996a7c1322a27b86482392f96be0a" + [[package]] name = "dyld" version = "0.1.0" @@ -154,6 +160,7 @@ checksum = "bd7a31eed1591dcbc95d92ad7161908e72f4677f8fabf2a32ca49b4237cbf211" name = "runtime" version = "0.1.0" dependencies = [ + "cslice", "dyld", "libasync", "libboard_zynq", diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index c73d3dc..befa694 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -12,6 +12,7 @@ default = ["target_zc706"] [dependencies] num-traits = { version = "0.2", default-features = false } num-derive = "0.3" +cslice = "0.3" libboard_zynq = { git = "https://git.m-labs.hk/M-Labs/zc706.git" } libsupport_zynq = { git = "https://git.m-labs.hk/M-Labs/zc706.git" } libasync = { git = "https://git.m-labs.hk/M-Labs/zc706.git" } diff --git a/runtime/src/main.rs b/runtime/src/main.rs index 2c9168c..6464695 100644 --- a/runtime/src/main.rs +++ b/runtime/src/main.rs @@ -13,6 +13,7 @@ use libsupport_zynq::ram; mod pl; +mod rtio; mod network; fn identifier_read(buf: &mut [u8]) -> &str { diff --git a/runtime/src/rtio.rs b/runtime/src/rtio.rs new file mode 100644 index 0000000..f9d2e85 --- /dev/null +++ b/runtime/src/rtio.rs @@ -0,0 +1,173 @@ +use core::ptr::{read_volatile, write_volatile}; +use cslice::CSlice; + +use libboard_zynq::println; + +use crate::pl::csr; + +pub const RTIO_O_STATUS_WAIT: u8 = 1; +pub const RTIO_O_STATUS_UNDERFLOW: u8 = 2; +pub const RTIO_O_STATUS_DESTINATION_UNREACHABLE: u8 = 4; +pub const RTIO_I_STATUS_WAIT_EVENT: u8 = 1; +pub const RTIO_I_STATUS_OVERFLOW: u8 = 2; +pub const RTIO_I_STATUS_WAIT_STATUS: u8 = 4; +pub const RTIO_I_STATUS_DESTINATION_UNREACHABLE: u8 = 8; + +#[repr(C)] +pub struct TimestampedData { + timestamp: i64, + data: i32, +} + +pub extern fn init() { + // TODO +} + +pub extern fn get_destination_status(destination: i32) -> bool { + // TODO + destination == 0 +} + +pub extern fn get_counter() -> i64 { + unsafe { + csr::rtio::counter_update_write(1); + csr::rtio::counter_read() as i64 + } +} + +// writing the LSB of o_data (offset=0) triggers the RTIO write +#[inline(always)] +pub unsafe fn rtio_o_data_write(offset: usize, data: u32) { + write_volatile( + csr::rtio::O_DATA_ADDR.offset((csr::rtio::O_DATA_SIZE - 1 - offset) as isize), + data); +} + +#[inline(always)] +pub unsafe fn rtio_i_data_read(offset: usize) -> u32 { + read_volatile( + csr::rtio::I_DATA_ADDR.offset((csr::rtio::I_DATA_SIZE - 1 - offset) as isize)) +} + +#[inline(never)] +unsafe fn process_exceptional_status(channel: i32, status: u8) { + let timestamp = *(csr::rtio::NOW_HI_ADDR as *const i64); + if status & RTIO_O_STATUS_WAIT != 0 { + while csr::rtio::o_status_read() & RTIO_O_STATUS_WAIT != 0 {} + } + if status & RTIO_O_STATUS_UNDERFLOW != 0 { + println!("RTIO underflow at {0} mu, channel {1}, slack {2} mu", + timestamp, channel as i64, timestamp - get_counter()); + } + if status & RTIO_O_STATUS_DESTINATION_UNREACHABLE != 0 { + println!("RTIO destination unreachable, output, at {0} mu, channel {1}", + timestamp, channel as i64); + } +} + +pub extern fn output(target: i32, data: i32) { + unsafe { + csr::rtio::target_write(target as u32); + // writing target clears o_data + rtio_o_data_write(0, data as _); + let status = csr::rtio::o_status_read(); + if status != 0 { + process_exceptional_status(target >> 8, status); + } + } +} + +pub extern fn output_wide(target: i32, data: CSlice) { + unsafe { + csr::rtio::target_write(target as u32); + // writing target clears o_data + for i in (0..data.len()).rev() { + rtio_o_data_write(i, data[i] as _) + } + let status = csr::rtio::o_status_read(); + if status != 0 { + process_exceptional_status(target >> 8, status); + } + } +} + +pub extern fn input_timestamp(timeout: i64, channel: i32) -> i64 { + unsafe { + csr::rtio::target_write((channel as u32) << 8); + csr::rtio::i_timeout_write(timeout as u64); + + let mut status = RTIO_I_STATUS_WAIT_STATUS; + while status & RTIO_I_STATUS_WAIT_STATUS != 0 { + status = csr::rtio::i_status_read(); + } + + if status & RTIO_I_STATUS_OVERFLOW != 0 { + csr::rtio::i_overflow_reset_write(1); + println!("RTIO input overflow on channel {0}", + channel as i64); + } + if status & RTIO_I_STATUS_WAIT_EVENT != 0 { + return -1 + } + if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 { + println!("RTIO destination unreachable, input, on channel {0}", + channel as i64); + } + + csr::rtio::i_timestamp_read() as i64 + } +} + +pub extern fn input_data(channel: i32) -> i32 { + unsafe { + csr::rtio::target_write((channel as u32) << 8); + csr::rtio::i_timeout_write(0xffffffff_ffffffff); + + let mut status = RTIO_I_STATUS_WAIT_STATUS; + while status & RTIO_I_STATUS_WAIT_STATUS != 0 { + status = csr::rtio::i_status_read(); + } + + if status & RTIO_I_STATUS_OVERFLOW != 0 { + csr::rtio::i_overflow_reset_write(1); + println!("RTIO input overflow on channel {0}", + channel as i64); + } + if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 { + println!("RTIO destination unreachable, input, on channel {0}", + channel as i64); + } + + rtio_i_data_read(0) as i32 + } +} + +pub extern fn input_timestamped_data(timeout: i64, channel: i32) -> TimestampedData { + unsafe { + csr::rtio::target_write((channel as u32) << 8); + csr::rtio::i_timeout_write(timeout as u64); + + let mut status = RTIO_I_STATUS_WAIT_STATUS; + while status & RTIO_I_STATUS_WAIT_STATUS != 0 { + status = csr::rtio::i_status_read(); + } + + if status & RTIO_I_STATUS_OVERFLOW != 0 { + csr::rtio::i_overflow_reset_write(1); + println!("RTIO input overflow on channel {0}", + channel as i64); + } + if status & RTIO_I_STATUS_WAIT_EVENT != 0 { + return TimestampedData { timestamp: -1, data: 0 } + } + if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 { + println!("RTIO destination unreachable, input, on channel {0}", + channel as i64); + } + + TimestampedData { + timestamp: csr::rtio::i_timestamp_read() as i64, + data: rtio_i_data_read(0) as i32 + } + } +}