soc/interconnect/axi: add Wishbone2AXILite
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Wed, 20 Nov 2019 11:32:22 +0000 (12:32 +0100)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Wed, 20 Nov 2019 11:32:22 +0000 (12:32 +0100)
litex/soc/interconnect/axi.py
test/test_axi.py

index 5d362c7b4bcc9ca42fb33957bc8e2e684d348c01..2681ff5ae3c27094844d8774d7ccc590c69846ec 100644 (file)
@@ -66,7 +66,7 @@ class AXIInterface(Record):
         self.ar = stream.Endpoint(ax_description(address_width, id_width))
         self.r  = stream.Endpoint(r_description(data_width, id_width))
 
-# AXI Lite Definition -----------------------------------------------------------------------------------
+# AXI Lite Definition ------------------------------------------------------------------------------
 
 def ax_lite_description(address_width):
     return [("addr",  address_width)]
@@ -336,3 +336,78 @@ class AXI2Wishbone(Module):
         axi2axi_lite      = AXI2AXILite(axi, axi_lite)
         axi_lite2wishbone = AXILite2Wishbone(axi_lite, wishbone, base_address)
         self.submodules += axi2axi_lite, axi_lite2wishbone
+
+# Wishbone to AXILite ------------------------------------------------------------------------------
+
+class Wishbone2AXILite(Module):
+    def __init__(self, wishbone, axi_lite, base_address=0x00000000):
+        wishbone_adr_shift = log2_int(axi_lite.data_width//8)
+        assert axi_lite.data_width    == len(wishbone.dat_r)
+        assert axi_lite.address_width == len(wishbone.adr) + wishbone_adr_shift
+
+        _cmd_done  = Signal()
+        _data_done = Signal()
+        _addr      = Signal(len(wishbone.adr))
+        self.comb += _addr.eq(wishbone.adr - base_address//4)
+
+        self.submodules.fsm = fsm = FSM(reset_state="IDLE")
+        fsm.act("IDLE",
+            NextValue(_cmd_done,  0),
+            NextValue(_data_done, 0),
+            If(wishbone.stb & wishbone.cyc,
+                If(wishbone.we,
+                    NextState("WRITE")
+                ).Else(
+                    NextState("READ")
+                )
+            )
+        )
+        fsm.act("WRITE",
+            # cmd
+            axi_lite.aw.valid.eq(~_cmd_done),
+            axi_lite.aw.addr[wishbone_adr_shift:].eq(_addr),
+            If(axi_lite.aw.valid & axi_lite.aw.ready,
+                NextValue(_cmd_done, 1)
+            ),
+            # data
+            axi_lite.w.valid.eq(~_data_done),
+            axi_lite.w.data.eq(wishbone.dat_w),
+            axi_lite.w.strb.eq(wishbone.sel),
+            If(axi_lite.w.valid & axi_lite.w.ready,
+                NextValue(_data_done, 1),
+            ),
+            # resp
+            axi_lite.b.ready.eq(_cmd_done & _data_done),
+            If(axi_lite.b.valid & axi_lite.b.ready,
+                If(axi_lite.b.resp == RESP_OKAY,
+                    wishbone.ack.eq(1),
+                    NextState("IDLE")
+                ).Else(
+                    NextState("ERROR")
+                )
+            )
+        )
+        fsm.act("READ",
+            # cmd
+            axi_lite.ar.valid.eq(~_cmd_done),
+            axi_lite.ar.addr[wishbone_adr_shift:].eq(_addr),
+            If(axi_lite.ar.valid & axi_lite.ar.ready,
+                NextValue(_cmd_done, 1)
+            ),
+            # data & resp
+            axi_lite.r.ready.eq(_cmd_done),
+            If(axi_lite.r.valid & axi_lite.r.ready,
+                If(axi_lite.r.resp == RESP_OKAY,
+                    wishbone.dat_r.eq(axi_lite.r.data),
+                    wishbone.ack.eq(1),
+                    NextState("IDLE"),
+                ).Else(
+                    NextState("ERROR")
+                )
+            )
+        )
+        fsm.act("ERROR",
+            wishbone.ack.eq(1),
+            wishbone.err.eq(1),
+            NextState("IDLE")
+        )
index 3f15de020557c3e5c9eb893ddf1288c888ffa4c4..3152a4134497d2e3beba081cda5f56e609577017 100644 (file)
@@ -326,3 +326,37 @@ class TestAXI(unittest.TestCase):
             r_valid_random  = 90,
             r_ready_random  = 90
         )
+
+    def test_wishbone2axi2wishbone(self):
+        class DUT(Module):
+            def __init__(self):
+                self.wishbone = wishbone.Interface(data_width=32)
+
+                # # #
+
+                axi = AXILiteInterface(data_width=32, address_width=32)
+                wb  = wishbone.Interface(data_width=32)
+
+                wishbone2axi = Wishbone2AXILite(self.wishbone, axi)
+                axi2wishbone = AXILite2Wishbone(axi, wb)
+                self.submodules += wishbone2axi, axi2wishbone
+
+                sram = wishbone.SRAM(1024, init=[0x12345678, 0xa55aa55a])
+                self.submodules += sram
+                self.comb += wb.connect(sram.bus)
+
+        def generator(dut):
+            dut.errors = 0
+            if (yield from dut.wishbone.read(0)) != 0x12345678:
+                dut.errors += 1
+            if (yield from dut.wishbone.read(1)) != 0xa55aa55a:
+                dut.errors += 1
+            for i in range(32):
+                yield from dut.wishbone.write(i, i)
+            for i in range(32):
+                if (yield from dut.wishbone.read(i)) != i:
+                    dut.errors += 1
+
+        dut = DUT()
+        run_simulation(dut, [generator(dut)], vcd_name="toto.vcd")
+        self.assertEqual(dut.errors, 0)