drtio: support collision/replace + detect sequence errors at satellite

This commit is contained in:
Sebastien Bourdeauducq 2017-04-06 01:06:56 +08:00
parent 56918fb375
commit 5e3aef45dc
4 changed files with 89 additions and 22 deletions

View File

@ -108,6 +108,9 @@ fn process_errors() {
if errors & 8 != 0 {
error!("write overflow");
}
if errors & 16 != 0 {
error!("write sequence error");
}
}

View File

@ -8,7 +8,7 @@ from artiq.gateware.rtio.cdc import BlindTransfer
class RTErrorsSatellite(Module, AutoCSR):
def __init__(self, rt_packet, ios):
self.protocol_error = CSR(4)
self.protocol_error = CSR(5)
self.rtio_error = CSR(2)
def error_csr(csr, *sources):
@ -23,14 +23,15 @@ class RTErrorsSatellite(Module, AutoCSR):
]
self.comb += csr.w[n].eq(pending)
# The master is normally responsible for avoiding output overflows and
# output underflows.
# The master is normally responsible for avoiding output overflows,
# output underflows, and sequence errors.
# Error reports here are only for diagnosing internal ARTIQ bugs.
error_csr(self.protocol_error,
rt_packet.unknown_packet_type,
rt_packet.packet_truncated,
ios.write_underflow,
ios.write_overflow)
ios.write_overflow,
ios.write_sequence_error)
error_csr(self.rtio_error,
ios.collision,
ios.busy)

View File

@ -11,6 +11,7 @@ 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.write_sequence_error = Signal()
self.collision = Signal()
self.busy = Signal()
@ -46,6 +47,10 @@ class IOS(Module):
fine_ts_width = rtlink.get_fine_ts_width(interface)
assert fine_ts_width <= max_fine_ts_width
we = Signal()
self.comb += we.eq(rt_packet.write_stb
& (rt_packet.write_channel == n))
# latency compensation
if interface.delay:
tsc_comp = Signal.like(self.tsc)
@ -71,30 +76,86 @@ class IOS(Module):
fifo_out.raw_bits().eq(fifo.dout)
]
# Buffer
buf_pending = Signal()
buf = Record(ev_layout)
buf_just_written = Signal()
# Special cases
replace = Signal()
sequence_error = Signal()
collision = Signal()
any_error = Signal()
if interface.enable_replace:
# Note: replace may be asserted at the same time as collision
# when addresses are different. In that case, it is a collision.
self.sync.rio += replace.eq(rt_packet.write_timestamp == buf.timestamp)
# Detect sequence errors on coarse timestamps only
# so that they are mutually exclusive with collision errors.
self.sync.rio += sequence_error.eq(rt_packet.write_timestamp[fine_ts_width:] <
buf.timestamp[fine_ts_width:])
if interface.enable_replace:
if address_width:
different_addresses = rt_packet.write_address != buf.address
else:
different_addresses = 0
if fine_ts_width:
self.sync.rio += collision.eq(
(rt_packet.write_timestamp[fine_ts_width:] == buf.timestamp[fine_ts_width:])
& ((rt_packet.write_timestamp[:fine_ts_width] != buf.timestamp[:fine_ts_width])
|different_addresses))
else:
self.sync.rio += collision.eq(
rt_packet.write_timestamp[fine_ts_width:] == buf.timestamp[fine_ts_width:])
self.comb += any_error.eq(sequence_error | collision)
self.sync.rio += [
If(we & sequence_error, self.write_sequence_error.eq(1)),
If(we & collision, self.collision.eq(1))
]
# Buffer read and FIFO write
self.comb += fifo_in.eq(buf)
in_guard_time = Signal()
self.comb += in_guard_time.eq(
buf.timestamp[fine_ts_width:] < tsc_comp + 4)
self.sync.rio += If(in_guard_time, buf_pending.eq(0))
report_underflow = Signal()
self.comb += \
If(buf_pending,
If(in_guard_time,
If(buf_just_written,
report_underflow.eq(1)
).Else(
fifo.we.eq(1)
)
),
If(we & ~replace & ~any_error,
fifo.we.eq(1)
)
)
self.sync.rio += If(report_underflow, self.write_underflow.eq(1))
# Buffer write
# Must come after read to handle concurrent read+write properly
self.sync.rio += [
buf_just_written.eq(0),
If(we & ~any_error,
buf_just_written.eq(1),
buf_pending.eq(1),
buf.timestamp.eq(
rt_packet.write_timestamp[max_fine_ts_width-fine_ts_width:]),
buf.data.eq(rt_packet.write_data) if data_width else [],
buf.address.eq(rt_packet.write_address) if address_width else [],
),
If(we & ~fifo.writable, self.write_overflow.eq(1))
]
# FIFO level
self.sync.rio += \
If(rt_packet.fifo_space_update &
(rt_packet.fifo_space_channel == n),
rt_packet.fifo_space.eq(channel.ofifo_depth - fifo.level))
# FIFO write
self.comb += fifo.we.eq(rt_packet.write_stb
& (rt_packet.write_channel == n))
self.sync.rio += [
If(fifo.we,
If(rt_packet.write_timestamp[max_fine_ts_width:] < (tsc_comp + 4),
self.write_underflow.eq(1)
),
If(~fifo.writable, self.write_overflow.eq(1))
)
]
if data_width:
self.comb += fifo_in.data.eq(rt_packet.write_data)
if address_width:
self.comb += fifo_in.address.eq(rt_packet.write_address)
self.comb += fifo_in.timestamp.eq(
rt_packet.write_timestamp[max_fine_ts_width-fine_ts_width:])
# FIFO read
self.sync.rio += [
fifo.re.eq(0),

View File

@ -22,6 +22,8 @@ class RTPacketSatellite(Module):
self.fifo_space_update = Signal()
self.fifo_space = Signal(16)
# write parameters are stable one cycle before stb is asserted,
# and when stb is asserted.
self.write_stb = Signal()
self.write_timestamp = Signal(64)
self.write_channel = Signal(16)