mirror of
https://github.com/enjoy-digital/litex.git
synced 2025-01-04 09:52:26 -05:00
soc/cores: init clock abstraction module
This commit is contained in:
parent
70a32ed86f
commit
63fc395006
1 changed files with 114 additions and 0 deletions
114
litex/soc/cores/clock.py
Normal file
114
litex/soc/cores/clock.py
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
"""
|
||||||
|
Clock Abstraction Modules
|
||||||
|
|
||||||
|
|
||||||
|
Made in Paris-CDG while waiting a delayed Air-France KLM flight...
|
||||||
|
"""
|
||||||
|
|
||||||
|
from migen import *
|
||||||
|
from migen.genlib.io import DifferentialInput
|
||||||
|
from migen.genlib.resetsync import AsyncResetSynchronizer
|
||||||
|
|
||||||
|
|
||||||
|
# TODO:
|
||||||
|
# - add S7PLL support for all family/speedgrades (currently Artix7 -3 speedgrade)
|
||||||
|
# - add S7MMCM support (should be very similar to S7PLL)
|
||||||
|
|
||||||
|
|
||||||
|
def period_ns(freq):
|
||||||
|
return 1e9/freq
|
||||||
|
|
||||||
|
|
||||||
|
class S7PLL(Module):
|
||||||
|
nclkouts_max = 6
|
||||||
|
clkin_freq_range = (10e6, 800e6)
|
||||||
|
vco_freq_range = (600e6, 1600e6)
|
||||||
|
clkfbout_mult_frange = (2, 64+1)
|
||||||
|
clkout_divide_range = (1, 128+1)
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.reset = Signal()
|
||||||
|
self.locked = Signal()
|
||||||
|
self.clkin_freq = None
|
||||||
|
self.vcxo_freq = None
|
||||||
|
self.nclkouts = 0
|
||||||
|
self.clkouts = {}
|
||||||
|
self.config = {}
|
||||||
|
|
||||||
|
def register_clkin(self, clkin, freq):
|
||||||
|
self.clkin = Signal()
|
||||||
|
if isinstance(clkin, Signal):
|
||||||
|
self.comb += self.clkin.eq(clkin)
|
||||||
|
elif isinstance(clkin, Record):
|
||||||
|
self.specials += DifferentialInput(clkin.p, clkin.n, self.clkin)
|
||||||
|
else:
|
||||||
|
raise ValueError
|
||||||
|
self.clkin_freq = freq
|
||||||
|
|
||||||
|
def create_clkout(self, cd, freq, phase=0):
|
||||||
|
assert self.nclkouts < self.nclkouts_max
|
||||||
|
clkout = Signal()
|
||||||
|
clkout_bufg = Signal()
|
||||||
|
self.specials += AsyncResetSynchronizer(cd, ~self.locked | self.reset),
|
||||||
|
self.specials += Instance("BUFG", i_I=clkout, o_O=clkout_bufg)
|
||||||
|
self.comb += cd.clk.eq(clkout_bufg)
|
||||||
|
self.clkouts[self.nclkouts] = (clkout, freq, phase)
|
||||||
|
self.nclkouts += 1
|
||||||
|
return clkout_bufg
|
||||||
|
|
||||||
|
def compute_config(self):
|
||||||
|
config = {}
|
||||||
|
config["divclk_divide"] = 1
|
||||||
|
for clkfbout_mult in range(*self.clkfbout_mult_frange):
|
||||||
|
all_valid = True
|
||||||
|
vco_freq = self.clkin_freq*clkfbout_mult
|
||||||
|
(vco_freq_min, vco_freq_max) = self.vco_freq_range
|
||||||
|
if vco_freq >= vco_freq_min and vco_freq <= vco_freq_max:
|
||||||
|
for n, (clk, f, p) in sorted(self.clkouts.items()):
|
||||||
|
valid = False
|
||||||
|
for d in range(*self.clkout_divide_range):
|
||||||
|
clk_freq = vco_freq/d
|
||||||
|
if clk_freq == f:
|
||||||
|
config["clkout{}_divide".format(n)] = d
|
||||||
|
config["clkout{}_phase".format(n)] = p
|
||||||
|
valid = True
|
||||||
|
break
|
||||||
|
if not valid:
|
||||||
|
all_valid = False
|
||||||
|
else:
|
||||||
|
all_valid = False
|
||||||
|
if all_valid:
|
||||||
|
config["vco"] = vco_freq
|
||||||
|
config["clkfbout_mult"] = clkfbout_mult
|
||||||
|
return config
|
||||||
|
raise ValueError("No PLL config found")
|
||||||
|
|
||||||
|
def add_idelayctrl(self, cd):
|
||||||
|
reset_counter = Signal(4, reset=15)
|
||||||
|
ic_reset = Signal(reset=1)
|
||||||
|
sync = getattr(self.sync, cd.name)
|
||||||
|
sync += \
|
||||||
|
If(reset_counter != 0,
|
||||||
|
reset_counter.eq(reset_counter - 1)
|
||||||
|
).Else(
|
||||||
|
ic_reset.eq(0)
|
||||||
|
)
|
||||||
|
self.specials += Instance("IDELAYCTRL", i_REFCLK=cd.clk, i_RST=ic_reset)
|
||||||
|
|
||||||
|
def do_finalize(self):
|
||||||
|
assert hasattr(self, "clkin")
|
||||||
|
config = self.compute_config()
|
||||||
|
pll_fb = Signal()
|
||||||
|
pll_params = dict(
|
||||||
|
p_STARTUP_WAIT="FALSE", o_LOCKED=self.locked,
|
||||||
|
|
||||||
|
# VCO
|
||||||
|
p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=period_ns(self.clkin_freq),
|
||||||
|
p_CLKFBOUT_MULT=config["clkfbout_mult"], p_DIVCLK_DIVIDE=config["divclk_divide"],
|
||||||
|
i_CLKIN1=self.clkin, i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb,
|
||||||
|
)
|
||||||
|
for n, (clk, f, p) in sorted(self.clkouts.items()):
|
||||||
|
pll_params["p_CLKOUT{}_DIVIDE".format(n)] = config["clkout{}_divide".format(n)]
|
||||||
|
pll_params["p_CLKOUT{}_PHASE".format(n)] = config["clkout{}_phase".format(n)]
|
||||||
|
pll_params["o_CLKOUT{}".format(n)] = clk
|
||||||
|
self.specials += Instance("PLLE2_BASE", **pll_params)
|
Loading…
Reference in a new issue