# TODO:
# - replace raise with exit on logging error.
# - add configurable CSR paging.
-# - manage IO/Linker regions.
+# - manage SoCLinkerRegion
logging.basicConfig(level=logging.INFO)
r += "Cached: {}".format(colorer(self.cached))
return r
+class SoCIORegion(SoCRegion): pass
-class SoCLinkerRegion(SoCRegion):
- pass
+class SoCLinkerRegion(SoCRegion): pass
# SoCBusHandler ------------------------------------------------------------------------------------
self.masters = {}
self.slaves = {}
self.regions = {}
+ self.io_regions = {}
+ self.ld_regions = {}
self.timeout = timeout
self.logger.info("{}-bit {} Bus, {}GiB Address Space.".format(
colorer(data_width), colorer(standard), colorer(2**address_width/2**30)))
# Add/Allog/Check Regions ----------------------------------------------------------------------
def add_region(self, name, region):
allocated = False
+ # Check if SoCIORegion
+ if isinstance(region, SoCIORegion):
+ if name in self.masters.keys():
+ self.logger.error("{} already declared as IO Region:".format(colorer(name, color="red")))
+ self.logger.error(self)
+ raise
+ self.io_regions[name] = region
+ overlap = self.check_regions_overlap(self.io_regions)
+ if overlap is not None:
+ self.logger.error("IO Region overlap between {} and {}:".format(
+ colorer(overlap[0], color="red"),
+ colorer(overlap[1], color="red")))
+ self.logger.error(str(self.regions[overlap[0]]))
+ self.logger.error(str(self.regions[overlap[1]]))
+ raise
+ self.logger.info("{} Region {} {}.".format(
+ colorer(name, color="underline"),
+ colorer("added", color="green"),
+ str(region)))
# Check if SoCLinkerRegion
- if isinstance(region, SoCLinkerRegion):
- self.logger.info("FIXME: SoCLinkerRegion")
+ elif isinstance(region, SoCLinkerRegion):
+ if name in self.masters.keys():
+ self.logger.error("{} already declared as Linker Region:".format(colorer(name, color="red")))
+ self.logger.error(self)
+ raise
+ self.ld_regions[name] = region
+ overlap = self.check_regions_overlap(self.ld_regions)
+ if overlap is not None:
+ self.logger.error("Linker Region overlap between {} and {}:".format(
+ colorer(overlap[0], color="red"),
+ colorer(overlap[1], color="red")))
+ self.logger.error(str(self.regions[overlap[0]]))
+ self.logger.error(str(self.regions[overlap[1]]))
+ raise
+ self.logger.info("{} Region {} {}.".format(
+ colorer(name, color="underline"),
+ colorer("added", color="green"),
+ str(region)))
# Check if SoCRegion
elif isinstance(region, SoCRegion):
# If no origin specified, allocate region.
self.regions[name] = region
# Else add region and check for overlaps.
else:
+ if not region.cached:
+ if not self.check_region_is_io(region):
+ self.logger.error("{} Region {}: {}".format(
+ colorer(name, color="red"),
+ colorer("not cached but not in IO region", color="red"),
+ str(region)))
+ self.logger.error(self)
+ raise
self.regions[name] = region
- overlap = self.check_region(self.regions)
+ overlap = self.check_regions_overlap(self.regions)
if overlap is not None:
self.logger.error("Region overlap between {} and {}:".format(
colorer(overlap[0], color="red"),
overlap = False
# Check Candidate does not overlap with allocated existing regions
for _, allocated in self.regions.items():
- if self.check_region({"0": allocated, "1": candidate}) is not None:
+ if self.check_regions_overlap({"0": allocated, "1": candidate}) is not None:
origin = allocated.origin + allocated.size
overlap = True
break
self.logger.error("Not enough Address Space to allocate Region")
raise
- def check_region(self, regions):
+ def check_regions_overlap(self, regions):
i = 0
while i < len(regions):
n0 = list(regions.keys())[i]
i += 1
return None
+ def check_region_is_in(self, region, container):
+ is_in = True
+ if not (region.origin >= container.origin):
+ is_in = False
+ if not ((region.origin + region.size) < (container.origin + container.size)):
+ is_in = False
+ return is_in
+
+ def check_region_is_io(self, region):
+ is_io = False
+ for _, io_region in self.io_regions.items():
+ if self.check_region_is_in(region, io_region):
+ is_io = True
+ return is_io
+
# Add Master/Slave -----------------------------------------------------------------------------
- def add_master(self, name=None, master=None, io_regions={}):
+ def add_master(self, name=None, master=None):
if name is None:
name = "master{:d}".format(len(self.masters))
if name in self.masters.keys():
def __str__(self):
r = "{}-bit {} Bus, {}GiB Address Space.\n".format(
colorer(self.data_width), colorer(self.standard), colorer(2**self.address_width/2**30))
+ r += "IO Regions: ({})\n".format(len(self.io_regions.keys())) if len(self.io_regions.keys()) else ""
+ io_regions = {k: v for k, v in sorted(self.io_regions.items(), key=lambda item: item[1].origin)}
+ for name, region in io_regions.items():
+ r += colorer(name, color="underline") + " "*(20-len(name)) + ": " + str(region) + "\n"
+ r += "Linker Regions: ({})\n".format(len(self.ld_regions.keys())) if len(self.ld_regions.keys()) else ""
+ ld_regions = {k: v for k, v in sorted(self.ld_regions.items(), key=lambda item: item[1].origin)}
+ for name, region in ld_regions.items():
+ r += colorer(name, color="underline") + " "*(20-len(name)) + ": " + str(region) + "\n"
r += "Bus Regions: ({})\n".format(len(self.regions.keys())) if len(self.regions.keys()) else ""
regions = {k: v for k, v in sorted(self.regions.items(), key=lambda item: item[1].origin)}
for name, region in regions.items():
self.logger.error("{} already declared as CSR Master:".format(colorer(name, color="red")))
self.logger.error(self)
raise
- print(master)
if master.data_width != self.data_width:
self.logger.error("{} Master/Handler data_width {} ({} vs {}).".format(
colorer(name),
self.logger.info("{} {} as CSR Master.".format(
colorer(name, color="underline"),
colorer("added", color="green")))
- # FIXME: handle IO regions
# Address map ----------------------------------------------------------------------------------
def address_map(self, name, memory):
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)
- self.bus.add_slave("csr", self.csr_bridge.wishbone, SoCRegion(origin=origin, size=csr_size))
+ 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)
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)
if hasattr(self, "ctrl"):
self.comb += self.cpu.reset.eq(self.ctrl.reset)
# Update SoC with CPU constraints
+ for n, (origin, size) in enumerate(self.cpu.io_regions.items()):
+ self.bus.add_region("io{}".format(n), SoCIORegion(origin=origin, size=size, cached=False))
self.soc_mem_map.update(self.cpu.mem_map) # FIXME
- self.soc_io_regions.update(self.cpu.io_regions) # FIXME
# Define constants
self.add_config("CPU_TYPE", str(name))
self.add_config("CPU_VARIANT", str(variant.split('+')[0]))
from litex.soc.cores import cpu
from litex.soc.interconnect import wishbone
from litex.soc.integration.common import *
-from litex.soc.integration.soc import SoCConstant, SoCRegion, SoC, SoCController
+from litex.soc.integration.soc import *
__all__ = [
"mem_decoder",
"main_ram": 0x40000000,
"csr": 0x82000000,
}
- io_regions = {}
def __init__(self, platform, clk_freq,
# CPU parameters
# SoC's CSR/Mem/Interrupt mapping (default or user defined + dynamically allocateds)
self.soc_mem_map = self.mem_map
- self.soc_io_regions = self.io_regions
# SoC's Config/Constants/Regions
self.config = {}
reset_address = self.soc_mem_map["rom"] if integrated_rom_size else cpu_reset_address)
else:
self.submodules.cpu = cpu.CPUNone()
- self.soc_io_regions.update(self.cpu.io_regions)
+ for n, (origin, size) in enumerate(self.cpu.io_regions.items()):
+ self.bus.add_region("io{}".format(n), SoCIORegion(origin=origin, size=size, cached=False))
# Add user's interrupts (needs to be done after CPU interrupts are allocated)
for name, loc in self.interrupt_map.items():
break
self.bus.add_slave(name=wb_name, slave=interface)
- def check_io_region(self, name, origin, length):
- for region_origin, region_length in self.soc_io_regions.items():
- if (origin >= region_origin) & ((origin + length) < (region_origin + region_length)):
- return
- msg = "{} region (0x{:08x}-0x{:08x}) is not located in an IO region.\n".format(
- name, origin, origin + length - 1)
- msg += "Available IO regions: "
- if not bool(self.soc_io_regions):
- msg += "None\n"
- else:
- msg += "\n"
- for region_origin, region_length in self.soc_io_regions.items():
- msg += "- 0x{:08x}-0x{:08x}\n".format(region_origin, region_origin + region_length - 1)
- raise ValueError(msg)
-
def add_memory_region(self, name, origin, length, type="cached"):
self.bus.add_region(name, SoCRegion(origin=origin, size=length, cached="cached" in type))
self.bus.add_slave("rom", interface, SoCRegion(origin=self.cpu.reset_address, size=rom_size))
def add_csr_region(self, name, origin, busword, obj):
- self.check_io_region(name, origin, 0x800)
self.csr_regions[name] = SoCCSRRegion(origin, busword, obj)
# Finalization ---------------------------------------------------------------------------------
SoC.do_finalize(self)
- # Check and add CSRs regions
+ # Add CSRs regions
for name, csrs, mapaddr, rmap in self.csr_bankarray.banks:
self.add_csr_region(name, (self.bus.regions["csr"].origin + 0x800*mapaddr),
self.csr.data_width, csrs)
- # Check and add Memory regions
+ # Add Memory regions
for name, memory, mapaddr, mmap in self.csr_bankarray.srams:
self.add_csr_region(name + "_" + memory.name_override,
(self.bus.regions["csr"].origin + 0x800*mapaddr),