diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 6e6212808..56435807d 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -178,7 +178,7 @@ pub mod hmc7043 { (true, FPGA_CLK_DIV, 0x08), // 8: GTP_CLK1 (false, 0, 0x10), // 9: AMC_MASTER_AUX_CLK (false, 0, 0x10), // 10: RTM_MASTER_AUX_CLK - (false, 0, 0x10), // 11: FPGA_ADC_SYSREF, LVDS + (true, FPGA_CLK_DIV, 0x10), // 11: FPGA_ADC_SYSREF, LVDS, used for DDMTD RTIO/SYSREF alignment (false, 0, 0x08), // 12: ADC1_CLK (false, 0, 0x08), // 13: ADC1_SYSREF ]; diff --git a/artiq/firmware/libboard_artiq/jesd204sync.rs b/artiq/firmware/libboard_artiq/jesd204sync.rs index eb51590e1..062135896 100644 --- a/artiq/firmware/libboard_artiq/jesd204sync.rs +++ b/artiq/firmware/libboard_artiq/jesd204sync.rs @@ -3,6 +3,15 @@ use board_misoc::{csr, config}; use hmc830_7043::hmc7043; use ad9154; +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); + } + Ok(()) +} + fn sysref_cal_dac(dacno: u8) -> Result { info!("calibrating SYSREF phase at DAC-{}...", dacno); diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 11866e389..c905d5df4 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -115,12 +115,9 @@ fn startup() { { board_artiq::ad9154::jesd_reset(false); board_artiq::ad9154::init(); - /* - TODO: if let Err(e) = board_artiq::jesd204sync::sysref_auto_rtio_align() { error!("failed to align SYSREF at FPGA: {}", e); } - */ if let Err(e) = board_artiq::jesd204sync::sysref_auto_dac_align() { error!("failed to align SYSREF at DAC: {}", e); } diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 2f226f4ab..180ccbcba 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -489,12 +489,9 @@ pub extern fn main() -> i32 { info!("TSC loaded from uplink"); #[cfg(has_ad9154)] { - /* - TODO: if let Err(e) = board_artiq::jesd204sync::sysref_auto_rtio_align() { error!("failed to align SYSREF at FPGA: {}", e); } - */ if let Err(e) = board_artiq::jesd204sync::sysref_auto_dac_align() { error!("failed to align SYSREF at DAC: {}", e); } diff --git a/artiq/gateware/jesd204_tools.py b/artiq/gateware/jesd204_tools.py index 1aa605a8d..b029c86c2 100644 --- a/artiq/gateware/jesd204_tools.py +++ b/artiq/gateware/jesd204_tools.py @@ -1,7 +1,7 @@ from collections import namedtuple from migen import * -from migen.genlib.cdc import MultiReg +from migen.genlib.cdc import MultiReg, BusSynchronizer from migen.genlib.resetsync import AsyncResetSynchronizer from misoc.interconnect.csr import * @@ -91,3 +91,69 @@ class UltrascaleTX(Module, AutoCSR): 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" +# by P. Moreira and I. Darwazeh +class DDMTD(Module, AutoCSR): + def __init__(self, input_pads, rtio_clk_freq=150e6): + N = 64 + self.dt = CSRStatus(N.bit_length()) + + # # # + + self.clock_domains.cd_helper = ClockDomain(reset_less=True) + helper_fb = Signal() + helper_output = Signal() + + input_se = Signal() + beat1 = Signal() + beat2 = Signal() + self.specials += [ + Instance("MMCME2_BASE", + p_CLKIN1_PERIOD=1e9/rtio_clk_freq, + i_CLKIN1=ClockSignal("rtio"), + i_RST=ResetSignal("rtio"), + + # VCO at 1200MHz with 150MHz RTIO frequency + p_CLKFBOUT_MULT_F=8.0, + p_DIVCLK_DIVIDE=1, + + o_CLKFBOUT=helper_fb, i_CLKFBIN=helper_fb, + + # helper PLL ratio: 64/65 (N=64) + p_CLKOUT0_DIVIDE_F=8.125, + o_CLKOUT0=helper_output, + ), + Instance("BUFG", i_I=helper_output, o_O=self.cd_helper.clk), + Instance("IBUFDS", i_I=input_pads.p, i_IB=input_pads.n, o_O=input_se), + Instance("FD", i_C=self.cd_helper.clk, i_D=input_se, o_Q=beat1), + Instance("FD", i_C=self.cd_helper.clk, i_D=ClockSignal("rtio"), o_Q=beat2), + ] + + counting = Signal() + counter = Signal(N.bit_length()) + + beat1_r = Signal() + beat2_r = Signal() + result = Signal.like(counter) + + self.sync.helper += [ + If(counting, + counter.eq(counter + 1) + ).Else( + result.eq(counter) + ), + + beat1_r.eq(beat1), + If(beat1 & ~beat1_r, counting.eq(1), counter.eq(0)), + beat2_r.eq(beat2), + If(beat2 & ~beat2_r, counting.eq(0)) + ] + + bsync = BusSynchronizer(len(result), "helper", "sys") + self.submodules += bsync + self.comb += [ + bsync.i.eq(result), + self.dt.status.eq(bsync.o) + ] diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 2970877c5..d82bbcc8e 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -223,6 +223,9 @@ class Standalone(MiniSoC, AMPSoC, RTMCommon): 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): """ @@ -391,6 +394,9 @@ class MasterDAC(MiniSoC, AMPSoC, RTMCommon): self.submodules.routing_table = rtio.RoutingTableAccess(self.cri_con) self.csr_devices.append("routing_table") + self.submodules.sysref_ddmtd = jesd204_tools.DDMTD(platform.request("adc_sysref")) + self.csr_devices.append("sysref_ddmtd") + def workaround_us_lvds_tristate(platform): # Those shoddy Kintex Ultrascale FPGAs take almost a microsecond to change the direction of a @@ -676,6 +682,9 @@ class Satellite(BaseSoC, RTMCommon): self.config["I2C_BUS_COUNT"] = 1 self.config["HAS_SI5324"] = None + self.submodules.sysref_ddmtd = jesd204_tools.DDMTD(platform.request("adc_sysref")) + self.csr_devices.append("sysref_ddmtd") + rtio_clk_period = 1e9/rtio_clk_freq gth = self.drtio_transceiver.gths[0] platform.add_period_constraint(gth.txoutclk, rtio_clk_period/2)