From 89150c9817c0006ecf68437688cf4e1889674078 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 13 Oct 2016 21:47:34 +0200 Subject: [PATCH] phaser: 10G line rate --- artiq/examples/phaser/repository/dac_setup.py | 6 +- artiq/examples/phaser/startup_kernel.py | 8 +- artiq/gateware/targets/kc705.py | 159 +++++++++--------- 3 files changed, 89 insertions(+), 84 deletions(-) diff --git a/artiq/examples/phaser/repository/dac_setup.py b/artiq/examples/phaser/repository/dac_setup.py index ced5971c8..ab72829b9 100644 --- a/artiq/examples/phaser/repository/dac_setup.py +++ b/artiq/examples/phaser/repository/dac_setup.py @@ -109,7 +109,7 @@ class DACSetup(EnvExperiment): self.ad9154.dac_write(AD9154_SPI_PAGEINDX, 0x3) # A and B dual - self.ad9154.dac_write(AD9154_INTERP_MODE, 4) # 8x + self.ad9154.dac_write(AD9154_INTERP_MODE, 3) # 4x 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, @@ -198,11 +198,11 @@ class DACSetup(EnvExperiment): 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(0)) + AD9154_ENHALFRATE_SET(1)) 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(0x1) | + AD9154_SPI_CDR_OVERSAMP_SET(0x0) | 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/examples/phaser/startup_kernel.py b/artiq/examples/phaser/startup_kernel.py index 089d49d92..b611eef1a 100644 --- a/artiq/examples/phaser/startup_kernel.py +++ b/artiq/examples/phaser/startup_kernel.py @@ -47,17 +47,17 @@ class StartupKernel(EnvExperiment): self.ad9154.clock_write(AD9516_OUT1, 0*AD9516_OUT1_POWER_DOWN | 2*AD9516_OUT1_LVPECLDIFFERENTIAL_VOLTAGE) - # FPGA deviceclk, dclk/4 + # FPGA deviceclk, dclk/2 self.ad9154.clock_write(AD9516_DIVIDER_4_3, AD9516_DIVIDER_4_BYPASS_2) self.ad9154.clock_write(AD9516_DIVIDER_4_0, - (4//2-1)*AD9516_DIVIDER_0_HIGH_CYCLES | - (4//2-1)*AD9516_DIVIDER_0_LOW_CYCLES) + (2//2-1)*AD9516_DIVIDER_0_HIGH_CYCLES | + (2//2-1)*AD9516_DIVIDER_0_LOW_CYCLES) self.ad9154.clock_write(AD9516_DIVIDER_4_4, 0*AD9516_DIVIDER_4_DCCOFF) self.ad9154.clock_write(AD9516_OUT9, 1*AD9516_OUT9_LVDS_OUTPUT_CURRENT | 2*AD9516_OUT9_LVDS_CMOS_OUTPUT_POLARITY | 0*AD9516_OUT9_SELECT_LVDS_CMOS) - # sysref f_data*S/(K*F), dclk/64 + # sysref f_data*S/(K*F), dclk/32 self.ad9154.clock_write(AD9516_DIVIDER_3_0, (32//2-1)*AD9516_DIVIDER_3_HIGH_CYCLES_1 | (32//2-1)*AD9516_DIVIDER_3_LOW_CYCLES_1) self.ad9154.clock_write(AD9516_DIVIDER_3_1, 0*AD9516_DIVIDER_3_PHASE_OFFSET_1 | diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index 8623f6eba..759f3a229 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -398,19 +398,10 @@ class _PhaserCRG(Module, AutoCSR): self._clock_sel = CSRStorage() self._pll_reset = CSRStorage(reset=1) self._pll_locked = CSRStatus() + self.refclk = Signal() self.clock_domains.cd_rtio = ClockDomain() self.clock_domains.cd_rtiox4 = ClockDomain(reset_less=True) - refclk_pads = platform.request("ad9154_refclk") - platform.add_period_constraint(refclk_pads.p, 8.) - 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=self.refclk), - Instance("BUFG", i_I=self.refclk, o_O=self.cd_refclk.clk), - ] - pll_locked = Signal() rtio_clk = Signal() rtiox4_clk = Signal() @@ -419,13 +410,13 @@ class _PhaserCRG(Module, AutoCSR): p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked, p_REF_JITTER1=0.01, p_REF_JITTER2=0.01, - p_CLKIN1_PERIOD=8.0, p_CLKIN2_PERIOD=8.0, - i_CLKIN1=rtio_internal_clk, i_CLKIN2=self.cd_refclk.clk, + p_CLKIN1_PERIOD=4.0, p_CLKIN2_PERIOD=4.0, + i_CLKIN1=0, i_CLKIN2=self.refclk, # Warning: CLKINSEL=0 means CLKIN2 is selected i_CLKINSEL=~self._clock_sel.storage, # VCO @ 1GHz when using 125MHz input - p_CLKFBOUT_MULT=8, p_DIVCLK_DIVIDE=1, + p_CLKFBOUT_MULT=8, p_DIVCLK_DIVIDE=2, i_CLKFBIN=self.cd_rtio.clk, i_RST=self._pll_reset.storage, @@ -436,70 +427,95 @@ class _PhaserCRG(Module, AutoCSR): ), Instance("BUFG", i_I=rtio_clk, o_O=self.cd_rtio.clk), Instance("BUFG", i_I=rtiox4_clk, o_O=self.cd_rtiox4.clk), - AsyncResetSynchronizer(self.cd_rtio, ~pll_locked), - MultiReg(pll_locked, self._pll_locked.status) + MultiReg(pll_locked | ~self._clock_sel.storage, + self._pll_locked.status) ] -class AD9154(Module, AutoCSR): - def __init__(self, platform, rtio_crg): - ad9154_spi = platform.request("ad9154_spi") - self.submodules.spi = spi_csr.SPIMaster(ad9154_spi) - self.comb += [ - ad9154_spi.en.eq(1), - platform.request("ad9154_txen", 0).eq(1), - platform.request("ad9154_txen", 1).eq(1), - ] - - sync_pads = platform.request("ad9154_sync") - jesd_sync = Signal() - self.specials += DifferentialInput( - sync_pads.p, sync_pads.n, jesd_sync) - self.jesd_sync = jesd_sync - +class AD9154JESD(Module, AutoCSR): + def __init__(self, platform): ps = JESD204BPhysicalSettings(l=4, m=4, n=16, np=16) 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 = 125e6 - rtio_freq = 125*1000*1000 - jesd_qpll = GTXQuadPLL( - rtio_crg.refclk, jesd_refclk_freq, jesd_linerate) - self.submodules += jesd_qpll - jesd_phys = [] + settings = JESD204BSettings(ps, ts, did=0x5a, bid=0x5) + linerate = 10e9 + refclk_freq = 250e6 + fabric_freq = 250*1000*1000 + + sync_pads = platform.request("ad9154_sync") + self.jsync = Signal() + self.refclk = Signal() + self.specials += DifferentialInput( + sync_pads.p, sync_pads.n, self.jsync) + + self.clock_domains.cd_jesd = ClockDomain() + refclk_pads = platform.request("ad9154_refclk") + platform.add_period_constraint(refclk_pads.p, 1e9/refclk_freq) + + self.specials += [ + Instance("IBUFDS_GTE2", i_CEB=0, + i_I=refclk_pads.p, i_IB=refclk_pads.n, o_O=self.refclk), + Instance("BUFR", i_I=self.refclk, o_O=self.cd_jesd.clk), + AsyncResetSynchronizer(self.cd_jesd, ResetSignal("rio_phy")), + ] + + qpll = GTXQuadPLL(self.refclk, refclk_freq, linerate) + self.submodules += qpll + phys = [] for i in range(4): - jesd_phy = JESD204BPhyTX( - jesd_qpll, platform.request("ad9154_jesd", i), - rtio_freq) - platform.add_period_constraint( - jesd_phy.gtx.cd_tx.clk, - 40/jesd_linerate*1e9) + phy = JESD204BPhyTX( + qpll, platform.request("ad9154_jesd", i), fabric_freq) + platform.add_period_constraint(phy.gtx.cd_tx.clk, 40*1e9/linerate) platform.add_false_path_constraints( - rtio_crg.cd_rtio.clk, - jesd_phy.gtx.cd_tx.clk) - jesd_phys.append(jesd_phy) - setattr(self.submodules, "jesd_phy"+str(i), jesd_phy) - self.submodules.jesd_core = JESD204BCoreTX( - jesd_phys, jesd_settings, converter_data_width=32) - self.comb += self.jesd_core.start.eq(jesd_sync) - self.comb += platform.request("user_led", 3).eq(jesd_sync) - self.submodules.jesd_control = JESD204BCoreTXControl(self.jesd_core) + self.cd_jesd.clk, + phy.gtx.cd_tx.clk) + phys.append(phy) + to_jesd = ClockDomainsRenamer("jesd") + self.submodules.core = to_jesd(JESD204BCoreTX(phys, settings, + converter_data_width=32)) + self.submodules.control = to_jesd(JESD204BCoreTXControl(self.core)) + + self.comb += [ + platform.request("ad9154_txen", 0).eq(1), + platform.request("ad9154_txen", 1).eq(1), + self.core.start.eq(self.jsync), + platform.request("user_led", 3).eq(self.jsync), + ] # blinking leds for transceiver reset status for i in range(4): led = platform.request("user_led", 4 + i) - counter = Signal(32) - sync = getattr(self.sync, "phy" + str(i)) + counter = Signal(max=fabric_freq//2 + 1) + sync = getattr(self.sync, "phy{}_tx".format(i)) sync += \ If(counter == 0, led.eq(~led), - counter.eq(rtio_freq//2) + counter.eq(fabric_freq//2) ).Else( - counter.eq(counter-1) + counter.eq(counter - 1) ) +class AD9154(Module, AutoCSR): + def __init__(self, platform): + ad9154_spi = platform.request("ad9154_spi") + self.comb += ad9154_spi.en.eq(1) + + self.submodules.spi = spi_csr.SPIMaster(ad9154_spi) + + self.submodules.jesd = AD9154JESD(platform) + + self.sawgs = [sawg.Channel(width=16, parallelism=4) for i in range(4)] + self.submodules += self.sawgs + + x = Signal() + y = Signal() + self.sync.jesd += x.eq(~x) + self.sync.rio_phy += y.eq(x) + for conv, ch in zip(self.jesd.core.sink.flatten(), self.sawgs): + self.comb += conv.eq(Mux(x != y, Cat(ch.o[:2]), Cat(ch.o[2:]))) + + class Phaser(_NIST_Ions): mem_map = { "ad9154": 0x50000000, @@ -512,7 +528,10 @@ class Phaser(_NIST_Ions): platform = self.platform platform.add_extension(phaser.fmc_adapter_io) - sysref_pads = platform.request("ad9154_sysref") + self.submodules.ad9154 = AD9154(platform) + self.register_kernel_cpu_csrdevice("ad9154") + self.config["AD9154_DAC_CS"] = 1 << 0 + self.config["AD9154_CLK_CS"] = 1 << 1 rtio_channels = [] @@ -525,13 +544,13 @@ class Phaser(_NIST_Ions): self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) + sysref_pads = platform.request("ad9154_sysref") phy = ttl_serdes_7series.Input_8X(sysref_pads.p, sysref_pads.n) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=32, ofifo_depth=2)) - jesd_sync = Signal() - phy = ttl_simple.Input(jesd_sync) + phy = ttl_simple.Input(self.ad9154.jesd.jsync) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=32, ofifo_depth=2)) @@ -539,29 +558,15 @@ class Phaser(_NIST_Ions): self.config["RTIO_REGULAR_TTL_COUNT"] = len(rtio_channels) self.config["RTIO_FIRST_SAWG_CHANNEL"] = len(rtio_channels) - sawgs = [sawg.Channel(width=16, parallelism=4) for i in range(4)] - self.submodules += sawgs - rtio_channels.extend(rtio.Channel.from_phy(phy) - for sawg in sawgs + for sawg in self.ad9154.sawgs for phy in sawg.phys) self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) rtio_channels.append(rtio.LogChannel()) self.add_rtio(rtio_channels, _PhaserCRG(platform, self.crg.cd_sys.clk)) - to_rtio = ClockDomainsRenamer({"sys": "rtio"}) - self.submodules.ad9154 = to_rtio(AD9154(platform, self.rtio_crg)) - self.register_kernel_cpu_csrdevice("ad9154") - self.config["AD9154_DAC_CS"] = 1 << 0 - self.config["AD9154_CLK_CS"] = 1 << 1 - for i, ch in enumerate(sawgs): - conv = getattr(self.ad9154.jesd_core.sink, - "converter{}".format(i)) - # while at 5 GBps, take every second sample... FIXME - self.comb += conv.eq(Cat(ch.o[::2])) - - self.comb += jesd_sync.eq(self.ad9154.jesd_sync) + self.comb += self.rtio_crg.refclk.eq(self.ad9154.jesd.refclk) def main():