cores/clock: use common XilinxClocking class for all Xilinx clocking modules
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Tue, 23 Apr 2019 04:35:39 +0000 (06:35 +0200)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Tue, 23 Apr 2019 04:35:39 +0000 (06:35 +0200)
litex/soc/cores/clock.py

index ba017690df3544e608ac1f98d695d28f96dadfe7..e496673db4a100ba39e8e4a5072e8f9ad58a33ef 100644 (file)
@@ -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 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]
 
-class S7MMCM(S7Clocking):
+    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(