From 6c049ad40ccf172137a76a8b8ae843fc0ab282b7 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 29 Sep 2017 16:32:57 +0800 Subject: [PATCH] rtio: report channel numbers in asynchronous errors --- artiq/firmware/libdrtioaux/lib.rs | 33 +++++++--- artiq/firmware/runtime/rtio_mgt.rs | 21 ++++--- artiq/firmware/satman/lib.rs | 12 +++- artiq/gateware/drtio/rt_errors_satellite.py | 37 ++++++++--- artiq/gateware/rtio/cdc.py | 14 ++++- artiq/gateware/rtio/core.py | 69 +++++++++++++-------- 6 files changed, 129 insertions(+), 57 deletions(-) diff --git a/artiq/firmware/libdrtioaux/lib.rs b/artiq/firmware/libdrtioaux/lib.rs index 51ff8faa8..46be40b34 100644 --- a/artiq/firmware/libdrtioaux/lib.rs +++ b/artiq/firmware/libdrtioaux/lib.rs @@ -21,9 +21,9 @@ pub enum Packet { RtioErrorRequest, RtioNoErrorReply, - RtioErrorSequenceErrorReply, - RtioErrorCollisionReply, - RtioErrorBusyReply, + RtioErrorSequenceErrorReply { channel: u16 }, + RtioErrorCollisionReply { channel: u16 }, + RtioErrorBusyReply { channel: u16 }, MonitorRequest { channel: u16, probe: u8 }, MonitorReply { value: u32 }, @@ -56,9 +56,15 @@ impl Packet { 0x20 => Packet::RtioErrorRequest, 0x21 => Packet::RtioNoErrorReply, - 0x22 => Packet::RtioErrorSequenceErrorReply, - 0x23 => Packet::RtioErrorCollisionReply, - 0x24 => Packet::RtioErrorBusyReply, + 0x22 => Packet::RtioErrorSequenceErrorReply { + channel: read_u16(reader)? + }, + 0x23 => Packet::RtioErrorCollisionReply { + channel: read_u16(reader)? + }, + 0x24 => Packet::RtioErrorBusyReply { + channel: read_u16(reader)? + }, 0x40 => Packet::MonitorRequest { channel: read_u16(reader)?, @@ -147,9 +153,18 @@ impl Packet { Packet::RtioErrorRequest => write_u8(writer, 0x20)?, Packet::RtioNoErrorReply => write_u8(writer, 0x21)?, - Packet::RtioErrorSequenceErrorReply => write_u8(writer, 0x22)?, - Packet::RtioErrorCollisionReply => write_u8(writer, 0x23)?, - Packet::RtioErrorBusyReply => write_u8(writer, 0x24)?, + Packet::RtioErrorSequenceErrorReply { channel } => { + write_u8(writer, 0x22)?; + write_u16(writer, channel)?; + }, + Packet::RtioErrorCollisionReply { channel } => { + write_u8(writer, 0x23)?; + write_u16(writer, channel)?; + }, + Packet::RtioErrorBusyReply { channel } => { + write_u8(writer, 0x24)?; + write_u16(writer, channel)?; + }, Packet::MonitorRequest { channel, probe } => { write_u8(writer, 0x40)?; diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index 992a62bb3..fe3697e6f 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -129,12 +129,12 @@ pub mod drtio { drtioaux::hw::send_link(linkno, &drtioaux::Packet::RtioErrorRequest).unwrap(); match drtioaux::hw::recv_timeout_link(linkno, None) { Ok(drtioaux::Packet::RtioNoErrorReply) => (), - Ok(drtioaux::Packet::RtioErrorSequenceErrorReply) => - error!("[LINK#{}] RTIO sequence error", linkno), - Ok(drtioaux::Packet::RtioErrorCollisionReply) => - error!("[LINK#{}] RTIO collision", linkno), - Ok(drtioaux::Packet::RtioErrorBusyReply) => - error!("[LINK#{}] RTIO busy", linkno), + Ok(drtioaux::Packet::RtioErrorSequenceErrorReply { channel }) => + error!("[LINK#{}] RTIO sequence error involving channel {}", linkno, channel), + Ok(drtioaux::Packet::RtioErrorCollisionReply { channel }) => + error!("[LINK#{}] RTIO collision involving channel {}", linkno, channel), + Ok(drtioaux::Packet::RtioErrorBusyReply { channel }) => + error!("[LINK#{}] RTIO busy error involving channel {}", linkno, channel), Ok(_) => error!("[LINK#{}] received unexpected aux packet", linkno), Err(e) => error!("[LINK#{}] aux packet error ({})", linkno, e) } @@ -190,13 +190,16 @@ fn async_error_thread(io: Io) { io.until(|| csr::rtio_core::async_error_read() != 0).unwrap(); let errors = csr::rtio_core::async_error_read(); if errors & 1 != 0 { - error!("RTIO collision"); + error!("RTIO collision involving channel {}", + csr::rtio_core::collision_channel_read()); } if errors & 2 != 0 { - error!("RTIO busy"); + error!("RTIO busy error involving channel {}", + csr::rtio_core::busy_channel_read()); } if errors & 4 != 0 { - error!("RTIO sequence error"); + error!("RTIO sequence error involving channel {}", + csr::rtio_core::sequence_error_channel_read()); } csr::rtio_core::async_error_write(errors); } diff --git a/artiq/firmware/satman/lib.rs b/artiq/firmware/satman/lib.rs index 4df701b4d..7620c33c8 100644 --- a/artiq/firmware/satman/lib.rs +++ b/artiq/firmware/satman/lib.rs @@ -23,20 +23,26 @@ fn process_aux_packet(p: &drtioaux::Packet) { errors = (board::csr::DRTIO[0].rtio_error_read)(); } if errors & 1 != 0 { + let channel; unsafe { + channel = (board::csr::DRTIO[0].sequence_error_channel_read)(); (board::csr::DRTIO[0].rtio_error_write)(1); } - drtioaux::hw::send_link(0, &drtioaux::Packet::RtioErrorSequenceErrorReply).unwrap(); + drtioaux::hw::send_link(0, &drtioaux::Packet::RtioErrorSequenceErrorReply { channel: channel }).unwrap(); } else if errors & 2 != 0 { + let channel; unsafe { + channel = (board::csr::DRTIO[0].collision_channel_read)(); (board::csr::DRTIO[0].rtio_error_write)(2); } - drtioaux::hw::send_link(0, &drtioaux::Packet::RtioErrorCollisionReply).unwrap(); + drtioaux::hw::send_link(0, &drtioaux::Packet::RtioErrorCollisionReply { channel: channel }).unwrap(); } else if errors & 4 != 0 { + let channel; unsafe { + channel = (board::csr::DRTIO[0].busy_channel_read)(); (board::csr::DRTIO[0].rtio_error_write)(4); } - drtioaux::hw::send_link(0, &drtioaux::Packet::RtioErrorBusyReply).unwrap(); + drtioaux::hw::send_link(0, &drtioaux::Packet::RtioErrorBusyReply { channel: channel }).unwrap(); } else { drtioaux::hw::send_link(0, &drtioaux::Packet::RtioNoErrorReply).unwrap(); diff --git a/artiq/gateware/drtio/rt_errors_satellite.py b/artiq/gateware/drtio/rt_errors_satellite.py index 9b3ab00a0..bf6e9a3d9 100644 --- a/artiq/gateware/drtio/rt_errors_satellite.py +++ b/artiq/gateware/drtio/rt_errors_satellite.py @@ -10,25 +10,39 @@ class RTErrorsSatellite(Module, AutoCSR): def __init__(self, rt_packet, outputs): self.protocol_error = CSR(4) self.rtio_error = CSR(3) + self.sequence_error_channel = CSRStatus(16) + self.collision_channel = CSRStatus(16) + self.busy_channel = CSRStatus(16) def error_csr(csr, *sources): - for n, (source, detect_edges) in enumerate(sources): + for n, (source, detect_edges, din, dout) in enumerate(sources): assert isinstance(source, Signal) - pending = Signal(related=source) - xfer = BlindTransfer(odomain="sys") + + if din is not None: + data_width = len(din) + else: + data_width = 0 + xfer = BlindTransfer(odomain="sys", data_width=data_width) self.submodules += xfer + if detect_edges: source_r = Signal() self.sync.rio += source_r.eq(source) self.comb += xfer.i.eq(source & source_r) else: self.comb += xfer.i.eq(source) + + pending = Signal(related=source) self.sync += [ If(csr.re & csr.r[n], pending.eq(0)), If(xfer.o, pending.eq(1)) ] self.comb += csr.w[n].eq(pending) + if din is not None: + self.comb += xfer.data_i.eq(din) + self.sync += If(xfer.o & ~pending, dout.eq(xfer.data_o)) + # The master is normally responsible for avoiding output overflows # and output underflows. The error reports here are only for diagnosing @@ -40,13 +54,16 @@ class RTErrorsSatellite(Module, AutoCSR): overflow.eq(outputs.cri.o_status[0]) ] error_csr(self.protocol_error, - (rt_packet.unknown_packet_type, False), - (rt_packet.packet_truncated, False), - (underflow, True), - (overflow, True) + (rt_packet.unknown_packet_type, False, None, None), + (rt_packet.packet_truncated, False, None, None), + (underflow, True, None, None), + (overflow, True, None, None) ) error_csr(self.rtio_error, - (outputs.sequence_error, False), - (outputs.collision, False), - (outputs.busy, False) + (outputs.sequence_error, False, + outputs.sequence_error_channel, self.sequence_error_channel.status), + (outputs.collision, False, + outputs.collision_channel, self.collision_channel.status), + (outputs.busy, False, + outputs.busy_channel, self.busy_channel.status) ) diff --git a/artiq/gateware/rtio/cdc.py b/artiq/gateware/rtio/cdc.py index 493b1e2e8..e5f75fba3 100644 --- a/artiq/gateware/rtio/cdc.py +++ b/artiq/gateware/rtio/cdc.py @@ -29,9 +29,14 @@ class GrayCodeTransfer(Module): class BlindTransfer(Module): - def __init__(self, idomain="rio", odomain="rsys"): + def __init__(self, idomain="rio", odomain="rsys", data_width=0): self.i = Signal() self.o = Signal() + if data_width: + self.data_i = Signal(data_width) + self.data_o = Signal(data_width) + + # # # ps = PulseSynchronizer(idomain, odomain) ps_ack = PulseSynchronizer(odomain, idomain) @@ -47,3 +52,10 @@ class BlindTransfer(Module): ps_ack.i.eq(ps.o), self.o.eq(ps.o) ] + + if data_width: + bxfer_data = Signal(data_width) + isync += If(ps.i, bxfer_data.eq(self.data_i)) + bxfer_data.attr.add("no_retiming") + self.specials += MultiReg(bxfer_data, self.data_o, + odomain=odomain) diff --git a/artiq/gateware/rtio/core.py b/artiq/gateware/rtio/core.py index c77d5084d..c2bee2947 100644 --- a/artiq/gateware/rtio/core.py +++ b/artiq/gateware/rtio/core.py @@ -20,6 +20,9 @@ class Core(Module, AutoCSR): self.reset = CSR() self.reset_phy = CSR() self.async_error = CSR(3) + self.collision_channel = CSRStatus(16) + self.busy_channel = CSRStatus(16) + self.sequence_error_channel = CSRStatus(16) # Clocking/Reset # Create rsys, rio and rio_phy domains based on sys and rtio @@ -71,26 +74,6 @@ class Core(Module, AutoCSR): self.cri.counter.eq(coarse_ts_cdc.o << glbl_fine_ts_width) ] - # Asychronous output errors - o_collision_sync = BlindTransfer() - o_busy_sync = BlindTransfer() - self.submodules += o_collision_sync, o_busy_sync - o_sequence_error_trig = Signal() - o_collision = Signal() - o_busy = Signal() - o_sequence_error = Signal() - self.sync += [ - If(self.async_error.re, - If(self.async_error.r[0], o_collision.eq(0)), - If(self.async_error.r[1], o_busy.eq(0)), - If(self.async_error.r[2], o_sequence_error.eq(0)), - ), - If(o_collision_sync.o, o_collision.eq(1)), - If(o_busy_sync.o, o_busy.eq(1)), - If(o_sequence_error_trig, o_sequence_error.eq(1)) - ] - self.comb += self.async_error.w.eq(Cat(o_collision, o_busy, o_sequence_error)) - # Outputs/Inputs quash_channels = [n for n, c in enumerate(channels) if isinstance(c, LogChannel)] @@ -101,14 +84,50 @@ class Core(Module, AutoCSR): self.submodules += outputs self.comb += outputs.coarse_timestamp.eq(coarse_ts) self.sync += outputs.minimum_coarse_timestamp.eq(coarse_ts + 16) - self.comb += [ - o_collision_sync.i.eq(outputs.collision), - o_busy_sync.i.eq(outputs.busy), - o_sequence_error_trig.eq(outputs.sequence_error) - ] inputs = InputCollector(channels, glbl_fine_ts_width, "async", quash_channels=quash_channels, interface=self.cri) self.submodules += inputs self.comb += inputs.coarse_timestamp.eq(coarse_ts) + + # Asychronous output errors + o_collision_sync = BlindTransfer(data_width=16) + o_busy_sync = BlindTransfer(data_width=16) + self.submodules += o_collision_sync, o_busy_sync + o_collision = Signal() + o_busy = Signal() + o_sequence_error = Signal() + self.sync += [ + If(self.async_error.re, + If(self.async_error.r[0], o_collision.eq(0)), + If(self.async_error.r[1], o_busy.eq(0)), + If(self.async_error.r[2], o_sequence_error.eq(0)), + ), + If(o_collision_sync.o, + o_collision.eq(1), + If(~o_collision, + self.collision_channel.status.eq(o_collision_sync.data_o) + ) + ), + If(o_busy_sync.o, + o_busy.eq(1), + If(~o_busy, + self.busy_channel.status.eq(o_busy_sync.data_o) + ) + ), + If(outputs.sequence_error, + o_sequence_error.eq(1), + If(~o_sequence_error, + self.sequence_error_channel.status.eq(outputs.sequence_error_channel) + ) + ) + ] + self.comb += self.async_error.w.eq(Cat(o_collision, o_busy, o_sequence_error)) + + self.comb += [ + o_collision_sync.i.eq(outputs.collision), + o_collision_sync.data_i.eq(outputs.collision_channel), + o_busy_sync.i.eq(outputs.busy), + o_busy_sync.data_i.eq(outputs.busy_channel) + ]