first cut at Arty A7 Clock-Reset-Generator with S7 PLL
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sun, 20 Mar 2022 11:34:42 +0000 (11:34 +0000)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sun, 20 Mar 2022 11:34:42 +0000 (11:34 +0000)
src/arty_crg.py
src/ls2.py

index 58a5024379798e36e6de0b71b3e350c1d11efdb5..e1a7c65a46944bd512ce9ce04f3d4e581e3a9b5b 100644 (file)
@@ -11,6 +11,8 @@
 
 from nmigen import (Elaboratable, Module, Signal, ClockDomain, Instance,
                     ClockSignal, ResetSignal)
+from nmigen.lib.cdc import ResetSynchronizer
+import math
 
 __ALL__ = ["ArtyCRG"]
 
@@ -26,13 +28,15 @@ def clkdiv_range(start, stop, step=1):
         yield int(current) if math.floor(current) == current else current
         current += step
 
+
 # Xilinx / Generic -----------------------------------------------------
 
-class XilinxClocking(Module):
+class XilinxClocking(Elaboratable):
     clkfbout_mult_frange = (2,  64+1)
     clkout_divide_range  = (1, 128+1)
 
-    def __init__(self, vco_margin=0):
+    def __init__(self, clkin, vco_margin=0):
+        self.clkin      = clkin
         self.vco_margin = vco_margin
         self.reset      = Signal()
         self.locked     = Signal()
@@ -43,48 +47,56 @@ class XilinxClocking(Module):
         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
+    def set_clkin_freq(self, freq):
         self.clkin_freq = freq
-        register_clkin_log(self.logger, clkin, freq)
 
     def create_clkout(self, cd, freq, phase=0, buf="bufg",
                             margin=1e-2, with_reset=True, ce=None):
         assert self.nclkouts < self.nclkouts_max
         clkout = Signal()
-        self.clkouts[self.nclkouts] = (clkout, freq, phase, margin)
-        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)
-            elif buf == "bufgce":
-                if ce is None:
-                    raise ValueError("BUFGCE requires user to provide "
-                                     "a clock enable ce Signal")
-                self.specials += Instance("BUFGCE", i_I=clkout,
-                                          o_O=clkout_buf, i_CE=ce)
-            elif buf == "bufio":
-                self.specials += Instance("BUFIO", i_I=clkout, 
-                                          o_O=clkout_buf)
+        self.clkouts[self.nclkouts] = (clkout, freq, phase, margin, cd,
+                                       buf, with_reset, ce)
+
+    def elaborate(self, platform):
+        assert self.clkin_freq is not None
+        m = Module()
+        comb = m.d.comb
+        for n, clkcfg in self.clkouts.items():
+            (clkout, freq, phase, margin, cd, buf, with_reset, ce) = clkcfg
+            if with_reset:
+                arst = Signal()
+                m.submodules += ResetSynchronizer(arst, domain=cd.name)
+                comb += arst.eq(~self.locked | self.reset)
+            if buf is None:
+                comb += cd.clk.eq(clkout)
             else:
-                raise ValueError("Unsupported clock buffer: {}".format(buf))
-        create_clkout_log(self.logger, cd.name, freq, margin, self.nclkouts)
-        self.nclkouts += 1
-        assert hasattr(self, "clkin")
+                clkout_buf = Signal()
+                comb += cd.clk.eq(clkout_buf)
+                if buf == "bufg":
+                    m.submodules += Instance("BUFG",
+                                              i_I=clkout,
+                                              o_O=clkout_buf)
+                elif buf == "bufr":
+                    m.submodules += Instance("BUFR",
+                                              i_I=clkout,
+                                              o_O=clkout_buf)
+                elif buf == "bufgce":
+                    if ce is None:
+                        raise ValueError("BUFGCE requires user to provide "
+                                         "a clock enable ce Signal")
+                    m.submodules += Instance("BUFGCE",
+                                              i_I=clkout,
+                                              o_O=clkout_buf,
+                                              i_CE=ce)
+                elif buf == "bufio":
+                    m.submodules += Instance("BUFIO",
+                                              i_I=clkout,
+                                              o_O=clkout_buf)
+                else:
+                    raise ValueError("Unsupported clock buffer: %s" % buf)
+            print(cd.name, freq, margin, self.nclkouts)
+
+        return m
 
     def compute_config(self):
         config = {}
@@ -99,7 +111,8 @@ class XilinxClocking(Module):
                 (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()):
+                    for n, clkcfg in sorted(self.clkouts.items()):
+                        (clkout, f, p, m, _, _, _, _) = clkcfg
                         valid = False
                         d_ranges = [self.clkout_divide_range]
                         r = getattr(self, "clkout%d_divide_range" % n, None)
@@ -123,7 +136,7 @@ class XilinxClocking(Module):
                 if all_valid:
                     config["vco"]           = vco_freq
                     config["clkfbout_mult"] = clkfbout_mult
