# SoCBusHandler ------------------------------------------------------------------------------------
class SoCBusHandler(Module):
- supported_standard = ["wishbone"]
+ supported_standard = ["wishbone", "axi-lite"]
supported_data_width = [32, 64]
supported_address_width = [32]
# Creation -------------------------------------------------------------------------------------
- def __init__(self, standard, data_width=32, address_width=32, timeout=1e6, reserved_regions={}):
- self.logger = logging.getLogger("SoCBusHandler")
+ def __init__(self, name="SoCBusHandler", standard="wishbone", data_width=32, address_width=32, timeout=1e6, reserved_regions={}):
+ self.logger = logging.getLogger(name)
self.logger.info("Creating Bus Handler...")
# Check Standard
if address_width not in self.supported_address_width:
self.logger.error("Unsupported {} {}, supporteds: {:s}".format(
colorer("Address Width", color="red"),
- colorer(data_width),
+ colorer(address_width),
colorer(", ".join(str(x) for x in self.supported_address_width))))
raise
def add_adapter(self, name, interface, direction="m2s"):
assert direction in ["m2s", "s2m"]
- if isinstance(interface, axi.AXILiteInterface):
- self.logger.info("{} Bus {} from {} to {}.".format(
- colorer(name),
- colorer("converted", color="cyan"),
- colorer("AXILite"),
- colorer("Wishbone")))
- new_interface = wishbone.Interface(data_width=interface.data_width)
- if direction == "m2s":
- converter = axi.AXILite2Wishbone(axi_lite=interface, wishbone=new_interface)
- elif direction == "s2m":
- converter = axi.Wishbone2AXILite(wishbone=new_interface, axi_lite=interface)
- self.submodules += converter
- interface = new_interface
-
+ # Data width conversion
if interface.data_width != self.data_width:
- self.logger.info("{} Bus {} from {}-bit to {}-bit.".format(
- colorer(name),
- colorer("converted", color="cyan"),
- colorer(interface.data_width),
- colorer(self.data_width)))
- new_interface = wishbone.Interface(data_width=self.data_width)
+ interface_cls = type(interface)
+ converter_cls = {
+ wishbone.Interface: wishbone.Converter,
+ axi.AXILiteInterface: axi.AXILiteConverter,
+ }[interface_cls]
+ converted_interface = interface_cls(data_width=self.data_width)
if direction == "m2s":
- converter = wishbone.Converter(master=interface, slave=new_interface)
- if direction == "s2m":
- converter = wishbone.Converter(master=new_interface, slave=interface)
+ master, slave = interface, converted_interface
+ elif direction == "s2m":
+ master, slave = converted_interface, interface
+ converter = converter_cls(master=master, slave=slave)
self.submodules += converter
- return new_interface
else:
- return interface
+ converted_interface = interface
+
+ # Wishbone <-> AXILite bridging
+ main_bus_cls = {
+ "wishbone": wishbone.Interface,
+ "axi-lite": axi.AXILiteInterface,
+ }[self.standard]
+ if isinstance(converted_interface, main_bus_cls):
+ bridged_interface = converted_interface
+ else:
+ bridged_interface = main_bus_cls(data_width=self.data_width)
+ if direction == "m2s":
+ master, slave = converted_interface, bridged_interface
+ elif direction == "s2m":
+ master, slave = bridged_interface, converted_interface
+ bridge_cls = {
+ (wishbone.Interface, axi.AXILiteInterface): axi.Wishbone2AXILite,
+ (axi.AXILiteInterface, wishbone.Interface): axi.AXILite2Wishbone,
+ }[type(master), type(slave)]
+ bridge = bridge_cls(master, slave)
+ self.submodules += bridge
+
+ if type(interface) != type(bridged_interface) or interface.data_width != bridged_interface.data_width:
+ fmt = "{name} Bus {converted} from {frombus} {frombits}-bit to {tobus} {tobits}-bit."
+ bus_names = {
+ wishbone.Interface: "Wishbone",
+ axi.AXILiteInterface: "AXI Lite",
+ }
+ self.logger.info(fmt.format(
+ name = colorer(name),
+ converted = colorer("converted", color="cyan"),
+ frombus = colorer(bus_names[type(interface)]),
+ frombits = colorer(interface.data_width),
+ tobus = colorer(bus_names[type(bridged_interface)]),
+ tobits = colorer(bridged_interface.data_width)))
+ return bridged_interface
def add_master(self, name=None, master=None):
if name is None:
setattr(self.submodules, name, SoCController(**kwargs))
self.csr.add(name, use_loc_if_exists=True)
- def add_ram(self, name, origin, size, contents=[], mode="rw", bus=None):
- if bus is None:
- bus = wishbone.Interface(data_width=self.bus.data_width)
-
- if isinstance(bus, wishbone.Interface):
- ram = wishbone.SRAM(size, bus=bus, init=contents, read_only=(mode == "r"))
- elif isinstance(bus, axi.AXILiteInterface):
- ram = axi.AXILiteSRAM(size, bus=bus, init=contents, read_only=(mode == "r"))
- else:
- raise TypeError(bus)
-
+ def add_ram(self, name, origin, size, contents=[], mode="rw"):
+ ram_cls = {
+ "wishbone": wishbone.SRAM,
+ "axi-lite": axi.AXILiteSRAM,
+ }[self.bus.standard]
+ interface_cls = {
+ "wishbone": wishbone.Interface,
+ "axi-lite": axi.AXILiteInterface,
+ }[self.bus.standard]
+ ram_bus = interface_cls(data_width=self.bus.data_width)
+ ram = ram_cls(size, bus=ram_bus, init=contents, read_only=(mode == "r"))
self.bus.add_slave(name, ram.bus, SoCRegion(origin=origin, size=size, mode=mode))
self.check_if_exists(name)
- self.logger.info("{} RAM {} {} {}.".format(
- colorer("Wishbone" if isinstance(bus, wishbone.Interface) else "AXILite"),
+ self.logger.info("RAM {} {} {}.".format(
colorer(name),
colorer("added", color="green"),
self.bus.regions[name]))
setattr(self.submodules, name, ram)
- def add_rom(self, name, origin, size, contents=[], bus=None):
- self.add_ram(name, origin, size, contents, mode="r", bus=bus)
+ def add_rom(self, name, origin, size, contents=[]):
+ self.add_ram(name, origin, size, contents, mode="r")
def add_csr_bridge(self, origin):
- self.submodules.csr_bridge = wishbone.Wishbone2CSR(
+ csr_bridge_cls = {
+ "wishbone": wishbone.Wishbone2CSR,
+ "axi-lite": axi.AXILite2CSR,
+ }[self.bus.standard]
+ self.submodules.csr_bridge = csr_bridge_cls(
bus_csr = csr_bus.Interface(
address_width = self.csr.address_width,
data_width = self.csr.data_width))
csr_size = 2**(self.csr.address_width + 2)
csr_region = SoCRegion(origin=origin, size=csr_size, cached=False)
- self.bus.add_slave("csr", self.csr_bridge.wishbone, csr_region)
+ bus = getattr(self.csr_bridge, self.bus.standard.replace('-', '_'))
+ self.bus.add_slave("csr", bus, csr_region)
self.csr.add_master(name="bridge", master=self.csr_bridge.csr)
self.add_config("CSR_DATA_WIDTH", self.csr.data_width)
self.add_config("CSR_ALIGNMENT", self.csr.alignment)
self.bus.add_region("io{}".format(n), SoCIORegion(origin=origin, size=size, cached=False))
self.mem_map.update(self.cpu.mem_map) # FIXME
# Add Bus Masters/CSR/IRQs
- if not isinstance(self.cpu, cpu.CPUNone):
+ if not isinstance(self.cpu, (cpu.CPUNone, cpu.Zynq7000)):
if reset_address is None:
reset_address = self.mem_map["rom"]
self.cpu.set_reset_address(reset_address)
self.irq.add(name, loc)
self.add_config("CPU_HAS_INTERRUPT")
+ # Create optional DMA Bus (for Cache Coherence)
+ if hasattr(self.cpu, "dma_bus"):
+ self.submodules.dma_bus = SoCBusHandler(
+ name = "SoCDMABusHandler",
+ standard = "wishbone",
+ data_width = self.bus.data_width,
+ )
+ dma_bus = wishbone.Interface(data_width=self.bus.data_width)
+ self.dma_bus.add_slave("dma", slave=dma_bus, region=SoCRegion(origin=0x00000000, size=0x80000000)) # FIXME: size
+ self.submodules += wishbone.Converter(dma_bus, self.cpu.dma_bus)
+ # Connect SoCController's reset to CPU reset
if hasattr(self, "ctrl"):
if hasattr(self.ctrl, "reset"):
self.comb += self.cpu.reset.eq(self.ctrl.reset)
self.logger.info(colorer("Finalized SoC:"))
self.logger.info(colorer("-"*80, color="bright"))
self.logger.info(self.bus)
+ if hasattr(self, "dma_bus"):
+ self.logger.info(self.dma_bus)
self.logger.info(self.csr)
self.logger.info(self.irq)
self.logger.info(colorer("-"*80, color="bright"))
+ interconnect_p2p_cls = {
+ "wishbone": wishbone.InterconnectPointToPoint,
+ "axi-lite": axi.AXILiteInterconnectPointToPoint,
+ }[self.bus.standard]
+ interconnect_shared_cls = {
+ "wishbone": wishbone.InterconnectShared,
+ "axi-lite": axi.AXILiteInterconnectShared,
+ }[self.bus.standard]
+
# SoC Bus Interconnect ---------------------------------------------------------------------
if len(self.bus.masters) and len(self.bus.slaves):
# If 1 bus_master, 1 bus_slave and no address translation, use InterconnectPointToPoint.
if ((len(self.bus.masters) == 1) and
(len(self.bus.slaves) == 1) and
(next(iter(self.bus.regions.values())).origin == 0)):
- self.submodules.bus_interconnect = wishbone.InterconnectPointToPoint(
+ self.submodules.bus_interconnect = interconnect_p2p_cls(
master = next(iter(self.bus.masters.values())),
slave = next(iter(self.bus.slaves.values())))
# Otherwise, use InterconnectShared.
else:
- self.submodules.bus_interconnect = wishbone.InterconnectShared(
+ self.submodules.bus_interconnect = interconnect_shared_cls(
masters = self.bus.masters.values(),
slaves = [(self.bus.regions[n].decoder(self.bus), s) for n, s in self.bus.slaves.items()],
register = True,
self.add_constant("CONFIG_BUS_DATA_WIDTH", self.bus.data_width)
self.add_constant("CONFIG_BUS_ADDRESS_WIDTH", self.bus.address_width)
+ # SoC DMA Bus Interconnect (Cache Coherence) -----------------------------------------------
+ if hasattr(self, "dma_bus"):
+ if len(self.dma_bus.masters) and len(self.dma_bus.slaves):
+ # If 1 bus_master, 1 bus_slave and no address translation, use InterconnectPointToPoint.
+ if ((len(self.dma_bus.masters) == 1) and
+ (len(self.dma_bus.slaves) == 1) and
+ (next(iter(self.dma_bus.regions.values())).origin == 0)):
+ self.submodules.bus_interconnect = wishbone.InterconnectPointToPoint(
+ master = next(iter(self.dma_bus.masters.values())),
+ slave = next(iter(self.dma_bus.slaves.values())))
+ # Otherwise, use InterconnectShared.
+ else:
+ self.submodules.dma_bus_interconnect = wishbone.InterconnectShared(
+ masters = self.dma_bus.masters.values(),
+ slaves = [(self.dma_bus.regions[n].decoder(self.dma_bus), s) for n, s in self.dma_bus.slaves.items()],
+ register = True)
+ self.bus.logger.info("DMA Interconnect: {} ({} <-> {}).".format(
+ colorer(self.dma_bus_interconnect.__class__.__name__),
+ colorer(len(self.dma_bus.masters)),
+ colorer(len(self.dma_bus.slaves))))
+ self.add_constant("CONFIG_CPU_HAS_DMA_BUS")
+
# SoC CSR Interconnect ---------------------------------------------------------------------
self.submodules.csr_bankarray = csr_bus.CSRBankArray(self,
address_map = self.csr.address_map,
self.add_constant(name + "_" + constant.name, constant.value.value)
# SoC CPU Check ----------------------------------------------------------------------------
- if not isinstance(self.cpu, cpu.CPUNone):
+ if not isinstance(self.cpu, (cpu.CPUNone, cpu.Zynq7000)):
if "sram" not in self.bus.regions.keys():
self.logger.error("CPU needs {} Region to be {} as Bus or Linker Region.".format(
colorer("sram"),
pads = self.platform.request(name)
if hasattr(pads, "rst"):
self.comb += pads.rst.eq(0)
- spisdcard = SPIMaster(pads, 32, self.sys_clk_freq, spi_clk_freq, mode="aligned")
+ spisdcard = SPIMaster(pads, 8, self.sys_clk_freq, spi_clk_freq)
spisdcard.add_clk_divider()
setattr(self.submodules, name, spisdcard)
self.add_csr(name)
bus = wishbone.Interface(data_width=self.bus.data_width, adr_width=self.bus.address_width)
self.submodules.sdblock2mem = SDBlock2MemDMA(bus=bus, endianness=self.cpu.endianness)
self.comb += self.sdcore.source.connect(self.sdblock2mem.sink)
- self.bus.add_master("sdblock2mem", master=bus)
+ dma_bus = self.bus if not hasattr(self, "dma_bus") else self.dma_bus
+ dma_bus.add_master("sdblock2mem", master=bus)
self.add_csr("sdblock2mem")
# Mem2Block DMA
bus = wishbone.Interface(data_width=self.bus.data_width, adr_width=self.bus.address_width)
self.submodules.sdmem2block = SDMem2BlockDMA(bus=bus, endianness=self.cpu.endianness)
self.comb += self.sdmem2block.source.connect(self.sdcore.sink)
- self.bus.add_master("sdmem2block", master=bus)
+ dma_bus = self.bus if not hasattr(self, "dma_bus") else self.dma_bus
+ dma_bus.add_master("sdmem2block", master=bus)
self.add_csr("sdmem2block")