From b15f0562a62ebbd48b87f2d662cd01845c857c62 Mon Sep 17 00:00:00 2001
From: Jaro Habiger <jarohabiger@googlemail.com>
Date: Tue, 18 Aug 2020 13:11:30 +0200
Subject: [PATCH] lib.fifo: fix {r,w}_level in AsyncFIFOBuffered

---
 nmigen/lib/fifo.py     |  9 +++++++--
 tests/test_lib_fifo.py | 13 +++++++++++++
 2 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/nmigen/lib/fifo.py b/nmigen/lib/fifo.py
index bbe0e9d..c78c964 100644
--- a/nmigen/lib/fifo.py
+++ b/nmigen/lib/fifo.py
@@ -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] += [
diff --git a/tests/test_lib_fifo.py b/tests/test_lib_fifo.py
index c8674ba..bd5a9d9 100644
--- a/tests/test_lib_fifo.py
+++ b/tests/test_lib_fifo.py
@@ -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)
-- 
2.30.2