)
)
+# AXI Lite to AXI ----------------------------------------------------------------------------------
+
+class AXILite2AXI(Module):
+ def __init__(self, axi_lite, axi, write_id=0, read_id=0, prot=0, burst_type="INCR"):
+ assert isinstance(axi_lite, AXILiteInterface)
+ assert isinstance(axi, AXIInterface)
+ assert axi_lite.data_width == axi.data_width
+ assert axi_lite.address_width == axi.address_width
+
+ # n bytes, encoded as log2(n)
+ burst_size = log2_int(axi.data_width // 8)
+ # burst type has no meaning as we use burst length of 1, but AXI slaves may require
+ # certain type of bursts, so it is probably safest to use INCR in general
+ burst_type = {
+ "FIXED": 0b00,
+ "INCR": 0b01,
+ "WRAP": 0b10,
+ }[burst_type]
+
+ self.comb += [
+ axi.aw.valid.eq(axi_lite.aw.valid),
+ axi_lite.aw.ready.eq(axi.aw.ready),
+ axi.aw.addr.eq(axi_lite.aw.addr),
+ axi.aw.burst.eq(burst_type),
+ axi.aw.len.eq(0), # 1 transfer per burst
+ axi.aw.size.eq(burst_size),
+ axi.aw.lock.eq(0), # Normal access
+ axi.aw.prot.eq(prot),
+ axi.aw.cache.eq(0b0011), # Normal Non-cacheable Bufferable
+ axi.aw.qos.eq(0),
+ axi.aw.id.eq(write_id),
+
+ axi.w.valid.eq(axi_lite.w.valid),
+ axi_lite.w.ready.eq(axi.w.ready),
+ axi.w.data.eq(axi_lite.w.data),
+ axi.w.strb.eq(axi_lite.w.strb),
+ axi.w.last.eq(1),
+
+ axi_lite.b.valid.eq(axi.b.valid),
+ axi_lite.b.resp.eq(axi.b.resp),
+ axi.b.ready.eq(axi_lite.b.ready),
+
+ axi.ar.valid.eq(axi_lite.ar.valid),
+ axi_lite.ar.ready.eq(axi.ar.ready),
+ axi.ar.addr.eq(axi_lite.ar.addr),
+ axi.ar.burst.eq(burst_type),
+ axi.ar.len.eq(0),
+ axi.ar.size.eq(burst_size),
+ axi.ar.lock.eq(0),
+ axi.ar.prot.eq(prot),
+ axi.ar.cache.eq(0b0011),
+ axi.ar.qos.eq(0),
+ axi.ar.id.eq(read_id),
+
+ axi_lite.r.valid.eq(axi.r.valid),
+ axi_lite.r.resp.eq(axi.r.resp),
+ axi_lite.r.data.eq(axi.r.data),
+ axi.r.ready.eq(axi_lite.r.ready),
+ ]
+
# AXI Lite to Wishbone -----------------------------------------------------------------------------
class AXILite2Wishbone(Module):
run_simulation(dut, [generator(dut)])
self.assertEqual(dut.errors, 0)
+ def test_axilite2axi2mem(self):
+ class DUT(Module):
+ def __init__(self, mem_bus="wishbone"):
+ self.axi_lite = AXILiteInterface()
+
+ axi = AXIInterface()
+ self.submodules.axil2axi = AXILite2AXI(self.axi_lite, axi)
+
+ interface_cls, converter_cls, sram_cls = {
+ "wishbone": (wishbone.Interface, AXI2Wishbone, wishbone.SRAM),
+ "axi_lite": (AXILiteInterface, AXI2AXILite, AXILiteSRAM),
+ }[mem_bus]
+
+ bus = interface_cls()
+ self.submodules += converter_cls(axi, bus)
+ sram = sram_cls(1024, init=[0x12345678, 0xa55aa55a])
+ self.submodules += sram
+ self.comb += bus.connect(sram.bus)
+
+ def generator(axi_lite, datas, resps):
+ data, resp = (yield from axi_lite.read(0x00))
+ resps.append((resp, RESP_OKAY))
+ datas.append((data, 0x12345678))
+ data, resp = (yield from axi_lite.read(0x04))
+ resps.append((resp, RESP_OKAY))
+ datas.append((data, 0xa55aa55a))
+ for i in range(32):
+ resp = (yield from axi_lite.write(4*i, i))
+ resps.append((resp, RESP_OKAY))
+ for i in range(32):
+ data, resp = (yield from axi_lite.read(4*i))
+ resps.append((resp, RESP_OKAY))
+ datas.append((data, i))
+
+ for mem_bus in ["wishbone", "axi_lite"]:
+ with self.subTest(mem_bus=mem_bus):
+ # to have more verbose error messages store errors in list((actual, expected))
+ datas = []
+ resps = []
+
+ def actual_expected(results): # split into (list(actual), list(expected))
+ return list(zip(*results))
+
+ dut = DUT(mem_bus)
+ run_simulation(dut, [generator(dut.axi_lite, datas, resps)])
+ self.assertEqual(*actual_expected(resps))
+ msg = "\n".join("0x{:08x} vs 0x{:08x}".format(actual, expected) for actual, expected in datas)
+ self.assertEqual(*actual_expected(datas), msg="actual vs expected:\n" + msg)
+
def test_axilite2csr(self):
@passive
def csr_mem_handler(csr, mem):