From a36c51eb83ea29599531ac9a14c264325c078bd1 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 8 May 2015 14:44:39 +0800 Subject: [PATCH] DDS over RTIO (batch mode not supported yet) --- artiq/coredevice/dds.py | 95 +++++--------------------- artiq/coredevice/runtime.py | 4 +- artiq/gateware/ad9858.py | 30 ++++---- artiq/gateware/rtio/core.py | 4 ++ artiq/gateware/rtio/phy/wishbone.py | 12 ++-- examples/master/ddb.pyon | 6 +- examples/master/repository/dds_test.py | 14 +++- soc/runtime/Makefile | 4 +- soc/runtime/bridge.c | 34 +++++++-- soc/runtime/dds.c | 86 +++++++++++------------ soc/runtime/dds.h | 21 +++--- soc/runtime/gen_service_table.py | 4 +- soc/runtime/ksupport.c | 1 - soc/runtime/rtio.c | 79 ++------------------- soc/runtime/rtio.h | 37 ++++++++-- soc/targets/artiq_kc705.py | 20 +++--- soc/targets/artiq_pipistrello.py | 21 +++--- 17 files changed, 201 insertions(+), 271 deletions(-) diff --git a/artiq/coredevice/dds.py b/artiq/coredevice/dds.py index f9af72eb4..6de0fbb0a 100644 --- a/artiq/coredevice/dds.py +++ b/artiq/coredevice/dds.py @@ -1,10 +1,10 @@ from artiq.language.core import * from artiq.language.db import * from artiq.language.units import * -from artiq.coredevice import ttl PHASE_MODE_DEFAULT = -1 +# keep in sync with dds.h PHASE_MODE_CONTINUOUS = 0 PHASE_MODE_ABSOLUTE = 1 PHASE_MODE_TRACKING = 2 @@ -13,34 +13,24 @@ PHASE_MODE_TRACKING = 2 class DDS(AutoDB): """Core device Direct Digital Synthesis (DDS) driver. - Controls DDS devices managed directly by the core device's runtime. It also - uses a RTIO TTL channel (through :class:`artiq.coredevice.ttl.TTLOut`) to - control a RF switch that gates the output of the DDS device. + Controls DDS devices managed directly by the core device's runtime. :param dds_sysclk: DDS system frequency, used for computing the frequency tuning words. - :param reg_channel: channel number of the DDS device to control. - :param rtio_switch: RTIO channel number of the RF switch associated with - the DDS device. - + :param channel: channel number of the DDS device to control. """ class DBKeys: core = Device() - dds_sysclk = Parameter(1*GHz) - reg_channel = Argument() - rtio_switch = Argument() + dds_sysclk = Argument(1*GHz) + channel = Argument() def build(self): - self.previous_on = False - self.previous_frequency = 0*MHz - self.set_phase_mode(PHASE_MODE_CONTINUOUS) - self.sw = ttl.TTLOut(core=self.core, channel=self.rtio_switch) + self.phase_mode = PHASE_MODE_CONTINUOUS @portable def frequency_to_ftw(self, frequency): """Returns the frequency tuning word corresponding to the given frequency. - """ return round(2**32*frequency/self.dds_sysclk) @@ -48,10 +38,14 @@ class DDS(AutoDB): def ftw_to_frequency(self, ftw): """Returns the frequency corresponding to the given frequency tuning word. - """ return ftw*self.dds_sysclk/2**32 + @kernel + def init(self): + """Resets and initializes the DDS.""" + syscall("dds_init", time_to_cycles(now()), self.channel) + @kernel def set_phase_mode(self, phase_mode): """Sets the phase mode of the DDS channel. Supported phase modes are: @@ -69,74 +63,21 @@ class DDS(AutoDB): accumulator is set to the value it would have if the DDS had been running at the specified frequency since the start of the experiment. - """ self.phase_mode = phase_mode - syscall("dds_phase_clear_en", self.reg_channel, - self.phase_mode != PHASE_MODE_CONTINUOUS) @kernel - def on(self, frequency, phase_mode=PHASE_MODE_DEFAULT, phase_offset=0): - """Sets the DDS channel to the specified frequency and turns it on. - - If the DDS channel was already on, a real-time frequency and phase - update is performed. + def set(self, frequency, phase_mode=PHASE_MODE_DEFAULT, phase_offset=0): + """Sets the DDS channel to the specified frequency and phase. :param frequency: frequency to generate. :param phase_mode: if specified, overrides the default phase mode set by ``set_phase_mode`` for this call. :param phase_offset: adds an offset, in turns, to the phase. - """ - if phase_mode != PHASE_MODE_DEFAULT: - old_phase_mode = self.phase_mode - self.set_phase_mode(phase_mode) + if phase_mode == PHASE_MODE_DEFAULT: + phase_mode = self.phase_mode - if self.previous_frequency != frequency: - merge = self.sw.o_previous_timestamp == time_to_cycles(now()) - if not merge: - self.sw.sync() - # Channel is already on: - # Precise timing of frequency change is required. - # Channel is off: - # Use soft timing on FUD to prevent conflicts when reprogramming - # several channels that need to be turned on at the same time. - rt_fud = merge or self.previous_on - if self.phase_mode != PHASE_MODE_CONTINUOUS: - sysclk_per_microcycle = int(self.dds_sysclk* - self.core.ref_period) - else: - sysclk_per_microcycle = 0 - syscall("dds_program", time_to_cycles(now()), self.reg_channel, - self.frequency_to_ftw(frequency), int(phase_offset*2**14), - sysclk_per_microcycle, - rt_fud, self.phase_mode == PHASE_MODE_TRACKING) - self.previous_frequency = frequency - self.sw.on() - self.previous_on = True - - if phase_mode != PHASE_MODE_DEFAULT: - self.set_phase_mode(old_phase_mode) - - @kernel - def off(self): - """Turns the DDS channel off. - - """ - self.sw.off() - self.previous_on = False - - @kernel - def pulse(self, frequency, duration, - phase_mode=PHASE_MODE_DEFAULT, phase_offset=0): - """Pulses the DDS channel for the specified duration at the specified - frequency. - - See ``on`` for a description of the parameters. - - Equivalent to a ``on``, ``delay``, ``off`` sequence. - - """ - self.on(frequency, phase_mode, phase_offset) - delay(duration) - self.off() + syscall("dds_set", time_to_cycles(now()), self.channel, + self.frequency_to_ftw(frequency), round(phase_offset*2**14), + self.phase_mode) diff --git a/artiq/coredevice/runtime.py b/artiq/coredevice/runtime.py index 3d84decc8..fb6bf7f1d 100644 --- a/artiq/coredevice/runtime.py +++ b/artiq/coredevice/runtime.py @@ -21,8 +21,8 @@ _syscalls = { "rtio_set_sensitivity": "Iii:n", "rtio_get_counter": "n:I", "rtio_get": "iI:I", - "dds_phase_clear_en": "ib:n", - "dds_program": "Iiiiibb:n", + "dds_init": "Ii:n", + "dds_set": "Iiiii:n", } diff --git a/artiq/gateware/ad9858.py b/artiq/gateware/ad9858.py index 938d13d73..26c790672 100644 --- a/artiq/gateware/ad9858.py +++ b/artiq/gateware/ad9858.py @@ -36,8 +36,8 @@ class AD9858(Module): Read timing: Address is set one cycle before assertion of rd_n. - rd_n is asserted for 3 cycles. - Data is sampled 2 cycles into the assertion of rd_n. + rd_n is asserted for read_wait_cycles, data is sampled at the end. + rd_n is deasserted and data bus is not driven again before hiz_wait_cycles. Design: All IO pads are registered. @@ -48,7 +48,7 @@ class AD9858(Module): Round-trip addr A setup (> RX, RD, D to Z), RD prop, D valid (< D valid), D prop is ~15 + 10 + 20 + 10 = 55ns """ - def __init__(self, pads, drive_fud=False, + def __init__(self, pads, read_wait_cycles=10, hiz_wait_cycles=3, bus=None): if bus is None: @@ -84,9 +84,8 @@ class AD9858(Module): bus.dat_r.eq(dr) ) - if drive_fud: - fud = Signal() - self.sync += pads.fud_n.eq(~fud) + fud = Signal() + self.sync += pads.fud_n.eq(~fud) pads.wr_n.reset = 1 pads.rd_n.reset = 1 @@ -106,7 +105,7 @@ class AD9858(Module): If(bus.adr[0], NextState("GPIO") ).Else( - NextState("FUD") if drive_fud else None + NextState("FUD") ) ).Else( If(bus.we, @@ -141,19 +140,18 @@ class AD9858(Module): ) fsm.act("WAIT_HIZ", rx.eq(1), - # For some reason, AD9858 has a address hold time to RD inactive. + # For some reason, AD9858 has an address hold time to RD inactive. hold_address.eq(1), self.hiz_timer.wait.eq(1), If(self.hiz_timer.done, NextState("IDLE")) ) - if drive_fud: - fsm.act("FUD", - # 4ns FUD setup to SYNCLK - # 0ns FUD hold to SYNCLK - fud.eq(1), - bus.ack.eq(1), - NextState("IDLE") - ) + fsm.act("FUD", + # 4ns FUD setup to SYNCLK + # 0ns FUD hold to SYNCLK + fud.eq(1), + bus.ack.eq(1), + NextState("IDLE") + ) fsm.act("GPIO", bus.ack.eq(1), bus_r_gpio.eq(1), diff --git a/artiq/gateware/rtio/core.py b/artiq/gateware/rtio/core.py index 946ded34d..cfa7ea01e 100644 --- a/artiq/gateware/rtio/core.py +++ b/artiq/gateware/rtio/core.py @@ -291,6 +291,10 @@ class RTIO(Module): fine_ts_width = max(rtlink.get_fine_ts_width(c.interface) for c in channels) + self.data_width = data_width + self.address_width = address_width + self.fine_ts_width = fine_ts_width + # CSRs self.kcsrs = _KernelCSRs(bits_for(len(channels)-1), data_width, address_width, diff --git a/artiq/gateware/rtio/phy/wishbone.py b/artiq/gateware/rtio/phy/wishbone.py index 773dcb9bf..b1184ca43 100644 --- a/artiq/gateware/rtio/phy/wishbone.py +++ b/artiq/gateware/rtio/phy/wishbone.py @@ -1,10 +1,14 @@ from migen.fhdl.std import * +from migen.bus import wishbone from artiq.gateware.rtio import rtlink class RT2WB(Module): - def __init__(self, wb, address_width): + def __init__(self, address_width, wb=None): + if wb is None: + wb = wishbone.Interface() + self.wb = wb self.rtlink = rtlink.Interface( rtlink.OInterface( flen(wb.dat_w), @@ -18,7 +22,7 @@ class RT2WB(Module): # # # active = Signal() - self.sync.rio_phy += [ + self.sync.rio += [ If(self.rtlink.o.stb, active.eq(1), wb.adr.eq(self.rtlink.o.address[:address_width]), @@ -35,6 +39,6 @@ class RT2WB(Module): wb.cyc.eq(active), wb.stb.eq(active), - self.i.stb.eq(wb.ack & ~wb.we), - self.i.data.eq(wb.dat_r) + self.rtlink.i.stb.eq(wb.ack & ~wb.we), + self.rtlink.i.data.eq(wb.dat_r) ] diff --git a/examples/master/ddb.pyon b/examples/master/ddb.pyon index a33fc8bec..618341244 100644 --- a/examples/master/ddb.pyon +++ b/examples/master/ddb.pyon @@ -54,19 +54,19 @@ "type": "local", "module": "artiq.coredevice.dds", "class": "DDS", - "arguments": {"reg_channel": 0, "rtio_switch": 5} + "arguments": {"channel": 0} }, "dds1": { "type": "local", "module": "artiq.coredevice.dds", "class": "DDS", - "arguments": {"reg_channel": 1, "rtio_switch": 6} + "arguments": {"channel": 1} }, "dds2": { "type": "local", "module": "artiq.coredevice.dds", "class": "DDS", - "arguments": {"reg_channel": 2, "rtio_switch": 7} + "arguments": {"channel": 2} }, "qc_q1_0": { diff --git a/examples/master/repository/dds_test.py b/examples/master/repository/dds_test.py index 7a18d6620..520faa5ce 100644 --- a/examples/master/repository/dds_test.py +++ b/examples/master/repository/dds_test.py @@ -9,10 +9,17 @@ class DDSTest(Experiment, AutoDB): dds0 = Device() dds1 = Device() dds2 = Device() + ttl0 = Device() + ttl1 = Device() + ttl2 = Device() led = Device() @kernel def run(self): + # with dds_batch: + # self.dds1.set(120*MHz) + # self.dds2.set(200*MHz) + for i in range(10000): if i & 0x200: self.led.on() @@ -20,7 +27,8 @@ class DDSTest(Experiment, AutoDB): self.led.off() with parallel: with sequential: - self.dds0.pulse(100*MHz + 4*i*kHz, 500*us) - self.dds1.pulse(120*MHz, 500*us) - self.dds2.pulse(200*MHz, 100*us) + self.dds0.set(100*MHz + 4*i*kHz) + self.ttl0.pulse(500*us) + self.ttl1.pulse(500*us) + self.ttl2.pulse(100*us) self.led.off() diff --git a/soc/runtime/Makefile b/soc/runtime/Makefile index a27e651f8..ba75870fc 100644 --- a/soc/runtime/Makefile +++ b/soc/runtime/Makefile @@ -34,7 +34,9 @@ ksupport.elf: $(OBJECTS_KSUPPORT) -T ksupport.ld \ -N -o $@ \ $(MSCDIR)/software/libbase/crt0-$(CPU).o \ - $^ + $^ \ + -L$(MSCDIR)/software/libcompiler-rt \ + -lcompiler-rt @chmod -x $@ ksupport_data.o: ksupport.bin diff --git a/soc/runtime/bridge.c b/soc/runtime/bridge.c index 68da7fa64..d467a9a22 100644 --- a/soc/runtime/bridge.c +++ b/soc/runtime/bridge.c @@ -4,6 +4,26 @@ #include "dds.h" #include "bridge.h" +static void dds_write(int addr, int data) +{ + rtio_chan_sel_write(RTIO_DDS_CHANNEL); + rtio_o_address_write(addr); + rtio_o_data_write(data); + rtio_o_timestamp_write(rtio_get_counter() + 8000); + rtio_o_we_write(1); +} + +static int dds_read(int addr) +{ + int r; + + dds_write(addr | 128, 0); + while(rtio_i_status_read() & RTIO_I_STATUS_EMPTY); + r = rtio_i_data_read(); + rtio_i_re_write(1); + return r; +} + static void send_ready(void) { struct msg_base msg; @@ -41,16 +61,16 @@ void bridge_main(void) struct msg_brg_dds_sel *msg; msg = (struct msg_brg_dds_sel *)umsg; - DDS_WRITE(DDS_GPIO, msg->channel); + dds_write(DDS_GPIO, msg->channel); mailbox_acknowledge(); break; } case MESSAGE_TYPE_BRG_DDS_RESET: { unsigned int g; - g = DDS_READ(DDS_GPIO); - DDS_WRITE(DDS_GPIO, g | (1 << 7)); - DDS_WRITE(DDS_GPIO, g); + g = dds_read(DDS_GPIO); + dds_write(DDS_GPIO, g | (1 << 7)); + dds_write(DDS_GPIO, g); mailbox_acknowledge(); break; @@ -61,7 +81,7 @@ void bridge_main(void) msg = (struct msg_brg_dds_read_request *)umsg; rmsg.type = MESSAGE_TYPE_BRG_DDS_READ_REPLY; - rmsg.data = DDS_READ(msg->address); + rmsg.data = dds_read(msg->address); mailbox_send_and_wait(&rmsg); break; } @@ -69,12 +89,12 @@ void bridge_main(void) struct msg_brg_dds_write *msg; msg = (struct msg_brg_dds_write *)umsg; - DDS_WRITE(msg->address, msg->data); + dds_write(msg->address, msg->data); mailbox_acknowledge(); break; } case MESSAGE_TYPE_BRG_DDS_FUD: - rtio_fud(rtio_get_counter() + 8000); + dds_write(DDS_FUD, 0); mailbox_acknowledge(); break; default: diff --git a/soc/runtime/dds.c b/soc/runtime/dds.c index 1d4bf5438..87aa8464c 100644 --- a/soc/runtime/dds.c +++ b/soc/runtime/dds.c @@ -4,64 +4,66 @@ #include "rtio.h" #include "dds.h" -void dds_init(void) -{ - int i; +#define DURATION_WRITE 5 +#define DURATION_PROGRAM (8*DURATION_WRITE) - for(i=0;i<8;i++) { - DDS_WRITE(DDS_GPIO, i); - DDS_WRITE(DDS_GPIO, i | (1 << 7)); - DDS_WRITE(DDS_GPIO, i); - dds_phase_clear_en(i, 0); - } -} +#define DDS_WRITE(addr, data) do { \ + rtio_o_address_write(addr); \ + rtio_o_data_write(data); \ + rtio_o_timestamp_write(now); \ + rtio_write_and_process_status(now, RTIO_DDS_CHANNEL); \ + now += DURATION_WRITE; \ + } while(0) -void dds_phase_clear_en(int channel, int phase_clear_en) +void dds_init(long long int timestamp, int channel) { + long long int now; + + rtio_chan_sel_write(RTIO_DDS_CHANNEL); + + now = timestamp - 7*DURATION_WRITE; + + DDS_WRITE(DDS_GPIO, channel); + DDS_WRITE(DDS_GPIO, channel | (1 << 7)); + DDS_WRITE(DDS_GPIO, channel); + DDS_WRITE(0x00, 0x78); DDS_WRITE(0x01, 0x00); - DDS_WRITE(0x02, phase_clear_en ? 0x40 : 0x00); + DDS_WRITE(0x02, 0x00); DDS_WRITE(0x03, 0x00); } -/* - * DDS phase modes: - * - continuous: Set sysclk_per_microcycle=0 to disable POW alteration. - * phase_tracking is ignored, set to 0. - * Disable phase accumulator clearing prior to programming. - * - absolute: Set sysclk_per_microcycle to its nominal value - * and phase_tracking=0. - * Enable phase accumulator clearing prior to programming. - * - tracking: Set sysclk_per_microcycle to its nominal value - * and phase_tracking=1. -* Enable phase accumulator clearing prior to programming. - */ -void dds_program(long long int timestamp, int channel, - unsigned int ftw, unsigned int pow, unsigned int sysclk_per_microcycle, - int rt_fud, int phase_tracking) +static void dds_set_one(long long int now, long long int timestamp, int channel, + unsigned int ftw, unsigned int pow, int phase_mode) { - long long int fud_time; - unsigned int phase_time_offset; - - rtio_fud_sync(); DDS_WRITE(DDS_GPIO, channel); + if(phase_mode == PHASE_MODE_CONTINUOUS) + /* Do not clear phase accumulator on FUD */ + DDS_WRITE(0x02, 0x00); + else + /* Clear phase accumulator on FUD */ + DDS_WRITE(0x02, 0x40); + DDS_WRITE(DDS_FTW0, ftw & 0xff); DDS_WRITE(DDS_FTW1, (ftw >> 8) & 0xff); DDS_WRITE(DDS_FTW2, (ftw >> 16) & 0xff); DDS_WRITE(DDS_FTW3, (ftw >> 24) & 0xff); - phase_time_offset = phase_tracking ? timestamp : 0; - if(rt_fud) - fud_time = timestamp; - else { - fud_time = rtio_get_counter() + 8000; - /* POW is mod 2**14, so wraparound on negative values is OK */ - phase_time_offset -= timestamp - fud_time; - } - pow += phase_time_offset*ftw*sysclk_per_microcycle >> 18; + if(phase_mode == PHASE_MODE_TRACKING) + /* We assume that the RTIO clock is DDS SYNCLK */ + pow += (timestamp >> RTIO_FINE_TS_WIDTH)*ftw >> 18; DDS_WRITE(DDS_POW0, pow & 0xff); DDS_WRITE(DDS_POW1, (pow >> 8) & 0x3f); - - rtio_fud(fud_time); +} + +void dds_set(long long int timestamp, int channel, + unsigned int ftw, unsigned int pow, int phase_mode) +{ + long long int now; + + rtio_chan_sel_write(RTIO_DDS_CHANNEL); + dds_set_one(timestamp - DURATION_PROGRAM, timestamp, channel, ftw, pow, phase_mode); + now = timestamp; + DDS_WRITE(DDS_FUD, 0); } diff --git a/soc/runtime/dds.h b/soc/runtime/dds.h index fdbd8103f..c38935277 100644 --- a/soc/runtime/dds.h +++ b/soc/runtime/dds.h @@ -4,24 +4,23 @@ #include #include -#define DDS_READ(addr) \ - MMPTR(DDS_BASE + (addr)*4) - -#define DDS_WRITE(addr, data) \ - MMPTR(DDS_BASE + (addr)*4) = data - #define DDS_FTW0 0x0a #define DDS_FTW1 0x0b #define DDS_FTW2 0x0c #define DDS_FTW3 0x0d #define DDS_POW0 0x0e #define DDS_POW1 0x0f +#define DDS_FUD 0x40 #define DDS_GPIO 0x41 -void dds_init(void); -void dds_phase_clear_en(int channel, int phase_clear_en); -void dds_program(long long int timestamp, int channel, - unsigned int ftw, unsigned int pow, unsigned int sysclk_per_microcycle, - int rt_fud, int phase_tracking); +enum { + PHASE_MODE_CONTINUOUS = 0, + PHASE_MODE_ABSOLUTE = 1, + PHASE_MODE_TRACKING = 2 +}; + +void dds_init(long long int timestamp, int channel); +void dds_set(long long int timestamp, int channel, + unsigned int ftw, unsigned int pow, int phase_mode); #endif /* __DDS_H */ diff --git a/soc/runtime/gen_service_table.py b/soc/runtime/gen_service_table.py index c4731be8f..a58236207 100755 --- a/soc/runtime/gen_service_table.py +++ b/soc/runtime/gen_service_table.py @@ -17,8 +17,8 @@ services = [ ("rtio_set_sensitivity", "rtio_set_sensitivity"), ("rtio_get_counter", "rtio_get_counter"), ("rtio_get", "rtio_get"), - ("dds_phase_clear_en", "dds_phase_clear_en"), - ("dds_program", "dds_program"), + ("dds_init", "dds_init"), + ("dds_set", "dds_set"), ]), ("eh", [ ("setjmp", "exception_setjmp"), diff --git a/soc/runtime/ksupport.c b/soc/runtime/ksupport.c index 964391341..a2eb090c6 100644 --- a/soc/runtime/ksupport.c +++ b/soc/runtime/ksupport.c @@ -78,7 +78,6 @@ long long int now_init(void) mailbox_acknowledge(); if(now < 0) { - dds_init(); rtio_init(); now = 125000; } diff --git a/soc/runtime/rtio.c b/soc/runtime/rtio.c index e1a2e9610..8fdcd2759 100644 --- a/soc/runtime/rtio.c +++ b/soc/runtime/rtio.c @@ -3,42 +3,17 @@ #include "exceptions.h" #include "rtio.h" -#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 - -long long int previous_fud_end_time; - void rtio_init(void) { - previous_fud_end_time = 0; rtio_reset_write(1); rtio_reset_write(0); rtio_reset_phy_write(0); } -static void write_and_process_status(long long int timestamp, int channel) +long long int rtio_get_counter(void) { - 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); - } - } + rtio_counter_update_write(1); + return rtio_counter_read(); } void rtio_set_o(long long int timestamp, int channel, int value) @@ -47,7 +22,7 @@ void rtio_set_o(long long int timestamp, int channel, int value) rtio_o_timestamp_write(timestamp); rtio_o_address_write(0); rtio_o_data_write(value); - write_and_process_status(timestamp, channel); + rtio_write_and_process_status(timestamp, channel); } void rtio_set_oe(long long int timestamp, int channel, int oe) @@ -56,7 +31,7 @@ void rtio_set_oe(long long int timestamp, int channel, int oe) rtio_o_timestamp_write(timestamp); rtio_o_address_write(1); rtio_o_data_write(oe); - write_and_process_status(timestamp, channel); + rtio_write_and_process_status(timestamp, channel); } void rtio_set_sensitivity(long long int timestamp, int channel, int sensitivity) @@ -65,13 +40,7 @@ void rtio_set_sensitivity(long long int timestamp, int channel, int sensitivity) rtio_o_timestamp_write(timestamp); rtio_o_address_write(2); rtio_o_data_write(sensitivity); - write_and_process_status(timestamp, channel); -} - -long long int rtio_get_counter(void) -{ - rtio_counter_update_write(1); - return rtio_counter_read(); + rtio_write_and_process_status(timestamp, channel); } long long int rtio_get(int channel, long long int time_limit) @@ -99,39 +68,3 @@ long long int rtio_get(int channel, long long int time_limit) rtio_i_re_write(1); return r; } - -void rtio_fud_sync(void) -{ - while(rtio_get_counter() < previous_fud_end_time); -} - -void rtio_fud(long long int fud_time) -{ - long long int fud_end_time; - int status; - - rtio_chan_sel_write(RTIO_FUD_CHANNEL); - rtio_o_address_write(0); - fud_end_time = fud_time + 3*8; - previous_fud_end_time = fud_end_time; - - rtio_o_timestamp_write(fud_time); - rtio_o_data_write(1); - rtio_o_we_write(1); - rtio_o_timestamp_write(fud_end_time); - rtio_o_data_write(0); - rtio_o_we_write(1); - status = rtio_o_status_read(); - if(status) { - if(status & RTIO_O_STATUS_UNDERFLOW) { - rtio_o_underflow_reset_write(1); - exception_raise_params(EID_RTIO_UNDERFLOW, - fud_time, RTIO_FUD_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, - fud_time, RTIO_FUD_CHANNEL, 0); - } - } -} diff --git a/soc/runtime/rtio.h b/soc/runtime/rtio.h index c1182e80b..6c30cec12 100644 --- a/soc/runtime/rtio.h +++ b/soc/runtime/rtio.h @@ -1,14 +1,43 @@ #ifndef __RTIO_H #define __RTIO_H +#include +#include "exceptions.h" + +#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 + void rtio_init(void); +long long int rtio_get_counter(void); + +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); + } + } +} + void rtio_set_o(long long int timestamp, int channel, int value); void rtio_set_oe(long long int timestamp, int channel, int oe); void rtio_set_sensitivity(long long int timestamp, int channel, int sensitivity); -long long int rtio_get_counter(void); long long int rtio_get(int channel, long long int time_limit); -void rtio_fud_sync(void); -void rtio_fud(long long int fud_time); - #endif /* __RTIO_H */ diff --git a/soc/targets/artiq_kc705.py b/soc/targets/artiq_kc705.py index 94fe5fc80..b42f445c7 100644 --- a/soc/targets/artiq_kc705.py +++ b/soc/targets/artiq_kc705.py @@ -11,6 +11,7 @@ from targets.kc705 import MiniSoC from artiq.gateware.soc import AMPSoC from artiq.gateware import rtio, ad9858, nist_qc1 from artiq.gateware.rtio.phy import ttl_simple +from artiq.gateware.rtio.phy.wishbone import RT2WB class _RTIOCRG(Module, AutoCSR): @@ -40,7 +41,6 @@ class NIST_QC1(MiniSoC, AMPSoC): csr_map.update(MiniSoC.csr_map) mem_map = { "rtio": 0x20000000, # (shadow @0xa0000000) - "dds": 0x50000000, # (shadow @0xd0000000) "mailbox": 0x70000000 # (shadow @0xf0000000) } mem_map.update(MiniSoC.mem_map) @@ -75,20 +75,20 @@ class NIST_QC1(MiniSoC, AMPSoC): self.submodules += phy rtio_channels.append(rtio.Channel(phy.rtlink)) - fud = Signal() - self.add_constant("RTIO_FUD_CHANNEL", len(rtio_channels)) - phy = ttl_simple.Output(fud) + self.add_constant("RTIO_DDS_CHANNEL", len(rtio_channels)) + self.submodules.dds = RenameClockDomains( + ad9858.AD9858(platform.request("dds")), + "rio") + phy = RT2WB(7, self.dds.bus) self.submodules += phy - rtio_channels.append(rtio.Channel(phy.rtlink)) + rtio_channels.append(rtio.Channel(phy.rtlink, ififo_depth=4)) # RTIO core self.submodules.rtiocrg = _RTIOCRG(platform, self.crg.pll_sys) self.submodules.rtio = rtio.RTIO(rtio_channels, clk_freq=125000000) + self.add_constant("RTIO_FINE_TS_WIDTH", self.rtio.fine_ts_width) - dds_pads = platform.request("dds") - self.submodules.dds = ad9858.AD9858(dds_pads) - self.comb += dds_pads.fud_n.eq(~fud) if isinstance(platform.toolchain, XilinxVivadoToolchain): platform.add_platform_command(""" @@ -106,9 +106,5 @@ set_false_path -from [get_clocks rio_clk] -to [get_clocks rsys_clk] self.add_csr_region("rtio", self.mem_map["rtio"] | 0x80000000, 32, rtio_csrs) - self.kernel_cpu.add_wb_slave(mem_decoder(self.mem_map["dds"]), - self.dds.bus) - self.add_memory_region("dds", self.mem_map["dds"] | 0x80000000, 64*4) - default_subtarget = NIST_QC1 diff --git a/soc/targets/artiq_pipistrello.py b/soc/targets/artiq_pipistrello.py index fac40e2f6..29259d529 100644 --- a/soc/targets/artiq_pipistrello.py +++ b/soc/targets/artiq_pipistrello.py @@ -9,6 +9,7 @@ from targets.pipistrello import BaseSoC from artiq.gateware.soc import AMPSoC from artiq.gateware import rtio, ad9858, nist_qc1 from artiq.gateware.rtio.phy import ttl_simple +from artiq.gateware.rtio.phy.wishbone import RT2WB class _RTIOCRG(Module, AutoCSR): @@ -61,7 +62,6 @@ class NIST_QC1(BaseSoC, AMPSoC): csr_map.update(BaseSoC.csr_map) mem_map = { "rtio": 0x20000000, # (shadow @0xa0000000) - "dds": 0x50000000, # (shadow @0xd0000000) "mailbox": 0x70000000 # (shadow @0xf0000000) } mem_map.update(BaseSoC.mem_map) @@ -110,20 +110,19 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd self.submodules += phy rtio_channels.append(rtio.Channel(phy.rtlink)) - fud = Signal() - self.add_constant("RTIO_FUD_CHANNEL", len(rtio_channels)) - phy = ttl_simple.Output(fud) + self.add_constant("RTIO_DDS_CHANNEL", len(rtio_channels)) + self.submodules.dds = RenameClockDomains( + ad9858.AD9858(platform.request("dds")), + "rio") + phy = RT2WB(7, self.dds.bus) self.submodules += phy - rtio_channels.append(rtio.Channel(phy.rtlink)) + rtio_channels.append(rtio.Channel(phy.rtlink, ififo_depth=4)) # RTIO core self.submodules.rtiocrg = _RTIOCRG(platform) self.submodules.rtio = rtio.RTIO(rtio_channels, clk_freq=125000000) - - dds_pads = platform.request("dds") - self.submodules.dds = ad9858.AD9858(dds_pads) - self.comb += dds_pads.fud_n.eq(~fud) + self.add_constant("RTIO_FINE_TS_WIDTH", self.rtio.fine_ts_width) # CPU connections rtio_csrs = self.rtio.get_csrs() @@ -133,9 +132,5 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd self.add_csr_region("rtio", self.mem_map["rtio"] | 0x80000000, 32, rtio_csrs) - self.kernel_cpu.add_wb_slave(mem_decoder(self.mem_map["dds"]), - self.dds.bus) - self.add_memory_region("dds", self.mem_map["dds"] | 0x80000000, 64*4) - default_subtarget = NIST_QC1