-                    compute_config_log(self.logger, config)
+                    print(config)
                     return config
         raise ValueError("No PLL config found")
 
@@ -134,10 +147,10 @@ class S7PLL(XilinxClocking):
     nclkouts_max = 6
     clkin_freq_range = (19e6, 800e6)
 
-    def __init__(self, speedgrade=-1):
+    def __init__(self, clkin, speedgrade=-1):
+        super().__init__(clkin)
         #self.logger = logging.getLogger("S7PLL")
         print ("Creating S7PLL, speedgrade %d" % speedgrade)
-        XilinxClocking.__init__(self)
         self.divclk_divide_range = (1, 56+1)
         self.vco_freq_range = {
             -1: (800e6, 1600e6),
@@ -145,8 +158,8 @@ class S7PLL(XilinxClocking):
             -3: (800e6, 2133e6),
         }[speedgrade]
 
-    def do_finalize(self):
-        XilinxClocking.do_finalize(self)
+    def elaborate(self, platform):
+        m = super().elaborate(platform)
         config = self.compute_config()
         pll_fb = Signal()
         self.params.update(
@@ -158,14 +171,14 @@ class S7PLL(XilinxClocking):
             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)]
+        for n, (clk, f, p, _, _, _, _, _) in sorted(self.clkouts.items()):
+            div = config["clkout{}_divide".format(n)]
+            phs = config["clkout{}_phase".format(n)]
+            self.params["p_CLKOUT{}_DIVIDE".format(n)] = div
+            self.params["p_CLKOUT{}_PHASE".format(n)] = phs
             self.params["o_CLKOUT{}".format(n)] = clk
-        self.specials += Instance("PLLE2_ADV", **self.params)
-
+        m.submodules += Instance("PLLE2_ADV", **self.params)
+        return m
 
 
 class ECP5PLL(Elaboratable):
@@ -341,7 +354,7 @@ class ArtyA7CRG(Elaboratable):
         #cd_clk200    = ClockDomain("cd_clk200")
         #cd_eth       = ClockDomain("cd_eth")
         dramsync      = ClockDomain("dramsync")
-    
+
         m.domains += sync
         #m.domains += sync2x
         #m.domains += sync4x
@@ -349,26 +362,28 @@ class ArtyA7CRG(Elaboratable):
         #m.domains += cd_clk200
         #m.domains += cd_eth
         m.domains += dramsync
-    
+
         clk100_ibuf = Signal()
         clk100_buf  = Signal()
         m.submodules += [
-            Instance("IBUF", i_I=ckl100, o_O=clk100_ibuf),
+            Instance("IBUF", i_I=clk100, o_O=clk100_ibuf),
             Instance("BUFG", i_I=clk100_ibuf, o_O=clk100_buf)
         ]
 
-        self.submodules.pll = pll = S7PLL(speedgrade=-1)
+        m.submodules.pll = pll = S7PLL(clk100_buf, speedgrade=-1)
         reset = platform.request(platform.default_rst).i
-        self.comb += pll.reset.eq(~reset)
-        pll.register_clkin(clk100_buf, 100e6)
-        pll.create_clkout(self.sync, sys_clk_freq)
+        m.d.comb += pll.reset.eq(~reset)
+        pll.set_clkin_freq(100e6)
 
-        platform.add_period_constraint(clk100_buf, 1e9/100e6)
-        platform.add_period_constraint(sync.clk, 1e9/sys_clk_freq)
-        platform.add_false_path_constraints(clk100_buf, sync.clk)
+        pll.create_clkout(sync, self.sys_clk_freq)
+
+        #platform.add_period_constraint(clk100_buf, 1e9/100e6)
+        #platform.add_period_constraint(sync.clk, 1e9/sys_clk_freq)
+        #platform.add_false_path_constraints(clk100_buf, sync.clk)
 
         # temporarily set dram sync clock exactly equal to main sync
         m.d.comb += ClockSignal("dramsync").eq(ClockSignal("sync"))
+        return m
 
 
 class ECPIX5CRG(Elaboratable):
index 1968aa752ab614e4b70f65359ed2649b2f7ae65d..5e0997d6eb2cc8fb116751f2cf88c3e1ff9b02b0 100644 (file)
@@ -52,6 +52,7 @@ from nmigen_boards.test.blinky import Blinky
 from icarusversa import IcarusVersaPlatform
 # Clock-Reset Generator (works for all ECP5 platforms)
 from crg import ECPIX5CRG
+from arty_crg import ArtyA7CRG
 
 import sys
 import os
@@ -273,7 +274,7 @@ class DDR3SoC(SoC, Elaboratable):
         if fpga in ['versa_ecp5', 'versa_ecp5_85', 'isim']:
             self.crg = ECPIX5CRG(clk_freq)
         if fpga in ['arty_a7']:
-            self.crg = ArtyCRG(clk_freq)
+            self.crg = ArtyA7CRG(clk_freq)
 
         # set up CPU, with 64-to-32-bit downconverters
         if add_cpu: