From 731f52992fd1acab48198bd62cdb37f68eaacaf0 Mon Sep 17 00:00:00 2001 From: mwojcik Date: Wed, 21 Jul 2021 12:49:15 +0200 Subject: [PATCH] moved related libraries, culled unnecessary ones --- src/libboard_artiqzynq/clock.rs | 38 ++++++ src/libboard_artiqzynq/drtio_routing.rs | 107 +++++++++++++++++ src/libboard_artiqzynq/drtioaux.rs | 153 ++++++++++++++++++++++++ src/libboard_artiqzynq/lib.rs | 5 + src/libproto_artiq/lib.rs | 18 +++ 5 files changed, 321 insertions(+) create mode 100644 src/libboard_artiqzynq/clock.rs create mode 100644 src/libboard_artiqzynq/drtio_routing.rs create mode 100644 src/libboard_artiqzynq/drtioaux.rs create mode 100644 src/libboard_artiqzynq/lib.rs create mode 100644 src/libproto_artiq/lib.rs diff --git a/src/libboard_artiqzynq/clock.rs b/src/libboard_artiqzynq/clock.rs new file mode 100644 index 00000000..c75753cc --- /dev/null +++ b/src/libboard_artiqzynq/clock.rs @@ -0,0 +1,38 @@ +use core::i64; +use csr; // <- port + +const INIT: u64 = i64::MAX as u64; +const FREQ: u64 = csr::CONFIG_CLOCK_FREQUENCY as u64; + +pub fn init() { + unsafe { + csr::timer0::en_write(0); + csr::timer0::load_write(INIT); + csr::timer0::reload_write(INIT); + csr::timer0::en_write(1); + } +} + +pub fn get_us() -> u64 { + unsafe { + csr::timer0::update_value_write(1); + (INIT - csr::timer0::value_read()) / (FREQ / 1_000_000) + } +} + +pub fn get_ms() -> u64 { + unsafe { + csr::timer0::update_value_write(1); + (INIT - csr::timer0::value_read()) / (FREQ / 1_000) + } +} + +pub fn spin_us(interval: u64) { + unsafe { + csr::timer0::update_value_write(1); + let threshold = csr::timer0::value_read() - interval * (FREQ / 1_000_000); + while csr::timer0::value_read() > threshold { + csr::timer0::update_value_write(1) + } + } +} diff --git a/src/libboard_artiqzynq/drtio_routing.rs b/src/libboard_artiqzynq/drtio_routing.rs new file mode 100644 index 00000000..fd65e2fc --- /dev/null +++ b/src/libboard_artiqzynq/drtio_routing.rs @@ -0,0 +1,107 @@ +use board_misoc::config; // <- port +#[cfg(has_drtio_routing)] +use board_misoc::csr; // <- port +use core::fmt; + +#[cfg(has_drtio_routing)] +pub const DEST_COUNT: usize = 256; +#[cfg(not(has_drtio_routing))] +pub const DEST_COUNT: usize = 0; +pub const MAX_HOPS: usize = 32; +pub const INVALID_HOP: u8 = 0xff; + +pub struct RoutingTable(pub [[u8; MAX_HOPS]; DEST_COUNT]); + +impl RoutingTable { + // default routing table is for star topology with no repeaters + pub fn default_master(default_n_links: usize) -> RoutingTable { + let mut ret = RoutingTable([[INVALID_HOP; MAX_HOPS]; DEST_COUNT]); + let n_entries = default_n_links + 1; // include local RTIO + for i in 0..n_entries { + ret.0[i][0] = i as u8; + } + for i in 1..n_entries { + ret.0[i][1] = 0x00; + } + ret + } + + // use this by default on satellite, as they receive + // the routing table from the master + pub fn default_empty() -> RoutingTable { + RoutingTable([[INVALID_HOP; MAX_HOPS]; DEST_COUNT]) + } +} + +impl fmt::Display for RoutingTable { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "RoutingTable {{")?; + for i in 0..DEST_COUNT { + if self.0[i][0] != INVALID_HOP { + write!(f, " {}:", i)?; + for j in 0..MAX_HOPS { + if self.0[i][j] == INVALID_HOP { + break; + } + write!(f, " {}", self.0[i][j])?; + } + write!(f, ";")?; + } + } + write!(f, " }}")?; + Ok(()) + } +} + +pub fn config_routing_table(default_n_links: usize) -> RoutingTable { + let mut ret = RoutingTable::default_master(default_n_links); + let ok = config::read("routing_table", |result| { + if let Ok(data) = result { + if data.len() == DEST_COUNT*MAX_HOPS { + for i in 0..DEST_COUNT { + for j in 0..MAX_HOPS { + ret.0[i][j] = data[i*MAX_HOPS+j]; + } + } + return true; + } + } + false + }); + if !ok { + warn!("could not read routing table from configuration, using default"); + } + info!("routing table: {}", ret); + ret +} + +#[cfg(has_drtio_routing)] +pub fn interconnect_enable(routing_table: &RoutingTable, rank: u8, destination: u8) { + let hop = routing_table.0[destination as usize][rank as usize]; + unsafe { + csr::routing_table::destination_write(destination); + csr::routing_table::hop_write(hop); + } +} + +#[cfg(has_drtio_routing)] +pub fn interconnect_disable(destination: u8) { + unsafe { + csr::routing_table::destination_write(destination); + csr::routing_table::hop_write(INVALID_HOP); + } +} + +#[cfg(has_drtio_routing)] +pub fn interconnect_enable_all(routing_table: &RoutingTable, rank: u8) { + for i in 0..DEST_COUNT { + interconnect_enable(routing_table, rank, i as u8); + } +} + +#[cfg(has_drtio_routing)] +pub fn interconnect_disable_all() { + for i in 0..DEST_COUNT { + interconnect_disable(i as u8); + } +} diff --git a/src/libboard_artiqzynq/drtioaux.rs b/src/libboard_artiqzynq/drtioaux.rs new file mode 100644 index 00000000..52be3652 --- /dev/null +++ b/src/libboard_artiqzynq/drtioaux.rs @@ -0,0 +1,153 @@ +use core::slice; +use crc; + +use io::{ProtoRead, ProtoWrite, Cursor, Error as IoError}; +use board_misoc::{csr::DRTIOAUX, mem::DRTIOAUX_MEM}; // <- port +use clock; +use proto_artiq::drtioaux_proto::Error as ProtocolError; + +pub use proto_artiq::drtioaux_proto::Packet; + +// this is parametric over T because there's no impl Fail for !. +#[derive(Fail, Debug)] +pub enum Error { + #[fail(display = "gateware reported error")] + GatewareError, + #[fail(display = "packet CRC failed")] + CorruptedPacket, + + #[fail(display = "link is down")] + LinkDown, + #[fail(display = "timed out waiting for data")] + TimedOut, + #[fail(display = "unexpected reply")] + UnexpectedReply, + + #[fail(display = "routing error")] + RoutingError, + + #[fail(display = "protocol error: {}", _0)] + Protocol(#[cause] ProtocolError) +} + +impl From> for Error { + fn from(value: ProtocolError) -> Error { + Error::Protocol(value) + } +} + +impl From> for Error { + fn from(value: IoError) -> Error { + Error::Protocol(ProtocolError::Io(value)) + } +} + +pub fn reset(linkno: u8) { + let linkno = linkno as usize; + unsafe { + // clear buffer first to limit race window with buffer overflow + // error. We assume the CPU is fast enough so that no two packets + // will be received between the buffer and the error flag are cleared. + (DRTIOAUX[linkno].aux_rx_present_write)(1); + (DRTIOAUX[linkno].aux_rx_error_write)(1); + } +} + +fn has_rx_error(linkno: u8) -> bool { + let linkno = linkno as usize; + unsafe { + let error = (DRTIOAUX[linkno].aux_rx_error_read)() != 0; + if error { + (DRTIOAUX[linkno].aux_rx_error_write)(1) + } + error + } +} + +fn receive(linkno: u8, f: F) -> Result, Error> + where F: FnOnce(&[u8]) -> Result> +{ + let linkidx = linkno as usize; + unsafe { + if (DRTIOAUX[linkidx].aux_rx_present_read)() == 1 { + let ptr = DRTIOAUX_MEM[linkidx].base + DRTIOAUX_MEM[linkidx].size / 2; + let len = (DRTIOAUX[linkidx].aux_rx_length_read)(); + let result = f(slice::from_raw_parts(ptr as *mut u8, len as usize)); + (DRTIOAUX[linkidx].aux_rx_present_write)(1); + Ok(Some(result?)) + } else { + Ok(None) + } + } +} + +pub fn recv(linkno: u8) -> Result, Error> { + if has_rx_error(linkno) { + return Err(Error::GatewareError) + } + + receive(linkno, |buffer| { + if buffer.len() < 8 { + return Err(IoError::UnexpectedEnd.into()) + } + + let mut reader = Cursor::new(buffer); + + let checksum_at = buffer.len() - 4; + let checksum = crc::crc32::checksum_ieee(&reader.get_ref()[0..checksum_at]); + reader.set_position(checksum_at); + if reader.read_u32()? != checksum { + return Err(Error::CorruptedPacket) + } + reader.set_position(0); + + Ok(Packet::read_from(&mut reader)?) + }) +} + +pub fn recv_timeout(linkno: u8, timeout_ms: Option) -> Result> { + let timeout_ms = timeout_ms.unwrap_or(10); + let limit = clock::get_ms() + timeout_ms; + while clock::get_ms() < limit { + match recv(linkno)? { + None => (), + Some(packet) => return Ok(packet), + } + } + Err(Error::TimedOut) +} + +fn transmit(linkno: u8, f: F) -> Result<(), Error> + where F: FnOnce(&mut [u8]) -> Result> +{ + let linkno = linkno as usize; + unsafe { + while (DRTIOAUX[linkno].aux_tx_read)() != 0 {} + let ptr = DRTIOAUX_MEM[linkno].base; + let len = DRTIOAUX_MEM[linkno].size / 2; + let len = f(slice::from_raw_parts_mut(ptr as *mut u8, len))?; + (DRTIOAUX[linkno].aux_tx_length_write)(len as u16); + (DRTIOAUX[linkno].aux_tx_write)(1); + Ok(()) + } +} + +pub fn send(linkno: u8, packet: &Packet) -> Result<(), Error> { + transmit(linkno, |buffer| { + let mut writer = Cursor::new(buffer); + + packet.write_to(&mut writer)?; + + let padding = 4 - (writer.position() % 4); + if padding != 4 { + for _ in 0..padding { + writer.write_u8(0)?; + } + } + + let checksum = crc::crc32::checksum_ieee(&writer.get_ref()[0..writer.position()]); + writer.write_u32(checksum)?; + + Ok(writer.position()) + }) +} diff --git a/src/libboard_artiqzynq/lib.rs b/src/libboard_artiqzynq/lib.rs new file mode 100644 index 00000000..da96785f --- /dev/null +++ b/src/libboard_artiqzynq/lib.rs @@ -0,0 +1,5 @@ +pub mod clock; + +#[cfg(has_drtio)] +pub mod drtioaux; +pub mod drtio_routing; diff --git a/src/libproto_artiq/lib.rs b/src/libproto_artiq/lib.rs new file mode 100644 index 00000000..e2dcd8bd --- /dev/null +++ b/src/libproto_artiq/lib.rs @@ -0,0 +1,18 @@ +#![no_std] +#![cfg_attr(feature = "alloc", feature(alloc))] + +extern crate failure; +#[macro_use] +extern crate failure_derive; +#[cfg(feature = "alloc")] +extern crate alloc; +extern crate cslice; +#[cfg(feature = "log")] +#[macro_use] +extern crate log; + +extern crate io; +extern crate dyld; + +// Internal protocols. +pub mod drtioaux_proto;