gen/genlib/cdc: add gearbox
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Wed, 19 Apr 2017 07:54:28 +0000 (09:54 +0200)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Wed, 19 Apr 2017 07:54:51 +0000 (09:54 +0200)
litex/gen/genlib/cdc.py

index 72efb03f74d63a8b5837b10f2d490cd0d00e5de6..6e7b0ad8b5a7b947e6d8817168b07efd96dca262 100644 (file)
@@ -1,6 +1,7 @@
 """
 Clock domain crossing module
 """
+from fractions import gcd
 
 from litex.gen.fhdl.structure import *
 from litex.gen.fhdl.module import Module
@@ -193,3 +194,59 @@ class ElasticBuffer(Module):
             rdport.adr.eq(rdpointer),
             self.dout.eq(rdport.dat_r)
         ]
+
+
+def lcm(a, b):
+    """Compute the lowest common multiple of a and b"""
+    return int(a * b / gcd(a, b))
+
+
+class Gearbox(Module):
+    def __init__(self, iwidth, idomain, owidth, odomain):
+        self.i = Signal(iwidth)
+        self.o = Signal(owidth)
+
+        # # #
+
+        reset = Signal()
+        cd_write = ClockDomain()
+        cd_read = ClockDomain()
+        self.comb += [
+            cd_write.clk.eq(ClockSignal(idomain)),
+            cd_read.clk.eq(ClockSignal(odomain)),
+            reset.eq(ResetSignal(idomain) | ResetSignal(odomain))
+        ]
+        self.specials += [
+            AsyncResetSynchronizer(cd_write, reset),
+            AsyncResetSynchronizer(cd_read, reset)
+        ]
+        self.clock_domains += cd_write, cd_read
+
+        storage = Signal(lcm(iwidth, owidth))
+        wrchunks = len(storage)//iwidth
+        rdchunks = len(storage)//owidth
+        wrpointer = Signal(max=wrchunks, reset=0 if iwidth > owidth else wrchunks-1)
+        rdpointer = Signal(max=rdchunks, reset=rdchunks-1 if iwidth > owidth else 0)
+
+        self.sync.write += \
+            If(wrpointer == wrchunks-1,
+                wrpointer.eq(0)
+            ).Else(
+                wrpointer.eq(wrpointer + 1)
+            )
+        cases = {}
+        for i in range(wrchunks):
+            cases[i] = [storage[iwidth*i:iwidth*(i+1)].eq(self.i)]
+        self.sync.write += Case(wrpointer, cases)
+
+
+        self.sync.read += \
+            If(rdpointer == rdchunks-1,
+                rdpointer.eq(0)
+            ).Else(
+                rdpointer.eq(rdpointer + 1)
+            )
+        cases = {}
+        for i in range(rdchunks):
+            cases[i] = [self.o.eq(storage[owidth*i:owidth*(i+1)])]
+        self.sync.read += Case(rdpointer, cases)
\ No newline at end of file