cores/clock: use common XilinxClocking class for all Xilinx clocking modules
This commit is contained in:
parent
83699ea0a5
commit
0d282f38f9
|
@ -10,9 +10,9 @@ from litex.soc.interconnect.csr import *
|
||||||
def period_ns(freq):
|
def period_ns(freq):
|
||||||
return 1e9/freq
|
return 1e9/freq
|
||||||
|
|
||||||
# Xilinx / 7-Series --------------------------------------------------------------------------------
|
# Xilinx / Generic ---------------------------------------------------------------------------------
|
||||||
|
|
||||||
class S7Clocking(Module, AutoCSR):
|
class XilinxClocking(Module, AutoCSR):
|
||||||
clkfbout_mult_frange = (2, 64+1)
|
clkfbout_mult_frange = (2, 64+1)
|
||||||
clkout_divide_range = (1, 128+1)
|
clkout_divide_range = (1, 128+1)
|
||||||
|
|
||||||
|
@ -118,45 +118,14 @@ class S7Clocking(Module, AutoCSR):
|
||||||
def do_finalize(self):
|
def do_finalize(self):
|
||||||
assert hasattr(self, "clkin")
|
assert hasattr(self, "clkin")
|
||||||
|
|
||||||
|
# Xilinx / Spartan6 --------------------------------------------------------------------------------
|
||||||
|
|
||||||
class S7PLL(S7Clocking):
|
class S6PLL(XilinxClocking):
|
||||||
nclkouts_max = 6
|
|
||||||
clkin_freq_range = (19e6, 800e6)
|
|
||||||
|
|
||||||
def __init__(self, speedgrade=-1):
|
|
||||||
S7Clocking.__init__(self)
|
|
||||||
self.divclk_divide_range = (1, 56+1)
|
|
||||||
self.vco_freq_range = {
|
|
||||||
-1: (800e6, 2133e6),
|
|
||||||
-2: (800e6, 1866e6),
|
|
||||||
-3: (800e6, 1600e6),
|
|
||||||
}[speedgrade]
|
|
||||||
|
|
||||||
def do_finalize(self):
|
|
||||||
S7Clocking.do_finalize(self)
|
|
||||||
config = self.compute_config()
|
|
||||||
pll_fb = Signal()
|
|
||||||
self.params.update(
|
|
||||||
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, m) in sorted(self.clkouts.items()):
|
|
||||||
self.params["p_CLKOUT{}_DIVIDE".format(n)] = config["clkout{}_divide".format(n)]
|
|
||||||
self.params["p_CLKOUT{}_PHASE".format(n)] = config["clkout{}_phase".format(n)]
|
|
||||||
self.params["o_CLKOUT{}".format(n)] = clk
|
|
||||||
self.specials += Instance("PLLE2_ADV", **self.params)
|
|
||||||
|
|
||||||
|
|
||||||
class S6PLL(S7Clocking):
|
|
||||||
nclkouts_max = 6
|
nclkouts_max = 6
|
||||||
clkin_freq_range = (19e6, 540e6)
|
clkin_freq_range = (19e6, 540e6)
|
||||||
|
|
||||||
def __init__(self, speedgrade=-1):
|
def __init__(self, speedgrade=-1):
|
||||||
S7Clocking.__init__(self)
|
XilinxClocking.__init__(self)
|
||||||
self.vco_freq_range = {
|
self.vco_freq_range = {
|
||||||
-1: (400e6, 1000e6),
|
-1: (400e6, 1000e6),
|
||||||
-2: (400e6, 1000e6),
|
-2: (400e6, 1000e6),
|
||||||
|
@ -164,7 +133,7 @@ class S6PLL(S7Clocking):
|
||||||
}[speedgrade]
|
}[speedgrade]
|
||||||
|
|
||||||
def do_finalize(self):
|
def do_finalize(self):
|
||||||
S7Clocking.do_finalize(self)
|
XilinxClocking.do_finalize(self)
|
||||||
config = self.compute_config()
|
config = self.compute_config()
|
||||||
pll_fb = Signal()
|
pll_fb = Signal()
|
||||||
self.params.update(
|
self.params.update(
|
||||||
|
@ -187,14 +156,14 @@ class S6PLL(S7Clocking):
|
||||||
self.specials += Instance("PLL_ADV", **self.params)
|
self.specials += Instance("PLL_ADV", **self.params)
|
||||||
|
|
||||||
|
|
||||||
class S6DCM(S7Clocking):
|
class S6DCM(XilinxClocking):
|
||||||
""" single output with f_out = f_in * {2 .. 256} / {1 .. 256} """
|
""" single output with f_out = f_in * {2 .. 256} / {1 .. 256} """
|
||||||
nclkouts_max = 1
|
nclkouts_max = 1
|
||||||
clkfbout_mult_frange = (2, 256 + 1)
|
clkfbout_mult_frange = (2, 256 + 1)
|
||||||
clkout_divide_range = (1, 256 + 1)
|
clkout_divide_range = (1, 256 + 1)
|
||||||
|
|
||||||
def __init__(self, speedgrade=-1):
|
def __init__(self, speedgrade=-1):
|
||||||
S7Clocking.__init__(self)
|
XilinxClocking.__init__(self)
|
||||||
self.clkin_freq_range = {
|
self.clkin_freq_range = {
|
||||||
-1: (0.5e6, 200e6),
|
-1: (0.5e6, 200e6),
|
||||||
-2: (0.5e6, 333e6),
|
-2: (0.5e6, 333e6),
|
||||||
|
@ -208,7 +177,7 @@ class S6DCM(S7Clocking):
|
||||||
}[speedgrade]
|
}[speedgrade]
|
||||||
|
|
||||||
def do_finalize(self):
|
def do_finalize(self):
|
||||||
S7Clocking.do_finalize(self)
|
XilinxClocking.do_finalize(self)
|
||||||
config = self.compute_config()
|
config = self.compute_config()
|
||||||
clk, f, p, m = sorted(self.clkouts.items())[0][1]
|
clk, f, p, m = sorted(self.clkouts.items())[0][1]
|
||||||
self.params.update(
|
self.params.update(
|
||||||
|
@ -224,12 +193,45 @@ class S6DCM(S7Clocking):
|
||||||
)
|
)
|
||||||
self.specials += Instance("DCM_CLKGEN", **self.params)
|
self.specials += Instance("DCM_CLKGEN", **self.params)
|
||||||
|
|
||||||
|
# Xilinx / 7-Series --------------------------------------------------------------------------------
|
||||||
|
|
||||||
class S7MMCM(S7Clocking):
|
class S7PLL(XilinxClocking):
|
||||||
|
nclkouts_max = 6
|
||||||
|
clkin_freq_range = (19e6, 800e6)
|
||||||
|
|
||||||
|
def __init__(self, speedgrade=-1):
|
||||||
|
XilinxClocking.__init__(self)
|
||||||
|
self.divclk_divide_range = (1, 56+1)
|
||||||
|
self.vco_freq_range = {
|
||||||
|
-1: (800e6, 2133e6),
|
||||||
|
-2: (800e6, 1866e6),
|
||||||
|
-3: (800e6, 1600e6),
|
||||||
|
}[speedgrade]
|
||||||
|
|
||||||
|
def do_finalize(self):
|
||||||
|
XilinxClocking.do_finalize(self)
|
||||||
|
config = self.compute_config()
|
||||||
|
pll_fb = Signal()
|
||||||
|
self.params.update(
|
||||||
|
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, m) in sorted(self.clkouts.items()):
|
||||||
|
self.params["p_CLKOUT{}_DIVIDE".format(n)] = config["clkout{}_divide".format(n)]
|
||||||
|
self.params["p_CLKOUT{}_PHASE".format(n)] = config["clkout{}_phase".format(n)]
|
||||||
|
self.params["o_CLKOUT{}".format(n)] = clk
|
||||||
|
self.specials += Instance("PLLE2_ADV", **self.params)
|
||||||
|
|
||||||
|
|
||||||
|
class S7MMCM(XilinxClocking):
|
||||||
nclkouts_max = 7
|
nclkouts_max = 7
|
||||||
|
|
||||||
def __init__(self, speedgrade=-1):
|
def __init__(self, speedgrade=-1):
|
||||||
S7Clocking.__init__(self)
|
XilinxClocking.__init__(self)
|
||||||
self.divclk_divide_range = (1, 106+1)
|
self.divclk_divide_range = (1, 106+1)
|
||||||
self.clkin_freq_range = {
|
self.clkin_freq_range = {
|
||||||
-1: (10e6, 800e6),
|
-1: (10e6, 800e6),
|
||||||
|
@ -244,7 +246,7 @@ class S7MMCM(S7Clocking):
|
||||||
}[speedgrade]
|
}[speedgrade]
|
||||||
|
|
||||||
def do_finalize(self):
|
def do_finalize(self):
|
||||||
S7Clocking.do_finalize(self)
|
XilinxClocking.do_finalize(self)
|
||||||
config = self.compute_config()
|
config = self.compute_config()
|
||||||
mmcm_fb = Signal()
|
mmcm_fb = Signal()
|
||||||
self.params.update(
|
self.params.update(
|
||||||
|
@ -283,118 +285,11 @@ class S7IDELAYCTRL(Module):
|
||||||
# TODO:
|
# TODO:
|
||||||
# - use Ultrascale primitives instead of 7-Series' ones. (Vivado recognize and convert them).
|
# - use Ultrascale primitives instead of 7-Series' ones. (Vivado recognize and convert them).
|
||||||
|
|
||||||
class USClocking(Module, AutoCSR):
|
class USPLL(XilinxClocking):
|
||||||
clkfbout_mult_frange = (2, 64+1)
|
|
||||||
clkout_divide_range = (1, 128+1)
|
|
||||||
|
|
||||||
def __init__(self, vco_margin=0):
|
|
||||||
self.vco_margin = vco_margin
|
|
||||||
self.reset = Signal()
|
|
||||||
self.locked = Signal()
|
|
||||||
self.clkin_freq = None
|
|
||||||
self.vcxo_freq = None
|
|
||||||
self.nclkouts = 0
|
|
||||||
self.clkouts = {}
|
|
||||||
self.config = {}
|
|
||||||
self.params = {}
|
|
||||||
|
|
||||||
def register_clkin(self, clkin, freq):
|
|
||||||
self.clkin = Signal()
|
|
||||||
if isinstance(clkin, (Signal, ClockSignal)):
|
|
||||||
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, buf="bufg", margin=1e-2, with_reset=True):
|
|
||||||
assert self.nclkouts < self.nclkouts_max
|
|
||||||
clkout = Signal()
|
|
||||||
self.clkouts[self.nclkouts] = (clkout, freq, phase, margin)
|
|
||||||
self.nclkouts += 1
|
|
||||||
if with_reset:
|
|
||||||
self.specials += AsyncResetSynchronizer(cd, ~self.locked | self.reset)
|
|
||||||
if buf is None:
|
|
||||||
self.comb += cd.clk.eq(clkout)
|
|
||||||
else:
|
|
||||||
clkout_buf = Signal()
|
|
||||||
self.comb += cd.clk.eq(clkout_buf)
|
|
||||||
if buf == "bufg":
|
|
||||||
self.specials += Instance("BUFG", i_I=clkout, o_O=clkout_buf)
|
|
||||||
elif buf == "bufr":
|
|
||||||
self.specials += Instance("BUFR", i_I=clkout, o_O=clkout_buf)
|
|
||||||
else:
|
|
||||||
raise ValueError
|
|
||||||
|
|
||||||
def compute_config(self):
|
|
||||||
config = {}
|
|
||||||
for divclk_divide in range(*self.divclk_divide_range):
|
|
||||||
config["divclk_divide"] = divclk_divide
|
|
||||||
for clkfbout_mult in range(*self.clkfbout_mult_frange):
|
|
||||||
all_valid = True
|
|
||||||
vco_freq = self.clkin_freq*clkfbout_mult/divclk_divide
|
|
||||||
(vco_freq_min, vco_freq_max) = self.vco_freq_range
|
|
||||||
if (vco_freq >= vco_freq_min*(1 + self.vco_margin) and
|
|
||||||
vco_freq <= vco_freq_max*(1 - self.vco_margin)):
|
|
||||||
for n, (clk, f, p, m) in sorted(self.clkouts.items()):
|
|
||||||
valid = False
|
|
||||||
for d in range(*self.clkout_divide_range):
|
|
||||||
clk_freq = vco_freq/d
|
|
||||||
if abs(clk_freq - f) < f*m:
|
|
||||||
config["clkout{}_freq".format(n)] = clk_freq
|
|
||||||
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 expose_drp(self):
|
|
||||||
self.drp_reset = CSR()
|
|
||||||
self.drp_read = CSR()
|
|
||||||
self.drp_write = CSR()
|
|
||||||
self.drp_drdy = CSRStatus()
|
|
||||||
self.drp_adr = CSRStorage(7)
|
|
||||||
self.drp_dat_w = CSRStorage(16)
|
|
||||||
self.drp_dat_r = CSRStatus(16)
|
|
||||||
|
|
||||||
# # #
|
|
||||||
|
|
||||||
drp_drdy = Signal()
|
|
||||||
self.params.update(
|
|
||||||
i_DCLK=ClockSignal(),
|
|
||||||
i_DWE=self.drp_write.re,
|
|
||||||
i_DEN=self.drp_read.re | self.drp_write.re,
|
|
||||||
o_DRDY=drp_drdy,
|
|
||||||
i_DADDR=self.drp_adr.storage,
|
|
||||||
i_DI=self.drp_dat_w.storage,
|
|
||||||
o_DO=self.drp_dat_r.status
|
|
||||||
)
|
|
||||||
self.sync += [
|
|
||||||
If(self.drp_read.re | self.drp_write.re,
|
|
||||||
self.drp_drdy.status.eq(0)
|
|
||||||
).Elif(drp_drdy,
|
|
||||||
self.drp_drdy.status.eq(1)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
|
|
||||||
def do_finalize(self):
|
|
||||||
assert hasattr(self, "clkin")
|
|
||||||
|
|
||||||
|
|
||||||
class USPLL(USClocking):
|
|
||||||
nclkouts_max = 6
|
nclkouts_max = 6
|
||||||
|
|
||||||
def __init__(self, speedgrade=-1):
|
def __init__(self, speedgrade=-1):
|
||||||
USClocking.__init__(self)
|
XilinxClocking.__init__(self)
|
||||||
self.divclk_divide_range = (1, 56+1)
|
self.divclk_divide_range = (1, 56+1)
|
||||||
self.clkin_freq_range = {
|
self.clkin_freq_range = {
|
||||||
-1: (70e6, 800e6),
|
-1: (70e6, 800e6),
|
||||||
|
@ -408,7 +303,7 @@ class USPLL(USClocking):
|
||||||
}[speedgrade]
|
}[speedgrade]
|
||||||
|
|
||||||
def do_finalize(self):
|
def do_finalize(self):
|
||||||
USClocking.do_finalize(self)
|
XilinxClocking.do_finalize(self)
|
||||||
config = self.compute_config()
|
config = self.compute_config()
|
||||||
pll_fb = Signal()
|
pll_fb = Signal()
|
||||||
self.params.update(
|
self.params.update(
|
||||||
|
@ -426,11 +321,11 @@ class USPLL(USClocking):
|
||||||
self.specials += Instance("PLLE2_ADV", **self.params)
|
self.specials += Instance("PLLE2_ADV", **self.params)
|
||||||
|
|
||||||
|
|
||||||
class USMMCM(USClocking):
|
class USMMCM(XilinxClocking):
|
||||||
nclkouts_max = 7
|
nclkouts_max = 7
|
||||||
|
|
||||||
def __init__(self, speedgrade=-1):
|
def __init__(self, speedgrade=-1):
|
||||||
USClocking.__init__(self)
|
XilinxClocking.__init__(self)
|
||||||
self.divclk_divide_range = (1, 106+1)
|
self.divclk_divide_range = (1, 106+1)
|
||||||
self.clkin_freq_range = {
|
self.clkin_freq_range = {
|
||||||
-1: (10e6, 800e6),
|
-1: (10e6, 800e6),
|
||||||
|
@ -444,7 +339,7 @@ class USMMCM(USClocking):
|
||||||
}[speedgrade]
|
}[speedgrade]
|
||||||
|
|
||||||
def do_finalize(self):
|
def do_finalize(self):
|
||||||
USClocking.do_finalize(self)
|
XilinxClocking.do_finalize(self)
|
||||||
config = self.compute_config()
|
config = self.compute_config()
|
||||||
mmcm_fb = Signal()
|
mmcm_fb = Signal()
|
||||||
self.params.update(
|
self.params.update(
|
||||||
|
|
Loading…
Reference in New Issue