forked from M-Labs/artiq
soc: support QC2 and AD9914 (untested)
This commit is contained in:
parent
b6310b72db
commit
944bfafefa
@ -6,15 +6,14 @@ from migen.bus.transactions import *
|
||||
from migen.sim.generic import run_simulation
|
||||
|
||||
|
||||
class AD9858(Module):
|
||||
"""Wishbone interface to the AD9858 DDS chip.
|
||||
class AD9xxx(Module):
|
||||
"""Wishbone interface to the AD9858 and AD9914 DDS chips.
|
||||
|
||||
Addresses 0-63 map the AD9858 registers.
|
||||
Data is zero-padded.
|
||||
Addresses 0-2**flen(pads.a)-1 map the AD9xxx registers.
|
||||
|
||||
Write to address 64 to pulse the FUD signal.
|
||||
Address 65 is a GPIO register that controls the sel, p and reset signals.
|
||||
sel is mapped to the lower bits, followed by p and reset.
|
||||
Write to address 2**flen(pads.a) to pulse the FUD signal.
|
||||
Address 2**flen(pads.a)+1 is a GPIO register that controls the
|
||||
sel and reset signals. sel is mapped to the lower bits, followed by reset.
|
||||
|
||||
Write timing:
|
||||
Address is set one cycle before assertion of we_n.
|
||||
@ -28,6 +27,7 @@ class AD9858(Module):
|
||||
Design:
|
||||
All IO pads are registered.
|
||||
|
||||
With QC1 adapter:
|
||||
LVDS driver/receiver propagation delays are 3.6+4.5 ns max
|
||||
LVDS state transition delays are 20, 15 ns max
|
||||
Schmitt trigger delays are 6.4ns max
|
||||
@ -38,15 +38,15 @@ class AD9858(Module):
|
||||
read_wait_cycles=10, hiz_wait_cycles=3,
|
||||
bus=None):
|
||||
if bus is None:
|
||||
bus = wishbone.Interface(data_width=8)
|
||||
bus = wishbone.Interface(data_width=flen(pads.d))
|
||||
self.bus = bus
|
||||
|
||||
# # #
|
||||
|
||||
dts = TSTriple(8)
|
||||
dts = TSTriple(flen(pads.d))
|
||||
self.specials += dts.get_tristate(pads.d)
|
||||
hold_address = Signal()
|
||||
dr = Signal(8)
|
||||
dr = Signal(flen(pads.d))
|
||||
rx = Signal()
|
||||
self.sync += [
|
||||
If(~hold_address, pads.a.eq(bus.adr)),
|
||||
@ -55,13 +55,14 @@ class AD9858(Module):
|
||||
dts.oe.eq(~rx)
|
||||
]
|
||||
|
||||
gpio = Signal(flen(pads.sel) + flen(pads.p) + 1)
|
||||
gpio = Signal(flen(pads.sel) + 1)
|
||||
gpio_load = Signal()
|
||||
self.sync += If(gpio_load, gpio.eq(bus.dat_w))
|
||||
self.comb += [
|
||||
Cat(pads.sel, pads.p).eq(gpio),
|
||||
pads.rst_n.eq(~gpio[-1]),
|
||||
]
|
||||
self.comb += pads.sel.eq(gpio),
|
||||
if hasattr(pads, "rst"):
|
||||
self.comb += pads.rst.eq(gpio[-1])
|
||||
else:
|
||||
self.comb += pads.rst_n.eq(~gpio[-1])
|
||||
|
||||
bus_r_gpio = Signal()
|
||||
self.comb += If(bus_r_gpio,
|
||||
@ -71,7 +72,10 @@ class AD9858(Module):
|
||||
)
|
||||
|
||||
fud = Signal()
|
||||
self.sync += pads.fud_n.eq(~fud)
|
||||
if hasattr(pads, "fud"):
|
||||
self.sync += pads.fud.eq(fud)
|
||||
else:
|
||||
self.sync += pads.fud_n.eq(~fud)
|
||||
|
||||
pads.wr_n.reset = 1
|
||||
pads.rd_n.reset = 1
|
||||
@ -87,7 +91,7 @@ class AD9858(Module):
|
||||
|
||||
fsm.act("IDLE",
|
||||
If(bus.cyc & bus.stb,
|
||||
If(bus.adr[6],
|
||||
If(bus.adr[flen(pads.a)],
|
||||
If(bus.adr[0],
|
||||
NextState("GPIO")
|
||||
).Else(
|
||||
@ -168,7 +172,6 @@ class _TestPads:
|
||||
self.a = Signal(6)
|
||||
self.d = Signal(8)
|
||||
self.sel = Signal(5)
|
||||
self.p = Signal(2)
|
||||
self.fud_n = Signal()
|
||||
self.wr_n = Signal()
|
||||
self.rd_n = Signal()
|
||||
@ -178,11 +181,11 @@ class _TestPads:
|
||||
class _TB(Module):
|
||||
def __init__(self):
|
||||
pads = _TestPads()
|
||||
self.submodules.dut = AD9858(pads, drive_fud=True)
|
||||
self.submodules.dut = AD9xxx(pads, drive_fud=True)
|
||||
self.submodules.initiator = wishbone.Initiator(_test_gen())
|
||||
self.submodules.interconnect = wishbone.InterconnectPointToPoint(
|
||||
self.initiator.bus, self.dut.bus)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
run_simulation(_TB(), vcd_name="ad9858.vcd")
|
||||
run_simulation(_TB(), vcd_name="ad9xxx.vcd")
|
@ -1,5 +1,6 @@
|
||||
from mibuild.generic_platform import *
|
||||
|
||||
|
||||
fmc_adapter_io = [
|
||||
("ttl", 0, Pins("LPC:LA00_CC_P"), IOStandard("LVTTL")),
|
||||
("ttl", 1, Pins("LPC:LA02_P"), IOStandard("LVTTL")),
|
||||
@ -28,10 +29,10 @@ fmc_adapter_io = [
|
||||
Subsignal("sel", Pins("LPC:LA24_N LPC:LA29_P LPC:LA28_P LPC:LA29_N "
|
||||
"LPC:LA28_N LPC:LA31_P LPC:LA30_P LPC:LA31_N "
|
||||
"LPC:LA30_N LPC:LA33_P LPC:LA33_N")),
|
||||
Subsignal("fud_n", Pins("LPC:LA21_N")),
|
||||
Subsignal("fud", Pins("LPC:LA21_N")),
|
||||
Subsignal("wr_n", Pins("LPC:LA24_P")),
|
||||
Subsignal("rd_n", Pins("LPC:LA25_N")),
|
||||
Subsignal("rst_in", Pins("LPC:LA25_P")),
|
||||
Subsignal("rst", Pins("LPC:LA25_P")),
|
||||
IOStandard("LVTTL")),
|
||||
|
||||
("i2c", 0,
|
||||
|
@ -1,14 +1,14 @@
|
||||
from migen.fhdl.std import *
|
||||
|
||||
from artiq.gateware import ad9858 as ad9858_ll
|
||||
from artiq.gateware import ad9xxx
|
||||
from artiq.gateware.rtio.phy.wishbone import RT2WB
|
||||
|
||||
|
||||
class AD9858(Module):
|
||||
def __init__(self, pads, nchannels=8, **kwargs):
|
||||
class _AD9xxx(Module):
|
||||
def __init__(self, ftw_base, pads, nchannels, **kwargs):
|
||||
self.submodules._ll = RenameClockDomains(
|
||||
ad9858_ll.AD9858(pads, **kwargs), "rio")
|
||||
self.submodules._rt2wb = RT2WB(7, self._ll.bus)
|
||||
ad9xxx.AD9xxx(pads, **kwargs), "rio")
|
||||
self.submodules._rt2wb = RT2WB(flen(pads.a)+1, self._ll.bus)
|
||||
self.rtlink = self._rt2wb.rtlink
|
||||
self.probes = [Signal(32) for i in range(nchannels)]
|
||||
|
||||
@ -16,21 +16,44 @@ class AD9858(Module):
|
||||
|
||||
# keep track of the currently selected channel
|
||||
current_channel = Signal(max=nchannels)
|
||||
self.sync.rio += If(self.rtlink.o.stb & (self.rtlink.o.address == 65),
|
||||
current_channel.eq(self.rtlink.o.data))
|
||||
self.sync.rio += If(self.rtlink.o.stb &
|
||||
(self.rtlink.o.address == 2**flen(pads.a)+1),
|
||||
current_channel.eq(self.rtlink.o.data))
|
||||
|
||||
# keep track of frequency tuning words, before they are FUDed
|
||||
ftws = [Signal(32) for i in range(nchannels)]
|
||||
for c, ftw in enumerate(ftws):
|
||||
for i in range(4):
|
||||
self.sync.rio += \
|
||||
If(self.rtlink.o.stb & \
|
||||
(self.rtlink.o.address == 0x0a+i) & \
|
||||
(current_channel == c),
|
||||
ftw[i*8:(i+1)*8].eq(self.rtlink.o.data)
|
||||
)
|
||||
if flen(pads.d) == 8:
|
||||
for i in range(4):
|
||||
self.sync.rio += \
|
||||
If(self.rtlink.o.stb & \
|
||||
(self.rtlink.o.address == ftw_base+i) & \
|
||||
(current_channel == c),
|
||||
ftw[i*8:(i+1)*8].eq(self.rtlink.o.data)
|
||||
)
|
||||
elif flen(pads.d) == 16:
|
||||
for i in range(2):
|
||||
self.sync.rio += \
|
||||
If(self.rtlink.o.stb & \
|
||||
(self.rtlink.o.address == ftw_base+2*i) & \
|
||||
(current_channel == c),
|
||||
ftw[i*16:(i+1)*16].eq(self.rtlink.o.data)
|
||||
)
|
||||
else:
|
||||
raise NotImplementedError
|
||||
|
||||
# FTW to probe on FUD
|
||||
for c, (probe, ftw) in enumerate(zip(self.probes, ftws)):
|
||||
fud = self.rtlink.o.stb & (self.rtlink.o.address == 64)
|
||||
fud = self.rtlink.o.stb & \
|
||||
(self.rtlink.o.address == 2**flen(pads.a))
|
||||
self.sync.rio += If(fud & (current_channel == c), probe.eq(ftw))
|
||||
|
||||
|
||||
class AD9858(_AD9xxx):
|
||||
def __init__(self, pads, nchannels, **kwargs):
|
||||
_AD9xxx.__init__(self, 0x0a, pads, nchannels, **kwargs)
|
||||
|
||||
|
||||
class AD9914(_AD9xxx):
|
||||
def __init__(self, pads, nchannels, **kwargs):
|
||||
_AD9xxx.__init__(self, 0x2d, pads, nchannels, **kwargs)
|
||||
|
@ -40,7 +40,7 @@ void dds_init(long long int timestamp, int channel)
|
||||
now = timestamp - DURATION_INIT;
|
||||
|
||||
DDS_WRITE(DDS_GPIO, channel);
|
||||
DDS_WRITE(DDS_GPIO, channel | (1 << 7));
|
||||
DDS_WRITE(DDS_GPIO, channel | (1 << 5));
|
||||
DDS_WRITE(DDS_GPIO, channel);
|
||||
|
||||
DDS_WRITE(0x00, 0x78);
|
||||
|
@ -10,7 +10,7 @@ from misoclib.mem.sdram.core.minicon import MiniconSettings
|
||||
from targets.kc705 import MiniSoC
|
||||
|
||||
from artiq.gateware.soc import AMPSoC
|
||||
from artiq.gateware import rtio, nist_qc1
|
||||
from artiq.gateware import rtio, nist_qc1, nist_qc2
|
||||
from artiq.gateware.rtio.phy import ttl_simple, dds
|
||||
|
||||
|
||||
@ -32,7 +32,7 @@ class _RTIOCRG(Module, AutoCSR):
|
||||
o_O=self.cd_rtio.clk)
|
||||
|
||||
|
||||
class NIST_QC1(MiniSoC, AMPSoC):
|
||||
class _NIST_QCx(MiniSoC, AMPSoC):
|
||||
csr_map = {
|
||||
"rtio": None, # mapped on Wishbone instead
|
||||
"rtio_crg": 13,
|
||||
@ -52,18 +52,44 @@ class NIST_QC1(MiniSoC, AMPSoC):
|
||||
sdram_controller_settings=MiniconSettings(l2_size=128*1024),
|
||||
with_timer=False, **kwargs)
|
||||
AMPSoC.__init__(self)
|
||||
platform.add_extension(nist_qc1.fmc_adapter_io)
|
||||
|
||||
self.submodules.leds = gpio.GPIOOut(Cat(
|
||||
platform.request("user_led", 0),
|
||||
platform.request("user_led", 1)))
|
||||
|
||||
def add_rtio(self, rtio_channels):
|
||||
self.submodules.rtio_crg = _RTIOCRG(self.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)
|
||||
self.add_constant("DDS_RTIO_CLK_RATIO", 8 >> self.rtio.fine_ts_width)
|
||||
self.submodules.rtio_moninj = rtio.MonInj(rtio_channels)
|
||||
|
||||
if isinstance(self.platform.toolchain, XilinxVivadoToolchain):
|
||||
self.platform.add_platform_command("""
|
||||
create_clock -name rsys_clk -period 8.0 [get_nets {rsys_clk}]
|
||||
create_clock -name rio_clk -period 8.0 [get_nets {rio_clk}]
|
||||
set_false_path -from [get_clocks rsys_clk] -to [get_clocks rio_clk]
|
||||
set_false_path -from [get_clocks rio_clk] -to [get_clocks rsys_clk]
|
||||
""", rsys_clk=self.rtio.cd_rsys.clk, rio_clk=self.rtio.cd_rio.clk)
|
||||
|
||||
rtio_csrs = self.rtio.get_csrs()
|
||||
self.submodules.rtiowb = wbgen.Bank(rtio_csrs)
|
||||
self.kernel_cpu.add_wb_slave(mem_decoder(self.mem_map["rtio"]),
|
||||
self.rtiowb.bus)
|
||||
self.add_csr_region("rtio", self.mem_map["rtio"] | 0x80000000, 32,
|
||||
rtio_csrs)
|
||||
|
||||
|
||||
class NIST_QC1(_NIST_QCx):
|
||||
def __init__(self, platform, cpu_type="or1k", **kwargs):
|
||||
_NIST_QCx.__init__(self, platform, cpu_type, **kwargs)
|
||||
platform.add_extension(nist_qc1.fmc_adapter_io)
|
||||
|
||||
self.comb += [
|
||||
platform.request("ttl_l_tx_en").eq(1),
|
||||
platform.request("ttl_h_tx_en").eq(1)
|
||||
]
|
||||
|
||||
# RTIO channels
|
||||
rtio_channels = []
|
||||
for i in range(2):
|
||||
phy = ttl_simple.Inout(platform.request("pmt", i))
|
||||
@ -81,35 +107,46 @@ class NIST_QC1(MiniSoC, AMPSoC):
|
||||
|
||||
self.add_constant("RTIO_DDS_CHANNEL", len(rtio_channels))
|
||||
self.add_constant("DDS_CHANNEL_COUNT", 8)
|
||||
phy = dds.AD9858(platform.request("dds"))
|
||||
self.add_constant("DDS_AD9858")
|
||||
phy = dds.AD9858(platform.request("dds"), 8)
|
||||
self.submodules += phy
|
||||
rtio_channels.append(rtio.Channel.from_phy(phy,
|
||||
ofifo_depth=512,
|
||||
ififo_depth=4))
|
||||
self.add_rtio(rtio_channels)
|
||||
|
||||
# RTIO core
|
||||
self.submodules.rtio_crg = _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)
|
||||
self.add_constant("DDS_RTIO_CLK_RATIO", 8 >> self.rtio.fine_ts_width)
|
||||
self.submodules.rtio_moninj = rtio.MonInj(rtio_channels)
|
||||
|
||||
if isinstance(platform.toolchain, XilinxVivadoToolchain):
|
||||
platform.add_platform_command("""
|
||||
create_clock -name rsys_clk -period 8.0 [get_nets {rsys_clk}]
|
||||
create_clock -name rio_clk -period 8.0 [get_nets {rio_clk}]
|
||||
set_false_path -from [get_clocks rsys_clk] -to [get_clocks rio_clk]
|
||||
set_false_path -from [get_clocks rio_clk] -to [get_clocks rsys_clk]
|
||||
""", rsys_clk=self.rtio.cd_rsys.clk, rio_clk=self.rtio.cd_rio.clk)
|
||||
class NIST_QC2(_NIST_QCx):
|
||||
def __init__(self, platform, cpu_type="or1k", **kwargs):
|
||||
_NIST_QCx.__init__(self, platform, cpu_type, **kwargs)
|
||||
platform.add_extension(nist_qc2.fmc_adapter_io)
|
||||
|
||||
# CPU connections
|
||||
rtio_csrs = self.rtio.get_csrs()
|
||||
self.submodules.rtiowb = wbgen.Bank(rtio_csrs)
|
||||
self.kernel_cpu.add_wb_slave(mem_decoder(self.mem_map["rtio"]),
|
||||
self.rtiowb.bus)
|
||||
self.add_csr_region("rtio", self.mem_map["rtio"] | 0x80000000, 32,
|
||||
rtio_csrs)
|
||||
rtio_channels = []
|
||||
for i in range(16):
|
||||
if i % 4 == 3:
|
||||
phy = ttl_simple.Inout(platform.request("ttl", i))
|
||||
self.submodules += phy
|
||||
rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=512))
|
||||
else:
|
||||
phy = ttl_simple.Output(platform.request("ttl", i))
|
||||
self.submodules += phy
|
||||
rtio_channels.append(rtio.Channel.from_phy(phy))
|
||||
|
||||
phy = ttl_simple.Output(platform.request("user_led", 2))
|
||||
self.submodules += phy
|
||||
rtio_channels.append(rtio.Channel.from_phy(phy))
|
||||
self.add_constant("RTIO_TTL_COUNT", len(rtio_channels))
|
||||
|
||||
self.add_constant("RTIO_DDS_CHANNEL", len(rtio_channels))
|
||||
self.add_constant("DDS_CHANNEL_COUNT", 11)
|
||||
self.add_constant("DDS_AD9914")
|
||||
self.add_constant("DDS_ONEHOT_SEL")
|
||||
phy = dds.AD9914(platform.request("dds"), 11)
|
||||
self.submodules += phy
|
||||
rtio_channels.append(rtio.Channel.from_phy(phy,
|
||||
ofifo_depth=512,
|
||||
ififo_depth=4))
|
||||
self.add_rtio(rtio_channels)
|
||||
|
||||
|
||||
default_subtarget = NIST_QC1
|
||||
|
@ -118,7 +118,7 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd
|
||||
|
||||
self.add_constant("RTIO_DDS_CHANNEL", len(rtio_channels))
|
||||
self.add_constant("DDS_CHANNEL_COUNT", 8)
|
||||
phy = dds.AD9858(platform.request("dds"))
|
||||
phy = dds.AD9858(platform.request("dds"), 8)
|
||||
self.submodules += phy
|
||||
rtio_channels.append(rtio.Channel.from_phy(phy,
|
||||
ofifo_depth=512,
|
||||
|
Loading…
Reference in New Issue
Block a user