gen/genlib/cdc: add ElasticBuffer
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Thu, 13 Oct 2016 15:04:39 +0000 (17:04 +0200)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Thu, 13 Oct 2016 15:04:39 +0000 (17:04 +0200)
litex/gen/genlib/cdc.py

index 90b5f907699c114720d57e9bc9cbb3575f248430..e9dd501d55f7c1e1c78db0670a9d2b331b20af13 100644 (file)
@@ -1,8 +1,9 @@
 from litex.gen.fhdl.structure import *
 from litex.gen.fhdl.module import Module
-from litex.gen.fhdl.specials import Special
+from litex.gen.fhdl.specials import Special, Memory
 from litex.gen.fhdl.bitcontainer import value_bits_sign
 from litex.gen.genlib.misc import WaitTimer
+from litex.gen.genlib.resetsync import AsyncResetSynchronizer
 
 
 class NoRetiming(Special):
@@ -139,3 +140,46 @@ class GrayCounter(Module):
             self.q_binary.eq(self.q_next_binary),
             self.q.eq(self.q_next)
         ]
+
+
+class ElasticBuffer(Module):
+    def __init__(self, width, depth, idomain, odomain):
+        self.reset = Signal()
+        self.din = Signal(width)
+        self.dout = Signal(width)
+
+        # # #
+
+        cd_write = ClockDomain()
+        cd_read = ClockDomain()
+        self.comb += [
+            cd_write.clk.eq(ClockSignal(idomain)),
+            cd_read.clk.eq(ClockSignal(odomain))
+        ]
+        self.specials += [
+            AsyncResetSynchronizer(cd_write, self.reset),
+            AsyncResetSynchronizer(cd_read, self.reset)
+        ]
+        self.clock_domains += cd_write, cd_read
+
+        wrpointer = Signal(max=depth, reset=depth//2)
+        rdpointer = Signal(max=depth)
+
+        storage = Memory(width, depth)
+        self.specials += storage
+
+        wrport = storage.get_port(write_capable=True, clock_domain="write")
+        rdport = storage.get_port(clock_domain="read")
+        self.specials += wrport, rdport
+
+        self.sync.write += wrpointer.eq(wrpointer + 1)
+        self.sync.read += rdpointer.eq(rdpointer + 1)
+
+        self.comb += [
+            wrport.we.eq(1),
+            wrport.adr.eq(wrpointer),
+            wrport.dat_w.eq(self.din),
+
+            rdport.adr.eq(rdpointer),
+            self.dout.eq(rdport.dat_r)
+        ]