mirror of https://github.com/m-labs/artiq.git
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.language.core import *
|
||||||
from artiq.coredevice.runtime_exceptions import RTIOSequenceError
|
|
||||||
|
|
||||||
|
|
||||||
class LLRTIOOut(AutoContext):
|
class LLRTIOOut(AutoContext):
|
||||||
"""Low-level RTIO output driver.
|
"""Low-level RTIO output driver.
|
||||||
|
|
||||||
Allows setting RTIO outputs at arbitrary times, without time unit
|
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
|
This is meant to be used mostly in drivers; consider using
|
||||||
``RTIOOut`` instead.
|
``RTIOOut`` instead.
|
||||||
|
@ -30,8 +29,6 @@ class LLRTIOOut(AutoContext):
|
||||||
:param value: value to set at the output.
|
:param value: value to set at the output.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if t <= self.previous_timestamp:
|
|
||||||
raise RTIOSequenceError
|
|
||||||
syscall("rtio_set", t, self.channel, value)
|
syscall("rtio_set", t, self.channel, value)
|
||||||
self.previous_timestamp = t
|
self.previous_timestamp = t
|
||||||
|
|
||||||
|
@ -53,6 +50,7 @@ class LLRTIOOut(AutoContext):
|
||||||
"""
|
"""
|
||||||
self.set_value(t, 0)
|
self.set_value(t, 0)
|
||||||
|
|
||||||
|
|
||||||
class _RTIOBase(AutoContext):
|
class _RTIOBase(AutoContext):
|
||||||
parameters = "channel"
|
parameters = "channel"
|
||||||
|
|
||||||
|
@ -66,15 +64,7 @@ class _RTIOBase(AutoContext):
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def _set_value(self, value):
|
def _set_value(self, value):
|
||||||
if time_to_cycles(now()) < self.previous_timestamp:
|
syscall("rtio_set", time_to_cycles(now()), self.channel, value)
|
||||||
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_timestamp = time_to_cycles(now())
|
||||||
self.previous_value = value
|
self.previous_value = value
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,6 @@ _syscalls = {
|
||||||
"gpio_set": "ib:n",
|
"gpio_set": "ib:n",
|
||||||
"rtio_oe": "ib:n",
|
"rtio_oe": "ib:n",
|
||||||
"rtio_set": "Iii:n",
|
"rtio_set": "Iii:n",
|
||||||
"rtio_replace": "Iii:n",
|
|
||||||
"rtio_get_counter": "n:I",
|
"rtio_get_counter": "n:I",
|
||||||
"rtio_get": "iI:I",
|
"rtio_get": "iI:I",
|
||||||
"rtio_pileup_count": "i:i",
|
"rtio_pileup_count": "i:i",
|
||||||
|
|
|
@ -88,17 +88,20 @@ class _RTIOCounter(Module):
|
||||||
class _RTIOBankO(Module):
|
class _RTIOBankO(Module):
|
||||||
def __init__(self, rbus, counter, fine_ts_width, fifo_depth, guard_io_cycles):
|
def __init__(self, rbus, counter, fine_ts_width, fifo_depth, guard_io_cycles):
|
||||||
self.sel = Signal(max=len(rbus))
|
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.timestamp = Signal(counter.width + fine_ts_width)
|
||||||
self.value = Signal(2)
|
self.value = Signal(2)
|
||||||
self.writable = Signal()
|
self.writable = Signal()
|
||||||
self.we = Signal() # maximum throughput 1/2
|
self.we = Signal() # maximum throughput 1/2
|
||||||
self.replace = Signal()
|
self.underflow = Signal() # valid 2 cycles after we
|
||||||
self.underflow = Signal() # valid 2 cycles after we/replace
|
|
||||||
self.underflow_reset = Signal()
|
self.underflow_reset = Signal()
|
||||||
|
self.sequence_error = Signal()
|
||||||
|
self.sequence_error_reset = Signal()
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
signal_underflow = Signal()
|
signal_underflow = Signal()
|
||||||
|
signal_sequence_error = Signal()
|
||||||
fifos = []
|
fifos = []
|
||||||
ev_layout = [("timestamp", counter.width + fine_ts_width),
|
ev_layout = [("timestamp", counter.width + fine_ts_width),
|
||||||
("value", 2)]
|
("value", 2)]
|
||||||
|
@ -110,18 +113,30 @@ class _RTIOBankO(Module):
|
||||||
fifos.append(fifo)
|
fifos.append(fifo)
|
||||||
|
|
||||||
# Buffer
|
# Buffer
|
||||||
buf_valid = Signal()
|
buf_pending = Signal()
|
||||||
buf = Record(ev_layout)
|
buf = Record(ev_layout)
|
||||||
buf_just_written = Signal()
|
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
|
# Buffer read and FIFO write
|
||||||
self.comb += fifo.din.eq(buf)
|
self.comb += fifo.din.eq(buf)
|
||||||
in_guard_time = Signal()
|
in_guard_time = Signal()
|
||||||
self.comb += in_guard_time.eq(
|
self.comb += in_guard_time.eq(
|
||||||
buf.timestamp[fine_ts_width:] < counter.o_value_sys + guard_io_cycles)
|
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 += \
|
self.comb += \
|
||||||
If(buf_valid,
|
If(buf_pending,
|
||||||
If(in_guard_time,
|
If(in_guard_time,
|
||||||
If(buf_just_written,
|
If(buf_just_written,
|
||||||
signal_underflow.eq(1)
|
signal_underflow.eq(1)
|
||||||
|
@ -129,18 +144,19 @@ class _RTIOBankO(Module):
|
||||||
fifo.we.eq(1)
|
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
|
# Buffer write
|
||||||
# Must come after read to handle concurrent read+write properly
|
# Must come after read to handle concurrent read+write properly
|
||||||
self.sync.rsys += [
|
self.sync.rsys += [
|
||||||
buf_just_written.eq(0),
|
buf_just_written.eq(0),
|
||||||
If((self.we | self.replace) & (self.sel == n),
|
If(self.we & (self.sel == n) & ~nop & ~sequence_error,
|
||||||
# Replace operations on empty buffers may happen
|
|
||||||
# on underflows, which will be correctly reported.
|
|
||||||
buf_just_written.eq(1),
|
buf_just_written.eq(1),
|
||||||
buf_valid.eq(1),
|
buf_pending.eq(1),
|
||||||
buf.timestamp.eq(self.timestamp),
|
buf.timestamp.eq(self.timestamp),
|
||||||
buf.value.eq(self.value)
|
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.writable.eq(Array(fifo.writable for fifo in fifos)[self.sel])
|
||||||
self.sync.rsys += [
|
self.sync.rsys += [
|
||||||
If(self.underflow_reset, self.underflow.eq(0)),
|
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_timestamp = CSRStorage(counter_width + fine_ts_width)
|
||||||
self._r_o_value = CSRStorage(2)
|
self._r_o_value = CSRStorage(2)
|
||||||
self._r_o_we = CSR()
|
self._r_o_we = CSR()
|
||||||
self._r_o_replace = CSR()
|
self._r_o_status = CSRStatus(3)
|
||||||
self._r_o_status = CSRStatus(2)
|
|
||||||
self._r_o_underflow_reset = CSR()
|
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_timestamp = CSRStatus(counter_width + fine_ts_width)
|
||||||
self._r_i_value = CSRStatus()
|
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.timestamp.eq(self._r_o_timestamp.storage),
|
||||||
self.bank_o.value.eq(self._r_o_value.storage),
|
self.bank_o.value.eq(self._r_o_value.storage),
|
||||||
self.bank_o.we.eq(self._r_o_we.re),
|
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._r_o_status.status.eq(Cat(~self.bank_o.writable, self.bank_o.underflow)),
|
self.bank_o.underflow,
|
||||||
self.bank_o.underflow_reset.eq(self._r_o_underflow_reset.re)
|
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
|
# Input
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#define RTIO_O_STATUS_FULL 1
|
#define RTIO_O_STATUS_FULL 1
|
||||||
#define RTIO_O_STATUS_UNDERFLOW 2
|
#define RTIO_O_STATUS_UNDERFLOW 2
|
||||||
|
#define RTIO_O_STATUS_SEQUENCE_ERROR 4
|
||||||
#define RTIO_I_STATUS_EMPTY 1
|
#define RTIO_I_STATUS_EMPTY 1
|
||||||
#define RTIO_I_STATUS_OVERFLOW 2
|
#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);
|
rtio_o_underflow_reset_write(1);
|
||||||
exception_raise(EID_RTIO_UNDERFLOW);
|
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);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,7 +59,7 @@ long long int rtio_get(int channel, long long int time_limit)
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
rtio_chan_sel_write(channel);
|
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) {
|
if(rtio_i_status_read() & RTIO_I_STATUS_OVERFLOW) {
|
||||||
rtio_i_overflow_reset_write(1);
|
rtio_i_overflow_reset_write(1);
|
||||||
exception_raise(EID_RTIO_OVERFLOW);
|
exception_raise(EID_RTIO_OVERFLOW);
|
||||||
|
@ -105,11 +98,10 @@ void rtio_fud_sync(void)
|
||||||
void rtio_fud(long long int fud_time)
|
void rtio_fud(long long int fud_time)
|
||||||
{
|
{
|
||||||
long long int fud_end_time;
|
long long int fud_end_time;
|
||||||
|
int status;
|
||||||
|
|
||||||
rtio_chan_sel_write(RTIO_FUD_CHANNEL);
|
rtio_chan_sel_write(RTIO_FUD_CHANNEL);
|
||||||
fud_end_time = fud_time + 3*8;
|
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;
|
previous_fud_end_time = fud_end_time;
|
||||||
|
|
||||||
rtio_o_timestamp_write(fud_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_timestamp_write(fud_end_time);
|
||||||
rtio_o_value_write(0);
|
rtio_o_value_write(0);
|
||||||
rtio_o_we_write(1);
|
rtio_o_we_write(1);
|
||||||
if(rtio_o_status_read() & RTIO_O_STATUS_UNDERFLOW) {
|
status = rtio_o_status_read();
|
||||||
|
if(status) {
|
||||||
|
if(status & RTIO_O_STATUS_UNDERFLOW) {
|
||||||
rtio_o_underflow_reset_write(1);
|
rtio_o_underflow_reset_write(1);
|
||||||
exception_raise(EID_RTIO_UNDERFLOW);
|
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_init(void);
|
||||||
void rtio_oe(int channel, int oe);
|
void rtio_oe(int channel, int oe);
|
||||||
void rtio_set(long long int timestamp, int channel, int value);
|
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_counter(void);
|
||||||
long long int rtio_get(int channel, long long int time_limit);
|
long long int rtio_get(int channel, long long int time_limit);
|
||||||
int rtio_pileup_count(int channel);
|
int rtio_pileup_count(int channel);
|
||||||
|
|
|
@ -13,7 +13,6 @@ static const struct symbol syscalls[] = {
|
||||||
{"gpio_set", gpio_set},
|
{"gpio_set", gpio_set},
|
||||||
{"rtio_oe", rtio_oe},
|
{"rtio_oe", rtio_oe},
|
||||||
{"rtio_set", rtio_set},
|
{"rtio_set", rtio_set},
|
||||||
{"rtio_replace", rtio_replace},
|
|
||||||
{"rtio_get_counter", rtio_get_counter},
|
{"rtio_get_counter", rtio_get_counter},
|
||||||
{"rtio_get", rtio_get},
|
{"rtio_get", rtio_get},
|
||||||
{"rtio_pileup_count", rtio_pileup_count},
|
{"rtio_pileup_count", rtio_pileup_count},
|
||||||
|
|
Loading…
Reference in New Issue