rtio: do housekeeping in gateware

This commit is contained in:
Sebastien Bourdeauducq 2014-12-01 17:32:36 +08:00
parent 99d530e498
commit cd587e4f12
6 changed files with 58 additions and 52 deletions

View File

@ -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

View File

@ -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",

View File

@ -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

View File

@ -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);
}
}
} }

View File

@ -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);

View File

@ -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},