soc/interconnect/axi: add AXILite -> AXI converter
This commit is contained in:
parent
8a0684b15e
commit
e78d950a31
|
@ -430,6 +430,66 @@ class AXI2AXILite(Module):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 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 -----------------------------------------------------------------------------
|
# AXI Lite to Wishbone -----------------------------------------------------------------------------
|
||||||
|
|
||||||
class AXILite2Wishbone(Module):
|
class AXILite2Wishbone(Module):
|
||||||
|
|
|
@ -177,6 +177,55 @@ class TestAXILite(unittest.TestCase):
|
||||||
run_simulation(dut, [generator(dut)])
|
run_simulation(dut, [generator(dut)])
|
||||||
self.assertEqual(dut.errors, 0)
|
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):
|
def test_axilite2csr(self):
|
||||||
@passive
|
@passive
|
||||||
def csr_mem_handler(csr, mem):
|
def csr_mem_handler(csr, mem):
|
||||||
|
|
Loading…
Reference in New Issue