lib.fifo: fix {r,w}_level in AsyncFIFOBuffered
authorJaro Habiger <jarohabiger@googlemail.com>
Tue, 18 Aug 2020 11:11:30 +0000 (13:11 +0200)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Fri, 31 Dec 2021 15:19:08 +0000 (15:19 +0000)
nmigen/lib/fifo.py
tests/test_lib_fifo.py

index bbe0e9dba984c245faeb205a6097f6db054e7d10..c78c96454676078feb6d5a48a755511fdd946cc0 100644 (file)
@@ -506,10 +506,15 @@ class AsyncFIFOBuffered(Elaboratable, FIFOInterface):
             fifo.w_data.eq(self.w_data),
             self.w_rdy.eq(fifo.w_rdy),
             fifo.w_en.eq(self.w_en),
-            self.w_level.eq(fifo.w_level),
         ]
 
-        m.d[self._r_domain] += self.r_level.eq(fifo.r_level + self.r_rdy - self.r_en)
+        r_consume_buffered = Signal()
+        m.d.comb += r_consume_buffered.eq(self.r_rdy - self.r_en)
+        m.d[self._r_domain] += self.r_level.eq(fifo.r_level + r_consume_buffered)
+
+        w_consume_buffered = Signal()
+        m.submodules.consume_buffered_cdc = AsyncFFSynchronizer(r_consume_buffered, w_consume_buffered, o_domain=self._w_domain)
+        m.d.comb += self.w_level.eq(fifo.w_level + w_consume_buffered)
 
         with m.If(self.r_en | ~self.r_rdy):
             m.d[self._r_domain] += [
index c8674ba01ff31739416dc6fc36dcd86cbdd97efe..bd5a9d9a60bc4ecc37c73ebb8b11b5e2ff113500 100644 (file)
@@ -282,6 +282,7 @@ class FIFOFormalCase(FHDLTestCase):
         self.check_async_fifo(AsyncFIFOBuffered(width=8, depth=4))
 
 
+# we need this testcase because we cant do model equivalence checking on the async fifos (at the moment)
 class AsyncFIFOSimCase(FHDLTestCase):
     def test_async_fifo_r_level_latency(self):
         fifo = AsyncFIFO(width=32, depth=10, r_domain="sync", w_domain="sync")
@@ -331,6 +332,18 @@ class AsyncFIFOSimCase(FHDLTestCase):
         with simulator.write_vcd("test.vcd"):
             simulator.run()
 
+    def test_async_fifo_level(self):
+        fifo = AsyncFIFO(width=32, depth=8, r_domain="read", w_domain="write")
+        self.check_async_fifo_level(fifo, fill_in=5, expected_level=5)
+
     def test_async_fifo_level_full(self):
         fifo = AsyncFIFO(width=32, depth=8, r_domain="read", w_domain="write")
         self.check_async_fifo_level(fifo, fill_in=10, expected_level=8)
+
+    def test_async_buffered_fifo_level(self):
+        fifo = AsyncFIFOBuffered(width=32, depth=9, r_domain="read", w_domain="write")
+        self.check_async_fifo_level(fifo, fill_in=5, expected_level=5)
+
+    def test_async_buffered_fifo_level_full(self):
+        fifo = AsyncFIFOBuffered(width=32, depth=9, r_domain="read", w_domain="write")
+        self.check_async_fifo_level(fifo, fill_in=10, expected_level=9)