forked from M-Labs/artiq
1
0
Fork 0

rtio: report channel numbers in asynchronous errors

This commit is contained in:
Sebastien Bourdeauducq 2017-09-29 16:32:57 +08:00
parent 5437f0e3e3
commit 6c049ad40c
6 changed files with 129 additions and 57 deletions

View File

@ -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)?;

View File

@ -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);
}

View File

@ -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();

View File

@ -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)
)

View File

@ -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)

View File

@ -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)
]