soc/interconnect: add initial axi code with bus definition and AXI2Wishbone
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Wed, 27 Feb 2019 21:26:57 +0000 (22:26 +0100)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Wed, 27 Feb 2019 21:26:57 +0000 (22:26 +0100)
litex/soc/interconnect/axi.py [new file with mode: 0644]

diff --git a/litex/soc/interconnect/axi.py b/litex/soc/interconnect/axi.py
new file mode 100644 (file)
index 0000000..7d0792c
--- /dev/null
@@ -0,0 +1,123 @@
+from migen import *
+
+from litex.soc.interconnect import stream
+
+# AXI Definition -----------------------------------------------------------------------------------
+
+BURST_FIXED    = 0b00
+BURST_INCR     = 0b01
+BURST_WRAP     = 0b10
+BURST_RESERVED = 0b11
+
+RESP_OKAY   = 0b00
+RESP_EXOKAY = 0b01
+RESP_SLVERR = 0b10
+RESP_DECERR = 0b11
+
+def ax_description(address_width, id_width):
+    return [
+        ("addr",  address_width),
+        ("burst", 2), # Burst type
+        ("len",   8), # Number of data (-1) transfers (up to 256)
+        ("size",  4), # Number of bytes (-1) of each data transfer (up to 1024 bits)
+        ("id",    id_width)
+    ]
+
+def w_description(data_width):
+    return [
+        ("data", data_width),
+        ("strb", data_width//8)
+    ]
+
+def b_description(id_width):
+    return [
+        ("resp", 2),
+        ("id", id_width)
+    ]
+
+def r_description(data_width, id_width):
+    return [
+        ("resp", 2),
+        ("data", data_width),
+        ("id", id_width)
+    ]
+
+
+class AXIInterface(Record):
+    def __init__(self, data_width, address_width, id_width=1, clock_domain="sys"):
+        self.data_width = data_width
+        self.address_width = address_width
+        self.id_width = id_width
+        self.clock_domain = clock_domain
+
+        self.aw = stream.Endpoint(ax_description(address_width, id_width))
+        self.w = stream.Endpoint(w_description(data_width))
+        self.b = stream.Endpoint(b_description(id_width))
+        self.ar = stream.Endpoint(ax_description(address_width, id_width))
+        self.r = stream.Endpoint(r_description(data_width, id_width))
+
+# AXI to Wishbone ----------------------------------------------------------------------------------
+
+class AXI2Wishbone(Module):
+    def __init__(self, axi, wishbone, base_address):
+        assert axi.data_width    == 32
+        assert axi.address_width == 32
+
+        _data       = Signal(axi.data_width)
+        _read_addr  = Signal(32)
+        _write_addr = Signal(32)
+
+        self.comb += _read_addr.eq(axi.ar.addr - base_address)
+        self.comb += _write_addr.eq(axi.aw.addr - base_address)
+
+        self.submodules.fsm = fsm = FSM(reset_state="IDLE")
+        fsm.act("IDLE",
+            If(axi.ar.valid,
+                NextState("DO-READ")
+            ).Elif(axi.aw.valid,
+                NextState("DO-WRITE")
+            )
+        )
+        axi_ar_addr = Signal(32)
+        self.comb += axi_ar_addr.eq(axi.ar.addr - base_address)
+        fsm.act("DO-READ",
+            wishbone.stb.eq(1),
+            wishbone.cyc.eq(1),
+            wishbone.adr.eq(_read_addr[2:]),
+            If(wishbone.ack,
+                NextValue(_data, wishbone.dat_r),
+                NextState("SEND-READ-RESPONSE")
+            )
+        )
+        fsm.act("SEND-READ-RESPONSE",
+            axi.r.valid.eq(1),
+            axi.r.last.eq(1),
+            axi.r.resp.eq(RESP_OKAY),
+            axi.r.id.eq(axi.ar.id),
+            axi.r.data.eq(_data),
+            If(axi.r.ready,
+                axi.ar.ready.eq(1),
+                NextState("IDLE")
+            )
+        )
+        fsm.act("DO-WRITE",
+            wishbone.stb.eq(1),
+            wishbone.cyc.eq(1),
+            wishbone.we.eq(1),
+            wishbone.adr.eq(_write_addr[2:]),
+            wishbone.sel.eq(axi.w.strb),
+            wishbone.dat_w.eq(axi.w.data),
+            If(wishbone.ack,
+                NextState("SEND-WRITE-RESPONSE")
+            )
+        )
+        fsm.act("SEND-WRITE-RESPONSE",
+            axi.b.valid.eq(1),
+            axi.b.resp.eq(RESP_OKAY),
+            axi.b.id.eq(axi.aw.id),
+            If(axi.b.ready,
+                axi.aw.ready.eq(1),
+                axi.w.ready.eq(1),
+                NextState("IDLE")
+            )
+        )