diff --git a/artiq/firmware/libboard_artiq/jesd204sync.rs b/artiq/firmware/libboard_artiq/jesd204sync.rs index 062135896..685f61822 100644 --- a/artiq/firmware/libboard_artiq/jesd204sync.rs +++ b/artiq/firmware/libboard_artiq/jesd204sync.rs @@ -1,13 +1,24 @@ -use board_misoc::{csr, config}; +use board_misoc::{csr, clock, config}; use hmc830_7043::hmc7043; use ad9154; +fn sysref_sh_error() -> bool { + unsafe { + csr::sysref_sampler::sh_error_reset_write(1); + clock::spin_us(1); + csr::sysref_sampler::sh_error_reset_write(0); + clock::spin_us(10); + csr::sysref_sampler::sh_error_read() != 0 + } +} + pub fn sysref_auto_rtio_align() -> Result<(), &'static str> { for _ in 0..256 { hmc7043::sysref_slip(); let dt = unsafe { csr::sysref_ddmtd::dt_read() }; - info!("dt={}", dt); + let sh_error = sysref_sh_error(); + info!("dt={} sysref_sh_error={}", dt, sh_error); } Ok(()) } diff --git a/artiq/gateware/jesd204_tools.py b/artiq/gateware/jesd204_tools.py index b029c86c2..b960366b4 100644 --- a/artiq/gateware/jesd204_tools.py +++ b/artiq/gateware/jesd204_tools.py @@ -22,7 +22,6 @@ class UltrascaleCRG(Module, AutoCSR): def __init__(self, platform, use_rtio_clock=False): self.ibuf_disable = CSRStorage(reset=1) self.jreset = CSRStorage(reset=1) - self.jref = Signal() self.refclk = Signal() self.clock_domains.cd_jesd = ClockDomain() @@ -42,23 +41,6 @@ class UltrascaleCRG(Module, AutoCSR): else: self.specials += Instance("BUFG_GT", i_I=refclk2, o_O=self.cd_jesd.clk) - jref = platform.request("dac_sysref") - jref_se = Signal() - jref_r = Signal() - self.specials += [ - Instance("IBUFDS_IBUFDISABLE", - p_USE_IBUFDISABLE="TRUE", p_SIM_DEVICE="ULTRASCALE", - i_IBUFDISABLE=self.ibuf_disable.storage, - i_I=jref.p, i_IB=jref.n, - o_O=jref_se), - # SYSREF normally meets s/h at the FPGA, except during margin - # scan and before full initialization. - # Be paranoid and use a double-register anyway. - Instance("FD", i_C=ClockSignal("jesd"), i_D=jref_se, o_Q=jref_r, - attr={("IOB", "TRUE")}), - Instance("FD", i_C=ClockSignal("jesd"), i_D=jref_r, o_Q=self.jref) - ] - PhyPads = namedtuple("PhyPads", "txp txn") @@ -90,7 +72,6 @@ class UltrascaleTX(Module, AutoCSR): phys, settings, converter_data_width=64) self.submodules.control = JESD204BCoreTXControl(self.core) self.core.register_jsync(platform.request("dac_sync", dac)) - self.core.register_jref(jesd_crg.jref) # See "Digital femtosecond time difference circuit for CERN's timing system" @@ -157,3 +138,60 @@ class DDMTD(Module, AutoCSR): bsync.i.eq(result), self.dt.status.eq(bsync.o) ] + + +# This assumes: +# * coarse RTIO frequency = 16*SYSREF frequency +# * fine RTIO frequency (rtiox) = 2*RTIO frequency +# * JESD and coarse RTIO clocks are the same +# (only reset may differ). +# +# Look at the 4 LSBs of the coarse RTIO timestamp counter +# to determine SYSREF phase. + +class SysrefSampler(Module, AutoCSR): + def __init__(self, sysref_pads, coarse_ts): + self.sh_error = CSRStatus() + self.sh_error_reset = CSRStorage() + self.sample_result = CSRStatus() + + self.jref = Signal() + + # # # + + sysref_se = Signal() + sysref_oversample = Signal(4) + self.specials += [ + Instance("IBUFDS", i_I=sysref_pads.p, i_IB=sysref_pads.n, o_O=sysref_se), + Instance("ISERDESE3", + p_IS_CLK_INVERTED=0, + p_IS_CLK_B_INVERTED=1, + p_DATA_WIDTH=4, + + i_D=sysref_se, + i_RST=ResetSignal("rtio"), + i_FIFO_RD_EN=0, + i_CLK=ClockSignal("rtiox"), + i_CLK_B=ClockSignal("rtiox"), # locally inverted + i_CLKDIV=ClockSignal("rtio"), + o_Q=sysref_oversample) + ] + + self.comb += self.jref.eq(sysref_oversample[1]) + sh_error = Signal() + sh_error_reset = Signal() + self.sync.rtio += [ + If(~( (sysref_oversample[0] == sysref_oversample[1]) + & (sysref_oversample[1] == sysref_oversample[2])), + sh_error.eq(1) + ), + If(sh_error_reset, sh_error.eq(0)) + ] + self.specials += [ + MultiReg(self.sh_error_reset.storage, sh_error_reset, "rtio"), + MultiReg(sh_error, self.sh_error.status) + ] + + sample = Signal() + self.sync.rtio += If(coarse_ts[:4] == 0, sample.eq(self.jref)) + self.specials += MultiReg(sample, self.sample_result.status) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index d82bbcc8e..96e22a7d5 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -114,119 +114,6 @@ class RTMCommon: self.add_wb_slave(self.mem_map["serwb"], 8192, serwb_core.etherbone.wishbone.bus) -class Standalone(MiniSoC, AMPSoC, RTMCommon): - """ - Local DAC/SAWG channels only. - """ - mem_map = { - "cri_con": 0x10000000, - "rtio": 0x11000000, - "rtio_dma": 0x12000000, - "serwb": 0x13000000, - "mailbox": 0x70000000 - } - mem_map.update(MiniSoC.mem_map) - - def __init__(self, with_sawg, **kwargs): - MiniSoC.__init__(self, - cpu_type="or1k", - sdram_controller_type="minicon", - l2_size=128*1024, - ethmac_nrxslots=4, - ethmac_ntxslots=4, - **kwargs) - AMPSoC.__init__(self) - RTMCommon.__init__(self) - add_identifier(self, suffix=".without-sawg" if not with_sawg else "") - self.config["HMC830_REF"] = "100" - - platform = self.platform - - self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("si5324").rst_n) - self.csr_devices.append("si5324_rst_n") - 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_AS_SYNTHESIZER"] = None - self.config["SI5324_SAYMA_REF"] = None - # ensure pins are properly biased and terminated - si5324_clkout = platform.request("si5324_clkout", 0) - self.specials += Instance( - "IBUFDS_GTE3", i_CEB=0, i_I=si5324_clkout.p, i_IB=si5324_clkout.n, - attr={("DONT_TOUCH", "true")}) - - # RTIO - rtio_channels = [] - for i in range(4): - phy = ttl_simple.Output(platform.request("user_led", i)) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - # To work around Ultrascale issues (https://www.xilinx.com/support/answers/67885.html), - # we generate the multiplied RTIO clock using the DRTIO GTH transceiver. - # Since there is no DRTIO here and therefoere no multiplied clock, we use ttl_simple. - sma_io = platform.request("sma_io", 0) - self.comb += sma_io.direction.eq(1) - phy = ttl_simple.Output(sma_io.level) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - sma_io = platform.request("sma_io", 1) - self.comb += sma_io.direction.eq(0) - phy = ttl_simple.InOut(sma_io.level) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - - self.submodules.ad9154_crg = jesd204_tools.UltrascaleCRG(platform) - if with_sawg: - cls = AD9154 - else: - cls = AD9154NoSAWG - self.submodules.ad9154_0 = cls(platform, self.crg, self.ad9154_crg, 0) - self.submodules.ad9154_1 = cls(platform, self.crg, self.ad9154_crg, 1) - self.csr_devices.append("ad9154_crg") - self.csr_devices.append("ad9154_0") - self.csr_devices.append("ad9154_1") - self.config["HAS_AD9154"] = None - self.add_csr_group("ad9154", ["ad9154_0", "ad9154_1"]) - self.config["RTIO_FIRST_SAWG_CHANNEL"] = len(rtio_channels) - rtio_channels.extend(rtio.Channel.from_phy(phy) - for sawg in self.ad9154_0.sawgs + - self.ad9154_1.sawgs - for phy in sawg.phys) - - self.config["HAS_RTIO_LOG"] = None - self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) - rtio_channels.append(rtio.LogChannel()) - - self.clock_domains.cd_rtio = ClockDomain() - self.comb += [ - self.cd_rtio.clk.eq(ClockSignal("jesd")), - self.cd_rtio.rst.eq(ResetSignal("jesd")) - ] - self.submodules.rtio_tsc = rtio.TSC("async") - self.submodules.rtio_core = rtio.Core(self.rtio_tsc, rtio_channels) - self.csr_devices.append("rtio_core") - self.submodules.rtio = rtio.KernelInitiator(self.rtio_tsc) - self.submodules.rtio_dma = ClockDomainsRenamer("sys_kernel")( - rtio.DMA(self.get_native_sdram_if())) - self.register_kernel_cpu_csrdevice("rtio") - self.register_kernel_cpu_csrdevice("rtio_dma") - self.submodules.cri_con = rtio.CRIInterconnectShared( - [self.rtio.cri, self.rtio_dma.cri], - [self.rtio_core.cri]) - self.register_kernel_cpu_csrdevice("cri_con") - self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) - self.csr_devices.append("rtio_moninj") - - self.submodules.rtio_analyzer = rtio.Analyzer(self.rtio_tsc, self.rtio_core.cri, - self.get_native_sdram_if()) - self.csr_devices.append("rtio_analyzer") - - self.submodules.sysref_ddmtd = jesd204_tools.DDMTD(platform.request("adc_sysref")) - self.csr_devices.append("sysref_ddmtd") - - class MasterDAC(MiniSoC, AMPSoC, RTMCommon): """ DRTIO master with local DAC/SAWG channels. @@ -396,6 +283,11 @@ class MasterDAC(MiniSoC, AMPSoC, RTMCommon): self.submodules.sysref_ddmtd = jesd204_tools.DDMTD(platform.request("adc_sysref")) self.csr_devices.append("sysref_ddmtd") + self.submodules.sysref_sampler = jesd204_tools.SysrefSampler( + platform.request("dac_sysref"), self.rtio_tsc.coarse_ts) + self.csr_devices.append("sysref_sampler") + self.ad9154_0.jesd.core.register_jref(self.sysref_sampler.jref) + self.ad9154_1.jesd.core.register_jref(self.sysref_sampler.jref) def workaround_us_lvds_tristate(platform): @@ -684,6 +576,11 @@ class Satellite(BaseSoC, RTMCommon): self.submodules.sysref_ddmtd = jesd204_tools.DDMTD(platform.request("adc_sysref")) self.csr_devices.append("sysref_ddmtd") + self.submodules.sysref_sampler = jesd204_tools.SysrefSampler( + platform.request("dac_sysref"), self.rtio_tsc.coarse_ts) + self.csr_devices.append("sysref_sampler") + self.ad9154_0.jesd.core.register_jref(self.sysref_sampler.jref) + self.ad9154_1.jesd.core.register_jref(self.sysref_sampler.jref) rtio_clk_period = 1e9/rtio_clk_freq gth = self.drtio_transceiver.gths[0] @@ -700,9 +597,8 @@ def main(): builder_args(parser) soc_sdram_args(parser) parser.set_defaults(output_dir="artiq_sayma") - parser.add_argument("-V", "--variant", default="standalone", - help="variant: " - "standalone/masterdac/master/satellite " + parser.add_argument("-V", "--variant", default="masterdac", + help="variant: masterdac/master/satellite " "(default: %(default)s)") parser.add_argument("--rtm-csr-csv", default=os.path.join("artiq_sayma", "rtm_gateware", "rtm_csr.csv"), @@ -714,9 +610,7 @@ def main(): args = parser.parse_args() variant = args.variant.lower() - if variant == "standalone": - cls = Standalone - elif variant == "masterdac": + if variant == "masterdac": cls = MasterDAC elif variant == "master": cls = lambda with_sawg, **kwargs: Master(**kwargs)