forked from M-Labs/artiq
1
0
Fork 0

soc: support QC2 and AD9914 (untested)

This commit is contained in:
Sebastien Bourdeauducq 2015-06-28 21:37:27 +02:00
parent b6310b72db
commit 944bfafefa
6 changed files with 130 additions and 66 deletions

View File

@ -6,15 +6,14 @@ from migen.bus.transactions import *
from migen.sim.generic import run_simulation from migen.sim.generic import run_simulation
class AD9858(Module): class AD9xxx(Module):
"""Wishbone interface to the AD9858 DDS chip. """Wishbone interface to the AD9858 and AD9914 DDS chips.
Addresses 0-63 map the AD9858 registers. Addresses 0-2**flen(pads.a)-1 map the AD9xxx registers.
Data is zero-padded.
Write to address 64 to pulse the FUD signal. Write to address 2**flen(pads.a) to pulse the FUD signal.
Address 65 is a GPIO register that controls the sel, p and reset signals. Address 2**flen(pads.a)+1 is a GPIO register that controls the
sel is mapped to the lower bits, followed by p and reset. sel and reset signals. sel is mapped to the lower bits, followed by reset.
Write timing: Write timing:
Address is set one cycle before assertion of we_n. Address is set one cycle before assertion of we_n.
@ -28,6 +27,7 @@ class AD9858(Module):
Design: Design:
All IO pads are registered. All IO pads are registered.
With QC1 adapter:
LVDS driver/receiver propagation delays are 3.6+4.5 ns max LVDS driver/receiver propagation delays are 3.6+4.5 ns max
LVDS state transition delays are 20, 15 ns max LVDS state transition delays are 20, 15 ns max
Schmitt trigger delays are 6.4ns max Schmitt trigger delays are 6.4ns max
@ -38,15 +38,15 @@ class AD9858(Module):
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:
bus = wishbone.Interface(data_width=8) bus = wishbone.Interface(data_width=flen(pads.d))
self.bus = bus self.bus = bus
# # # # # #
dts = TSTriple(8) dts = TSTriple(flen(pads.d))
self.specials += dts.get_tristate(pads.d) self.specials += dts.get_tristate(pads.d)
hold_address = Signal() hold_address = Signal()
dr = Signal(8) dr = Signal(flen(pads.d))
rx = Signal() rx = Signal()
self.sync += [ self.sync += [
If(~hold_address, pads.a.eq(bus.adr)), If(~hold_address, pads.a.eq(bus.adr)),
@ -55,13 +55,14 @@ class AD9858(Module):
dts.oe.eq(~rx) dts.oe.eq(~rx)
] ]
gpio = Signal(flen(pads.sel) + flen(pads.p) + 1) gpio = Signal(flen(pads.sel) + 1)
gpio_load = Signal() gpio_load = Signal()
self.sync += If(gpio_load, gpio.eq(bus.dat_w)) self.sync += If(gpio_load, gpio.eq(bus.dat_w))
self.comb += [ self.comb += pads.sel.eq(gpio),
Cat(pads.sel, pads.p).eq(gpio), if hasattr(pads, "rst"):
pads.rst_n.eq(~gpio[-1]), self.comb += pads.rst.eq(gpio[-1])
] else:
self.comb += pads.rst_n.eq(~gpio[-1])
bus_r_gpio = Signal() bus_r_gpio = Signal()
self.comb += If(bus_r_gpio, self.comb += If(bus_r_gpio,
@ -71,6 +72,9 @@ class AD9858(Module):
) )
fud = Signal() fud = Signal()
if hasattr(pads, "fud"):
self.sync += pads.fud.eq(fud)
else:
self.sync += pads.fud_n.eq(~fud) self.sync += pads.fud_n.eq(~fud)
pads.wr_n.reset = 1 pads.wr_n.reset = 1
@ -87,7 +91,7 @@ class AD9858(Module):
fsm.act("IDLE", fsm.act("IDLE",
If(bus.cyc & bus.stb, If(bus.cyc & bus.stb,
If(bus.adr[6], If(bus.adr[flen(pads.a)],
If(bus.adr[0], If(bus.adr[0],
NextState("GPIO") NextState("GPIO")
).Else( ).Else(
@ -168,7 +172,6 @@ class _TestPads:
self.a = Signal(6) self.a = Signal(6)
self.d = Signal(8) self.d = Signal(8)
self.sel = Signal(5) self.sel = Signal(5)
self.p = Signal(2)
self.fud_n = Signal() self.fud_n = Signal()
self.wr_n = Signal() self.wr_n = Signal()
self.rd_n = Signal() self.rd_n = Signal()
@ -178,11 +181,11 @@ class _TestPads:
class _TB(Module): class _TB(Module):
def __init__(self): def __init__(self):
pads = _TestPads() 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.initiator = wishbone.Initiator(_test_gen())
self.submodules.interconnect = wishbone.InterconnectPointToPoint( self.submodules.interconnect = wishbone.InterconnectPointToPoint(
self.initiator.bus, self.dut.bus) self.initiator.bus, self.dut.bus)
if __name__ == "__main__": if __name__ == "__main__":
run_simulation(_TB(), vcd_name="ad9858.vcd") run_simulation(_TB(), vcd_name="ad9xxx.vcd")

View File

@ -1,5 +1,6 @@
from mibuild.generic_platform import * from mibuild.generic_platform import *
fmc_adapter_io = [ fmc_adapter_io = [
("ttl", 0, Pins("LPC:LA00_CC_P"), IOStandard("LVTTL")), ("ttl", 0, Pins("LPC:LA00_CC_P"), IOStandard("LVTTL")),
("ttl", 1, Pins("LPC:LA02_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 " 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:LA28_N LPC:LA31_P LPC:LA30_P LPC:LA31_N "
"LPC:LA30_N LPC:LA33_P LPC:LA33_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("wr_n", Pins("LPC:LA24_P")),
Subsignal("rd_n", Pins("LPC:LA25_N")), Subsignal("rd_n", Pins("LPC:LA25_N")),
Subsignal("rst_in", Pins("LPC:LA25_P")), Subsignal("rst", Pins("LPC:LA25_P")),
IOStandard("LVTTL")), IOStandard("LVTTL")),
("i2c", 0, ("i2c", 0,

View File

@ -1,14 +1,14 @@
from migen.fhdl.std import * 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 from artiq.gateware.rtio.phy.wishbone import RT2WB
class AD9858(Module): class _AD9xxx(Module):
def __init__(self, pads, nchannels=8, **kwargs): def __init__(self, ftw_base, pads, nchannels, **kwargs):
self.submodules._ll = RenameClockDomains( self.submodules._ll = RenameClockDomains(
ad9858_ll.AD9858(pads, **kwargs), "rio") ad9xxx.AD9xxx(pads, **kwargs), "rio")
self.submodules._rt2wb = RT2WB(7, self._ll.bus) self.submodules._rt2wb = RT2WB(flen(pads.a)+1, self._ll.bus)
self.rtlink = self._rt2wb.rtlink self.rtlink = self._rt2wb.rtlink
self.probes = [Signal(32) for i in range(nchannels)] self.probes = [Signal(32) for i in range(nchannels)]
@ -16,21 +16,44 @@ class AD9858(Module):
# keep track of the currently selected channel # keep track of the currently selected channel
current_channel = Signal(max=nchannels) current_channel = Signal(max=nchannels)
self.sync.rio += If(self.rtlink.o.stb & (self.rtlink.o.address == 65), self.sync.rio += If(self.rtlink.o.stb &
(self.rtlink.o.address == 2**flen(pads.a)+1),
current_channel.eq(self.rtlink.o.data)) current_channel.eq(self.rtlink.o.data))
# keep track of frequency tuning words, before they are FUDed # keep track of frequency tuning words, before they are FUDed
ftws = [Signal(32) for i in range(nchannels)] ftws = [Signal(32) for i in range(nchannels)]
for c, ftw in enumerate(ftws): for c, ftw in enumerate(ftws):
if flen(pads.d) == 8:
for i in range(4): for i in range(4):
self.sync.rio += \ self.sync.rio += \
If(self.rtlink.o.stb & \ If(self.rtlink.o.stb & \
(self.rtlink.o.address == 0x0a+i) & \ (self.rtlink.o.address == ftw_base+i) & \
(current_channel == c), (current_channel == c),
ftw[i*8:(i+1)*8].eq(self.rtlink.o.data) 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 # FTW to probe on FUD
for c, (probe, ftw) in enumerate(zip(self.probes, ftws)): 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)) 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)

View File

@ -40,7 +40,7 @@ void dds_init(long long int timestamp, int channel)
now = timestamp - DURATION_INIT; now = timestamp - DURATION_INIT;
DDS_WRITE(DDS_GPIO, channel); 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(DDS_GPIO, channel);
DDS_WRITE(0x00, 0x78); DDS_WRITE(0x00, 0x78);

View File

@ -10,7 +10,7 @@ from misoclib.mem.sdram.core.minicon import MiniconSettings
from targets.kc705 import MiniSoC from targets.kc705 import MiniSoC
from artiq.gateware.soc import AMPSoC 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 from artiq.gateware.rtio.phy import ttl_simple, dds
@ -32,7 +32,7 @@ class _RTIOCRG(Module, AutoCSR):
o_O=self.cd_rtio.clk) o_O=self.cd_rtio.clk)
class NIST_QC1(MiniSoC, AMPSoC): class _NIST_QCx(MiniSoC, AMPSoC):
csr_map = { csr_map = {
"rtio": None, # mapped on Wishbone instead "rtio": None, # mapped on Wishbone instead
"rtio_crg": 13, "rtio_crg": 13,
@ -52,18 +52,44 @@ class NIST_QC1(MiniSoC, AMPSoC):
sdram_controller_settings=MiniconSettings(l2_size=128*1024), sdram_controller_settings=MiniconSettings(l2_size=128*1024),
with_timer=False, **kwargs) with_timer=False, **kwargs)
AMPSoC.__init__(self) AMPSoC.__init__(self)
platform.add_extension(nist_qc1.fmc_adapter_io)
self.submodules.leds = gpio.GPIOOut(Cat( self.submodules.leds = gpio.GPIOOut(Cat(
platform.request("user_led", 0), platform.request("user_led", 0),
platform.request("user_led", 1))) 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 += [ self.comb += [
platform.request("ttl_l_tx_en").eq(1), platform.request("ttl_l_tx_en").eq(1),
platform.request("ttl_h_tx_en").eq(1) platform.request("ttl_h_tx_en").eq(1)
] ]
# RTIO channels
rtio_channels = [] rtio_channels = []
for i in range(2): for i in range(2):
phy = ttl_simple.Inout(platform.request("pmt", i)) 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("RTIO_DDS_CHANNEL", len(rtio_channels))
self.add_constant("DDS_CHANNEL_COUNT", 8) 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 self.submodules += phy
rtio_channels.append(rtio.Channel.from_phy(phy, rtio_channels.append(rtio.Channel.from_phy(phy,
ofifo_depth=512, ofifo_depth=512,
ififo_depth=4)) 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): class NIST_QC2(_NIST_QCx):
platform.add_platform_command(""" def __init__(self, platform, cpu_type="or1k", **kwargs):
create_clock -name rsys_clk -period 8.0 [get_nets {rsys_clk}] _NIST_QCx.__init__(self, platform, cpu_type, **kwargs)
create_clock -name rio_clk -period 8.0 [get_nets {rio_clk}] platform.add_extension(nist_qc2.fmc_adapter_io)
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)
# CPU connections rtio_channels = []
rtio_csrs = self.rtio.get_csrs() for i in range(16):
self.submodules.rtiowb = wbgen.Bank(rtio_csrs) if i % 4 == 3:
self.kernel_cpu.add_wb_slave(mem_decoder(self.mem_map["rtio"]), phy = ttl_simple.Inout(platform.request("ttl", i))
self.rtiowb.bus) self.submodules += phy
self.add_csr_region("rtio", self.mem_map["rtio"] | 0x80000000, 32, rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=512))
rtio_csrs) 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 default_subtarget = NIST_QC1

View File

@ -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("RTIO_DDS_CHANNEL", len(rtio_channels))
self.add_constant("DDS_CHANNEL_COUNT", 8) self.add_constant("DDS_CHANNEL_COUNT", 8)
phy = dds.AD9858(platform.request("dds")) phy = dds.AD9858(platform.request("dds"), 8)
self.submodules += phy self.submodules += phy
rtio_channels.append(rtio.Channel.from_phy(phy, rtio_channels.append(rtio.Channel.from_phy(phy,
ofifo_depth=512, ofifo_depth=512,