genlib/fifo: add asynchronous FIFO
authorSebastien Bourdeauducq <sebastien@milkymist.org>
Thu, 25 Apr 2013 11:30:37 +0000 (13:30 +0200)
committerSebastien Bourdeauducq <sebastien@milkymist.org>
Thu, 25 Apr 2013 11:30:37 +0000 (13:30 +0200)
migen/genlib/fifo.py

index 23f8c9be133700cd6afcc853c61726083bbcff1f..9f88ab5e3a17d1b269de31b17c2ba9b45738d4e1 100644 (file)
@@ -1,6 +1,7 @@
 from migen.fhdl.structure import *
 from migen.fhdl.specials import Memory
 from migen.fhdl.module import Module
+from migen.genlib.cdc import MultiReg, GrayCounter
 
 def _inc(signal, modulo):
        if modulo == 2**len(signal):
@@ -12,7 +13,7 @@ def _inc(signal, modulo):
                        signal.eq(signal + 1)
                )
 
-class SyncFIFO(Module):
+class _FIFOInterface:
        def __init__(self, width, depth):
                self.din = Signal(width)
                self.we = Signal()
@@ -21,6 +22,10 @@ class SyncFIFO(Module):
                self.re = Signal()
                self.readable = Signal() # not empty
 
+class SyncFIFO(Module, _FIFOInterface):
+       def __init__(self, width, depth):
+               _FIFOInterface.__init__(self, width, depth)
+
                ###
 
                do_write = Signal()
@@ -62,3 +67,47 @@ class SyncFIFO(Module):
                        self.writable.eq(level != depth),
                        self.readable.eq(level != 0)
                ]
+
+class AsyncFIFO(Module, _FIFOInterface):
+       def __init__(self, width, depth):
+               _FIFOInterface.__init__(self, width, depth)
+
+               ###
+
+               depth_bits = log2_int(depth, True)
+
+               produce = GrayCounter(depth_bits+1)
+               self.add_submodule(produce, "write")
+               consume = GrayCounter(depth_bits+1)
+               self.add_submodule(consume, "read")
+               self.comb += [
+                       produce.ce.eq(self.writable & self.we),
+                       consume.ce.eq(self.readable & self.re)
+               ]
+
+               # TODO: disable retiming on produce.q and consume.q
+
+               produce_rdomain = Signal(depth_bits+1)
+               self.specials += MultiReg(produce.q, produce_rdomain, "read")
+               consume_wdomain = Signal(depth_bits+1)
+               self.specials += MultiReg(consume.q, consume_wdomain, "write")
+               self.comb += [
+                       self.writable.eq((produce.q[-1] == consume_wdomain[-1])
+                        | (produce.q[-2] == consume_wdomain[-2])
+                        | (produce.q[:-2] != consume_wdomain[:-2])),
+                       self.readable.eq(consume.q != produce_rdomain)
+               ]
+
+               storage = Memory(width, depth)
+               self.specials += storage
+               wrport = storage.get_port(write_capable=True, clock_domain="write")
+               self.comb += [
+                       wrport.adr.eq(produce.q_binary[:-1]),
+                       wrport.dat_w.eq(self.din),
+                       wrport.we.eq(produce.ce)
+               ]
+               rdport = storage.get_port(clock_domain="read")
+               self.comb += [
+                       rdport.adr.eq(consume.q_binary[:-1]),
+                       self.dout.eq(rdport.dat_r)
+               ]