From 008678b74120469078eee1a884ab3572eca03a88 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 2 Apr 2017 23:45:55 +0800 Subject: [PATCH] drtio: add infrastructure for reporting busy/collision errors --- artiq/firmware/libdrtioaux/lib.rs | 58 ++++++++++++++++----- artiq/firmware/runtime/moninj.rs | 52 ++++++------------ artiq/firmware/runtime/rtio_mgt.rs | 21 +++++++- artiq/firmware/satman/lib.rs | 21 ++++++++ artiq/gateware/drtio/rt_errors_satellite.py | 43 ++++++++------- artiq/gateware/drtio/rt_ios_satellite.py | 6 ++- 6 files changed, 126 insertions(+), 75 deletions(-) diff --git a/artiq/firmware/libdrtioaux/lib.rs b/artiq/firmware/libdrtioaux/lib.rs index 4cdf0416c..eaf3da4df 100644 --- a/artiq/firmware/libdrtioaux/lib.rs +++ b/artiq/firmware/libdrtioaux/lib.rs @@ -20,6 +20,12 @@ use proto::*; pub enum Packet { EchoRequest, EchoReply, + + RtioErrorRequest, + RtioNoErrorReply, + RtioErrorCollisionReply, + RtioErrorBusyReply, + MonitorRequest { channel: u16, probe: u8 }, MonitorReply { value: u32 }, InjectionRequest { channel: u16, overrd: u8, value: u8 }, @@ -30,25 +36,31 @@ pub enum Packet { impl Packet { pub fn read_from(reader: &mut Read) -> io::Result { Ok(match read_u8(reader)? { - 0 => Packet::EchoRequest, - 1 => Packet::EchoReply, - 2 => Packet::MonitorRequest { + 0x00 => Packet::EchoRequest, + 0x01 => Packet::EchoReply, + + 0x20 => Packet::RtioErrorRequest, + 0x21 => Packet::RtioNoErrorReply, + 0x22 => Packet::RtioErrorCollisionReply, + 0x23 => Packet::RtioErrorBusyReply, + + 0x40 => Packet::MonitorRequest { channel: read_u16(reader)?, probe: read_u8(reader)? }, - 3 => Packet::MonitorReply { + 0x41 => Packet::MonitorReply { value: read_u32(reader)? }, - 4 => Packet::InjectionRequest { + 0x50 => Packet::InjectionRequest { channel: read_u16(reader)?, overrd: read_u8(reader)?, value: read_u8(reader)? }, - 5 => Packet::InjectionStatusRequest { + 0x51 => Packet::InjectionStatusRequest { channel: read_u16(reader)?, overrd: read_u8(reader)? }, - 6 => Packet::InjectionStatusReply { + 0x52 => Packet::InjectionStatusReply { value: read_u8(reader)? }, _ => return Err(io::Error::new(io::ErrorKind::InvalidData, "unknown packet type")) @@ -57,30 +69,36 @@ impl Packet { pub fn write_to(&self, writer: &mut Write) -> io::Result<()> { match *self { - Packet::EchoRequest => write_u8(writer, 0)?, - Packet::EchoReply => write_u8(writer, 1)?, + Packet::EchoRequest => write_u8(writer, 0x00)?, + Packet::EchoReply => write_u8(writer, 0x01)?, + + Packet::RtioErrorRequest => write_u8(writer, 0x20)?, + Packet::RtioNoErrorReply => write_u8(writer, 0x21)?, + Packet::RtioErrorCollisionReply => write_u8(writer, 0x22)?, + Packet::RtioErrorBusyReply => write_u8(writer, 0x23)?, + Packet::MonitorRequest { channel, probe } => { - write_u8(writer, 2)?; + write_u8(writer, 0x40)?; write_u16(writer, channel)?; write_u8(writer, probe)?; }, Packet::MonitorReply { value } => { - write_u8(writer, 3)?; + write_u8(writer, 0x41)?; write_u32(writer, value)?; }, Packet::InjectionRequest { channel, overrd, value } => { - write_u8(writer, 4)?; + write_u8(writer, 0x50)?; write_u16(writer, channel)?; write_u8(writer, overrd)?; write_u8(writer, value)?; }, Packet::InjectionStatusRequest { channel, overrd } => { - write_u8(writer, 5)?; + write_u8(writer, 0x51)?; write_u16(writer, channel)?; write_u8(writer, overrd)?; }, Packet::InjectionStatusReply { value } => { - write_u8(writer, 6)?; + write_u8(writer, 0x52)?; write_u8(writer, value)?; } } @@ -161,6 +179,18 @@ pub mod hw { } } + pub fn recv_timeout(timeout_ms: u64) -> io::Result { + let limit = board::clock::get_ms() + timeout_ms; + while board::clock::get_ms() < limit { + match recv() { + Ok(None) => (), + Ok(Some(packet)) => return Ok(packet), + Err(e) => return Err(e) + } + } + return Err(io::Error::new(io::ErrorKind::TimedOut, "timed out waiting for data")) + } + fn tx_get_buffer() -> &'static mut [u8] { unsafe { while board::csr::drtio::aux_tx_read() != 0 {} diff --git a/artiq/firmware/runtime/moninj.rs b/artiq/firmware/runtime/moninj.rs index a0eb3bdf9..b2fa5369c 100644 --- a/artiq/firmware/runtime/moninj.rs +++ b/artiq/firmware/runtime/moninj.rs @@ -35,32 +35,22 @@ fn read_probe_local(channel: u16, probe: u8) -> u32 { } #[cfg(has_drtio)] -fn read_probe_drtio(io: &Io, channel: u16, probe: u8) -> u32 { +fn read_probe_drtio(channel: u16, probe: u8) -> u32 { if rtio_mgt::drtio::link_is_running() { let request = drtioaux::Packet::MonitorRequest { channel: channel, probe: probe }; drtioaux::hw::send(&request).unwrap(); - - let timeout = clock::get_ms() + 20; - while clock::get_ms() < timeout { - if !rtio_mgt::drtio::link_is_running() { - return 0 - } - match drtioaux::hw::recv() { - Ok(None) => (), - Ok(Some(drtioaux::Packet::MonitorReply { value })) => return value, - Ok(Some(_)) => warn!("received unexpected aux packet"), - Err(e) => warn!("aux packet error ({})", e) - } - io.relinquish().unwrap(); + match drtioaux::hw::recv_timeout(10) { + Ok(drtioaux::Packet::MonitorReply { value }) => return value, + Ok(_) => error!("received unexpected aux packet"), + Err(e) => error!("aux packet error ({})", e) } - warn!("aux packet timeout"); 0 } else { 0 } } -fn read_probe(_io: &Io, channel: u32, probe: u8) -> u32 { +fn read_probe(channel: u32, probe: u8) -> u32 { #[cfg(has_rtio_moninj)] { if channel & 0xff0000 == 0 { @@ -70,7 +60,7 @@ fn read_probe(_io: &Io, channel: u32, probe: u8) -> u32 { #[cfg(has_drtio)] { if channel & 0xff0000 != 0 { - return read_probe_drtio(_io, channel as u16, probe) + return read_probe_drtio(channel as u16, probe) } } error!("read_probe: unrecognized channel number {}", channel); @@ -126,35 +116,25 @@ fn read_injection_status_local(channel: u16, overrd: u8) -> u8 { } #[cfg(has_drtio)] -fn read_injection_status_drtio(io: &Io, channel: u16, overrd: u8) -> u8 { +fn read_injection_status_drtio(channel: u16, overrd: u8) -> u8 { if rtio_mgt::drtio::link_is_running() { let request = drtioaux::Packet::InjectionStatusRequest { channel: channel, overrd: overrd }; drtioaux::hw::send(&request).unwrap(); - - let timeout = clock::get_ms() + 20; - while clock::get_ms() < timeout { - if !rtio_mgt::drtio::link_is_running() { - return 0 - } - match drtioaux::hw::recv() { - Ok(None) => (), - Ok(Some(drtioaux::Packet::InjectionStatusReply { value })) => return value, - Ok(Some(_)) => warn!("received unexpected aux packet"), - Err(e) => warn!("aux packet error ({})", e) - } - io.relinquish().unwrap(); + match drtioaux::hw::recv_timeout(10) { + Ok(drtioaux::Packet::InjectionStatusReply { value }) => return value, + Ok(_) => error!("received unexpected aux packet"), + Err(e) => error!("aux packet error ({})", e) } - warn!("aux packet timeout"); 0 } else { 0 } } -fn read_injection_status(_io: &Io, channel: u32, probe: u8) -> u8 { +fn read_injection_status(channel: u32, probe: u8) -> u8 { #[cfg(has_rtio_moninj)] { if channel & 0xff0000 == 0 { @@ -164,7 +144,7 @@ fn read_injection_status(_io: &Io, channel: u32, probe: u8) -> u8 { #[cfg(has_drtio)] { if channel & 0xff0000 != 0 { - return read_injection_status_drtio(_io, channel as u16, probe) + return read_injection_status_drtio(channel as u16, probe) } } error!("read_injection_status: unrecognized channel number {}", channel); @@ -191,7 +171,7 @@ fn connection_worker(io: &Io, mut stream: &mut TcpStream) -> io::Result<()> { }, HostMessage::Inject { channel, overrd, value } => inject(channel, overrd, value), HostMessage::GetInjectionStatus { channel, overrd } => { - let value = read_injection_status(io, channel, overrd); + let value = read_injection_status(channel, overrd); let reply = DeviceMessage::InjectionStatus { channel: channel, overrd: overrd, @@ -206,7 +186,7 @@ fn connection_worker(io: &Io, mut stream: &mut TcpStream) -> io::Result<()> { if clock::get_ms() > next_check { for (&(channel, probe), previous) in watch_list.iter_mut() { - let current = read_probe(io, channel, probe); + let current = read_probe(channel, probe); if previous.is_none() || (previous.unwrap() != current) { let message = DeviceMessage::MonitorStatus { channel: channel, diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index 74a7c52d6..76e88e080 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -43,7 +43,8 @@ pub mod drtio { pub fn startup(io: &Io) { io.spawn(4096, link_thread); - io.spawn(4096, error_thread); + io.spawn(4096, local_error_thread); + io.spawn(4096, aux_error_thread); } static mut LINK_RUNNING: bool = false; @@ -144,7 +145,7 @@ pub mod drtio { } } - pub fn error_thread(io: Io) { + pub fn local_error_thread(io: Io) { loop { unsafe { io.until(|| csr::drtio::protocol_error_read() != 0).unwrap(); @@ -162,6 +163,22 @@ pub mod drtio { } } } + + pub fn aux_error_thread(io: Io) { + loop { + io.sleep(200).unwrap(); + if link_is_running() { + drtioaux::hw::send(&drtioaux::Packet::RtioErrorRequest).unwrap(); + match drtioaux::hw::recv_timeout(10) { + Ok(drtioaux::Packet::RtioNoErrorReply) => (), + Ok(drtioaux::Packet::RtioErrorCollisionReply) => error!("RTIO collision (in satellite)"), + Ok(drtioaux::Packet::RtioErrorBusyReply) => error!("RTIO busy (in satellite)"), + Ok(_) => error!("received unexpected aux packet"), + Err(e) => error!("aux packet error ({})", e) + } + } + } + } } #[cfg(not(has_drtio))] diff --git a/artiq/firmware/satman/lib.rs b/artiq/firmware/satman/lib.rs index fe6633067..409ffdcd5 100644 --- a/artiq/firmware/satman/lib.rs +++ b/artiq/firmware/satman/lib.rs @@ -16,6 +16,27 @@ fn process_aux_packet(p: &drtioaux::Packet) { // and u16 otherwise; hence the `as _` conversion. match *p { drtioaux::Packet::EchoRequest => drtioaux::hw::send(&drtioaux::Packet::EchoReply).unwrap(), + + drtioaux::Packet::RtioErrorRequest => { + let errors; + unsafe { + errors = board::csr::drtio::rtio_error_read(); + } + if errors & 1 != 0 { + unsafe { + board::csr::drtio::rtio_error_write(1); + } + drtioaux::hw::send(&drtioaux::Packet::RtioErrorCollisionReply).unwrap(); + } else if errors & 2 != 0 { + unsafe { + board::csr::drtio::rtio_error_write(2); + } + drtioaux::hw::send(&drtioaux::Packet::RtioErrorBusyReply).unwrap(); + } else { + drtioaux::hw::send(&drtioaux::Packet::RtioNoErrorReply).unwrap(); + } + } + drtioaux::Packet::MonitorRequest { channel, probe } => { let value; #[cfg(has_rtio_moninj)] diff --git a/artiq/gateware/drtio/rt_errors_satellite.py b/artiq/gateware/drtio/rt_errors_satellite.py index 36b3e1365..cf9af97cf 100644 --- a/artiq/gateware/drtio/rt_errors_satellite.py +++ b/artiq/gateware/drtio/rt_errors_satellite.py @@ -8,29 +8,28 @@ from misoc.interconnect.csr import * class RTErrorsSatellite(Module, AutoCSR): def __init__(self, rt_packet, ios): self.protocol_error = CSR(4) + self.rtio_error = CSR(2) + + def error_csr(csr, *sources): + for n, source in enumerate(sources): + pending = Signal(related=source) + ps = PulseSynchronizer("rtio", "sys") + self.submodules += ps + self.comb += ps.i.eq(source) + self.sync += [ + If(csr.re & csr.r[n], pending.eq(0)), + If(ps.o, pending.eq(1)) + ] + self.comb += csr.w[n].eq(pending) # The master is normally responsible for avoiding output overflows and # output underflows. # Error reports here are only for diagnosing internal ARTIQ bugs. - - unknown_packet_type = Signal() - packet_truncated = Signal() - write_overflow = Signal() - write_underflow = Signal() - self.comb += self.protocol_error.w.eq( - Cat(unknown_packet_type, packet_truncated, - write_underflow, write_overflow)) - - for n, (target, source) in enumerate([ - (unknown_packet_type, rt_packet.unknown_packet_type), - (packet_truncated, rt_packet.packet_truncated), - (write_underflow, ios.write_underflow), - (write_overflow, ios.write_overflow)]): - ps = PulseSynchronizer("rtio", "sys") - self.submodules += ps - self.comb += ps.i.eq(source) - self.sync += [ - If(self.protocol_error.re & self.protocol_error.r[n], target.eq(0)), - If(ps.o, target.eq(1)) - ] - + error_csr(self.protocol_error, + rt_packet.unknown_packet_type, + rt_packet.packet_truncated, + ios.write_underflow, + ios.write_overflow) + error_csr(self.rtio_error, + ios.collision, + ios.busy) diff --git a/artiq/gateware/drtio/rt_ios_satellite.py b/artiq/gateware/drtio/rt_ios_satellite.py index a1a94746e..79cd0b72b 100644 --- a/artiq/gateware/drtio/rt_ios_satellite.py +++ b/artiq/gateware/drtio/rt_ios_satellite.py @@ -11,6 +11,8 @@ class IOS(Module): def __init__(self, rt_packet, channels, max_fine_ts_width, full_ts_width): self.write_underflow = Signal() self.write_overflow = Signal() + self.collision = Signal() + self.busy = Signal() self.rt_packet = rt_packet self.max_fine_ts_width = max_fine_ts_width @@ -26,7 +28,9 @@ class IOS(Module): self.sync.rio += [ self.write_underflow.eq(0), - self.write_overflow.eq(0) + self.write_overflow.eq(0), + self.collision.eq(0), + self.busy.eq(0) ] for n, channel in enumerate(channels): self.add_output(n, channel)