soc/interconnect: remove axi_lite
axi_lite code was defining AXI4Lite signals and doing a AXI4Lite bridge to the CSR bus when LiteX was not having proper AXI support. LiteX now has proper AXI support and it also cover what axi_lite was doing: To create a AXILite to CSR bus, user can create an AXILite2Wishbone bridge and then connect the CSR bus directly to the wishbone bus as done in the others non-AXI SoC.
This commit is contained in:
parent
745d83a332
commit
67159349d6
|
@ -1,180 +0,0 @@
|
||||||
"""AXI4Lite support for LiteX"""
|
|
||||||
|
|
||||||
# Copyright (C) 2018 by Sergiusz Bazanski
|
|
||||||
# Permission to use, copy, modify, and/or distribute this software for any
|
|
||||||
# purpose with or without fee is hereby granted.
|
|
||||||
|
|
||||||
import math
|
|
||||||
|
|
||||||
from migen import *
|
|
||||||
from migen.genlib.record import *
|
|
||||||
|
|
||||||
from litex.soc.interconnect import csr_bus
|
|
||||||
|
|
||||||
# Layout of AXI4 Lite Bus
|
|
||||||
_layout = [
|
|
||||||
# Write Address
|
|
||||||
("aw", [
|
|
||||||
("addr", "address_width", DIR_M_TO_S),
|
|
||||||
("prot", 3, DIR_M_TO_S),
|
|
||||||
("valid", 1, DIR_M_TO_S),
|
|
||||||
("ready", 1, DIR_S_TO_M),
|
|
||||||
]),
|
|
||||||
|
|
||||||
# Write Data
|
|
||||||
("w", [
|
|
||||||
("data", "data_width", DIR_M_TO_S),
|
|
||||||
("strb", "strb_width", DIR_M_TO_S),
|
|
||||||
("valid", 1, DIR_M_TO_S),
|
|
||||||
("ready", 1, DIR_S_TO_M),
|
|
||||||
]),
|
|
||||||
|
|
||||||
# Write Response
|
|
||||||
("b", [
|
|
||||||
("resp", 2, DIR_S_TO_M),
|
|
||||||
("valid", 1, DIR_S_TO_M),
|
|
||||||
("ready", 1, DIR_M_TO_S),
|
|
||||||
]),
|
|
||||||
|
|
||||||
# Read Address
|
|
||||||
("ar", [
|
|
||||||
("addr", "address_width", DIR_M_TO_S),
|
|
||||||
("prot", 3, DIR_M_TO_S),
|
|
||||||
("valid", 1, DIR_M_TO_S),
|
|
||||||
("ready", 1, DIR_S_TO_M),
|
|
||||||
]),
|
|
||||||
|
|
||||||
# Read Data
|
|
||||||
("r", [
|
|
||||||
("data", "data_width", DIR_S_TO_M),
|
|
||||||
("resp", 2, DIR_S_TO_M),
|
|
||||||
("valid", 1, DIR_S_TO_M),
|
|
||||||
("ready", 1, DIR_M_TO_S),
|
|
||||||
]),
|
|
||||||
]
|
|
||||||
|
|
||||||
class Interface(Record):
|
|
||||||
"""AXI4Lite Bus Interface"""
|
|
||||||
def __init__(self, data_width=32, address_width=6):
|
|
||||||
super().__init__(set_layout_parameters(_layout,
|
|
||||||
data_width=data_width,
|
|
||||||
address_width=address_width,
|
|
||||||
strb_width=data_width//8))
|
|
||||||
|
|
||||||
|
|
||||||
class AXILite2CSR(Module):
|
|
||||||
"""
|
|
||||||
A bridge between AXI4Lite and a CSR bus.
|
|
||||||
|
|
||||||
This bridge will let you connect an CSR bus to an AXI4 Lite master. Please
|
|
||||||
bear in mind that CSR is word-addressed but AXI4 is byte-addressed. This
|
|
||||||
bridge performs translation, so your AXI bus should be at least two bits
|
|
||||||
wider then your CSR bus.
|
|
||||||
|
|
||||||
The bridge does not support unaligned reads/writes - it will round down
|
|
||||||
every access to the nearest word. If it tries to access unmapped memory,
|
|
||||||
it will return whaterver word is currently active on the CSR bus -
|
|
||||||
including writes.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, bus_axi, bus_csr):
|
|
||||||
self.axi = axi = bus_axi
|
|
||||||
self.csr = csr = bus_csr
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
ar, r, aw, w, b = axi.ar, axi.r, axi.aw, axi.w, axi.b
|
|
||||||
|
|
||||||
# Machine is currently busy talking to CSR, hold your horses.
|
|
||||||
busy = Signal()
|
|
||||||
|
|
||||||
# A write transaction is happening on the bus.
|
|
||||||
write_transaction = Signal()
|
|
||||||
# A read transaction is happening on the bus.
|
|
||||||
read_transaction = Signal()
|
|
||||||
self.comb += [
|
|
||||||
write_transaction.eq(aw.valid & aw.ready & w.valid & w.ready),
|
|
||||||
read_transaction.eq(ar.valid & ar.ready),
|
|
||||||
]
|
|
||||||
|
|
||||||
# Write transaction generation.
|
|
||||||
self.sync += [
|
|
||||||
aw.ready.eq(0),
|
|
||||||
w.ready.eq(0),
|
|
||||||
If(aw.valid & w.valid,
|
|
||||||
If(~aw.ready & ~busy & ~ar.valid,
|
|
||||||
aw.ready.eq(1),
|
|
||||||
w.ready.eq(1)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
# Write response generation.
|
|
||||||
self.sync += [
|
|
||||||
b.valid.eq(0),
|
|
||||||
If(write_transaction,
|
|
||||||
If(b.ready & ~b.valid,
|
|
||||||
b.valid.eq(1),
|
|
||||||
# Response 0 -> OKAY
|
|
||||||
b.resp.eq(0),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
# Read transaction generation.
|
|
||||||
self.sync += [
|
|
||||||
ar.ready.eq(0),
|
|
||||||
If(ar.valid & ~ar.ready & ~busy,
|
|
||||||
ar.ready.eq(1),
|
|
||||||
)
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
# Registered data to be written to CSR, set by FSM.
|
|
||||||
wdata = Signal(csr.dat_w.nbits)
|
|
||||||
# Combinatorial byte address to assert on CSR bus, driven by FSM.
|
|
||||||
addr = Signal(ar.addr.nbits)
|
|
||||||
# Drive AXI & CSR combinatorial signals.
|
|
||||||
self.comb += [
|
|
||||||
csr.adr.eq(addr >> int(math.log(r.data.nbits//8, 2.0))),
|
|
||||||
csr.dat_w.eq(wdata),
|
|
||||||
|
|
||||||
r.data.eq(csr.dat_r),
|
|
||||||
r.resp.eq(0),
|
|
||||||
]
|
|
||||||
|
|
||||||
# CSR interaction FSM.
|
|
||||||
self.submodules.fsm = fsm = FSM(reset_state='IDLE')
|
|
||||||
self.comb += [
|
|
||||||
busy.eq(~fsm.ongoing('IDLE')),
|
|
||||||
r.valid.eq(fsm.ongoing('READING')),
|
|
||||||
csr.we.eq(fsm.ongoing('WRITING')),
|
|
||||||
]
|
|
||||||
|
|
||||||
# Idle state - wait for a transaction to happen on AXI. Immediately
|
|
||||||
# assert read/write address on CSR if such an transaction is occuring.
|
|
||||||
fsm.act('IDLE',
|
|
||||||
If(read_transaction,
|
|
||||||
addr.eq(ar.addr),
|
|
||||||
NextState('READING'),
|
|
||||||
).Elif(write_transaction,
|
|
||||||
addr.eq(aw.addr),
|
|
||||||
# Register data from AXI.
|
|
||||||
NextValue(wdata, w.data),
|
|
||||||
NextState('WRITING'),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
# Perform write to CSR.
|
|
||||||
fsm.act('WRITING',
|
|
||||||
addr.eq(aw.addr),
|
|
||||||
# CSR writes are single cycle, go back to IDLE.
|
|
||||||
NextState('IDLE'),
|
|
||||||
)
|
|
||||||
|
|
||||||
# Respond to read to AXI.
|
|
||||||
fsm.act('READING',
|
|
||||||
addr.eq(ar.addr),
|
|
||||||
# If AXI master is ready to receive data, go back to IDLE.
|
|
||||||
If(r.ready,
|
|
||||||
NextState('IDLE'),
|
|
||||||
)
|
|
||||||
)
|
|
|
@ -1,104 +0,0 @@
|
||||||
import unittest
|
|
||||||
|
|
||||||
from migen import *
|
|
||||||
|
|
||||||
from litex.soc.interconnect import csr
|
|
||||||
from litex.soc.interconnect import csr_bus
|
|
||||||
from litex.soc.interconnect import axi_lite
|
|
||||||
|
|
||||||
class CSRModule(Module, csr.AutoCSR):
|
|
||||||
def __init__(self):
|
|
||||||
self.foo = csr.CSRStorage(32, reset=1)
|
|
||||||
self.bar = csr.CSRStorage(32, reset=1)
|
|
||||||
|
|
||||||
|
|
||||||
class AXILiteDUT(Module):
|
|
||||||
def __init__(self):
|
|
||||||
self.csr = csr_bus.Interface(data_width=32, address_width=12)
|
|
||||||
self.axi = axi_lite.Interface(data_width=32, address_width=14)
|
|
||||||
self.submodules.csrmodule = CSRModule()
|
|
||||||
self.submodules.dut = axi_lite.AXILite2CSR(self.axi, self.csr)
|
|
||||||
self.submodules.csrbankarray = csr_bus.CSRBankArray(
|
|
||||||
self, self.map_csr, data_width=32, address_width=12)
|
|
||||||
self.submodules.csrcon = csr_bus.Interconnect(
|
|
||||||
self.csr, self.csrbankarray.get_buses())
|
|
||||||
|
|
||||||
def map_csr(self, name, memory):
|
|
||||||
return {"csrmodule": 0}[name]
|
|
||||||
|
|
||||||
|
|
||||||
class TestAXILite(unittest.TestCase):
|
|
||||||
def test_write_read(self):
|
|
||||||
def generator(dut):
|
|
||||||
axi = dut.axi
|
|
||||||
|
|
||||||
for _ in range(8):
|
|
||||||
yield
|
|
||||||
|
|
||||||
# Write test
|
|
||||||
yield axi.aw.valid.eq(1)
|
|
||||||
yield axi.aw.addr.eq(4)
|
|
||||||
yield axi.w.valid.eq(1)
|
|
||||||
yield axi.b.ready.eq(1)
|
|
||||||
yield axi.w.data.eq(0x2137)
|
|
||||||
|
|
||||||
while (yield axi.aw.ready) != 1:
|
|
||||||
yield
|
|
||||||
while (yield axi.w.ready) != 1:
|
|
||||||
yield
|
|
||||||
yield axi.aw.valid.eq(0)
|
|
||||||
yield axi.w.valid.eq(0)
|
|
||||||
|
|
||||||
for _ in range(8):
|
|
||||||
yield
|
|
||||||
|
|
||||||
# Read test
|
|
||||||
yield axi.ar.valid.eq(1)
|
|
||||||
yield axi.r.ready.eq(1)
|
|
||||||
yield axi.ar.addr.eq(4)
|
|
||||||
|
|
||||||
while (yield axi.ar.ready != 1):
|
|
||||||
yield
|
|
||||||
yield axi.ar.valid.eq(0)
|
|
||||||
while (yield axi.r.valid != 1):
|
|
||||||
yield
|
|
||||||
yield axi.r.ready.eq(0)
|
|
||||||
|
|
||||||
read = yield axi.r.data
|
|
||||||
assert read == 0x2137
|
|
||||||
|
|
||||||
for _ in range(8):
|
|
||||||
yield
|
|
||||||
dut = AXILiteDUT()
|
|
||||||
run_simulation(dut, generator(dut.dut))
|
|
||||||
|
|
||||||
def test_simultaneous(dut):
|
|
||||||
def generator(dut):
|
|
||||||
axi = dut.axi
|
|
||||||
|
|
||||||
for _ in range(8):
|
|
||||||
yield
|
|
||||||
|
|
||||||
# Write
|
|
||||||
yield axi.aw.valid.eq(1)
|
|
||||||
yield axi.aw.addr.eq(2)
|
|
||||||
yield axi.w.valid.eq(1)
|
|
||||||
yield axi.b.ready.eq(1)
|
|
||||||
yield axi.w.data.eq(0x2137)
|
|
||||||
# Read
|
|
||||||
yield axi.ar.valid.eq(1)
|
|
||||||
yield axi.r.ready.eq(1)
|
|
||||||
yield axi.ar.addr.eq(2)
|
|
||||||
|
|
||||||
yield
|
|
||||||
yield
|
|
||||||
|
|
||||||
is_reading = yield axi.ar.ready
|
|
||||||
is_writing = yield axi.aw.ready
|
|
||||||
|
|
||||||
assert is_reading
|
|
||||||
assert not is_writing
|
|
||||||
|
|
||||||
|
|
||||||
dut = AXILiteDUT()
|
|
||||||
run_simulation(dut, generator(dut.dut))
|
|
Loading…
Reference in New Issue