lib.cdc: add ResetSynchronizer.
authorwhitequark <cz@m-labs.hk>
Sat, 26 Jan 2019 18:07:59 +0000 (18:07 +0000)
committerwhitequark <cz@m-labs.hk>
Sat, 26 Jan 2019 18:07:59 +0000 (18:07 +0000)
nmigen/lib/cdc.py
nmigen/test/test_lib_cdc.py

index 7ff459dba38661a22b3f320c49281881c92e8faf..c7624bc7b644d9fcf04d48cdb804539ad164b70b 100644 (file)
@@ -1,7 +1,7 @@
 from .. import *
 
 
-__all__ = ["MultiReg"]
+__all__ = ["MultiReg", "ResetSynchronizer"]
 
 
 class MultiReg:
@@ -23,3 +23,28 @@ class MultiReg:
             m.d[self.odomain] += o.eq(i)
         m.d.comb += self.o.eq(self._regs[-1])
         return m
+
+
+class ResetSynchronizer:
+    def __init__(self, arst, domain="sync", n=2):
+        self.arst = arst
+        self.domain = domain
+
+        self._regs = [Signal(name="arst{}".format(i), reset=1,
+                             attrs={"no_retiming": True})
+                      for i in range(n)]
+
+    def elaborate(self, platform):
+        if hasattr(platform, "get_reset_sync"):
+            return platform.get_reset_sync(self)
+
+        m = Module()
+        m.domains += ClockDomain("_reset_sync", async_reset=True)
+        for i, o in zip((0, *self._regs), self._regs):
+            m.d._reset_sync += o.eq(i)
+        m.d.comb += [
+            ClockSignal("_reset_sync").eq(ClockSignal(self.domain)),
+            ResetSignal("_reset_sync").eq(self.arst),
+            ResetSignal(self.domain).eq(self._regs[-1])
+        ]
+        return m
index af68d2f925f917b19a7fe558eed312aa8923213e..4a6c1cfb4b7e147cc0bcfa298cb496625c02d620 100644 (file)
@@ -1,5 +1,7 @@
 from .tools import *
 from ..hdl.ast import *
+from ..hdl.cd import *
+from ..hdl.dsl import *
 from ..back.pysim import *
 from ..lib.cdc import *
 
@@ -23,7 +25,7 @@ class MultiRegTestCase(FHDLTestCase):
             sim.add_process(process)
             sim.run()
 
-    def test_basic(self):
+    def test_reset_value(self):
         i = Signal(reset=1)
         o = Signal()
         frag = MultiReg(i, o, reset=1)
@@ -40,3 +42,42 @@ class MultiRegTestCase(FHDLTestCase):
                 self.assertEqual((yield o), 0)
             sim.add_process(process)
             sim.run()
+
+
+class ResetSynchronizerTestCase(FHDLTestCase):
+    def test_basic(self):
+        arst = Signal()
+        m = Module()
+        m.domains += ClockDomain("sync")
+        m.submodules += ResetSynchronizer(arst)
+        s = Signal(reset=1)
+        m.d.sync += s.eq(0)
+
+        with Simulator(m, vcd_file=open("test.vcd", "w")) as sim:
+            sim.add_clock(1e-6)
+            def process():
+                # initial reset
+                self.assertEqual((yield s), 1)
+                yield Tick(); yield Delay(1e-8)
+                self.assertEqual((yield s), 1)
+                yield Tick(); yield Delay(1e-8)
+                self.assertEqual((yield s), 1)
+                yield Tick(); yield Delay(1e-8)
+                self.assertEqual((yield s), 0)
+                yield Tick(); yield Delay(1e-8)
+
+                yield arst.eq(1)
+                yield Delay(1e-8)
+                self.assertEqual((yield s), 1)
+                yield Tick(); yield Delay(1e-8)
+                self.assertEqual((yield s), 1)
+                yield arst.eq(0)
+                yield Tick(); yield Delay(1e-8)
+                self.assertEqual((yield s), 1)
+                yield Tick(); yield Delay(1e-8)
+                self.assertEqual((yield s), 1)
+                yield Tick(); yield Delay(1e-8)
+                self.assertEqual((yield s), 0)
+                yield Tick(); yield Delay(1e-8)
+            sim.add_process(process)
+            sim.run()