diff --git a/litex/soc/cores/clock.py b/litex/soc/cores/clock.py index 083e44a31..9a42a0de5 100644 --- a/litex/soc/cores/clock.py +++ b/litex/soc/cores/clock.py @@ -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: diff --git a/test/test_clock.py b/test/test_clock.py index 527963c83..2000ea503 100644 --- a/test/test_clock.py +++ b/test/test_clock.py @@ -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()