diff --git a/artiq/gateware/drtio/wrpll/__init__.py b/artiq/gateware/drtio/wrpll/__init__.py index d004bc955..25e510f4c 100644 --- a/artiq/gateware/drtio/wrpll/__init__.py +++ b/artiq/gateware/drtio/wrpll/__init__.py @@ -1 +1,2 @@ from artiq.gateware.drtio.wrpll.core import WRPLL +from artiq.gateware.drtio.wrpll.ddmtd import DDMTDSamplerExtFF, DDMTDSamplerGTP diff --git a/artiq/gateware/drtio/wrpll/core.py b/artiq/gateware/drtio/wrpll/core.py index 6465c004b..81527ae58 100644 --- a/artiq/gateware/drtio/wrpll/core.py +++ b/artiq/gateware/drtio/wrpll/core.py @@ -23,19 +23,5 @@ class WRPLL(Module, AutoCSR): ddmtd_counter = Signal(N) self.sync.helper += ddmtd_counter.eq(ddmtd_counter + 1) - if hasattr(ddmtd_inputs, "rec_clk"): - ddmtd_input_rec_clk = ddmtd_inputs.rec_clk - else: - ddmtd_input_rec_clk = Signal() - self.specials += Instance("IBUFDS", - i_I=ddmtd_inputs.rec_clk_p, i_IB=ddmtd_inputs.rec_clk_n, - o_O=ddmtd_input_rec_clk) - if hasattr(ddmtd_inputs, "main_xo"): - ddmtd_input_main_xo = ddmtd_inputs.main_xo - else: - ddmtd_input_main_xo = Signal() - self.specials += Instance("IBUFDS", - i_I=ddmtd_inputs.main_xo_p, i_IB=ddmtd_inputs.main_xo_n, - o_O=ddmtd_input_main_xo) - self.submodules.ddmtd_helper = DDMTD(ddmtd_counter, ddmtd_input_rec_clk) - self.submodules.ddmtd_main = DDMTD(ddmtd_counter, ddmtd_input_main_xo) + self.submodules.ddmtd_helper = DDMTD(ddmtd_counter, ddmtd_inputs.rec_clk) + self.submodules.ddmtd_main = DDMTD(ddmtd_counter, ddmtd_inputs.main_xo) diff --git a/artiq/gateware/drtio/wrpll/ddmtd.py b/artiq/gateware/drtio/wrpll/ddmtd.py index d05d0445b..d5a35a70f 100644 --- a/artiq/gateware/drtio/wrpll/ddmtd.py +++ b/artiq/gateware/drtio/wrpll/ddmtd.py @@ -3,6 +3,47 @@ from migen.genlib.cdc import PulseSynchronizer, MultiReg from misoc.interconnect.csr import * +class DDMTDSamplerExtFF(Module): + def __init__(self, ddmtd_inputs): + # TODO: s/h timing at FPGA pads + if hasattr(ddmtd_inputs, "rec_clk"): + self.rec_clk = ddmtd_inputs.rec_clk + else: + self.rec_clk = Signal() + self.specials += Instance("IBUFDS", + i_I=ddmtd_inputs.rec_clk_p, i_IB=ddmtd_inputs.rec_clk_n, + o_O=self.rec_clk) + if hasattr(ddmtd_inputs, "main_xo"): + self.main_xo = ddmtd_inputs.main_xo + else: + self.main_xo = Signal() + self.specials += Instance("IBUFDS", + i_I=ddmtd_inputs.main_xo_p, i_IB=ddmtd_inputs.main_xo_n, + o_O=self.main_xo) + + +class DDMTDSamplerGTP(Module): + def __init__(self, gtp, main_xo_pads): + self.rec_clk = Signal() + self.main_xo = Signal() + + # Getting this signal from IBUFDS_GTE2 is problematic because: + # 1. the clock gets divided by 2 + # 2. the transceiver PLL craps out if an improper clock signal is applied, + # so we are disabling the buffer until the clock is stable. + # 3. UG482 says "The O and ODIV2 outputs are not phase matched to each other", + # which may or may not be a problem depending on what it actually means. + main_xo_se = Signal() + self.specials += Instance("IBUFDS", + i_I=main_xo_pads.p, i_IB=main_xo_pads.n, + o_O=main_xo_se) + + self.sync.helper += [ + self.rec_clk.eq(gtp.cd_rtio_rx0.clk), + self.main_xo.eq(main_xo_se) + ] + + class DDMTDEdgeDetector(Module): def __init__(self, input_signal): self.rising = Signal() diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 6cb234f51..d90142cbc 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -19,7 +19,7 @@ from artiq.gateware import jesd204_tools from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_ultrascale, sawg from artiq.gateware.drtio.transceiver import gth_ultrascale from artiq.gateware.drtio.siphaser import SiPhaser7Series -from artiq.gateware.drtio.wrpll import WRPLL +from artiq.gateware.drtio.wrpll import WRPLL, DDMTDSamplerExtFF from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer from artiq.gateware.drtio import * from artiq.build_soc import * @@ -136,11 +136,13 @@ class SatelliteBase(MiniSoC): platform.request("ddmtd_main_dcxo_oe").eq(1), platform.request("ddmtd_helper_dcxo_oe").eq(1) ] + self.submodules.wrpll_sampler = DDMTDSamplerExtFF( + platform.request("ddmtd_inputs")) self.submodules.wrpll = WRPLL( helper_clk_pads=platform.request("ddmtd_helper_clk"), main_dcxo_i2c=platform.request("ddmtd_main_dcxo_i2c"), helper_dxco_i2c=platform.request("ddmtd_helper_dcxo_i2c"), - ddmtd_inputs=platform.request("ddmtd_inputs")) + ddmtd_inputs=self.wrpll_sampler) self.csr_devices.append("wrpll") else: self.comb += platform.request("filtered_clk_sel").eq(1) diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index d7dc3d207..29ac40779 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -19,6 +19,7 @@ from artiq.gateware import rtio from artiq.gateware.rtio.phy import ttl_serdes_7series from artiq.gateware.drtio.transceiver import gtp_7series from artiq.gateware.drtio.siphaser import SiPhaser7Series +from artiq.gateware.drtio.wrpll import WRPLL, DDMTDSamplerGTP from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer from artiq.gateware.drtio import * from artiq.build_soc import add_identifier @@ -73,7 +74,7 @@ class _SatelliteBase(BaseSoC): } mem_map.update(BaseSoC.mem_map) - def __init__(self, rtio_clk_freq, **kwargs): + def __init__(self, rtio_clk_freq, *, with_wrpll, **kwargs): BaseSoC.__init__(self, cpu_type="or1k", **kwargs) @@ -132,21 +133,37 @@ class _SatelliteBase(BaseSoC): self.add_memory_group("drtioaux_mem", ["drtioaux0_mem"]) self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) - self.comb += platform.request("filtered_clk_sel").eq(1) - self.submodules.siphaser = SiPhaser7Series( - si5324_clkin=platform.request("si5324_clkin"), - rx_synchronizer=self.rx_synchronizer, - ref_clk=self.crg.cd_sys.clk, ref_div2=True, - rtio_clk_freq=rtio_clk_freq) - platform.add_false_path_constraints( - self.crg.cd_sys.clk, self.siphaser.mmcm_freerun_output) - self.csr_devices.append("siphaser") - i2c = self.platform.request("i2c") - self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda]) - self.csr_devices.append("i2c") - self.config["I2C_BUS_COUNT"] = 1 - self.config["HAS_SI5324"] = None - self.config["SI5324_SOFT_RESET"] = None + if with_wrpll: + self.comb += [ + platform.request("filtered_clk_sel").eq(0), + platform.request("ddmtd_main_dcxo_oe").eq(1), + platform.request("ddmtd_helper_dcxo_oe").eq(1) + ] + self.submodules.wrpll_sampler = DDMTDSamplerGTP( + self.drtio_transceiver, + platform.request("cdr_clk_clean_fabric")) + self.submodules.wrpll = WRPLL( + helper_clk_pads=platform.request("ddmtd_helper_clk"), + main_dcxo_i2c=platform.request("ddmtd_main_dcxo_i2c"), + helper_dxco_i2c=platform.request("ddmtd_helper_dcxo_i2c"), + ddmtd_inputs=self.wrpll_sampler) + self.csr_devices.append("wrpll") + else: + self.comb += platform.request("filtered_clk_sel").eq(1) + self.submodules.siphaser = SiPhaser7Series( + si5324_clkin=platform.request("si5324_clkin"), + rx_synchronizer=self.rx_synchronizer, + ref_clk=self.crg.cd_sys.clk, ref_div2=True, + rtio_clk_freq=rtio_clk_freq) + platform.add_false_path_constraints( + self.crg.cd_sys.clk, self.siphaser.mmcm_freerun_output) + self.csr_devices.append("siphaser") + i2c = self.platform.request("i2c") + self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda]) + self.csr_devices.append("i2c") + self.config["I2C_BUS_COUNT"] = 1 + self.config["HAS_SI5324"] = None + self.config["SI5324_SOFT_RESET"] = None rtio_clk_period = 1e9/rtio_clk_freq gtp = self.drtio_transceiver.gtps[0] @@ -245,10 +262,12 @@ def main(): soc_sayma_rtm_args(parser) parser.add_argument("--rtio-clk-freq", default=150, type=int, help="RTIO clock frequency in MHz") + parser.add_argument("--with-wrpll", default=False, action="store_true") parser.set_defaults(output_dir=os.path.join("artiq_sayma", "rtm")) args = parser.parse_args() - soc = Satellite(rtio_clk_freq=1e6*args.rtio_clk_freq, + soc = Satellite( + rtio_clk_freq=1e6*args.rtio_clk_freq, with_wrpll=args.with_wrpll, **soc_sayma_rtm_argdict(args)) builder = SatmanSoCBuilder(soc, **builder_argdict(args)) try: