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,
|
RtioErrorRequest,
|
||||||
RtioNoErrorReply,
|
RtioNoErrorReply,
|
||||||
RtioErrorSequenceErrorReply,
|
RtioErrorSequenceErrorReply { channel: u16 },
|
||||||
RtioErrorCollisionReply,
|
RtioErrorCollisionReply { channel: u16 },
|
||||||
RtioErrorBusyReply,
|
RtioErrorBusyReply { channel: u16 },
|
||||||
|
|
||||||
MonitorRequest { channel: u16, probe: u8 },
|
MonitorRequest { channel: u16, probe: u8 },
|
||||||
MonitorReply { value: u32 },
|
MonitorReply { value: u32 },
|
||||||
|
@ -56,9 +56,15 @@ impl Packet {
|
||||||
|
|
||||||
0x20 => Packet::RtioErrorRequest,
|
0x20 => Packet::RtioErrorRequest,
|
||||||
0x21 => Packet::RtioNoErrorReply,
|
0x21 => Packet::RtioNoErrorReply,
|
||||||
0x22 => Packet::RtioErrorSequenceErrorReply,
|
0x22 => Packet::RtioErrorSequenceErrorReply {
|
||||||
0x23 => Packet::RtioErrorCollisionReply,
|
channel: read_u16(reader)?
|
||||||
0x24 => Packet::RtioErrorBusyReply,
|
},
|
||||||
|
0x23 => Packet::RtioErrorCollisionReply {
|
||||||
|
channel: read_u16(reader)?
|
||||||
|
},
|
||||||
|
0x24 => Packet::RtioErrorBusyReply {
|
||||||
|
channel: read_u16(reader)?
|
||||||
|
},
|
||||||
|
|
||||||
0x40 => Packet::MonitorRequest {
|
0x40 => Packet::MonitorRequest {
|
||||||
channel: read_u16(reader)?,
|
channel: read_u16(reader)?,
|
||||||
|
@ -147,9 +153,18 @@ impl Packet {
|
||||||
|
|
||||||
Packet::RtioErrorRequest => write_u8(writer, 0x20)?,
|
Packet::RtioErrorRequest => write_u8(writer, 0x20)?,
|
||||||
Packet::RtioNoErrorReply => write_u8(writer, 0x21)?,
|
Packet::RtioNoErrorReply => write_u8(writer, 0x21)?,
|
||||||
Packet::RtioErrorSequenceErrorReply => write_u8(writer, 0x22)?,
|
Packet::RtioErrorSequenceErrorReply { channel } => {
|
||||||
Packet::RtioErrorCollisionReply => write_u8(writer, 0x23)?,
|
write_u8(writer, 0x22)?;
|
||||||
Packet::RtioErrorBusyReply => write_u8(writer, 0x24)?,
|
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 } => {
|
Packet::MonitorRequest { channel, probe } => {
|
||||||
write_u8(writer, 0x40)?;
|
write_u8(writer, 0x40)?;
|
||||||
|
|
|
@ -129,12 +129,12 @@ pub mod drtio {
|
||||||
drtioaux::hw::send_link(linkno, &drtioaux::Packet::RtioErrorRequest).unwrap();
|
drtioaux::hw::send_link(linkno, &drtioaux::Packet::RtioErrorRequest).unwrap();
|
||||||
match drtioaux::hw::recv_timeout_link(linkno, None) {
|
match drtioaux::hw::recv_timeout_link(linkno, None) {
|
||||||
Ok(drtioaux::Packet::RtioNoErrorReply) => (),
|
Ok(drtioaux::Packet::RtioNoErrorReply) => (),
|
||||||
Ok(drtioaux::Packet::RtioErrorSequenceErrorReply) =>
|
Ok(drtioaux::Packet::RtioErrorSequenceErrorReply { channel }) =>
|
||||||
error!("[LINK#{}] RTIO sequence error", linkno),
|
error!("[LINK#{}] RTIO sequence error involving channel {}", linkno, channel),
|
||||||
Ok(drtioaux::Packet::RtioErrorCollisionReply) =>
|
Ok(drtioaux::Packet::RtioErrorCollisionReply { channel }) =>
|
||||||
error!("[LINK#{}] RTIO collision", linkno),
|
error!("[LINK#{}] RTIO collision involving channel {}", linkno, channel),
|
||||||
Ok(drtioaux::Packet::RtioErrorBusyReply) =>
|
Ok(drtioaux::Packet::RtioErrorBusyReply { channel }) =>
|
||||||
error!("[LINK#{}] RTIO busy", linkno),
|
error!("[LINK#{}] RTIO busy error involving channel {}", linkno, channel),
|
||||||
Ok(_) => error!("[LINK#{}] received unexpected aux packet", linkno),
|
Ok(_) => error!("[LINK#{}] received unexpected aux packet", linkno),
|
||||||
Err(e) => error!("[LINK#{}] aux packet error ({})", linkno, e)
|
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();
|
io.until(|| csr::rtio_core::async_error_read() != 0).unwrap();
|
||||||
let errors = csr::rtio_core::async_error_read();
|
let errors = csr::rtio_core::async_error_read();
|
||||||
if errors & 1 != 0 {
|
if errors & 1 != 0 {
|
||||||
error!("RTIO collision");
|
error!("RTIO collision involving channel {}",
|
||||||
|
csr::rtio_core::collision_channel_read());
|
||||||
}
|
}
|
||||||
if errors & 2 != 0 {
|
if errors & 2 != 0 {
|
||||||
error!("RTIO busy");
|
error!("RTIO busy error involving channel {}",
|
||||||
|
csr::rtio_core::busy_channel_read());
|
||||||
}
|
}
|
||||||
if errors & 4 != 0 {
|
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);
|
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)();
|
errors = (board::csr::DRTIO[0].rtio_error_read)();
|
||||||
}
|
}
|
||||||
if errors & 1 != 0 {
|
if errors & 1 != 0 {
|
||||||
|
let channel;
|
||||||
unsafe {
|
unsafe {
|
||||||
|
channel = (board::csr::DRTIO[0].sequence_error_channel_read)();
|
||||||
(board::csr::DRTIO[0].rtio_error_write)(1);
|
(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 {
|
} else if errors & 2 != 0 {
|
||||||
|
let channel;
|
||||||
unsafe {
|
unsafe {
|
||||||
|
channel = (board::csr::DRTIO[0].collision_channel_read)();
|
||||||
(board::csr::DRTIO[0].rtio_error_write)(2);
|
(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 {
|
} else if errors & 4 != 0 {
|
||||||
|
let channel;
|
||||||
unsafe {
|
unsafe {
|
||||||
|
channel = (board::csr::DRTIO[0].busy_channel_read)();
|
||||||
(board::csr::DRTIO[0].rtio_error_write)(4);
|
(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 {
|
else {
|
||||||
drtioaux::hw::send_link(0, &drtioaux::Packet::RtioNoErrorReply).unwrap();
|
drtioaux::hw::send_link(0, &drtioaux::Packet::RtioNoErrorReply).unwrap();
|
||||||
|
|
|
@ -10,25 +10,39 @@ class RTErrorsSatellite(Module, AutoCSR):
|
||||||
def __init__(self, rt_packet, outputs):
|
def __init__(self, rt_packet, outputs):
|
||||||
self.protocol_error = CSR(4)
|
self.protocol_error = CSR(4)
|
||||||
self.rtio_error = CSR(3)
|
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):
|
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)
|
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
|
self.submodules += xfer
|
||||||
|
|
||||||
if detect_edges:
|
if detect_edges:
|
||||||
source_r = Signal()
|
source_r = Signal()
|
||||||
self.sync.rio += source_r.eq(source)
|
self.sync.rio += source_r.eq(source)
|
||||||
self.comb += xfer.i.eq(source & source_r)
|
self.comb += xfer.i.eq(source & source_r)
|
||||||
else:
|
else:
|
||||||
self.comb += xfer.i.eq(source)
|
self.comb += xfer.i.eq(source)
|
||||||
|
|
||||||
|
pending = Signal(related=source)
|
||||||
self.sync += [
|
self.sync += [
|
||||||
If(csr.re & csr.r[n], pending.eq(0)),
|
If(csr.re & csr.r[n], pending.eq(0)),
|
||||||
If(xfer.o, pending.eq(1))
|
If(xfer.o, pending.eq(1))
|
||||||
]
|
]
|
||||||
self.comb += csr.w[n].eq(pending)
|
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
|
# The master is normally responsible for avoiding output overflows
|
||||||
# and output underflows. The error reports here are only for diagnosing
|
# 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])
|
overflow.eq(outputs.cri.o_status[0])
|
||||||
]
|
]
|
||||||
error_csr(self.protocol_error,
|
error_csr(self.protocol_error,
|
||||||
(rt_packet.unknown_packet_type, False),
|
(rt_packet.unknown_packet_type, False, None, None),
|
||||||
(rt_packet.packet_truncated, False),
|
(rt_packet.packet_truncated, False, None, None),
|
||||||
(underflow, True),
|
(underflow, True, None, None),
|
||||||
(overflow, True)
|
(overflow, True, None, None)
|
||||||
)
|
)
|
||||||
error_csr(self.rtio_error,
|
error_csr(self.rtio_error,
|
||||||
(outputs.sequence_error, False),
|
(outputs.sequence_error, False,
|
||||||
(outputs.collision, False),
|
outputs.sequence_error_channel, self.sequence_error_channel.status),
|
||||||
(outputs.busy, False)
|
(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):
|
class BlindTransfer(Module):
|
||||||
def __init__(self, idomain="rio", odomain="rsys"):
|
def __init__(self, idomain="rio", odomain="rsys", data_width=0):
|
||||||
self.i = Signal()
|
self.i = Signal()
|
||||||
self.o = Signal()
|
self.o = Signal()
|
||||||
|
if data_width:
|
||||||
|
self.data_i = Signal(data_width)
|
||||||
|
self.data_o = Signal(data_width)
|
||||||
|
|
||||||
|
# # #
|
||||||
|
|
||||||
ps = PulseSynchronizer(idomain, odomain)
|
ps = PulseSynchronizer(idomain, odomain)
|
||||||
ps_ack = PulseSynchronizer(odomain, idomain)
|
ps_ack = PulseSynchronizer(odomain, idomain)
|
||||||
|
@ -47,3 +52,10 @@ class BlindTransfer(Module):
|
||||||
ps_ack.i.eq(ps.o),
|
ps_ack.i.eq(ps.o),
|
||||||
self.o.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 = CSR()
|
||||||
self.reset_phy = CSR()
|
self.reset_phy = CSR()
|
||||||
self.async_error = CSR(3)
|
self.async_error = CSR(3)
|
||||||
|
self.collision_channel = CSRStatus(16)
|
||||||
|
self.busy_channel = CSRStatus(16)
|
||||||
|
self.sequence_error_channel = CSRStatus(16)
|
||||||
|
|
||||||
# Clocking/Reset
|
# Clocking/Reset
|
||||||
# Create rsys, rio and rio_phy domains based on sys and rtio
|
# 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)
|
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
|
# Outputs/Inputs
|
||||||
quash_channels = [n for n, c in enumerate(channels) if isinstance(c, LogChannel)]
|
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.submodules += outputs
|
||||||
self.comb += outputs.coarse_timestamp.eq(coarse_ts)
|
self.comb += outputs.coarse_timestamp.eq(coarse_ts)
|
||||||
self.sync += outputs.minimum_coarse_timestamp.eq(coarse_ts + 16)
|
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",
|
inputs = InputCollector(channels, glbl_fine_ts_width, "async",
|
||||||
quash_channels=quash_channels,
|
quash_channels=quash_channels,
|
||||||
interface=self.cri)
|
interface=self.cri)
|
||||||
self.submodules += inputs
|
self.submodules += inputs
|
||||||
self.comb += inputs.coarse_timestamp.eq(coarse_ts)
|
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