diff --git a/artiq/coredevice/rtio.py b/artiq/coredevice/rtio.py index d8dffb511..c95297cd6 100644 --- a/artiq/coredevice/rtio.py +++ b/artiq/coredevice/rtio.py @@ -1,12 +1,11 @@ from artiq.language.core import * -from artiq.coredevice.runtime_exceptions import RTIOSequenceError class LLRTIOOut(AutoContext): """Low-level RTIO output driver. Allows setting RTIO outputs at arbitrary times, without time unit - conversion and without zero-length transition suppression. + conversion. This is meant to be used mostly in drivers; consider using ``RTIOOut`` instead. @@ -30,8 +29,6 @@ class LLRTIOOut(AutoContext): :param value: value to set at the output. """ - if t <= self.previous_timestamp: - raise RTIOSequenceError syscall("rtio_set", t, self.channel, value) self.previous_timestamp = t @@ -53,6 +50,7 @@ class LLRTIOOut(AutoContext): """ self.set_value(t, 0) + class _RTIOBase(AutoContext): parameters = "channel" @@ -66,17 +64,9 @@ class _RTIOBase(AutoContext): @kernel def _set_value(self, value): - if time_to_cycles(now()) < self.previous_timestamp: - raise RTIOSequenceError - if self.previous_value != value: - if self.previous_timestamp == time_to_cycles(now()): - syscall("rtio_replace", time_to_cycles(now()), - self.channel, value) - else: - syscall("rtio_set", time_to_cycles(now()), - self.channel, value) - self.previous_timestamp = time_to_cycles(now()) - self.previous_value = value + syscall("rtio_set", time_to_cycles(now()), self.channel, value) + self.previous_timestamp = time_to_cycles(now()) + self.previous_value = value class RTIOOut(_RTIOBase): diff --git a/artiq/coredevice/runtime.py b/artiq/coredevice/runtime.py index 4e377d796..2e8884022 100644 --- a/artiq/coredevice/runtime.py +++ b/artiq/coredevice/runtime.py @@ -15,7 +15,6 @@ _syscalls = { "gpio_set": "ib:n", "rtio_oe": "ib:n", "rtio_set": "Iii:n", - "rtio_replace": "Iii:n", "rtio_get_counter": "n:I", "rtio_get": "iI:I", "rtio_pileup_count": "i:i", diff --git a/soc/artiqlib/rtio/core.py b/soc/artiqlib/rtio/core.py index f59b2434a..01504047b 100644 --- a/soc/artiqlib/rtio/core.py +++ b/soc/artiqlib/rtio/core.py @@ -88,17 +88,20 @@ class _RTIOCounter(Module): class _RTIOBankO(Module): def __init__(self, rbus, counter, fine_ts_width, fifo_depth, guard_io_cycles): self.sel = Signal(max=len(rbus)) + # timestamp and value must be valid 1 cycle before we self.timestamp = Signal(counter.width + fine_ts_width) self.value = Signal(2) self.writable = Signal() self.we = Signal() # maximum throughput 1/2 - self.replace = Signal() - self.underflow = Signal() # valid 2 cycles after we/replace + self.underflow = Signal() # valid 2 cycles after we self.underflow_reset = Signal() + self.sequence_error = Signal() + self.sequence_error_reset = Signal() # # # signal_underflow = Signal() + signal_sequence_error = Signal() fifos = [] ev_layout = [("timestamp", counter.width + fine_ts_width), ("value", 2)] @@ -110,18 +113,30 @@ class _RTIOBankO(Module): fifos.append(fifo) # Buffer - buf_valid = Signal() + buf_pending = Signal() buf = Record(ev_layout) buf_just_written = Signal() + # Special cases + replace = Signal() + sequence_error = Signal() + nop = Signal() + self.sync.rsys += [ + replace.eq(self.timestamp == buf.timestamp[fine_ts_width:]), + sequence_error.eq(self.timestamp < buf.timestamp[fine_ts_width:]), + nop.eq(self.value == buf.value) + ] + self.comb += If(self.we & (self.sel == n) & sequence_error, + signal_sequence_error.eq(1)) + # Buffer read and FIFO write self.comb += fifo.din.eq(buf) in_guard_time = Signal() self.comb += in_guard_time.eq( buf.timestamp[fine_ts_width:] < counter.o_value_sys + guard_io_cycles) - self.sync.rsys += If(in_guard_time, buf_valid.eq(0)) + self.sync.rsys += If(in_guard_time, buf_pending.eq(0)) self.comb += \ - If(buf_valid, + If(buf_pending, If(in_guard_time, If(buf_just_written, signal_underflow.eq(1) @@ -129,18 +144,19 @@ class _RTIOBankO(Module): fifo.we.eq(1) ) ), - If(self.we & (self.sel == n), fifo.we.eq(1)) + If((self.we & (self.sel == n) + & ~replace & ~nop & ~sequence_error), + fifo.we.eq(1) + ) ) # Buffer write # Must come after read to handle concurrent read+write properly self.sync.rsys += [ buf_just_written.eq(0), - If((self.we | self.replace) & (self.sel == n), - # Replace operations on empty buffers may happen - # on underflows, which will be correctly reported. + If(self.we & (self.sel == n) & ~nop & ~sequence_error, buf_just_written.eq(1), - buf_valid.eq(1), + buf_pending.eq(1), buf.timestamp.eq(self.timestamp), buf.value.eq(self.value) ) @@ -174,7 +190,9 @@ class _RTIOBankO(Module): self.writable.eq(Array(fifo.writable for fifo in fifos)[self.sel]) self.sync.rsys += [ If(self.underflow_reset, self.underflow.eq(0)), - If(signal_underflow, self.underflow.eq(1)) + If(self.sequence_error_reset, self.sequence_error.eq(0)), + If(signal_underflow, self.underflow.eq(1)), + If(signal_sequence_error, self.sequence_error.eq(1)) ] @@ -298,9 +316,9 @@ class RTIO(Module, AutoCSR): self._r_o_timestamp = CSRStorage(counter_width + fine_ts_width) self._r_o_value = CSRStorage(2) self._r_o_we = CSR() - self._r_o_replace = CSR() - self._r_o_status = CSRStatus(2) + self._r_o_status = CSRStatus(3) self._r_o_underflow_reset = CSR() + self._r_o_sequence_error_reset = CSR() self._r_i_timestamp = CSRStatus(counter_width + fine_ts_width) self._r_i_value = CSRStatus() @@ -350,9 +368,11 @@ class RTIO(Module, AutoCSR): self.bank_o.timestamp.eq(self._r_o_timestamp.storage), self.bank_o.value.eq(self._r_o_value.storage), self.bank_o.we.eq(self._r_o_we.re), - self.bank_o.replace.eq(self._r_o_replace.re), - self._r_o_status.status.eq(Cat(~self.bank_o.writable, self.bank_o.underflow)), - self.bank_o.underflow_reset.eq(self._r_o_underflow_reset.re) + self._r_o_status.status.eq(Cat(~self.bank_o.writable, + self.bank_o.underflow, + self.bank_o.sequence_error)), + self.bank_o.underflow_reset.eq(self._r_o_underflow_reset.re), + self.bank_o.sequence_error_reset.eq(self._r_o_sequence_error_reset.re) ] # Input diff --git a/soc/runtime/rtio.c b/soc/runtime/rtio.c index f297196bf..f09ce03ce 100644 --- a/soc/runtime/rtio.c +++ b/soc/runtime/rtio.c @@ -5,6 +5,7 @@ #define RTIO_O_STATUS_FULL 1 #define RTIO_O_STATUS_UNDERFLOW 2 +#define RTIO_O_STATUS_SEQUENCE_ERROR 4 #define RTIO_I_STATUS_EMPTY 1 #define RTIO_I_STATUS_OVERFLOW 2 @@ -39,18 +40,10 @@ void rtio_set(long long int timestamp, int channel, int value) rtio_o_underflow_reset_write(1); exception_raise(EID_RTIO_UNDERFLOW); } - } -} - -void rtio_replace(long long int timestamp, int channel, int value) -{ - rtio_chan_sel_write(channel); - rtio_o_timestamp_write(timestamp); - rtio_o_value_write(value); - rtio_o_replace_write(1); - if(rtio_o_status_read() & RTIO_O_STATUS_UNDERFLOW) { - rtio_o_underflow_reset_write(1); - exception_raise(EID_RTIO_UNDERFLOW); + if(status & RTIO_O_STATUS_SEQUENCE_ERROR) { + rtio_o_sequence_error_reset_write(1); + exception_raise(EID_RTIO_SEQUENCE_ERROR); + } } } @@ -66,7 +59,7 @@ long long int rtio_get(int channel, long long int time_limit) int status; rtio_chan_sel_write(channel); - while(status = rtio_i_status_read()) { + while((status = rtio_i_status_read())) { if(rtio_i_status_read() & RTIO_I_STATUS_OVERFLOW) { rtio_i_overflow_reset_write(1); exception_raise(EID_RTIO_OVERFLOW); @@ -105,11 +98,10 @@ void rtio_fud_sync(void) void rtio_fud(long long int fud_time) { long long int fud_end_time; + int status; rtio_chan_sel_write(RTIO_FUD_CHANNEL); fud_end_time = fud_time + 3*8; - if(fud_time < previous_fud_end_time) - exception_raise(EID_RTIO_SEQUENCE_ERROR); previous_fud_end_time = fud_end_time; rtio_o_timestamp_write(fud_time); @@ -118,8 +110,15 @@ void rtio_fud(long long int fud_time) rtio_o_timestamp_write(fud_end_time); rtio_o_value_write(0); rtio_o_we_write(1); - if(rtio_o_status_read() & RTIO_O_STATUS_UNDERFLOW) { - rtio_o_underflow_reset_write(1); - exception_raise(EID_RTIO_UNDERFLOW); + status = rtio_o_status_read(); + if(status) { + if(status & RTIO_O_STATUS_UNDERFLOW) { + rtio_o_underflow_reset_write(1); + exception_raise(EID_RTIO_UNDERFLOW); + } + if(status & RTIO_O_STATUS_SEQUENCE_ERROR) { + rtio_o_sequence_error_reset_write(1); + exception_raise(EID_RTIO_SEQUENCE_ERROR); + } } } diff --git a/soc/runtime/rtio.h b/soc/runtime/rtio.h index 6ed35bb55..072236048 100644 --- a/soc/runtime/rtio.h +++ b/soc/runtime/rtio.h @@ -4,7 +4,6 @@ void rtio_init(void); void rtio_oe(int channel, int oe); void rtio_set(long long int timestamp, int channel, int value); -void rtio_replace(long long int timestamp, int channel, int value); long long int rtio_get_counter(void); long long int rtio_get(int channel, long long int time_limit); int rtio_pileup_count(int channel); diff --git a/soc/runtime/services.c b/soc/runtime/services.c index f07f8eadb..064bcc102 100644 --- a/soc/runtime/services.c +++ b/soc/runtime/services.c @@ -13,7 +13,6 @@ static const struct symbol syscalls[] = { {"gpio_set", gpio_set}, {"rtio_oe", rtio_oe}, {"rtio_set", rtio_set}, - {"rtio_replace", rtio_replace}, {"rtio_get_counter", rtio_get_counter}, {"rtio_get", rtio_get}, {"rtio_pileup_count", rtio_pileup_count},