mirror of https://github.com/m-labs/artiq.git
rtio: detect collision errors
This commit is contained in:
parent
b548d50a2f
commit
1d34c06d79
|
@ -41,6 +41,22 @@ class RTIOSequenceError(RuntimeException):
|
|||
return "at {} on channel {}".format(self.p0*self.core.ref_period,
|
||||
self.p1)
|
||||
|
||||
class RTIOCollisionError(RuntimeException):
|
||||
"""Raised when an event is submitted on a given channel with the same
|
||||
coarse timestamp as the previous one but with a different fine timestamp.
|
||||
|
||||
Coarse timestamps correspond to the RTIO system clock (typically around
|
||||
125MHz) whereas fine timestamps correspond to the RTIO SERDES clock
|
||||
(typically around 1GHz).
|
||||
|
||||
The offending event is discarded and the RTIO core keeps operating.
|
||||
"""
|
||||
eid = 5
|
||||
|
||||
def __str__(self):
|
||||
return "at {} on channel {}".format(self.p0*self.core.ref_period,
|
||||
self.p1)
|
||||
|
||||
|
||||
class RTIOOverflow(RuntimeException):
|
||||
"""Raised when at least one event could not be registered into the RTIO
|
||||
|
@ -50,7 +66,7 @@ class RTIOOverflow(RuntimeException):
|
|||
read attempt and discarding some events. Reading can be reattempted after
|
||||
the exception is caught, and events will be partially retrieved.
|
||||
"""
|
||||
eid = 5
|
||||
eid = 6
|
||||
|
||||
def __str__(self):
|
||||
return "on channel {}".format(self.p0)
|
||||
|
@ -60,7 +76,7 @@ class DDSBatchError(RuntimeException):
|
|||
"""Raised when attempting to start a DDS batch while already in a batch,
|
||||
or when too many commands are batched.
|
||||
"""
|
||||
eid = 6
|
||||
eid = 7
|
||||
|
||||
|
||||
exception_map = {e.eid: e for e in globals().values()
|
||||
|
|
|
@ -100,6 +100,7 @@ class _OutputManager(Module):
|
|||
|
||||
self.underflow = Signal() # valid 1 cycle after we, pulsed
|
||||
self.sequence_error = Signal()
|
||||
self.collision_error = Signal()
|
||||
|
||||
# # #
|
||||
|
||||
|
@ -116,13 +117,24 @@ class _OutputManager(Module):
|
|||
# Special cases
|
||||
replace = Signal()
|
||||
sequence_error = Signal()
|
||||
collision_error = Signal()
|
||||
any_error = Signal()
|
||||
nop = Signal()
|
||||
self.sync.rsys += [
|
||||
replace.eq(self.ev.timestamp[fine_ts_width:] \
|
||||
== buf.timestamp[fine_ts_width:]),
|
||||
sequence_error.eq(self.ev.timestamp[fine_ts_width:] \
|
||||
# Note: replace does not perform any RTLink address checks,
|
||||
# i.e. a write to a different address will be silently replaced
|
||||
# as well.
|
||||
replace.eq(self.ev.timestamp == buf.timestamp),
|
||||
# Detect sequence errors on coarse timestamps only
|
||||
# so that they are mutually exclusive with collision errors.
|
||||
sequence_error.eq(self.ev.timestamp[fine_ts_width:]
|
||||
< buf.timestamp[fine_ts_width:])
|
||||
]
|
||||
if fine_ts_width:
|
||||
self.sync.rsys += collision_error.eq(
|
||||
(self.ev.timestamp[fine_ts_width:] == buf.timestamp[fine_ts_width:])
|
||||
& (self.ev.timestamp[:fine_ts_width] != buf.timestamp[:fine_ts_width]))
|
||||
self.comb += any_error.eq(sequence_error | collision_error)
|
||||
if interface.suppress_nop:
|
||||
# disable NOP at reset: do not suppress a first write with all 0s
|
||||
nop_en = Signal(reset=0)
|
||||
|
@ -134,11 +146,14 @@ class _OutputManager(Module):
|
|||
if hasattr(self.ev, a)],
|
||||
default=0)),
|
||||
# buf now contains valid data. enable NOP.
|
||||
If(self.we & ~sequence_error, nop_en.eq(1)),
|
||||
If(self.we & ~any_error, nop_en.eq(1)),
|
||||
# underflows cancel the write. allow it to be retried.
|
||||
If(self.underflow, nop_en.eq(0))
|
||||
]
|
||||
self.comb += self.sequence_error.eq(self.we & sequence_error)
|
||||
self.comb += [
|
||||
self.sequence_error.eq(self.we & sequence_error),
|
||||
self.collision_error.eq(self.we & collision_error)
|
||||
]
|
||||
|
||||
# Buffer read and FIFO write
|
||||
self.comb += fifo.din.eq(buf)
|
||||
|
@ -156,7 +171,7 @@ class _OutputManager(Module):
|
|||
fifo.we.eq(1)
|
||||
)
|
||||
),
|
||||
If(self.we & ~replace & ~nop & ~sequence_error,
|
||||
If(self.we & ~replace & ~nop & ~any_error,
|
||||
fifo.we.eq(1)
|
||||
)
|
||||
)
|
||||
|
@ -165,7 +180,7 @@ class _OutputManager(Module):
|
|||
# Must come after read to handle concurrent read+write properly
|
||||
self.sync.rsys += [
|
||||
buf_just_written.eq(0),
|
||||
If(self.we & ~nop & ~sequence_error,
|
||||
If(self.we & ~nop & ~any_error,
|
||||
buf_just_written.eq(1),
|
||||
buf_pending.eq(1),
|
||||
buf.eq(self.ev)
|
||||
|
@ -286,9 +301,10 @@ class _KernelCSRs(AutoCSR):
|
|||
self.o_address = CSRStorage(address_width)
|
||||
self.o_timestamp = CSRStorage(full_ts_width)
|
||||
self.o_we = CSR()
|
||||
self.o_status = CSRStatus(3)
|
||||
self.o_status = CSRStatus(4)
|
||||
self.o_underflow_reset = CSR()
|
||||
self.o_sequence_error_reset = CSR()
|
||||
self.o_collision_error_reset = CSR()
|
||||
|
||||
if data_width:
|
||||
self.i_data = CSRStatus(data_width)
|
||||
|
@ -369,17 +385,22 @@ class RTIO(Module):
|
|||
|
||||
underflow = Signal()
|
||||
sequence_error = Signal()
|
||||
collision_error = Signal()
|
||||
self.sync.rsys += [
|
||||
If(selected & self.kcsrs.o_underflow_reset.re,
|
||||
underflow.eq(0)),
|
||||
If(selected & self.kcsrs.o_sequence_error_reset.re,
|
||||
sequence_error.eq(0)),
|
||||
If(selected & self.kcsrs.o_collision_error_reset.re,
|
||||
collision_error.eq(0)),
|
||||
If(o_manager.underflow, underflow.eq(1)),
|
||||
If(o_manager.sequence_error, sequence_error.eq(1))
|
||||
If(o_manager.sequence_error, sequence_error.eq(1)),
|
||||
If(o_manager.collision_error, collision_error.eq(1))
|
||||
]
|
||||
o_statuses.append(Cat(~o_manager.writable,
|
||||
underflow,
|
||||
sequence_error))
|
||||
sequence_error,
|
||||
collision_error))
|
||||
|
||||
if channel.interface.i is not None:
|
||||
i_manager = _InputManager(channel.interface.i, self.counter,
|
||||
|
|
|
@ -155,6 +155,19 @@ class SequenceError(EnvExperiment):
|
|||
self.ttl_out.pulse(25*us)
|
||||
|
||||
|
||||
class CollisionError(EnvExperiment):
|
||||
def build(self):
|
||||
self.attr_device("core")
|
||||
self.attr_device("ttl_out_serdes")
|
||||
|
||||
@kernel
|
||||
def run(self):
|
||||
delay(5*ms) # make sure we won't get underflow
|
||||
for i in range(16):
|
||||
self.ttl_out_serdes.pulse_mu(1)
|
||||
delay_mu(1)
|
||||
|
||||
|
||||
class TimeKeepsRunning(EnvExperiment):
|
||||
def build(self):
|
||||
self.attr_device("core")
|
||||
|
@ -211,7 +224,7 @@ class CoredeviceTest(ExperimentCase):
|
|||
|
||||
def test_loopback_count(self):
|
||||
npulses = 2
|
||||
r = self.execute(LoopbackCount, npulses=npulses)
|
||||
self.execute(LoopbackCount, npulses=npulses)
|
||||
count = self.rdb.get("count")
|
||||
self.assertEqual(count, npulses)
|
||||
|
||||
|
@ -223,6 +236,10 @@ class CoredeviceTest(ExperimentCase):
|
|||
with self.assertRaises(runtime_exceptions.RTIOSequenceError):
|
||||
self.execute(SequenceError)
|
||||
|
||||
def test_collision_error(self):
|
||||
with self.assertRaises(runtime_exceptions.RTIOCollisionError):
|
||||
self.execute(CollisionError)
|
||||
|
||||
def test_watchdog(self):
|
||||
# watchdog only works on the device
|
||||
with self.assertRaises(IOError):
|
||||
|
|
|
@ -135,6 +135,7 @@
|
|||
|
||||
"ttl_inout": "pmt0",
|
||||
"ttl_out": "ttl0",
|
||||
"ttl_out_serdes": "ttl0",
|
||||
|
||||
"pmt": "pmt0",
|
||||
"bd_dds": "dds0",
|
||||
|
|
|
@ -7,8 +7,9 @@ enum {
|
|||
EID_RPC_EXCEPTION = 2,
|
||||
EID_RTIO_UNDERFLOW = 3,
|
||||
EID_RTIO_SEQUENCE_ERROR = 4,
|
||||
EID_RTIO_OVERFLOW = 5,
|
||||
EID_DDS_BATCH_ERROR = 6,
|
||||
EID_RTIO_COLLISION_ERROR = 5,
|
||||
EID_RTIO_OVERFLOW = 6,
|
||||
EID_DDS_BATCH_ERROR = 7
|
||||
};
|
||||
|
||||
int exception_setjmp(void *jb) __attribute__((returns_twice));
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <generated/csr.h>
|
||||
|
||||
#include "exceptions.h"
|
||||
#include "rtio.h"
|
||||
|
||||
void rtio_init(void)
|
||||
|
@ -14,3 +15,24 @@ long long int rtio_get_counter(void)
|
|||
rtio_counter_update_write(1);
|
||||
return rtio_counter_read();
|
||||
}
|
||||
|
||||
void rtio_process_exceptional_status(int status, long long int timestamp, int channel)
|
||||
{
|
||||
if(status & RTIO_O_STATUS_FULL)
|
||||
while(rtio_o_status_read() & RTIO_O_STATUS_FULL);
|
||||
if(status & RTIO_O_STATUS_UNDERFLOW) {
|
||||
rtio_o_underflow_reset_write(1);
|
||||
exception_raise_params(EID_RTIO_UNDERFLOW,
|
||||
timestamp, channel, rtio_get_counter());
|
||||
}
|
||||
if(status & RTIO_O_STATUS_SEQUENCE_ERROR) {
|
||||
rtio_o_sequence_error_reset_write(1);
|
||||
exception_raise_params(EID_RTIO_SEQUENCE_ERROR,
|
||||
timestamp, channel, 0);
|
||||
}
|
||||
if(status & RTIO_O_STATUS_COLLISION_ERROR) {
|
||||
rtio_o_collision_error_reset_write(1);
|
||||
exception_raise_params(EID_RTIO_COLLISION_ERROR,
|
||||
timestamp, channel, 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,16 +2,17 @@
|
|||
#define __RTIO_H
|
||||
|
||||
#include <generated/csr.h>
|
||||
#include "exceptions.h"
|
||||
|
||||
#define RTIO_O_STATUS_FULL 1
|
||||
#define RTIO_O_STATUS_UNDERFLOW 2
|
||||
#define RTIO_O_STATUS_SEQUENCE_ERROR 4
|
||||
#define RTIO_O_STATUS_COLLISION_ERROR 8
|
||||
#define RTIO_I_STATUS_EMPTY 1
|
||||
#define RTIO_I_STATUS_OVERFLOW 2
|
||||
|
||||
void rtio_init(void);
|
||||
long long int rtio_get_counter(void);
|
||||
void rtio_process_exceptional_status(int status, long long int timestamp, int channel);
|
||||
|
||||
static inline void rtio_write_and_process_status(long long int timestamp, int channel)
|
||||
{
|
||||
|
@ -19,20 +20,8 @@ static inline void rtio_write_and_process_status(long long int timestamp, int ch
|
|||
|
||||
rtio_o_we_write(1);
|
||||
status = rtio_o_status_read();
|
||||
if(status) {
|
||||
if(status & RTIO_O_STATUS_FULL)
|
||||
while(rtio_o_status_read() & RTIO_O_STATUS_FULL);
|
||||
if(status & RTIO_O_STATUS_UNDERFLOW) {
|
||||
rtio_o_underflow_reset_write(1);
|
||||
exception_raise_params(EID_RTIO_UNDERFLOW,
|
||||
timestamp, channel, rtio_get_counter());
|
||||
}
|
||||
if(status & RTIO_O_STATUS_SEQUENCE_ERROR) {
|
||||
rtio_o_sequence_error_reset_write(1);
|
||||
exception_raise_params(EID_RTIO_SEQUENCE_ERROR,
|
||||
timestamp, channel, 0);
|
||||
}
|
||||
}
|
||||
if(status)
|
||||
rtio_process_exceptional_status(status, timestamp, channel);
|
||||
}
|
||||
|
||||
#endif /* __RTIO_H */
|
||||
|
|
Loading…
Reference in New Issue