soc/cores: init clock abstraction module
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Mon, 24 Sep 2018 18:25:57 +0000 (20:25 +0200)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Mon, 24 Sep 2018 20:49:01 +0000 (22:49 +0200)
litex/soc/cores/clock.py [new file with mode: 0644]

diff --git a/litex/soc/cores/clock.py b/litex/soc/cores/clock.py
new file mode 100644 (file)
index 0000000..d36f660
--- /dev/null
@@ -0,0 +1,114 @@
+"""
+Clock Abstraction Modules
+
+
+Made in Paris-CDG while waiting a delayed Air-France KLM flight...
+"""
+
+from migen import *
+from migen.genlib.io import DifferentialInput
+from migen.genlib.resetsync import AsyncResetSynchronizer
+
+
+# TODO:
+# - add S7PLL support for all family/speedgrades (currently Artix7 -3 speedgrade)
+# - add S7MMCM support (should be very similar to S7PLL)
+
+
+def period_ns(freq):
+    return 1e9/freq
+
+
+class S7PLL(Module):
+    nclkouts_max = 6
+    clkin_freq_range = (10e6, 800e6)
+    vco_freq_range = (600e6, 1600e6)
+    clkfbout_mult_frange = (2, 64+1)
+    clkout_divide_range = (1, 128+1)
+
+    def __init__(self):
+        self.reset = Signal()
+        self.locked = Signal()
+        self.clkin_freq = None
+        self.vcxo_freq = None
+        self.nclkouts = 0
+        self.clkouts = {}
+        self.config = {}
+
+    def register_clkin(self, clkin, freq):
+        self.clkin = Signal()
+        if isinstance(clkin, Signal):
+            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):
+        assert self.nclkouts < self.nclkouts_max
+        clkout = Signal()
+        clkout_bufg = Signal()
+        self.specials += AsyncResetSynchronizer(cd, ~self.locked | self.reset),
+        self.specials += Instance("BUFG", i_I=clkout, o_O=clkout_bufg)
+        self.comb += cd.clk.eq(clkout_bufg)
+        self.clkouts[self.nclkouts] = (clkout, freq, phase)
+        self.nclkouts += 1
+        return clkout_bufg
+
+    def compute_config(self):
+        config = {}
+        config["divclk_divide"] = 1
+        for clkfbout_mult in range(*self.clkfbout_mult_frange):
+            all_valid = True
+            vco_freq = self.clkin_freq*clkfbout_mult
+            (vco_freq_min, vco_freq_max) = self.vco_freq_range
+            if vco_freq >= vco_freq_min and vco_freq <= vco_freq_max:
+                for n, (clk, f, p) in sorted(self.clkouts.items()):
+                    valid = False
+                    for d in range(*self.clkout_divide_range):
+                        clk_freq = vco_freq/d
+                        if clk_freq == f:
+                            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 add_idelayctrl(self, cd):
+        reset_counter = Signal(4, reset=15)
+        ic_reset = Signal(reset=1)
+        sync = getattr(self.sync, cd.name)
+        sync += \
+            If(reset_counter != 0,
+                reset_counter.eq(reset_counter - 1)
+            ).Else(
+                ic_reset.eq(0)
+            )
+        self.specials += Instance("IDELAYCTRL", i_REFCLK=cd.clk, i_RST=ic_reset)
+
+    def do_finalize(self):
+        assert hasattr(self, "clkin")
+        config = self.compute_config()
+        pll_fb = Signal()
+        pll_params = dict(
+            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) in sorted(self.clkouts.items()):
+            pll_params["p_CLKOUT{}_DIVIDE".format(n)] = config["clkout{}_divide".format(n)]
+            pll_params["p_CLKOUT{}_PHASE".format(n)] = config["clkout{}_phase".format(n)]
+            pll_params["o_CLKOUT{}".format(n)] = clk
+        self.specials += Instance("PLLE2_BASE", **pll_params)