diff --git a/litex/soc/cores/clock.py b/litex/soc/cores/clock.py index ba017690d..e496673db 100644 --- a/litex/soc/cores/clock.py +++ b/litex/soc/cores/clock.py @@ -10,9 +10,9 @@ from litex.soc.interconnect.csr import * def period_ns(freq): return 1e9/freq -# Xilinx / 7-Series -------------------------------------------------------------------------------- +# Xilinx / Generic --------------------------------------------------------------------------------- -class S7Clocking(Module, AutoCSR): +class XilinxClocking(Module, AutoCSR): clkfbout_mult_frange = (2, 64+1) clkout_divide_range = (1, 128+1) @@ -118,45 +118,14 @@ class S7Clocking(Module, AutoCSR): def do_finalize(self): assert hasattr(self, "clkin") +# Xilinx / Spartan6 -------------------------------------------------------------------------------- -class S7PLL(S7Clocking): - 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): +class S6PLL(XilinxClocking): nclkouts_max = 6 clkin_freq_range = (19e6, 540e6) def __init__(self, speedgrade=-1): - S7Clocking.__init__(self) + XilinxClocking.__init__(self) self.vco_freq_range = { -1: (400e6, 1000e6), -2: (400e6, 1000e6), @@ -164,7 +133,7 @@ class S6PLL(S7Clocking): }[speedgrade] def do_finalize(self): - S7Clocking.do_finalize(self) + XilinxClocking.do_finalize(self) config = self.compute_config() pll_fb = Signal() self.params.update( @@ -187,14 +156,14 @@ class S6PLL(S7Clocking): self.specials += Instance("PLL_ADV", **self.params) -class S6DCM(S7Clocking): +class S6DCM(XilinxClocking): """ single output with f_out = f_in * {2 .. 256} / {1 .. 256} """ nclkouts_max = 1 clkfbout_mult_frange = (2, 256 + 1) clkout_divide_range = (1, 256 + 1) def __init__(self, speedgrade=-1): - S7Clocking.__init__(self) + XilinxClocking.__init__(self) self.clkin_freq_range = { -1: (0.5e6, 200e6), -2: (0.5e6, 333e6), @@ -208,7 +177,7 @@ class S6DCM(S7Clocking): }[speedgrade] def do_finalize(self): - S7Clocking.do_finalize(self) + XilinxClocking.do_finalize(self) config = self.compute_config() clk, f, p, m = sorted(self.clkouts.items())[0][1] self.params.update( @@ -224,12 +193,45 @@ class S6DCM(S7Clocking): ) 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 def __init__(self, speedgrade=-1): - S7Clocking.__init__(self) + XilinxClocking.__init__(self) self.divclk_divide_range = (1, 106+1) self.clkin_freq_range = { -1: (10e6, 800e6), @@ -244,7 +246,7 @@ class S7MMCM(S7Clocking): }[speedgrade] def do_finalize(self): - S7Clocking.do_finalize(self) + XilinxClocking.do_finalize(self) config = self.compute_config() mmcm_fb = Signal() self.params.update( @@ -283,118 +285,11 @@ class S7IDELAYCTRL(Module): # TODO: # - use Ultrascale primitives instead of 7-Series' ones. (Vivado recognize and convert them). -class USClocking(Module, AutoCSR): - 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): +class USPLL(XilinxClocking): nclkouts_max = 6 def __init__(self, speedgrade=-1): - USClocking.__init__(self) + XilinxClocking.__init__(self) self.divclk_divide_range = (1, 56+1) self.clkin_freq_range = { -1: (70e6, 800e6), @@ -408,7 +303,7 @@ class USPLL(USClocking): }[speedgrade] def do_finalize(self): - USClocking.do_finalize(self) + XilinxClocking.do_finalize(self) config = self.compute_config() pll_fb = Signal() self.params.update( @@ -426,11 +321,11 @@ class USPLL(USClocking): self.specials += Instance("PLLE2_ADV", **self.params) -class USMMCM(USClocking): +class USMMCM(XilinxClocking): nclkouts_max = 7 def __init__(self, speedgrade=-1): - USClocking.__init__(self) + XilinxClocking.__init__(self) self.divclk_divide_range = (1, 106+1) self.clkin_freq_range = { -1: (10e6, 800e6), @@ -444,7 +339,7 @@ class USMMCM(USClocking): }[speedgrade] def do_finalize(self): - USClocking.do_finalize(self) + XilinxClocking.do_finalize(self) config = self.compute_config() mmcm_fb = Signal() self.params.update(