forked from M-Labs/artiq
DDS over RTIO (batch mode not supported yet)
This commit is contained in:
parent
a91bb48ced
commit
a36c51eb83
|
@ -1,10 +1,10 @@
|
||||||
from artiq.language.core import *
|
from artiq.language.core import *
|
||||||
from artiq.language.db import *
|
from artiq.language.db import *
|
||||||
from artiq.language.units import *
|
from artiq.language.units import *
|
||||||
from artiq.coredevice import ttl
|
|
||||||
|
|
||||||
|
|
||||||
PHASE_MODE_DEFAULT = -1
|
PHASE_MODE_DEFAULT = -1
|
||||||
|
# keep in sync with dds.h
|
||||||
PHASE_MODE_CONTINUOUS = 0
|
PHASE_MODE_CONTINUOUS = 0
|
||||||
PHASE_MODE_ABSOLUTE = 1
|
PHASE_MODE_ABSOLUTE = 1
|
||||||
PHASE_MODE_TRACKING = 2
|
PHASE_MODE_TRACKING = 2
|
||||||
|
@ -13,34 +13,24 @@ PHASE_MODE_TRACKING = 2
|
||||||
class DDS(AutoDB):
|
class DDS(AutoDB):
|
||||||
"""Core device Direct Digital Synthesis (DDS) driver.
|
"""Core device Direct Digital Synthesis (DDS) driver.
|
||||||
|
|
||||||
Controls DDS devices managed directly by the core device's runtime. It also
|
Controls DDS devices managed directly by the core device's runtime.
|
||||||
uses a RTIO TTL channel (through :class:`artiq.coredevice.ttl.TTLOut`) to
|
|
||||||
control a RF switch that gates the output of the DDS device.
|
|
||||||
|
|
||||||
:param dds_sysclk: DDS system frequency, used for computing the frequency
|
:param dds_sysclk: DDS system frequency, used for computing the frequency
|
||||||
tuning words.
|
tuning words.
|
||||||
:param reg_channel: channel number of the DDS device to control.
|
:param channel: channel number of the DDS device to control.
|
||||||
:param rtio_switch: RTIO channel number of the RF switch associated with
|
|
||||||
the DDS device.
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
class DBKeys:
|
class DBKeys:
|
||||||
core = Device()
|
core = Device()
|
||||||
dds_sysclk = Parameter(1*GHz)
|
dds_sysclk = Argument(1*GHz)
|
||||||
reg_channel = Argument()
|
channel = Argument()
|
||||||
rtio_switch = Argument()
|
|
||||||
|
|
||||||
def build(self):
|
def build(self):
|
||||||
self.previous_on = False
|
self.phase_mode = PHASE_MODE_CONTINUOUS
|
||||||
self.previous_frequency = 0*MHz
|
|
||||||
self.set_phase_mode(PHASE_MODE_CONTINUOUS)
|
|
||||||
self.sw = ttl.TTLOut(core=self.core, channel=self.rtio_switch)
|
|
||||||
|
|
||||||
@portable
|
@portable
|
||||||
def frequency_to_ftw(self, frequency):
|
def frequency_to_ftw(self, frequency):
|
||||||
"""Returns the frequency tuning word corresponding to the given
|
"""Returns the frequency tuning word corresponding to the given
|
||||||
frequency.
|
frequency.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return round(2**32*frequency/self.dds_sysclk)
|
return round(2**32*frequency/self.dds_sysclk)
|
||||||
|
|
||||||
|
@ -48,10 +38,14 @@ class DDS(AutoDB):
|
||||||
def ftw_to_frequency(self, ftw):
|
def ftw_to_frequency(self, ftw):
|
||||||
"""Returns the frequency corresponding to the given frequency tuning
|
"""Returns the frequency corresponding to the given frequency tuning
|
||||||
word.
|
word.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return ftw*self.dds_sysclk/2**32
|
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
|
@kernel
|
||||||
def set_phase_mode(self, phase_mode):
|
def set_phase_mode(self, phase_mode):
|
||||||
"""Sets the phase mode of the DDS channel. Supported phase modes are:
|
"""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
|
accumulator is set to the value it would have if the DDS had been
|
||||||
running at the specified frequency since the start of the
|
running at the specified frequency since the start of the
|
||||||
experiment.
|
experiment.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self.phase_mode = phase_mode
|
self.phase_mode = phase_mode
|
||||||
syscall("dds_phase_clear_en", self.reg_channel,
|
|
||||||
self.phase_mode != PHASE_MODE_CONTINUOUS)
|
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def on(self, frequency, phase_mode=PHASE_MODE_DEFAULT, phase_offset=0):
|
def set(self, frequency, phase_mode=PHASE_MODE_DEFAULT, phase_offset=0):
|
||||||
"""Sets the DDS channel to the specified frequency and turns it on.
|
"""Sets the DDS channel to the specified frequency and phase.
|
||||||
|
|
||||||
If the DDS channel was already on, a real-time frequency and phase
|
|
||||||
update is performed.
|
|
||||||
|
|
||||||
:param frequency: frequency to generate.
|
:param frequency: frequency to generate.
|
||||||
:param phase_mode: if specified, overrides the default phase mode set
|
:param phase_mode: if specified, overrides the default phase mode set
|
||||||
by ``set_phase_mode`` for this call.
|
by ``set_phase_mode`` for this call.
|
||||||
:param phase_offset: adds an offset, in turns, to the phase.
|
:param phase_offset: adds an offset, in turns, to the phase.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if phase_mode != PHASE_MODE_DEFAULT:
|
if phase_mode == PHASE_MODE_DEFAULT:
|
||||||
old_phase_mode = self.phase_mode
|
phase_mode = self.phase_mode
|
||||||
self.set_phase_mode(phase_mode)
|
|
||||||
|
|
||||||
if self.previous_frequency != frequency:
|
syscall("dds_set", time_to_cycles(now()), self.channel,
|
||||||
merge = self.sw.o_previous_timestamp == time_to_cycles(now())
|
self.frequency_to_ftw(frequency), round(phase_offset*2**14),
|
||||||
if not merge:
|
self.phase_mode)
|
||||||
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()
|
|
||||||
|
|
|
@ -21,8 +21,8 @@ _syscalls = {
|
||||||
"rtio_set_sensitivity": "Iii:n",
|
"rtio_set_sensitivity": "Iii:n",
|
||||||
"rtio_get_counter": "n:I",
|
"rtio_get_counter": "n:I",
|
||||||
"rtio_get": "iI:I",
|
"rtio_get": "iI:I",
|
||||||
"dds_phase_clear_en": "ib:n",
|
"dds_init": "Ii:n",
|
||||||
"dds_program": "Iiiiibb:n",
|
"dds_set": "Iiiii:n",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -36,8 +36,8 @@ class AD9858(Module):
|
||||||
|
|
||||||
Read timing:
|
Read timing:
|
||||||
Address is set one cycle before assertion of rd_n.
|
Address is set one cycle before assertion of rd_n.
|
||||||
rd_n is asserted for 3 cycles.
|
rd_n is asserted for read_wait_cycles, data is sampled at the end.
|
||||||
Data is sampled 2 cycles into the assertion of rd_n.
|
rd_n is deasserted and data bus is not driven again before hiz_wait_cycles.
|
||||||
|
|
||||||
Design:
|
Design:
|
||||||
All IO pads are registered.
|
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
|
Round-trip addr A setup (> RX, RD, D to Z), RD prop, D valid (< D
|
||||||
valid), D prop is ~15 + 10 + 20 + 10 = 55ns
|
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,
|
read_wait_cycles=10, hiz_wait_cycles=3,
|
||||||
bus=None):
|
bus=None):
|
||||||
if bus is None:
|
if bus is None:
|
||||||
|
@ -84,9 +84,8 @@ class AD9858(Module):
|
||||||
bus.dat_r.eq(dr)
|
bus.dat_r.eq(dr)
|
||||||
)
|
)
|
||||||
|
|
||||||
if drive_fud:
|
fud = Signal()
|
||||||
fud = Signal()
|
self.sync += pads.fud_n.eq(~fud)
|
||||||
self.sync += pads.fud_n.eq(~fud)
|
|
||||||
|
|
||||||
pads.wr_n.reset = 1
|
pads.wr_n.reset = 1
|
||||||
pads.rd_n.reset = 1
|
pads.rd_n.reset = 1
|
||||||
|
@ -106,7 +105,7 @@ class AD9858(Module):
|
||||||
If(bus.adr[0],
|
If(bus.adr[0],
|
||||||
NextState("GPIO")
|
NextState("GPIO")
|
||||||
).Else(
|
).Else(
|
||||||
NextState("FUD") if drive_fud else None
|
NextState("FUD")
|
||||||
)
|
)
|
||||||
).Else(
|
).Else(
|
||||||
If(bus.we,
|
If(bus.we,
|
||||||
|
@ -141,19 +140,18 @@ class AD9858(Module):
|
||||||
)
|
)
|
||||||
fsm.act("WAIT_HIZ",
|
fsm.act("WAIT_HIZ",
|
||||||
rx.eq(1),
|
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),
|
hold_address.eq(1),
|
||||||
self.hiz_timer.wait.eq(1),
|
self.hiz_timer.wait.eq(1),
|
||||||
If(self.hiz_timer.done, NextState("IDLE"))
|
If(self.hiz_timer.done, NextState("IDLE"))
|
||||||
)
|
)
|
||||||
if drive_fud:
|
fsm.act("FUD",
|
||||||
fsm.act("FUD",
|
# 4ns FUD setup to SYNCLK
|
||||||
# 4ns FUD setup to SYNCLK
|
# 0ns FUD hold to SYNCLK
|
||||||
# 0ns FUD hold to SYNCLK
|
fud.eq(1),
|
||||||
fud.eq(1),
|
bus.ack.eq(1),
|
||||||
bus.ack.eq(1),
|
NextState("IDLE")
|
||||||
NextState("IDLE")
|
)
|
||||||
)
|
|
||||||
fsm.act("GPIO",
|
fsm.act("GPIO",
|
||||||
bus.ack.eq(1),
|
bus.ack.eq(1),
|
||||||
bus_r_gpio.eq(1),
|
bus_r_gpio.eq(1),
|
||||||
|
|
|
@ -291,6 +291,10 @@ class RTIO(Module):
|
||||||
fine_ts_width = max(rtlink.get_fine_ts_width(c.interface)
|
fine_ts_width = max(rtlink.get_fine_ts_width(c.interface)
|
||||||
for c in channels)
|
for c in channels)
|
||||||
|
|
||||||
|
self.data_width = data_width
|
||||||
|
self.address_width = address_width
|
||||||
|
self.fine_ts_width = fine_ts_width
|
||||||
|
|
||||||
# CSRs
|
# CSRs
|
||||||
self.kcsrs = _KernelCSRs(bits_for(len(channels)-1),
|
self.kcsrs = _KernelCSRs(bits_for(len(channels)-1),
|
||||||
data_width, address_width,
|
data_width, address_width,
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
from migen.fhdl.std import *
|
from migen.fhdl.std import *
|
||||||
|
from migen.bus import wishbone
|
||||||
|
|
||||||
from artiq.gateware.rtio import rtlink
|
from artiq.gateware.rtio import rtlink
|
||||||
|
|
||||||
|
|
||||||
class RT2WB(Module):
|
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(
|
self.rtlink = rtlink.Interface(
|
||||||
rtlink.OInterface(
|
rtlink.OInterface(
|
||||||
flen(wb.dat_w),
|
flen(wb.dat_w),
|
||||||
|
@ -18,7 +22,7 @@ class RT2WB(Module):
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
active = Signal()
|
active = Signal()
|
||||||
self.sync.rio_phy += [
|
self.sync.rio += [
|
||||||
If(self.rtlink.o.stb,
|
If(self.rtlink.o.stb,
|
||||||
active.eq(1),
|
active.eq(1),
|
||||||
wb.adr.eq(self.rtlink.o.address[:address_width]),
|
wb.adr.eq(self.rtlink.o.address[:address_width]),
|
||||||
|
@ -35,6 +39,6 @@ class RT2WB(Module):
|
||||||
wb.cyc.eq(active),
|
wb.cyc.eq(active),
|
||||||
wb.stb.eq(active),
|
wb.stb.eq(active),
|
||||||
|
|
||||||
self.i.stb.eq(wb.ack & ~wb.we),
|
self.rtlink.i.stb.eq(wb.ack & ~wb.we),
|
||||||
self.i.data.eq(wb.dat_r)
|
self.rtlink.i.data.eq(wb.dat_r)
|
||||||
]
|
]
|
||||||
|
|
|
@ -54,19 +54,19 @@
|
||||||
"type": "local",
|
"type": "local",
|
||||||
"module": "artiq.coredevice.dds",
|
"module": "artiq.coredevice.dds",
|
||||||
"class": "DDS",
|
"class": "DDS",
|
||||||
"arguments": {"reg_channel": 0, "rtio_switch": 5}
|
"arguments": {"channel": 0}
|
||||||
},
|
},
|
||||||
"dds1": {
|
"dds1": {
|
||||||
"type": "local",
|
"type": "local",
|
||||||
"module": "artiq.coredevice.dds",
|
"module": "artiq.coredevice.dds",
|
||||||
"class": "DDS",
|
"class": "DDS",
|
||||||
"arguments": {"reg_channel": 1, "rtio_switch": 6}
|
"arguments": {"channel": 1}
|
||||||
},
|
},
|
||||||
"dds2": {
|
"dds2": {
|
||||||
"type": "local",
|
"type": "local",
|
||||||
"module": "artiq.coredevice.dds",
|
"module": "artiq.coredevice.dds",
|
||||||
"class": "DDS",
|
"class": "DDS",
|
||||||
"arguments": {"reg_channel": 2, "rtio_switch": 7}
|
"arguments": {"channel": 2}
|
||||||
},
|
},
|
||||||
|
|
||||||
"qc_q1_0": {
|
"qc_q1_0": {
|
||||||
|
|
|
@ -9,10 +9,17 @@ class DDSTest(Experiment, AutoDB):
|
||||||
dds0 = Device()
|
dds0 = Device()
|
||||||
dds1 = Device()
|
dds1 = Device()
|
||||||
dds2 = Device()
|
dds2 = Device()
|
||||||
|
ttl0 = Device()
|
||||||
|
ttl1 = Device()
|
||||||
|
ttl2 = Device()
|
||||||
led = Device()
|
led = Device()
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def run(self):
|
def run(self):
|
||||||
|
# with dds_batch:
|
||||||
|
# self.dds1.set(120*MHz)
|
||||||
|
# self.dds2.set(200*MHz)
|
||||||
|
|
||||||
for i in range(10000):
|
for i in range(10000):
|
||||||
if i & 0x200:
|
if i & 0x200:
|
||||||
self.led.on()
|
self.led.on()
|
||||||
|
@ -20,7 +27,8 @@ class DDSTest(Experiment, AutoDB):
|
||||||
self.led.off()
|
self.led.off()
|
||||||
with parallel:
|
with parallel:
|
||||||
with sequential:
|
with sequential:
|
||||||
self.dds0.pulse(100*MHz + 4*i*kHz, 500*us)
|
self.dds0.set(100*MHz + 4*i*kHz)
|
||||||
self.dds1.pulse(120*MHz, 500*us)
|
self.ttl0.pulse(500*us)
|
||||||
self.dds2.pulse(200*MHz, 100*us)
|
self.ttl1.pulse(500*us)
|
||||||
|
self.ttl2.pulse(100*us)
|
||||||
self.led.off()
|
self.led.off()
|
||||||
|
|
|
@ -34,7 +34,9 @@ ksupport.elf: $(OBJECTS_KSUPPORT)
|
||||||
-T ksupport.ld \
|
-T ksupport.ld \
|
||||||
-N -o $@ \
|
-N -o $@ \
|
||||||
$(MSCDIR)/software/libbase/crt0-$(CPU).o \
|
$(MSCDIR)/software/libbase/crt0-$(CPU).o \
|
||||||
$^
|
$^ \
|
||||||
|
-L$(MSCDIR)/software/libcompiler-rt \
|
||||||
|
-lcompiler-rt
|
||||||
@chmod -x $@
|
@chmod -x $@
|
||||||
|
|
||||||
ksupport_data.o: ksupport.bin
|
ksupport_data.o: ksupport.bin
|
||||||
|
|
|
@ -4,6 +4,26 @@
|
||||||
#include "dds.h"
|
#include "dds.h"
|
||||||
#include "bridge.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)
|
static void send_ready(void)
|
||||||
{
|
{
|
||||||
struct msg_base msg;
|
struct msg_base msg;
|
||||||
|
@ -41,16 +61,16 @@ void bridge_main(void)
|
||||||
struct msg_brg_dds_sel *msg;
|
struct msg_brg_dds_sel *msg;
|
||||||
|
|
||||||
msg = (struct msg_brg_dds_sel *)umsg;
|
msg = (struct msg_brg_dds_sel *)umsg;
|
||||||
DDS_WRITE(DDS_GPIO, msg->channel);
|
dds_write(DDS_GPIO, msg->channel);
|
||||||
mailbox_acknowledge();
|
mailbox_acknowledge();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MESSAGE_TYPE_BRG_DDS_RESET: {
|
case MESSAGE_TYPE_BRG_DDS_RESET: {
|
||||||
unsigned int g;
|
unsigned int g;
|
||||||
|
|
||||||
g = DDS_READ(DDS_GPIO);
|
g = dds_read(DDS_GPIO);
|
||||||
DDS_WRITE(DDS_GPIO, g | (1 << 7));
|
dds_write(DDS_GPIO, g | (1 << 7));
|
||||||
DDS_WRITE(DDS_GPIO, g);
|
dds_write(DDS_GPIO, g);
|
||||||
|
|
||||||
mailbox_acknowledge();
|
mailbox_acknowledge();
|
||||||
break;
|
break;
|
||||||
|
@ -61,7 +81,7 @@ void bridge_main(void)
|
||||||
|
|
||||||
msg = (struct msg_brg_dds_read_request *)umsg;
|
msg = (struct msg_brg_dds_read_request *)umsg;
|
||||||
rmsg.type = MESSAGE_TYPE_BRG_DDS_READ_REPLY;
|
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);
|
mailbox_send_and_wait(&rmsg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -69,12 +89,12 @@ void bridge_main(void)
|
||||||
struct msg_brg_dds_write *msg;
|
struct msg_brg_dds_write *msg;
|
||||||
|
|
||||||
msg = (struct msg_brg_dds_write *)umsg;
|
msg = (struct msg_brg_dds_write *)umsg;
|
||||||
DDS_WRITE(msg->address, msg->data);
|
dds_write(msg->address, msg->data);
|
||||||
mailbox_acknowledge();
|
mailbox_acknowledge();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MESSAGE_TYPE_BRG_DDS_FUD:
|
case MESSAGE_TYPE_BRG_DDS_FUD:
|
||||||
rtio_fud(rtio_get_counter() + 8000);
|
dds_write(DDS_FUD, 0);
|
||||||
mailbox_acknowledge();
|
mailbox_acknowledge();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -4,64 +4,66 @@
|
||||||
#include "rtio.h"
|
#include "rtio.h"
|
||||||
#include "dds.h"
|
#include "dds.h"
|
||||||
|
|
||||||
void dds_init(void)
|
#define DURATION_WRITE 5
|
||||||
{
|
#define DURATION_PROGRAM (8*DURATION_WRITE)
|
||||||
int i;
|
|
||||||
|
|
||||||
for(i=0;i<8;i++) {
|
#define DDS_WRITE(addr, data) do { \
|
||||||
DDS_WRITE(DDS_GPIO, i);
|
rtio_o_address_write(addr); \
|
||||||
DDS_WRITE(DDS_GPIO, i | (1 << 7));
|
rtio_o_data_write(data); \
|
||||||
DDS_WRITE(DDS_GPIO, i);
|
rtio_o_timestamp_write(now); \
|
||||||
dds_phase_clear_en(i, 0);
|
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(0x00, 0x78);
|
||||||
DDS_WRITE(0x01, 0x00);
|
DDS_WRITE(0x01, 0x00);
|
||||||
DDS_WRITE(0x02, phase_clear_en ? 0x40 : 0x00);
|
DDS_WRITE(0x02, 0x00);
|
||||||
DDS_WRITE(0x03, 0x00);
|
DDS_WRITE(0x03, 0x00);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static void dds_set_one(long long int now, long long int timestamp, int channel,
|
||||||
* DDS phase modes:
|
unsigned int ftw, unsigned int pow, int phase_mode)
|
||||||
* - 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)
|
|
||||||
{
|
{
|
||||||
long long int fud_time;
|
|
||||||
unsigned int phase_time_offset;
|
|
||||||
|
|
||||||
rtio_fud_sync();
|
|
||||||
DDS_WRITE(DDS_GPIO, channel);
|
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_FTW0, ftw & 0xff);
|
||||||
DDS_WRITE(DDS_FTW1, (ftw >> 8) & 0xff);
|
DDS_WRITE(DDS_FTW1, (ftw >> 8) & 0xff);
|
||||||
DDS_WRITE(DDS_FTW2, (ftw >> 16) & 0xff);
|
DDS_WRITE(DDS_FTW2, (ftw >> 16) & 0xff);
|
||||||
DDS_WRITE(DDS_FTW3, (ftw >> 24) & 0xff);
|
DDS_WRITE(DDS_FTW3, (ftw >> 24) & 0xff);
|
||||||
|
|
||||||
phase_time_offset = phase_tracking ? timestamp : 0;
|
if(phase_mode == PHASE_MODE_TRACKING)
|
||||||
if(rt_fud)
|
/* We assume that the RTIO clock is DDS SYNCLK */
|
||||||
fud_time = timestamp;
|
pow += (timestamp >> RTIO_FINE_TS_WIDTH)*ftw >> 18;
|
||||||
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;
|
|
||||||
DDS_WRITE(DDS_POW0, pow & 0xff);
|
DDS_WRITE(DDS_POW0, pow & 0xff);
|
||||||
DDS_WRITE(DDS_POW1, (pow >> 8) & 0x3f);
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,24 +4,23 @@
|
||||||
#include <hw/common.h>
|
#include <hw/common.h>
|
||||||
#include <generated/mem.h>
|
#include <generated/mem.h>
|
||||||
|
|
||||||
#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_FTW0 0x0a
|
||||||
#define DDS_FTW1 0x0b
|
#define DDS_FTW1 0x0b
|
||||||
#define DDS_FTW2 0x0c
|
#define DDS_FTW2 0x0c
|
||||||
#define DDS_FTW3 0x0d
|
#define DDS_FTW3 0x0d
|
||||||
#define DDS_POW0 0x0e
|
#define DDS_POW0 0x0e
|
||||||
#define DDS_POW1 0x0f
|
#define DDS_POW1 0x0f
|
||||||
|
#define DDS_FUD 0x40
|
||||||
#define DDS_GPIO 0x41
|
#define DDS_GPIO 0x41
|
||||||
|
|
||||||
void dds_init(void);
|
enum {
|
||||||
void dds_phase_clear_en(int channel, int phase_clear_en);
|
PHASE_MODE_CONTINUOUS = 0,
|
||||||
void dds_program(long long int timestamp, int channel,
|
PHASE_MODE_ABSOLUTE = 1,
|
||||||
unsigned int ftw, unsigned int pow, unsigned int sysclk_per_microcycle,
|
PHASE_MODE_TRACKING = 2
|
||||||
int rt_fud, int phase_tracking);
|
};
|
||||||
|
|
||||||
|
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 */
|
#endif /* __DDS_H */
|
||||||
|
|
|
@ -17,8 +17,8 @@ services = [
|
||||||
("rtio_set_sensitivity", "rtio_set_sensitivity"),
|
("rtio_set_sensitivity", "rtio_set_sensitivity"),
|
||||||
("rtio_get_counter", "rtio_get_counter"),
|
("rtio_get_counter", "rtio_get_counter"),
|
||||||
("rtio_get", "rtio_get"),
|
("rtio_get", "rtio_get"),
|
||||||
("dds_phase_clear_en", "dds_phase_clear_en"),
|
("dds_init", "dds_init"),
|
||||||
("dds_program", "dds_program"),
|
("dds_set", "dds_set"),
|
||||||
]),
|
]),
|
||||||
("eh", [
|
("eh", [
|
||||||
("setjmp", "exception_setjmp"),
|
("setjmp", "exception_setjmp"),
|
||||||
|
|
|
@ -78,7 +78,6 @@ long long int now_init(void)
|
||||||
mailbox_acknowledge();
|
mailbox_acknowledge();
|
||||||
|
|
||||||
if(now < 0) {
|
if(now < 0) {
|
||||||
dds_init();
|
|
||||||
rtio_init();
|
rtio_init();
|
||||||
now = 125000;
|
now = 125000;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,42 +3,17 @@
|
||||||
#include "exceptions.h"
|
#include "exceptions.h"
|
||||||
#include "rtio.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)
|
void rtio_init(void)
|
||||||
{
|
{
|
||||||
previous_fud_end_time = 0;
|
|
||||||
rtio_reset_write(1);
|
rtio_reset_write(1);
|
||||||
rtio_reset_write(0);
|
rtio_reset_write(0);
|
||||||
rtio_reset_phy_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_counter_update_write(1);
|
||||||
|
return rtio_counter_read();
|
||||||
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_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_timestamp_write(timestamp);
|
||||||
rtio_o_address_write(0);
|
rtio_o_address_write(0);
|
||||||
rtio_o_data_write(value);
|
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)
|
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_timestamp_write(timestamp);
|
||||||
rtio_o_address_write(1);
|
rtio_o_address_write(1);
|
||||||
rtio_o_data_write(oe);
|
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)
|
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_timestamp_write(timestamp);
|
||||||
rtio_o_address_write(2);
|
rtio_o_address_write(2);
|
||||||
rtio_o_data_write(sensitivity);
|
rtio_o_data_write(sensitivity);
|
||||||
write_and_process_status(timestamp, channel);
|
rtio_write_and_process_status(timestamp, channel);
|
||||||
}
|
|
||||||
|
|
||||||
long long int rtio_get_counter(void)
|
|
||||||
{
|
|
||||||
rtio_counter_update_write(1);
|
|
||||||
return rtio_counter_read();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
long long int rtio_get(int channel, long long int time_limit)
|
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);
|
rtio_i_re_write(1);
|
||||||
return r;
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,14 +1,43 @@
|
||||||
#ifndef __RTIO_H
|
#ifndef __RTIO_H
|
||||||
#define __RTIO_H
|
#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_I_STATUS_EMPTY 1
|
||||||
|
#define RTIO_I_STATUS_OVERFLOW 2
|
||||||
|
|
||||||
void rtio_init(void);
|
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_o(long long int timestamp, int channel, int value);
|
||||||
void rtio_set_oe(long long int timestamp, int channel, int oe);
|
void rtio_set_oe(long long int timestamp, int channel, int oe);
|
||||||
void rtio_set_sensitivity(long long int timestamp, int channel, int sensitivity);
|
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);
|
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 */
|
#endif /* __RTIO_H */
|
||||||
|
|
|
@ -11,6 +11,7 @@ from targets.kc705 import MiniSoC
|
||||||
from artiq.gateware.soc import AMPSoC
|
from artiq.gateware.soc import AMPSoC
|
||||||
from artiq.gateware import rtio, ad9858, nist_qc1
|
from artiq.gateware import rtio, ad9858, nist_qc1
|
||||||
from artiq.gateware.rtio.phy import ttl_simple
|
from artiq.gateware.rtio.phy import ttl_simple
|
||||||
|
from artiq.gateware.rtio.phy.wishbone import RT2WB
|
||||||
|
|
||||||
|
|
||||||
class _RTIOCRG(Module, AutoCSR):
|
class _RTIOCRG(Module, AutoCSR):
|
||||||
|
@ -40,7 +41,6 @@ class NIST_QC1(MiniSoC, AMPSoC):
|
||||||
csr_map.update(MiniSoC.csr_map)
|
csr_map.update(MiniSoC.csr_map)
|
||||||
mem_map = {
|
mem_map = {
|
||||||
"rtio": 0x20000000, # (shadow @0xa0000000)
|
"rtio": 0x20000000, # (shadow @0xa0000000)
|
||||||
"dds": 0x50000000, # (shadow @0xd0000000)
|
|
||||||
"mailbox": 0x70000000 # (shadow @0xf0000000)
|
"mailbox": 0x70000000 # (shadow @0xf0000000)
|
||||||
}
|
}
|
||||||
mem_map.update(MiniSoC.mem_map)
|
mem_map.update(MiniSoC.mem_map)
|
||||||
|
@ -75,20 +75,20 @@ class NIST_QC1(MiniSoC, AMPSoC):
|
||||||
self.submodules += phy
|
self.submodules += phy
|
||||||
rtio_channels.append(rtio.Channel(phy.rtlink))
|
rtio_channels.append(rtio.Channel(phy.rtlink))
|
||||||
|
|
||||||
fud = Signal()
|
self.add_constant("RTIO_DDS_CHANNEL", len(rtio_channels))
|
||||||
self.add_constant("RTIO_FUD_CHANNEL", len(rtio_channels))
|
self.submodules.dds = RenameClockDomains(
|
||||||
phy = ttl_simple.Output(fud)
|
ad9858.AD9858(platform.request("dds")),
|
||||||
|
"rio")
|
||||||
|
phy = RT2WB(7, self.dds.bus)
|
||||||
self.submodules += phy
|
self.submodules += phy
|
||||||
rtio_channels.append(rtio.Channel(phy.rtlink))
|
rtio_channels.append(rtio.Channel(phy.rtlink, ififo_depth=4))
|
||||||
|
|
||||||
# RTIO core
|
# RTIO core
|
||||||
self.submodules.rtiocrg = _RTIOCRG(platform, self.crg.pll_sys)
|
self.submodules.rtiocrg = _RTIOCRG(platform, self.crg.pll_sys)
|
||||||
self.submodules.rtio = rtio.RTIO(rtio_channels,
|
self.submodules.rtio = rtio.RTIO(rtio_channels,
|
||||||
clk_freq=125000000)
|
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):
|
if isinstance(platform.toolchain, XilinxVivadoToolchain):
|
||||||
platform.add_platform_command("""
|
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,
|
self.add_csr_region("rtio", self.mem_map["rtio"] | 0x80000000, 32,
|
||||||
rtio_csrs)
|
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
|
default_subtarget = NIST_QC1
|
||||||
|
|
|
@ -9,6 +9,7 @@ from targets.pipistrello import BaseSoC
|
||||||
from artiq.gateware.soc import AMPSoC
|
from artiq.gateware.soc import AMPSoC
|
||||||
from artiq.gateware import rtio, ad9858, nist_qc1
|
from artiq.gateware import rtio, ad9858, nist_qc1
|
||||||
from artiq.gateware.rtio.phy import ttl_simple
|
from artiq.gateware.rtio.phy import ttl_simple
|
||||||
|
from artiq.gateware.rtio.phy.wishbone import RT2WB
|
||||||
|
|
||||||
|
|
||||||
class _RTIOCRG(Module, AutoCSR):
|
class _RTIOCRG(Module, AutoCSR):
|
||||||
|
@ -61,7 +62,6 @@ class NIST_QC1(BaseSoC, AMPSoC):
|
||||||
csr_map.update(BaseSoC.csr_map)
|
csr_map.update(BaseSoC.csr_map)
|
||||||
mem_map = {
|
mem_map = {
|
||||||
"rtio": 0x20000000, # (shadow @0xa0000000)
|
"rtio": 0x20000000, # (shadow @0xa0000000)
|
||||||
"dds": 0x50000000, # (shadow @0xd0000000)
|
|
||||||
"mailbox": 0x70000000 # (shadow @0xf0000000)
|
"mailbox": 0x70000000 # (shadow @0xf0000000)
|
||||||
}
|
}
|
||||||
mem_map.update(BaseSoC.mem_map)
|
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
|
self.submodules += phy
|
||||||
rtio_channels.append(rtio.Channel(phy.rtlink))
|
rtio_channels.append(rtio.Channel(phy.rtlink))
|
||||||
|
|
||||||
fud = Signal()
|
self.add_constant("RTIO_DDS_CHANNEL", len(rtio_channels))
|
||||||
self.add_constant("RTIO_FUD_CHANNEL", len(rtio_channels))
|
self.submodules.dds = RenameClockDomains(
|
||||||
phy = ttl_simple.Output(fud)
|
ad9858.AD9858(platform.request("dds")),
|
||||||
|
"rio")
|
||||||
|
phy = RT2WB(7, self.dds.bus)
|
||||||
self.submodules += phy
|
self.submodules += phy
|
||||||
rtio_channels.append(rtio.Channel(phy.rtlink))
|
rtio_channels.append(rtio.Channel(phy.rtlink, ififo_depth=4))
|
||||||
|
|
||||||
# RTIO core
|
# RTIO core
|
||||||
self.submodules.rtiocrg = _RTIOCRG(platform)
|
self.submodules.rtiocrg = _RTIOCRG(platform)
|
||||||
self.submodules.rtio = rtio.RTIO(rtio_channels,
|
self.submodules.rtio = rtio.RTIO(rtio_channels,
|
||||||
clk_freq=125000000)
|
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)
|
|
||||||
|
|
||||||
# CPU connections
|
# CPU connections
|
||||||
rtio_csrs = self.rtio.get_csrs()
|
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,
|
self.add_csr_region("rtio", self.mem_map["rtio"] | 0x80000000, 32,
|
||||||
rtio_csrs)
|
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
|
default_subtarget = NIST_QC1
|
||||||
|
|
Loading…
Reference in New Issue