from migen import * from migen.build.platforms.sinara import kasli from migen.genlib.resetsync import AsyncResetSynchronizer class TransceiverCRG(Module): def __init__(self, platform, clk125, gte=True): self.platform = platform # Generated clock domains self.clock_domains.cd_sys = ClockDomain() self.clock_domains.cd_sys5x = ClockDomain() self.clock_domains.cd_rx_sys = ClockDomain() self.clock_domains.cd_rx_sys5x = ClockDomain() self.clock_domains.cd_clk200 = ClockDomain() # Configure system clock using GTP ports self.sys_clk_freq = 125e6 clk125_buf = Signal() clk125_div2 = Signal() if gte: self.specials += Instance("IBUFDS_GTE2", i_CEB=0, i_I=clk125.p, i_IB=clk125.n, o_O=clk125_buf, o_ODIV2=clk125_div2) else: self.specials += Instance("IBUFDS", i_I=clk125.p, i_IB=clk125.n, o_O=clk125_buf) div2_pll_fb = Signal() inner_pll_locked = Signal() self.specials += Instance("PLLE2_BASE", p_CLKIN1_PERIOD=8.0, i_CLKIN1=clk125_buf, i_CLKFBIN=div2_pll_fb, o_CLKFBOUT=div2_pll_fb, o_LOCKED=inner_pll_locked, # VCO @ 1GHz p_CLKFBOUT_MULT=8, p_DIVCLK_DIVIDE=1, # 200MHz for IDELAYCTRL p_CLKOUT0_DIVIDE=16, p_CLKOUT0_PHASE=0.0, o_CLKOUT0=clk125_div2, ), # MMCM to generate different frequencies mmcm_fb = Signal() mmcm_locked = Signal() mmcm_sys = Signal() mmcm_sys5x = Signal() mmcm_rx_sys = Signal() mmcm_rx_sys5x = Signal() # PLL to IDELAYCTRL clock pll_locked = Signal() pll_fb = Signal() pll_clk200 = Signal() # Actual MMCM/PLL instances self.specials += [ Instance("MMCME2_BASE", p_CLKIN1_PERIOD=16.0, i_CLKIN1=clk125_div2, i_CLKFBIN=mmcm_fb, o_CLKFBOUT=mmcm_fb, o_LOCKED=mmcm_locked, # VCO @ 1.25GHz with MULT=20 p_CLKFBOUT_MULT_F=20.0, p_DIVCLK_DIVIDE=1, # ~125MHz p_CLKOUT0_DIVIDE_F=10.0, p_CLKOUT0_PHASE=0.0, o_CLKOUT0=mmcm_sys, # ~625MHz p_CLKOUT1_DIVIDE=2, p_CLKOUT1_PHASE=0.0, o_CLKOUT1=mmcm_sys5x, # ~125MHz separated from sysclk, for RX p_CLKOUT2_DIVIDE=10, p_CLKOUT2_PHASE=0.0, o_CLKOUT2=mmcm_rx_sys, # ~625MHz separated from sysclk, for RX p_CLKOUT3_DIVIDE=2, p_CLKOUT3_PHASE=0.0, o_CLKOUT3=mmcm_rx_sys5x, # Leftovers... # p_CLKOUT2_DIVIDE=2, p_CLKOUT2_PHASE=90.0, o_CLKOUT2=mmcm_sys4x_dqs, ), Instance("PLLE2_BASE", p_CLKIN1_PERIOD=16.0, i_CLKIN1=clk125_div2, i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb, o_LOCKED=pll_locked, # VCO @ 1GHz p_CLKFBOUT_MULT=16, p_DIVCLK_DIVIDE=1, # 200MHz for IDELAYCTRL p_CLKOUT0_DIVIDE=5, p_CLKOUT0_PHASE=0.0, o_CLKOUT0=pll_clk200, ), ] self.specials += [ Instance("BUFG", i_I=mmcm_sys, o_O=self.cd_sys.clk), Instance("BUFG", i_I=mmcm_sys5x, o_O=self.cd_sys5x.clk), Instance("BUFG", i_I=mmcm_rx_sys, o_O=self.cd_rx_sys.clk), Instance("BUFG", i_I=mmcm_rx_sys5x, o_O=self.cd_rx_sys5x.clk), Instance("BUFG", i_I=pll_clk200, o_O=self.cd_clk200.clk), AsyncResetSynchronizer(self.cd_clk200, ~pll_locked), ] reset_counter = Signal(4, reset=15) ic_reset = Signal(reset=1) self.sync.clk200 += \ If(reset_counter != 0, reset_counter.eq(reset_counter - 1) ).Else( ic_reset.eq(0) ) self.specials += Instance("IDELAYCTRL", i_REFCLK=ClockSignal("clk200"), i_RST=ic_reset) # Add clock costraints for all clock signals platform.add_period_constraint(self.cd_sys.clk, 8.) platform.add_period_constraint(self.cd_sys5x.clk, 1.6) platform.add_period_constraint(self.cd_rx_sys.clk, 8.) platform.add_period_constraint(self.cd_rx_sys5x.clk, 1.6) platform.add_period_constraint(self.cd_clk200.clk, 5.) 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}}]]" ) 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 == DDLY}} " "-of [get_cells -filter {{REF_NAME == ISERDESE2}}]]" )