serdes-transceiver/kasli_crg.py

149 lines
5.2 KiB
Python

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}}]]"
)