From: Florent Kermarrec Date: Mon, 10 Feb 2020 13:35:36 +0000 (+0100) Subject: soc: add SOCIORegion and manage it X-Git-Tag: 24jan2021_ls180~677^2~34 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=de100fddf5f9e517d4b428cf5d5af9ba4e742d98;p=litex.git soc: add SOCIORegion and manage it --- diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index 50df1989..696375f0 100755 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -19,7 +19,7 @@ from litex.soc.interconnect import wishbone2csr # TODO: # - replace raise with exit on logging error. # - add configurable CSR paging. -# - manage IO/Linker regions. +# - manage SoCLinkerRegion logging.basicConfig(level=logging.INFO) @@ -77,9 +77,9 @@ class SoCRegion: r += "Cached: {}".format(colorer(self.cached)) return r +class SoCIORegion(SoCRegion): pass -class SoCLinkerRegion(SoCRegion): - pass +class SoCLinkerRegion(SoCRegion): pass # SoCBusHandler ------------------------------------------------------------------------------------ @@ -121,6 +121,8 @@ class SoCBusHandler(Module): 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))) @@ -137,9 +139,44 @@ class SoCBusHandler(Module): # 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. @@ -149,8 +186,16 @@ class SoCBusHandler(Module): 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"), @@ -190,7 +235,7 @@ class SoCBusHandler(Module): 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 @@ -201,7 +246,7 @@ class SoCBusHandler(Module): 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] @@ -218,8 +263,23 @@ class SoCBusHandler(Module): 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(): @@ -280,6 +340,14 @@ class SoCBusHandler(Module): 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(): @@ -429,7 +497,6 @@ class SoCCSRHandler(SoCLocHandler): 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), @@ -441,7 +508,6 @@ class SoCCSRHandler(SoCLocHandler): 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): @@ -639,8 +705,9 @@ class SoC(Module): 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) @@ -662,8 +729,9 @@ class SoC(Module): 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])) diff --git a/litex/soc/integration/soc_core.py b/litex/soc/integration/soc_core.py index c09e8808..5417479c 100644 --- a/litex/soc/integration/soc_core.py +++ b/litex/soc/integration/soc_core.py @@ -20,7 +20,7 @@ from migen import * 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", @@ -45,7 +45,6 @@ class SoCCore(SoC): "main_ram": 0x40000000, "csr": 0x82000000, } - io_regions = {} def __init__(self, platform, clk_freq, # CPU parameters @@ -90,7 +89,6 @@ class SoCCore(SoC): # 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 = {} @@ -130,7 +128,8 @@ class SoCCore(SoC): 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(): @@ -183,21 +182,6 @@ class SoCCore(SoC): 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)) @@ -208,7 +192,6 @@ class SoCCore(SoC): 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 --------------------------------------------------------------------------------- @@ -227,12 +210,12 @@ class SoCCore(SoC): 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),