diff --git a/src/gateware/kasli_soc.py b/src/gateware/kasli_soc.py index 45eb1e0c..bd9be937 100755 --- a/src/gateware/kasli_soc.py +++ b/src/gateware/kasli_soc.py @@ -76,6 +76,36 @@ class RTIOCRG(Module, AutoCSR): ] +class _RTIOClockMultiplier(Module, AutoCSR): + def __init__(self, rtio_clk_freq): + self.pll_reset = CSRStorage(reset=1) + self.pll_locked = CSRStatus() + self.clock_domains.cd_rtiox4 = ClockDomain(reset_less=True) + + # See "Global Clock Network Deskew Using Two BUFGs" in ug472. + clkfbout = Signal() + clkfbin = Signal() + rtiox4_clk = Signal() + pll_locked = Signal() + self.specials += [ + Instance("MMCME2_BASE", + p_CLKIN1_PERIOD=1e9/rtio_clk_freq, + i_CLKIN1=ClockSignal("rtio"), + i_RST=self.pll_reset.storage, + o_LOCKED=pll_locked, + + p_CLKFBOUT_MULT_F=8.0, p_DIVCLK_DIVIDE=1, + + o_CLKFBOUT=clkfbout, i_CLKFBIN=clkfbin, + + p_CLKOUT0_DIVIDE_F=2.0, o_CLKOUT0=rtiox4_clk, + ), + Instance("BUFG", i_I=clkfbout, o_O=clkfbin), + Instance("BUFG", i_I=rtiox4_clk, o_O=self.cd_rtiox4.clk), + + MultiReg(pll_locked, self.pll_locked.status) + ] + eem_iostandard_dict = { 0: "LVDS_25", 1: "LVDS_25", @@ -176,7 +206,7 @@ class GenericStandalone(SoCCore): self.platform.add_false_path_constraints( self.rtio_crg.cd_rtio.clk, getattr(self, grabber).deserializer.cd_cl.clk) - + class GenericMaster(SoCCore): mem_map = { # "cri_con": 0x10000000, @@ -338,11 +368,11 @@ class GenericSatellite(SoCCore): platform.add_platform_command("set_input_jitter clk_fpga_0 0.24") self.crg = self.ps7 # HACK for eem_7series to find the clock - - # todo: replace rtio_crg with rtioclockmultiplier + self.submodules.rtio_crg = _RTIOClockMultiplier(rtio_clk_freq) + self.csr_devices.append("rtio_crg") # put range(1) to make it work while axi doesn't support anything but P2P - data_pads = [platform.request("sfp", i) for i in range(4)] + data_pads = [platform.request("sfp", i) for i in range(1)] self.submodules.drtio_transceiver = gtx_7series.GTX( clock_pads=platform.request("clk125_gtp"), # referred to as clk gtp in schematics, but for gtx? diff --git a/src/gateware/zc706.py b/src/gateware/zc706.py index 7bdf7196..9c17b4fb 100755 --- a/src/gateware/zc706.py +++ b/src/gateware/zc706.py @@ -69,6 +69,49 @@ class RTIOCRG(Module, AutoCSR): MultiReg(pll_locked, self.pll_locked.status) ] + +class _RTIOClockMultiplier(Module, AutoCSR): + def __init__(self, rtio_clk_freq): + self.pll_reset = CSRStorage(reset=1) + self.pll_locked = CSRStatus() + self.clock_domains.cd_rtiox4 = ClockDomain(reset_less=True) + + # See "Global Clock Network Deskew Using Two BUFGs" in ug472. + clkfbout = Signal() + clkfbin = Signal() + rtiox4_clk = Signal() + pll_locked = Signal() + self.specials += [ + Instance("MMCME2_BASE", + p_CLKIN1_PERIOD=1e9/rtio_clk_freq, + i_CLKIN1=ClockSignal("rtio"), + i_RST=self.pll_reset.storage, + o_LOCKED=pll_locked, + + p_CLKFBOUT_MULT_F=8.0, p_DIVCLK_DIVIDE=1, + + o_CLKFBOUT=clkfbout, i_CLKFBIN=clkfbin, + + p_CLKOUT0_DIVIDE_F=2.0, o_CLKOUT0=rtiox4_clk, + ), + Instance("BUFG", i_I=clkfbout, o_O=clkfbin), + Instance("BUFG", i_I=rtiox4_clk, o_O=self.cd_rtiox4.clk), + + MultiReg(pll_locked, self.pll_locked.status) + ] + + +def fix_serdes_timing_path(platform): + # ignore timing of path from OSERDESE2 through the pad to ISERDESE2 + platform.add_platform_command( + "set_false_path -quiet " + "-through [get_pins -filter {{REF_PIN_NAME == OQ || REF_PIN_NAME == TQ}} " + "-of [get_cells -filter {{REF_NAME == OSERDESE2}}]] " + "-to [get_pins -filter {{REF_PIN_NAME == D}} " + "-of [get_cells -filter {{REF_NAME == ISERDESE2}}]]" + ) + + class ZC706(SoCCore): def __init__(self, acpki=False): self.acpki = acpki @@ -148,7 +191,7 @@ class _MasterBase(SoCCore): platform.add_platform_command("create_clock -name clk_fpga_0 -period 8 [get_pins \"PS7/FCLKCLK[0]\"]") platform.add_platform_command("set_input_jitter clk_fpga_0 0.24") - sys_clk_freq = 125e6 + self.sys_clk_freq = 125e6 platform = self.platform @@ -161,7 +204,7 @@ class _MasterBase(SoCCore): self.submodules.drtio_transceiver = gtx_7series.GTX( clock_pads=platform.request("si5324_clkout"), pads=data_pads, - sys_clk_freq=sys_clk_freq) + sys_clk_freq=self.sys_clk_freq) self.csr_devices.append("drtio_transceiver") self.submodules.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3) @@ -247,7 +290,7 @@ class _SatelliteBase(SoCCore): platform.add_platform_command("set_input_jitter clk_fpga_0 0.24") # init end - sys_clk_freq = 125e6 + self.sys_clk_freq = 125e6 platform = self.platform # SFP @@ -263,7 +306,7 @@ class _SatelliteBase(SoCCore): self.submodules.drtio_transceiver = gtx_7series.GTX( clock_pads=platform.request("si5324_clkout"), pads=data_pads, - sys_clk_freq=sys_clk_freq) + sys_clk_freq=self.sys_clk_freq) self.csr_devices.append("drtio_transceiver") drtioaux_csr_group = [] @@ -505,11 +548,17 @@ class NIST_CLOCK(ZC706, _NIST_CLOCK_RTIO): class NIST_CLOCK_Master(_MasterBase, _NIST_CLOCK_RTIO): def __init__(self, acpki): _MasterBase.__init__(self, acpki) + self.submodules.rtio_crg = _RTIOClockMultiplier(self.sys_clk_freq) + self.csr_devices.append("rtio_crg") + fix_serdes_timing_path(self.platform) _NIST_CLOCK_RTIO.__init__(self) class NIST_CLOCK_Satellite(_SatelliteBase, _NIST_CLOCK_RTIO): def __init__(self, acpki): _SatelliteBase.__init__(self, acpki) + self.submodules.rtio_crg = _RTIOClockMultiplier(self.sys_clk_freq) + self.csr_devices.append("rtio_crg") + fix_serdes_timing_path(self.platform) _NIST_CLOCK_RTIO.__init__(self) class NIST_QC2(ZC706, _NIST_QC2_RTIO): @@ -520,11 +569,17 @@ class NIST_QC2(ZC706, _NIST_QC2_RTIO): class NIST_QC2_Master(_MasterBase, _NIST_QC2_RTIO): def __init__(self, acpki): _MasterBase.__init__(self, acpki) + self.submodules.rtio_crg = _RTIOClockMultiplier(self.sys_clk_freq) + self.csr_devices.append("rtio_crg") + fix_serdes_timing_path(self.platform) _NIST_QC2_RTIO.__init__(self) class NIST_QC2_Satellite(_SatelliteBase, _NIST_QC2_RTIO): def __init__(self, acpki): _SatelliteBase.__init__(self, acpki) + self.submodules.rtio_crg = _RTIOClockMultiplier(self.sys_clk_freq) + self.csr_devices.append("rtio_crg") + fix_serdes_timing_path(self.platform) _NIST_QC2_RTIO.__init__(self)