forked from M-Labs/artiq
drtio: support collision/replace + detect sequence errors at satellite
This commit is contained in:
parent
56918fb375
commit
5e3aef45dc
|
@ -108,6 +108,9 @@ fn process_errors() {
|
||||||
if errors & 8 != 0 {
|
if errors & 8 != 0 {
|
||||||
error!("write overflow");
|
error!("write overflow");
|
||||||
}
|
}
|
||||||
|
if errors & 16 != 0 {
|
||||||
|
error!("write sequence error");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ from artiq.gateware.rtio.cdc import BlindTransfer
|
||||||
|
|
||||||
class RTErrorsSatellite(Module, AutoCSR):
|
class RTErrorsSatellite(Module, AutoCSR):
|
||||||
def __init__(self, rt_packet, ios):
|
def __init__(self, rt_packet, ios):
|
||||||
self.protocol_error = CSR(4)
|
self.protocol_error = CSR(5)
|
||||||
self.rtio_error = CSR(2)
|
self.rtio_error = CSR(2)
|
||||||
|
|
||||||
def error_csr(csr, *sources):
|
def error_csr(csr, *sources):
|
||||||
|
@ -23,14 +23,15 @@ class RTErrorsSatellite(Module, AutoCSR):
|
||||||
]
|
]
|
||||||
self.comb += csr.w[n].eq(pending)
|
self.comb += csr.w[n].eq(pending)
|
||||||
|
|
||||||
# The master is normally responsible for avoiding output overflows and
|
# The master is normally responsible for avoiding output overflows,
|
||||||
# output underflows.
|
# output underflows, and sequence errors.
|
||||||
# Error reports here are only for diagnosing internal ARTIQ bugs.
|
# Error reports here are only for diagnosing internal ARTIQ bugs.
|
||||||
error_csr(self.protocol_error,
|
error_csr(self.protocol_error,
|
||||||
rt_packet.unknown_packet_type,
|
rt_packet.unknown_packet_type,
|
||||||
rt_packet.packet_truncated,
|
rt_packet.packet_truncated,
|
||||||
ios.write_underflow,
|
ios.write_underflow,
|
||||||
ios.write_overflow)
|
ios.write_overflow,
|
||||||
|
ios.write_sequence_error)
|
||||||
error_csr(self.rtio_error,
|
error_csr(self.rtio_error,
|
||||||
ios.collision,
|
ios.collision,
|
||||||
ios.busy)
|
ios.busy)
|
||||||
|
|
|
@ -11,6 +11,7 @@ class IOS(Module):
|
||||||
def __init__(self, rt_packet, channels, max_fine_ts_width, full_ts_width):
|
def __init__(self, rt_packet, channels, max_fine_ts_width, full_ts_width):
|
||||||
self.write_underflow = Signal()
|
self.write_underflow = Signal()
|
||||||
self.write_overflow = Signal()
|
self.write_overflow = Signal()
|
||||||
|
self.write_sequence_error = Signal()
|
||||||
self.collision = Signal()
|
self.collision = Signal()
|
||||||
self.busy = Signal()
|
self.busy = Signal()
|
||||||
|
|
||||||
|
@ -46,6 +47,10 @@ class IOS(Module):
|
||||||
fine_ts_width = rtlink.get_fine_ts_width(interface)
|
fine_ts_width = rtlink.get_fine_ts_width(interface)
|
||||||
assert fine_ts_width <= max_fine_ts_width
|
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
|
# latency compensation
|
||||||
if interface.delay:
|
if interface.delay:
|
||||||
tsc_comp = Signal.like(self.tsc)
|
tsc_comp = Signal.like(self.tsc)
|
||||||
|
@ -71,30 +76,86 @@ class IOS(Module):
|
||||||
fifo_out.raw_bits().eq(fifo.dout)
|
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
|
# FIFO level
|
||||||
self.sync.rio += \
|
self.sync.rio += \
|
||||||
If(rt_packet.fifo_space_update &
|
If(rt_packet.fifo_space_update &
|
||||||
(rt_packet.fifo_space_channel == n),
|
(rt_packet.fifo_space_channel == n),
|
||||||
rt_packet.fifo_space.eq(channel.ofifo_depth - fifo.level))
|
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
|
# FIFO read
|
||||||
self.sync.rio += [
|
self.sync.rio += [
|
||||||
fifo.re.eq(0),
|
fifo.re.eq(0),
|
||||||
|
|
|
@ -22,6 +22,8 @@ class RTPacketSatellite(Module):
|
||||||
self.fifo_space_update = Signal()
|
self.fifo_space_update = Signal()
|
||||||
self.fifo_space = Signal(16)
|
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_stb = Signal()
|
||||||
self.write_timestamp = Signal(64)
|
self.write_timestamp = Signal(64)
|
||||||
self.write_channel = Signal(16)
|
self.write_channel = Signal(16)
|
||||||
|
|
Loading…
Reference in New Issue