reorg of the ECP5 Clock-Reset to be able to add
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Fri, 15 Apr 2022 15:48:43 +0000 (16:48 +0100)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Fri, 15 Apr 2022 16:48:12 +0000 (17:48 +0100)
a 2nd clock (DRAM)

src/ecp5_crg.py

index 72c1af5685f196deab60e4fdb11ba7fdde916e74..bd91df1a4e9c4ff19b9275def55d64faaf102e58 100644 (file)
@@ -177,7 +177,7 @@ class ECP5CRG(Elaboratable):
         self.dram_clk_freq = dram_clk_freq
         self.pod_bits = pod_bits
 
-    def phase2_domain(self, m, pll, name, freq):
+    def phase2_domain(self, m, pll, name, freq, esyncb):
         """creates a domain that can be used with xdr=4 platform resources.
 
         this requires creating a domain at *twice* the frequency,
@@ -187,29 +187,35 @@ class ECP5CRG(Elaboratable):
             pads.a.o_fclk.eq(ClockSignal("dramsync2x")),
         """
 
+        # create names
+        cd2x = "%s2x" % name
+        cd2x_ub = cd2x+"_unbuf"
+        cd = name
         # Generating sync2x from extclk
-        cd_2x = ClockDomain("%s2x" % name, local=False)
-        cd_2x_unbuf = ClockDomain("%s2x_unbuf" % name,
-                                      local=False, reset_less=True)
+        cd_2x = ClockDomain(cd2x, local=False)
+        cd_2x_unbuf = ClockDomain(cd2x_ub, local=False, reset_less=True)
         cd_ = ClockDomain("%s" % name, local=False)
 
         # create PLL clocks
-        pll.create_clkout(ClockSignal("%s2x_unbuf" % name), 2*freq)
-        m.submodules += Instance("ECLKSYNCB",
-                i_ECLKI = ClockSignal("%s2x_unbuf" % name),
-                i_STOP  = 0,
-                o_ECLKO = ClockSignal("%s2x" % name))
+        pll.create_clkout(ClockSignal(cd2x_ub), 2*freq)
+        if esyncb:
+            m.submodules["%s_eclksyncb" % cd] = Instance("ECLKSYNCB",
+                    i_ECLKI = ClockSignal(cd2x_ub),
+                    i_STOP  = 0,
+                    o_ECLKO = ClockSignal(cd2x))
+        else:
+            m.d.comb += ClockSignal(cd2x).eq(ClockSignal(cd2x_ub)) # no esyncb
         m.domains += cd_2x_unbuf
         m.domains += cd_2x
         m.domains += cd_
 
         # # Generating sync from sync2x
-        m.submodules += Instance("CLKDIVF",
+        m.submodules["%s_clkdivf" % cd] = Instance("CLKDIVF",
             p_DIV="2.0",
             i_ALIGNWD=0,
-            i_CLKI=ClockSignal("%s2x" % name),
+            i_CLKI=ClockSignal(cd2x),
             i_RST=0,
-            o_CDIVX=ClockSignal("%s" % name))
+            o_CDIVX=ClockSignal(cd))
 
     def elaborate(self, platform):
         m = Module()
@@ -229,18 +235,16 @@ class ECP5CRG(Elaboratable):
         gsr0 = Signal()
         gsr1 = Signal()
 
-        m.submodules += [
-            Instance("FD1S3AX", p_GSR="DISABLED",
+        m.submodules.gsr0 = Instance("FD1S3AX", p_GSR="DISABLED",
                                 i_CK=ClockSignal("rawclk"),
                                 i_D=~reset,
-                                o_Q=gsr0),
-            Instance("FD1S3AX", p_GSR="DISABLED",
+                                o_Q=gsr0)
+        m.submodules.gsr1 = Instance("FD1S3AX", p_GSR="DISABLED",
                                 i_CK=ClockSignal("rawclk"),
                                 i_D=gsr0,
-                                o_Q=gsr1),
-            Instance("SGSR", i_CLK=ClockSignal("rawclk"),
-                             i_GSR=gsr1),
-        ]
+                                o_Q=gsr1)
+        m.submodules.sgsr = Instance("SGSR", i_CLK=ClockSignal("rawclk"),
+                             i_GSR=gsr1)
 
         # PLL
         m.submodules.pll = pll = PLL(ClockSignal("rawclk"), reset=~reset)
@@ -259,19 +263,28 @@ class ECP5CRG(Elaboratable):
         # create PLL input clock from platform default frequency
         pll.set_clkin_freq(platform.default_clk_frequency)
 
-        # create 25 mhz "init" clock, straight (no 2x phase stuff)
-        cd_init = ClockDomain("init", local=False)
-        pll.create_clkout(ClockSignal("init"), 25e6)
-        m.domains += cd_init
-        m.d.comb += ResetSignal("init").eq(reset_ok)
-
-        # Generating sync2x and sync from extclk, which is *only* how
-        # xdr=4 can be requested on the sync domain
-        self.phase2_domain(m, pll, "sync", self.sys_clk_freq)
+        # single or double main sync clock domain.  double needs a 2nd PLL
+        # to match up with the CLKESYNCB, one per quadrant inside the ECP5
+        if self.dram_clk_freq is not None:
+            m.domains += ClockDomain("sync_unbuf", local=False, reset_less=True)
+            m.domains += ClockDomain("sync", local=False)
+            pll.create_clkout(ClockSignal("sync_unbuf"), self.sys_clk_freq)
+            m.d.comb += ClockSignal("sync").eq(ClockSignal("sync_unbuf"))
+        else:
+            # Generating sync2x and sync from extclk, which is *only* how
+            # xdr=4 can be requested on the sync domain. also do not request
+            # an edge-clock-stop
+            self.phase2_domain(m, pll, "sync", self.sys_clk_freq, True)
+            m.d.comb += ResetSignal("sync2x").eq(reset_ok)
         m.d.comb += ResetSignal("sync").eq(reset_ok)
 
+        # DRAM clock: if not requested set to sync, otherwise create with
+        # a CLKESYNCB (which is set to no-stop at the moment)
         if self.dram_clk_freq is not None:
-            self.phase2_domain(m, pll, "dramsync", self.dram_clk_freq)
+            self.phase2_domain(m, pll, "dramsync", self.dram_clk_freq, True)
+            # resets for the dram domains
+            m.d.comb += ResetSignal("dramsync2x").eq(reset_ok)
+            m.d.comb += ResetSignal("dramsync").eq(reset_ok)
         else:
             # alias dramsync and dramsync2x to sync and sync2x
             cd_dramsync = ClockDomain("dramsync", local=False)
@@ -282,9 +295,11 @@ class ECP5CRG(Elaboratable):
             m.domains += cd_dramsync2x
             m.d.comb += ClockSignal("dramsync2x").eq(ClockSignal("sync2x"))
 
-        # resets for the dram domains
-        m.d.comb += ResetSignal("dramsync2x").eq(reset_ok)
-        m.d.comb += ResetSignal("dramsync").eq(reset_ok)
+        # create 25 mhz "init" clock, straight (no 2x phase stuff)
+        cd_init = ClockDomain("init", local=False)
+        pll.create_clkout(ClockSignal("init"), 25e6)
+        m.domains += cd_init
+        m.d.comb += ResetSignal("init").eq(reset_ok)
 
         return m