soc: add initial DMA bus support (optionally provided by CPU(s) for cache coherency).
When provided, the modules doing DMA shall connect the DMA to the dma_bus to allow the CPU(s) to manage cache coherency and avoid the manual cache flushes. This has been tested with VexRiscv SMP and LiteSDCard doing DMA while loading Linux binaries.
This commit is contained in:
parent
2361abb12d
commit
d38048baac
|
@ -106,8 +106,8 @@ class SoCBusHandler(Module):
|
||||||
supported_address_width = [32]
|
supported_address_width = [32]
|
||||||
|
|
||||||
# Creation -------------------------------------------------------------------------------------
|
# Creation -------------------------------------------------------------------------------------
|
||||||
def __init__(self, standard, data_width=32, address_width=32, timeout=1e6, reserved_regions={}):
|
def __init__(self, name="SoCBusHandler", standard="wishbone", data_width=32, address_width=32, timeout=1e6, reserved_regions={}):
|
||||||
self.logger = logging.getLogger("SoCBusHandler")
|
self.logger = logging.getLogger(name)
|
||||||
self.logger.info("Creating Bus Handler...")
|
self.logger.info("Creating Bus Handler...")
|
||||||
|
|
||||||
# Check Standard
|
# Check Standard
|
||||||
|
@ -130,7 +130,7 @@ class SoCBusHandler(Module):
|
||||||
if address_width not in self.supported_address_width:
|
if address_width not in self.supported_address_width:
|
||||||
self.logger.error("Unsupported {} {}, supporteds: {:s}".format(
|
self.logger.error("Unsupported {} {}, supporteds: {:s}".format(
|
||||||
colorer("Address Width", color="red"),
|
colorer("Address Width", color="red"),
|
||||||
colorer(data_width),
|
colorer(address_width),
|
||||||
colorer(", ".join(str(x) for x in self.supported_address_width))))
|
colorer(", ".join(str(x) for x in self.supported_address_width))))
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
@ -815,7 +815,18 @@ class SoC(Module):
|
||||||
self.irq.add(name, loc)
|
self.irq.add(name, loc)
|
||||||
self.add_config("CPU_HAS_INTERRUPT")
|
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"):
|
||||||
if hasattr(self.ctrl, "reset"):
|
if hasattr(self.ctrl, "reset"):
|
||||||
self.comb += self.cpu.reset.eq(self.ctrl.reset)
|
self.comb += self.cpu.reset.eq(self.ctrl.reset)
|
||||||
|
@ -840,6 +851,8 @@ class SoC(Module):
|
||||||
self.logger.info(colorer("Finalized SoC:"))
|
self.logger.info(colorer("Finalized SoC:"))
|
||||||
self.logger.info(colorer("-"*80, color="bright"))
|
self.logger.info(colorer("-"*80, color="bright"))
|
||||||
self.logger.info(self.bus)
|
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.csr)
|
||||||
self.logger.info(self.irq)
|
self.logger.info(self.irq)
|
||||||
self.logger.info(colorer("-"*80, color="bright"))
|
self.logger.info(colorer("-"*80, color="bright"))
|
||||||
|
@ -871,6 +884,28 @@ class SoC(Module):
|
||||||
self.add_constant("CONFIG_BUS_DATA_WIDTH", self.bus.data_width)
|
self.add_constant("CONFIG_BUS_DATA_WIDTH", self.bus.data_width)
|
||||||
self.add_constant("CONFIG_BUS_ADDRESS_WIDTH", self.bus.address_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 ---------------------------------------------------------------------
|
# SoC CSR Interconnect ---------------------------------------------------------------------
|
||||||
self.submodules.csr_bankarray = csr_bus.CSRBankArray(self,
|
self.submodules.csr_bankarray = csr_bus.CSRBankArray(self,
|
||||||
address_map = self.csr.address_map,
|
address_map = self.csr.address_map,
|
||||||
|
@ -1299,10 +1334,8 @@ class LiteXSoC(SoC):
|
||||||
bus = wishbone.Interface(data_width=self.bus.data_width, adr_width=self.bus.address_width)
|
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.submodules.sdblock2mem = SDBlock2MemDMA(bus=bus, endianness=self.cpu.endianness)
|
||||||
self.comb += self.sdcore.source.connect(self.sdblock2mem.sink)
|
self.comb += self.sdcore.source.connect(self.sdblock2mem.sink)
|
||||||
if hasattr(self.cpu, "dmabus"): # FIXME: VexRiscv SMP / DMA test.
|
dma_bus = self.bus if not hasattr(self, "dma_bus") else self.dma_bus
|
||||||
self.submodules += wishbone.Converter(bus, self.cpu.dmabus)
|
dma_bus.add_master("sdblock2mem", master=bus)
|
||||||
else:
|
|
||||||
self.bus.add_master("sdblock2mem", master=bus)
|
|
||||||
self.add_csr("sdblock2mem")
|
self.add_csr("sdblock2mem")
|
||||||
|
|
||||||
# Mem2Block DMA
|
# Mem2Block DMA
|
||||||
|
@ -1310,5 +1343,6 @@ class LiteXSoC(SoC):
|
||||||
bus = wishbone.Interface(data_width=self.bus.data_width, adr_width=self.bus.address_width)
|
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.submodules.sdmem2block = SDMem2BlockDMA(bus=bus, endianness=self.cpu.endianness)
|
||||||
self.comb += self.sdmem2block.source.connect(self.sdcore.sink)
|
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")
|
self.add_csr("sdmem2block")
|
||||||
|
|
|
@ -576,11 +576,13 @@ sdcard_set_block_count(count);
|
||||||
|
|
||||||
sdcard_stop_transmission();
|
sdcard_stop_transmission();
|
||||||
|
|
||||||
|
#ifndef CONFIG_CPU_HAS_DMA_BUS
|
||||||
/* Flush CPU caches */
|
/* Flush CPU caches */
|
||||||
flush_cpu_dcache();
|
flush_cpu_dcache();
|
||||||
#ifdef CONFIG_L2_SIZE
|
#ifdef CONFIG_L2_SIZE
|
||||||
flush_l2_cache();
|
flush_l2_cache();
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue