cores/clock: add initial Xilinx Ultrascale Plus PLL/MMCM/IDELAYCTRL support.

This commit is contained in:
Florent Kermarrec 2020-09-03 18:57:05 +02:00
parent 6d8a367abe
commit f7b6dd05ae
2 changed files with 103 additions and 1 deletions

View File

@ -472,7 +472,7 @@ class USMMCM(XilinxClocking):
def __init__(self, speedgrade=-1):
self.logger = logging.getLogger("USMMCM")
self.logger.info("Creating UMMCM, {}.".format(colorer("speedgrade {}".format(speedgrade))))
self.logger.info("Creating USMMCM, {}.".format(colorer("speedgrade {}".format(speedgrade))))
XilinxClocking.__init__(self)
self.divclk_divide_range = (1, 106+1)
self.clkin_freq_range = {
@ -543,6 +543,93 @@ class USIDELAYCTRL(Module):
AsyncResetSynchronizer(self.cd_ic, ic_reset)
]
# Xilinx / Ultrascale Plus -------------------------------------------------------------------------
# TODO:
# - use Ultrascale Plus primitives instead of 7-Series' ones. (Vivado recognize and convert them).
class USPPLL(XilinxClocking):
nclkouts_max = 6
def __init__(self, speedgrade=-1):
self.logger = logging.getLogger("USPPLL")
self.logger.info("Creating USPPLL, {}.".format(colorer("speedgrade {}".format(speedgrade))))
XilinxClocking.__init__(self)
self.divclk_divide_range = (1, 56+1)
self.clkin_freq_range = {
-1: (70e6, 800e6),
-2: (70e6, 933e6),
-3: (70e6, 1066e6),
}[speedgrade]
self.vco_freq_range = {
-1: (750e6, 1500e6),
-2: (750e6, 1500e6),
-3: (750e6, 1500e6),
}[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, i_RST=self.reset,
# VCO
p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=1e9/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 USPMMCM(XilinxClocking):
nclkouts_max = 7
def __init__(self, speedgrade=-1):
self.logger = logging.getLogger("USPMMCM")
self.logger.info("Creating USPMMCM, {}.".format(colorer("speedgrade {}".format(speedgrade))))
XilinxClocking.__init__(self)
self.divclk_divide_range = (1, 106+1)
self.clkin_freq_range = {
-1: (10e6, 800e6),
-2: (10e6, 933e6),
-3: (10e6, 1066e6),
}[speedgrade]
self.vco_freq_range = {
-1: (800e6, 1600e6),
-2: (800e6, 1600e6),
-3: (800e6, 1600e6),
}[speedgrade]
def do_finalize(self):
XilinxClocking.do_finalize(self)
config = self.compute_config()
mmcm_fb = Signal()
self.params.update(
p_BANDWIDTH="OPTIMIZED", o_LOCKED=self.locked, i_RST=self.reset,
# VCO
p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=1e9/self.clkin_freq,
p_CLKFBOUT_MULT_F=config["clkfbout_mult"], p_DIVCLK_DIVIDE=config["divclk_divide"],
i_CLKIN1=self.clkin, i_CLKFBIN=mmcm_fb, o_CLKFBOUT=mmcm_fb,
)
for n, (clk, f, p, m) in sorted(self.clkouts.items()):
if n == 0:
self.params["p_CLKOUT{}_DIVIDE_F".format(n)] = config["clkout{}_divide".format(n)]
else:
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("MMCME2_ADV", **self.params)
class USPIDELAYCTRL(USIDELAYCTRL): pass
# Lattice / iCE40 ----------------------------------------------------------------------------------
# TODO:

View File

@ -55,6 +55,21 @@ class TestClock(unittest.TestCase):
mmcm.create_clkout(ClockDomain("clkout{}".format(i)), 200e6)
mmcm.compute_config()
# Xilinx / Ultrascale Plus
def test_usppll(self):
pll = USPPLL()
pll.register_clkin(Signal(), 100e6)
for i in range(pll.nclkouts_max):
pll.create_clkout(ClockDomain("clkout{}".format(i)), 200e6)
pll.compute_config()
def test_uspmmcm(self):
mmcm = USPMMCM()
mmcm.register_clkin(Signal(), 100e6)
for i in range(mmcm.nclkouts_max):
mmcm.create_clkout(ClockDomain("clkout{}".format(i)), 200e6)
mmcm.compute_config()
# Lattice / iCE40
def test_ice40pll(self):
pll = USMMCM()