forked from M-Labs/artiq
rtio: do housekeeping in gateware
This commit is contained in:
parent
99d530e498
commit
cd587e4f12
@ -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):
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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},
|
||||
|
Loading…
Reference in New Issue
Block a user