forked from M-Labs/artiq
rtio: report channel numbers in asynchronous errors
This commit is contained in:
parent
5437f0e3e3
commit
6c049ad40c
|
@ -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)?;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
]
|
||||
|
|
Loading…
Reference in New Issue