2023-04-23 11:42:18 +08:00
|
|
|
from migen import *
|
|
|
|
from migen.build.platforms.sinara import kasli
|
|
|
|
from migen.genlib.resetsync import AsyncResetSynchronizer
|
|
|
|
|
|
|
|
|
2023-04-26 05:08:33 +08:00
|
|
|
class TransceiverCRG(Module):
|
|
|
|
def __init__(self, platform, clk125):
|
2023-04-23 11:42:18 +08:00
|
|
|
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()
|
|
|
|
|
|
|
|
self.specials += Instance("IBUFDS_GTE2",
|
|
|
|
i_CEB=0,
|
|
|
|
i_I=clk125.p, i_IB=clk125.n,
|
|
|
|
o_O=clk125_buf,
|
|
|
|
o_ODIV2=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}}]]"
|
|
|
|
)
|