Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: m-labs/artiq
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: c40ae9dbd3c8
Choose a base ref
...
head repository: m-labs/artiq
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 1d34c06d797b
Choose a head ref
  • 2 commits
  • 7 files changed
  • 1 contributor

Commits on Jul 29, 2015

  1. Copy the full SHA
    b548d50 View commit details
  2. Copy the full SHA
    1d34c06 View commit details
Showing with 99 additions and 32 deletions.
  1. +18 −2 artiq/coredevice/runtime_exceptions.py
  2. +31 −10 artiq/gateware/rtio/core.py
  3. +20 −3 artiq/test/coredevice.py
  4. +1 −0 examples/master/ddb.pyon
  5. +3 −2 soc/runtime/exceptions.h
  6. +22 −0 soc/runtime/rtio.c
  7. +4 −15 soc/runtime/rtio.h
20 changes: 18 additions & 2 deletions artiq/coredevice/runtime_exceptions.py
Original file line number Diff line number Diff line change
@@ -41,6 +41,22 @@ def __str__(self):
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()
41 changes: 31 additions & 10 deletions artiq/gateware/rtio/core.py
Original file line number Diff line number Diff line change
@@ -100,6 +100,7 @@ def __init__(self, interface, counter, fifo_depth, guard_io_cycles):

self.underflow = Signal() # valid 1 cycle after we, pulsed
self.sequence_error = Signal()
self.collision_error = Signal()

# # #

@@ -116,13 +117,24 @@ def __init__(self, interface, counter, fifo_depth, guard_io_cycles):
# 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 @@ def __init__(self, interface, counter, fifo_depth, guard_io_cycles):
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 @@ def __init__(self, interface, counter, fifo_depth, guard_io_cycles):
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 @@ def __init__(self, interface, counter, fifo_depth, guard_io_cycles):
# 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 @@ def __init__(self, chan_sel_width,
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 @@ def __init__(self, channels, full_ts_width=63, guard_io_cycles=20):

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,
23 changes: 20 additions & 3 deletions artiq/test/coredevice.py
Original file line number Diff line number Diff line change
@@ -76,7 +76,7 @@ def run(self):
class PulseRate(EnvExperiment):
def build(self):
self.attr_device("core")
self.attr_device("loop_out")
self.attr_device("ttl_out")

def set_pulse_rate(self, pulse_rate):
self.set_result("pulse_rate", pulse_rate)
@@ -87,7 +87,7 @@ def run(self):
while True:
try:
for i in range(1000):
self.loop_out.pulse_mu(dt)
self.ttl_out.pulse_mu(dt)
delay_mu(dt)
except RTIOUnderflow:
dt += 1
@@ -155,6 +155,19 @@ def run(self):
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 @@ def test_pulse_rate(self):

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 @@ def test_sequence_error(self):
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):
1 change: 1 addition & 0 deletions examples/master/ddb.pyon
Original file line number Diff line number Diff line change
@@ -135,6 +135,7 @@

"ttl_inout": "pmt0",
"ttl_out": "ttl0",
"ttl_out_serdes": "ttl0",

"pmt": "pmt0",
"bd_dds": "dds0",
5 changes: 3 additions & 2 deletions soc/runtime/exceptions.h
Original file line number Diff line number Diff line change
@@ -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));
22 changes: 22 additions & 0 deletions soc/runtime/rtio.c
Original file line number Diff line number Diff line change
@@ -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);
}
}
19 changes: 4 additions & 15 deletions soc/runtime/rtio.h
Original file line number Diff line number Diff line change
@@ -2,37 +2,26 @@
#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)
{
int status;

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 */