From 4d87f0e9e076c8739580214bd7e0f62af251286a Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 6 Oct 2016 12:00:01 +0200 Subject: [PATCH] phaser: instantiate jesd204b core, wire up --- README_PHASER.rst | 2 +- artiq/coredevice/ad9154.py | 29 ++++++++ artiq/examples/phaser/device_db.pyon | 14 +--- artiq/examples/phaser/startup_kernel.py | 98 +++++++++++++++---------- artiq/gateware/targets/kc705.py | 79 +++++++++++++------- artiq/runtime/ad9154.c | 15 ++++ artiq/runtime/ad9154.h | 4 + artiq/runtime/ksupport.c | 3 + doc/manual/core_device.rst | 4 +- 9 files changed, 167 insertions(+), 81 deletions(-) diff --git a/README_PHASER.rst b/README_PHASER.rst index 780d17320..9bd637b86 100644 --- a/README_PHASER.rst +++ b/README_PHASER.rst @@ -27,7 +27,7 @@ The additions and modifications to ARTIQ that were implemented for this project * In ARTIQ, the SAWG and Phaser code: https://github.com/m-labs/artiq/compare/phaser * The CORDIC core has been reused from the PDQ2 gateware https://github.com/m-labs/pdq2 -* The Migen/MiSoC JESD204B core: https://github.com/m-labs/jesd204 +* The Migen/MiSoC JESD204B core: https://github.com/m-labs/jesd204b Installation diff --git a/artiq/coredevice/ad9154.py b/artiq/coredevice/ad9154.py index d13fb4a2e..09612f944 100644 --- a/artiq/coredevice/ad9154.py +++ b/artiq/coredevice/ad9154.py @@ -27,6 +27,21 @@ def ad9516_read(addr: TInt32) -> TInt32: raise NotImplementedError("syscall not simulated") +@syscall(flags={"nounwind", "nowrite"}) +def jesd_enable(en: TInt32) -> TNone: + raise NotImplementedError("syscall not simulated") + + +@syscall(flags={"nounwind", "nowrite"}) +def jesd_ready() -> TInt32: + raise NotImplementedError("syscall not simulated") + + +@syscall(flags={"nounwind", "nowrite"}) +def jesd_prbs(prbs: TInt32) -> TNone: + raise NotImplementedError("syscall not simulated") + + class AD9154: """AD9154-FMC-EBZ SPI support @@ -66,3 +81,17 @@ class AD9154: def clock_read(self, addr): """Read AD9516 SPI register at `addr`.""" return ad9516_read(addr) + + @kernel + def jesd_enable(self, en): + """Enables the JESD204B core startup sequence.""" + jesd_enable(en) + + @kernel + def jesd_ready(self): + """Returns `True` if the JESD links are up.""" + return jesd_ready() + + @kernel + def jesd_prbs(self, prbs): + jesd_prbs(prbs) diff --git a/artiq/examples/phaser/device_db.pyon b/artiq/examples/phaser/device_db.pyon index c9bfe06f5..f1b441921 100644 --- a/artiq/examples/phaser/device_db.pyon +++ b/artiq/examples/phaser/device_db.pyon @@ -44,34 +44,28 @@ "class": "TTLInOut", "arguments": {"channel": 2} }, - "sync": { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLInOut", - "arguments": {"channel": 3} - }, "sawg0": { "type": "local", "module": "artiq.coredevice.sawg", "class": "SAWG", - "arguments": {"channel_base": 4, "parallelism": 4} + "arguments": {"channel_base": 3, "parallelism": 4} }, "sawg1": { "type": "local", "module": "artiq.coredevice.sawg", "class": "SAWG", - "arguments": {"channel_base": 7, "parallelism": 4} + "arguments": {"channel_base": 6, "parallelism": 4} }, "sawg2": { "type": "local", "module": "artiq.coredevice.sawg", "class": "SAWG", - "arguments": {"channel_base": 10, "parallelism": 4} + "arguments": {"channel_base": 9, "parallelism": 4} }, "sawg3": { "type": "local", "module": "artiq.coredevice.sawg", "class": "SAWG", - "arguments": {"channel_base": 13, "parallelism": 4} + "arguments": {"channel_base": 12, "parallelism": 4} } } diff --git a/artiq/examples/phaser/startup_kernel.py b/artiq/examples/phaser/startup_kernel.py index 76c8a6816..5b1821b17 100644 --- a/artiq/examples/phaser/startup_kernel.py +++ b/artiq/examples/phaser/startup_kernel.py @@ -1,7 +1,33 @@ +from jesd204b.common import (JESD204BPhysicalSettings, + JESD204BTransportSettings, + JESD204BSettings) from artiq.experiment import * from artiq.coredevice.ad9516_reg import * from artiq.coredevice.ad9154_reg import * +# ad9154 mode 2: +ps = JESD204BPhysicalSettings( + l=4, # lanes + m=4, # converters + n=16, # bits/converter + np=16, # bits/sample + sc=250*1e6, # data clock, unused: FIXME +) +ts = JESD204BTransportSettings( + f=2, # octets/(lane and frame) + s=1, # samples/(converter and frame) + k=16, # frames/multiframe + cs=1, # +) +jesd_settings = JESD204BSettings(ps, ts, did=0x5a, bid=0x5) +jesd_checksum = jesd_settings.get_configuration_data()[-1] +jesd_data_freq = 250e6 +jesd_linerate = 5e9 +# external clk=2000MHz +# pclock=250MHz +# deviceclock_fpga=500MHz +# deviceclock_dac=2000MHz + class StartupKernel(EnvExperiment): def build(self): @@ -11,26 +37,16 @@ class StartupKernel(EnvExperiment): @kernel def run(self): - # ad9154 mode 2: - # M=4 converters - # L=4 lanes - # S=1 samples/converter and /frame - # F=2 octets/lane and /frame - # K=16 frames/multiframe (or 32) - # HD=0 high density - # N=16 bits/converter - # NB=16 bits/sample - # - # external clk=2000MHz - # pclock=250MHz - # fdata=500MHz - # fline=10GHz - # deviceclock_fpga=500MHz - # deviceclock_dac=2000MHz self.core.reset() + self.ad9154.jesd_enable(0) self.ad9154.init() self.clock_setup() self.dac_setup() + self.ad9154.jesd_prbs(0) + t = now_mu() + seconds_to_mu(.1*s) + while self.core.get_rtio_counter_mu() < t: + pass + self.ad9154.jesd_enable(1) @kernel def clock_setup(self): @@ -123,7 +139,7 @@ class StartupKernel(EnvExperiment): self.ad9154.dac_write(AD9154_SPI_PAGEINDX, 0x3) # A and B dual - self.ad9154.dac_write(AD9154_INTERP_MODE, 3) # 4x + self.ad9154.dac_write(AD9154_INTERP_MODE, 4) # 8x self.ad9154.dac_write(AD9154_MIX_MODE, 0) self.ad9154.dac_write(AD9154_DATA_FORMAT, AD9154_BINARY_FORMAT_SET(0)) # s16 self.ad9154.dac_write(AD9154_DATAPATH_CTRL, @@ -160,24 +176,28 @@ class StartupKernel(EnvExperiment): self.ad9154.dac_write(AD9154_GENERAL_JRX_CTRL_0, AD9154_LINK_EN_SET(0x0) | AD9154_LINK_PAGE_SET(0) | AD9154_LINK_MODE_SET(0) | AD9154_CHECKSUM_MODE_SET(0)) - self.ad9154.dac_write(AD9154_ILS_DID, 0x00) # device id - self.ad9154.dac_write(AD9154_ILS_BID, 0x00) # band id + self.ad9154.dac_write(AD9154_ILS_DID, jesd_settings.did) + self.ad9154.dac_write(AD9154_ILS_BID, jesd_settings.bid) self.ad9154.dac_write(AD9154_ILS_LID0, 0x00) # lane id - self.ad9154.dac_write(AD9154_ILS_SCR_L, AD9154_L_1_SET(4 - 1) | AD9154_SCR_SET(1)) - self.ad9154.dac_write(AD9154_ILS_F, 2 - 1) - self.ad9154.dac_write(AD9154_ILS_K, 16 - 1) - self.ad9154.dac_write(AD9154_ILS_M, 4 - 1) - self.ad9154.dac_write(AD9154_ILS_CS_N, AD9154_N_1_SET(16 - 1) | AD9154_CS_SET(0)) - self.ad9154.dac_write(AD9154_ILS_NP, AD9154_NP_1_SET(16 - 1) | - AD9154_SUBCLASSV_SET(1)) - self.ad9154.dac_write(AD9154_ILS_S, AD9154_S_1_SET(1 - 1) | AD9154_JESDV_SET(1)) - self.ad9154.dac_write(AD9154_ILS_HD_CF, AD9154_HD_SET(0) | AD9154_CF_SET(0)) - self.ad9154.dac_write(AD9154_ILS_CHECKSUM, - 0x00 + 0x00 + 0x00 + 1 + (4 - 1) + # DID BID LID SCR L - (2 - 1) + (16 - 1) + (4 - 1) + (16 - 1) + # F K M N - 1 + (16 - 1) + 1 + (1 - 1) + 0 # SUBC NP JESDV S HD - ) - self.ad9154.dac_write(AD9154_LANEDESKEW, 0xf0) + self.ad9154.dac_write(AD9154_ILS_SCR_L, + AD9154_L_1_SET(jesd_settings.phy.l - 1) | + AD9154_SCR_SET(1)) + self.ad9154.dac_write(AD9154_ILS_F, jesd_settings.transport.f - 1) + self.ad9154.dac_write(AD9154_ILS_K, jesd_settings.transport.k - 1) + self.ad9154.dac_write(AD9154_ILS_M, jesd_settings.phy.m - 1) + self.ad9154.dac_write(AD9154_ILS_CS_N, + AD9154_N_1_SET(jesd_settings.phy.n - 1) | + AD9154_CS_SET(0)) + self.ad9154.dac_write(AD9154_ILS_NP, + AD9154_NP_1_SET(jesd_settings.phy.np - 1) | + AD9154_SUBCLASSV_SET(jesd_settings.phy.subclassv)) + self.ad9154.dac_write(AD9154_ILS_S, + AD9154_S_1_SET(jesd_settings.transport.s - 1) | + AD9154_JESDV_SET(jesd_settings.phy.jesdv)) + self.ad9154.dac_write(AD9154_ILS_HD_CF, + AD9154_HD_SET(0) | AD9154_CF_SET(0)) + self.ad9154.dac_write(AD9154_ILS_CHECKSUM, jesd_checksum) + self.ad9154.dac_write(AD9154_LANEDESKEW, 0x0f) for i in range(8): self.ad9154.dac_write(AD9154_BADDISPARITY, AD9154_RST_IRQ_DIS_SET(0) | AD9154_DISABLE_ERR_CNTR_DIS_SET(0) | @@ -197,22 +217,22 @@ class StartupKernel(EnvExperiment): self.ad9154.dac_write(AD9154_BADDISPARITY, AD9154_RST_IRQ_UCC_SET(0) | AD9154_DISABLE_ERR_CNTR_UCC_SET(0) | AD9154_RST_ERR_CNTR_UCC_SET(0) | AD9154_LANE_ADDR_UCC_SET(i)) - self.ad9154.dac_write(AD9154_CTRLREG1, 2) # F + self.ad9154.dac_write(AD9154_CTRLREG1, jesd_settings.transport.f) self.ad9154.dac_write(AD9154_CTRLREG2, AD9154_ILAS_MODE_SET(0) | AD9154_THRESHOLD_MASK_EN_SET(0)) - self.ad9154.dac_write(AD9154_KVAL, 1) # 4*K multiframes during ILAS - self.ad9154.dac_write(AD9154_LANEENABLE, 0xf0) + self.ad9154.dac_write(AD9154_KVAL, 1) # *4*K multiframes during ILAS + self.ad9154.dac_write(AD9154_LANEENABLE, 0x0f) self.ad9154.dac_write(AD9154_TERM_BLK1_CTRLREG0, 1) self.ad9154.dac_write(AD9154_TERM_BLK2_CTRLREG0, 1) self.ad9154.dac_write(AD9154_SERDES_SPI_REG, 1) self.ad9154.dac_write(AD9154_CDR_OPERATING_MODE_REG_0, AD9154_CDR_OVERSAMP_SET(0) | AD9154_CDR_RESERVED_SET(0x2) | - AD9154_ENHALFRATE_SET(1)) + AD9154_ENHALFRATE_SET(0)) self.ad9154.dac_write(AD9154_CDR_RESET, 0) self.ad9154.dac_write(AD9154_CDR_RESET, 1) self.ad9154.dac_write(AD9154_REF_CLK_DIVIDER_LDO, - AD9154_SPI_CDR_OVERSAMP_SET(0x0) | + AD9154_SPI_CDR_OVERSAMP_SET(0x1) | AD9154_SPI_LDO_BYPASS_FILT_SET(1) | AD9154_SPI_LDO_REF_SEL_SET(0)) self.ad9154.dac_write(AD9154_LDO_FILTER_1, 0x62) # magic diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index 9bb439232..2ca5ba001 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -11,6 +11,13 @@ from migen.build.xilinx.ise import XilinxISEToolchain from migen.fhdl.specials import Keep from migen.genlib.io import DifferentialInput +from jesd204b.common import (JESD204BTransportSettings, + JESD204BPhysicalSettings, + JESD204BSettings) +from jesd204b.phy import JESD204BPhyTX +from jesd204b.core import JESD204BCoreTX +from jesd204b.core import JESD204BCoreTXControl + from misoc.interconnect.csr import * from misoc.interconnect import wishbone from misoc.cores import gpio @@ -395,13 +402,12 @@ class _PhaserCRG(Module, AutoCSR): refclk_pads = platform.request("ad9154_refclk") platform.add_period_constraint(refclk_pads.p, 2.) - refclk = Signal() - refclk = Signal() + self.refclk = Signal() self.clock_domains.cd_refclk = ClockDomain() self.specials += [ Instance("IBUFDS_GTE2", i_CEB=0, - i_I=refclk_pads.p, i_IB=refclk_pads.n, o_O=refclk), - Instance("BUFG", i_I=refclk, o_O=self.cd_refclk.clk), + i_I=refclk_pads.p, i_IB=refclk_pads.n, o_O=self.refclk), + Instance("BUFG", i_I=self.refclk, o_O=self.cd_refclk.clk), ] pll_locked = Signal() @@ -436,7 +442,10 @@ class _PhaserCRG(Module, AutoCSR): class Phaser(_NIST_Ions): - mem_map = {"ad9154_spi": 0x18000000} + mem_map = { + "ad9154_spi": 0x50000000, + "jesd_control": 0x40000000, + } mem_map.update(_NIST_Ions.mem_map) def __init__(self, cpu_type="or1k", **kwargs): @@ -446,16 +455,6 @@ class Phaser(_NIST_Ions): platform.add_extension(phaser.fmc_adapter_io) sysref_pads = platform.request("ad9154_sysref") - #sysref = Signal() - #self.specials += DifferentialInput( - # sysref_pads.p, sysref_pads.n, sysref) - sync_pads = platform.request("ad9154_sync") - #sync = Signal() - #self.specials += DifferentialInput( - # sync_pads.p, sync_pads.n, sync) - - #for i in range(4): - # jesd_pads = platform.request("ad9154_jesd", i) rtio_channels = [] @@ -473,11 +472,6 @@ class Phaser(_NIST_Ions): rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=32, ofifo_depth=2)) - phy = ttl_serdes_7series.Input_8X(sync_pads.p, sync_pads.n) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=32, - ofifo_depth=2)) - self.config["RTIO_REGULAR_TTL_COUNT"] = len(rtio_channels) ad9154_spi = self.platform.request("ad9154_spi") @@ -495,14 +489,6 @@ class Phaser(_NIST_Ions): sawgs = [sawg.Channel(width=16, parallelism=4) for i in range(4)] self.submodules += sawgs - # TODO: dummy, hookup jesd204b phy here - o = Signal((16, True)) - for ch in sawgs: # gather up dangling outputs - for oi in ch.o: - o0, o = o, Signal.like(o) - self.sync += o.eq(o0 + oi) - self.sync.rio_phy += platform.request("user_led").eq(o[-1]) - rtio_channels.extend(rtio.Channel.from_phy(phy) for sawg in sawgs for phy in sawg.phys) @@ -511,6 +497,43 @@ class Phaser(_NIST_Ions): rtio_channels.append(rtio.LogChannel()) self.add_rtio(rtio_channels, _PhaserCRG) + # jesd_sysref = Signal() + # self.specials += DifferentialInput( + # sysref_pads.p, sysref_pads.n, jesd_sysref) + sync_pads = platform.request("ad9154_sync") + jesd_sync = Signal() + self.specials += DifferentialInput( + sync_pads.p, sync_pads.n, jesd_sync) + + ps = JESD204BPhysicalSettings(l=4, m=4, n=16, np=16, sc=250*1e6) + ts = JESD204BTransportSettings(f=2, s=1, k=16, cs=1) + jesd_settings = JESD204BSettings(ps, ts, did=0x5a, bid=0x5) + jesd_linerate = 5e9 + jesd_refclk_freq = 500e6 + rtio_freq = 125*1000*1000 + jesd_phys = [JESD204BPhyTX( + self.rtio_crg.refclk, jesd_refclk_freq, + platform.request("ad9154_jesd", i), + jesd_linerate, rtio_freq, i) for i in range(4)] + self.submodules += jesd_phys + for jesd_phy in jesd_phys: + platform.add_period_constraint( + jesd_phy.gtx.cd_tx.clk, + 40/jesd_linerate*1e9) + self.platform.add_false_path_constraints( + self.rtio_crg.cd_rtio.clk, + jesd_phy.gtx.cd_tx.clk) + self.submodules.jesd_core = JESD204BCoreTX( + jesd_phys, jesd_settings, converter_data_width=32) + self.comb += self.jesd_core.start.eq(jesd_sync) + self.submodules.jesd_control = JESD204BCoreTXControl(self.jesd_core) + self.register_kernel_cpu_csrdevice("jesd_control") + for i, ch in enumerate(sawgs): + conv = getattr(self.jesd_core.transport.sink, + "converter{}".format(i)) + # while at 5 GBps, take every second sample... FIXME + self.comb += conv.eq(Cat(ch.o[::2])) + def main(): parser = argparse.ArgumentParser( diff --git a/artiq/runtime/ad9154.c b/artiq/runtime/ad9154.c index c646b72be..83a00a614 100644 --- a/artiq/runtime/ad9154.c +++ b/artiq/runtime/ad9154.c @@ -54,4 +54,19 @@ uint8_t ad9516_read(uint16_t addr) return ad9154_spi_data_read_read(); } +void jesd_enable(int en) +{ + jesd_control_enable_write(en); +} + +int jesd_ready(void) +{ + return jesd_control_ready_read(); +} + +void jesd_prbs(int p) +{ + jesd_control_prbs_config_write(p); +} + #endif /* CONFIG_AD9154_DAC_CS */ diff --git a/artiq/runtime/ad9154.h b/artiq/runtime/ad9154.h index 3db7ea633..66041c89a 100644 --- a/artiq/runtime/ad9154.h +++ b/artiq/runtime/ad9154.h @@ -10,5 +10,9 @@ uint8_t ad9154_read(uint16_t addr); void ad9516_write(uint16_t addr, uint8_t data); uint8_t ad9516_read(uint16_t addr); +void jesd_enable(int en); +int jesd_ready(void); +void jesd_prbs(int p); + #endif #endif diff --git a/artiq/runtime/ksupport.c b/artiq/runtime/ksupport.c index 1c24e6f84..acd6df595 100644 --- a/artiq/runtime/ksupport.c +++ b/artiq/runtime/ksupport.c @@ -144,6 +144,9 @@ static const struct symbol runtime_exports[] = { {"ad9154_read", &ad9154_read}, {"ad9516_write", &ad9516_write}, {"ad9516_read", &ad9516_read}, + {"jesd_enable", &jesd_enable}, + {"jesd_ready", &jesd_ready}, + {"jesd_prbs", &jesd_prbs}, #endif /* end */ diff --git a/doc/manual/core_device.rst b/doc/manual/core_device.rst index 389e11fa4..7f48d719a 100644 --- a/doc/manual/core_device.rst +++ b/doc/manual/core_device.rst @@ -170,10 +170,8 @@ The Phaser adapter is an AD9154-FMC-EBZ, a 4 channel 2.4 GHz DAC on an FMC HPC c +--------------+------------+--------------+ | 2 | SYSREF | Input | +--------------+------------+--------------+ -| 3 | SYNC | Input | -+--------------+------------+--------------+ -The SAWG channels start with RTIO channel number 4, each occupying 3 channels. +The SAWG channels start with RTIO channel number 3, each occupying 3 channels. The board has one non-RTIO SPI bus that is accessible through :mod:`artiq.coredevice.ad9154`.