From a4ef9b29b9781f576caba316c7920c902a8d8c8f Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 9 Oct 2019 10:14:14 +0200 Subject: [PATCH] soc_core/cpu: add io_regions and deprecate shadow_base (with API retro-compat) The shadow_base parameter has always been difficult to apprehend, replace it with io_regions (uncached regions) defined user or the CPU. The equivalent of a shadow_base parameter of 0x80000000 in the old API is: io_regions = {0x80000000: 0x80000000} # origin, length It's still possible to use shadow_base with retro-compat, but user is encouraged to update and features will be removed in the future. --- litex/soc/cores/cpu/lm32/core.py | 1 + litex/soc/cores/cpu/minerva/core.py | 1 + litex/soc/cores/cpu/mor1kx/core.py | 3 +- litex/soc/cores/cpu/picorv32/core.py | 1 + litex/soc/cores/cpu/rocket/core.py | 1 + litex/soc/cores/cpu/vexriscv/core.py | 1 + litex/soc/integration/builder.py | 3 +- litex/soc/integration/export.py | 4 +- litex/soc/integration/soc_core.py | 64 ++++++++++++++++++++++------ 9 files changed, 60 insertions(+), 19 deletions(-) diff --git a/litex/soc/cores/cpu/lm32/core.py b/litex/soc/cores/cpu/lm32/core.py index 4122dd6a0..47d65fa0a 100644 --- a/litex/soc/cores/cpu/lm32/core.py +++ b/litex/soc/cores/cpu/lm32/core.py @@ -21,6 +21,7 @@ class LM32(CPU): endianness = "big" gcc_triple = "lm32-elf" linker_output_format = "elf32-lm32" + io_regions = {0x80000000: 0x80000000} # origin, length @property def gcc_flags(self): diff --git a/litex/soc/cores/cpu/minerva/core.py b/litex/soc/cores/cpu/minerva/core.py index bcb3172b6..3cda5a195 100644 --- a/litex/soc/cores/cpu/minerva/core.py +++ b/litex/soc/cores/cpu/minerva/core.py @@ -18,6 +18,7 @@ class Minerva(CPU): endianness = "little" gcc_triple = ("riscv64-unknown-elf", "riscv32-unknown-elf", "riscv-none-embed") linker_output_format = "elf32-littleriscv" + io_regions = {0x80000000: 0x80000000} # origin, length @property def gcc_flags(self): diff --git a/litex/soc/cores/cpu/mor1kx/core.py b/litex/soc/cores/cpu/mor1kx/core.py index b595d81a3..16a43e893 100644 --- a/litex/soc/cores/cpu/mor1kx/core.py +++ b/litex/soc/cores/cpu/mor1kx/core.py @@ -21,6 +21,7 @@ class MOR1KX(CPU): gcc_triple = "or1k-elf" clang_triple = "or1k-linux" linker_output_format = "elf32-or1k" + io_regions = {0x80000000: 0x80000000} # origin, length @property def mem_map_linux(self): @@ -31,7 +32,7 @@ class MOR1KX(CPU): "main_ram" : 0x00000000, "rom" : 0x10000000, "sram" : 0x50000000, - "csr" : 0x60000000, + "csr" : 0xe0000000, } @property diff --git a/litex/soc/cores/cpu/picorv32/core.py b/litex/soc/cores/cpu/picorv32/core.py index 70adc3b4f..c9b3af5fd 100644 --- a/litex/soc/cores/cpu/picorv32/core.py +++ b/litex/soc/cores/cpu/picorv32/core.py @@ -36,6 +36,7 @@ class PicoRV32(CPU): endianness = "little" gcc_triple = ("riscv64-unknown-elf", "riscv32-unknown-elf", "riscv-none-embed") linker_output_format = "elf32-littleriscv" + io_regions = {0x80000000: 0x80000000} # origin, length @property def gcc_flags(self): diff --git a/litex/soc/cores/cpu/rocket/core.py b/litex/soc/cores/cpu/rocket/core.py index b7e28f67a..4f46ae2b2 100644 --- a/litex/soc/cores/cpu/rocket/core.py +++ b/litex/soc/cores/cpu/rocket/core.py @@ -56,6 +56,7 @@ class RocketRV64(CPU): endianness = "little" gcc_triple = ("riscv64-unknown-elf") linker_output_format = "elf64-littleriscv" + io_regions = {0x80000000: 0x80000000} # origin, length @property def mem_map(self): diff --git a/litex/soc/cores/cpu/vexriscv/core.py b/litex/soc/cores/cpu/vexriscv/core.py index 3ae10fb86..375dd9a9e 100644 --- a/litex/soc/cores/cpu/vexriscv/core.py +++ b/litex/soc/cores/cpu/vexriscv/core.py @@ -80,6 +80,7 @@ class VexRiscv(CPU, AutoCSR): endianness = "little" gcc_triple = ("riscv64-unknown-elf", "riscv32-unknown-elf", "riscv-none-embed") linker_output_format = "elf32-littleriscv" + io_regions = {0x80000000: 0x80000000} # origin, length @property def mem_map_linux(self): diff --git a/litex/soc/integration/builder.py b/litex/soc/integration/builder.py index c1adcd190..6119d056e 100644 --- a/litex/soc/integration/builder.py +++ b/litex/soc/integration/builder.py @@ -110,8 +110,7 @@ class Builder: write_to_file( os.path.join(generated_dir, "csr.h"), cpu_interface.get_csr_header(self.soc.csr_regions, - self.soc.constants, - shadow_base=self.soc.shadow_base) + self.soc.constants) ) write_to_file( os.path.join(generated_dir, "git.h"), diff --git a/litex/soc/integration/export.py b/litex/soc/integration/export.py index ef1d37a4d..08014a49f 100644 --- a/litex/soc/integration/export.py +++ b/litex/soc/integration/export.py @@ -156,7 +156,7 @@ def _get_rw_functions_c(reg_name, reg_base, nwords, busword, alignment, read_onl return r -def get_csr_header(regions, constants, with_access_functions=True, with_shadow_base=True, shadow_base=0x80000000): +def get_csr_header(regions, constants, with_access_functions=True): alignment = constants.get("CONFIG_CSR_ALIGNMENT", 32) r = generated_banner("//") r += "#ifndef __GENERATED_CSR_H\n#define __GENERATED_CSR_H\n" @@ -174,8 +174,6 @@ def get_csr_header(regions, constants, with_access_functions=True, with_shadow_b r += "#endif /* ! CSR_ACCESSORS_DEFINED */\n" for name, region in regions.items(): origin = region.origin - if not with_shadow_base: - origin &= (~shadow_base) r += "\n/* "+name+" */\n" r += "#define CSR_"+name.upper()+"_BASE "+hex(origin)+"L\n" if not isinstance(region.obj, Memory): diff --git a/litex/soc/integration/soc_core.py b/litex/soc/integration/soc_core.py index d991d703f..94aa037b2 100644 --- a/litex/soc/integration/soc_core.py +++ b/litex/soc/integration/soc_core.py @@ -69,16 +69,16 @@ class SoCCore(Module): csr_map = {} interrupt_map = {} mem_map = { - "rom": 0x00000000, # (default shadow @0x80000000) - "sram": 0x01000000, # (default shadow @0x81000000) - "csr": 0x02000000, # (default shadow @0x82000000) - "main_ram": 0x40000000, # (default shadow @0xc0000000) + "rom": 0x00000000, + "sram": 0x01000000, + "main_ram": 0x40000000, + "csr": 0x82000000, } + io_regions = {} + def __init__(self, platform, clk_freq, # CPU parameters cpu_type="vexriscv", cpu_reset_address=0x00000000, cpu_variant=None, - # MEM MAP parameters - shadow_base=0x80000000, # ROM parameters integrated_rom_size=0, integrated_rom_init=[], # SRAM parameters @@ -96,7 +96,8 @@ class SoCCore(Module): # Controller parameters with_ctrl=True, # Wishbone parameters - with_wishbone=True, wishbone_timeout_cycles=1e6): + with_wishbone=True, wishbone_timeout_cycles=1e6, + **kwargs): self.platform = platform self.clk_freq = clk_freq @@ -104,6 +105,7 @@ class SoCCore(Module): self.soc_csr_map = {} self.soc_interrupt_map = {} self.soc_mem_map = self.mem_map + self.soc_io_regions = self.io_regions # SoC's Config/Constants/Regions self.config = {} @@ -118,6 +120,8 @@ class SoCCore(Module): # CSR masters list self._csr_masters = [] + self.add_retro_compat(kwargs) + # Parameters managment --------------------------------------------------------------------- if cpu_type == "None": cpu_type = None @@ -128,9 +132,6 @@ class SoCCore(Module): self.cpu_type = cpu_type self.cpu_variant = cpu.check_format_cpu_variant(cpu_variant) - self.shadow_base = shadow_base - self.config["SHADOW_BASE"] = shadow_base - self.integrated_rom_size = integrated_rom_size self.integrated_rom_initialized = integrated_rom_init != [] self.integrated_sram_size = integrated_sram_size @@ -174,6 +175,9 @@ class SoCCore(Module): # Update Memory Map (if defined by CPU) self.soc_mem_map.update(self.cpu.mem_map) + # Update IO Regions (if defined by CPU) + self.soc_io_regions.update(self.cpu.io_regions) + # Set reset address self.cpu.set_reset_address(self.soc_mem_map["rom"] if integrated_rom_size else cpu_reset_address) self.config["CPU_RESET_ADDR"] = self.cpu.reset_address @@ -348,7 +352,20 @@ class SoCCore(Module): raise FinalizeError self._csr_masters.append(csrm) - def add_memory_region(self, name, origin, length): + 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{:x} not located in an IO region.\n".format( + name, origin, origin + length - 1) + msg += "Avalaible IO regions:\n" + for region_origin, region_length in self.soc_io_regions.items(): + msg += "- 0x{:08x}-0x{:x}\n".format(region_origin, region_origin + region_length - 1) + raise ValueError(msg) + + def add_memory_region(self, name, origin, length, io_region=False): + if io_region: + self.check_io_region(name, origin, length) def in_this_region(addr): return addr >= origin and addr < origin + length for n, r in self.mem_regions.items(): @@ -375,6 +392,7 @@ class SoCCore(Module): raise ValueError("CSR region conflict between {} and {}".format(n, name)) def add_csr_region(self, name, origin, busword, obj): + self.check_io_region(name, origin, 0x800) self.check_csr_region(name, origin) self.csr_regions[name] = SoCCSRRegion(origin, busword, obj) @@ -433,14 +451,14 @@ class SoCCore(Module): # Check and add CSRs regions for name, csrs, mapaddr, rmap in self.csrbankarray.banks: self.check_csr_range(name, 0x800*mapaddr) - self.add_csr_region(name, (self.soc_mem_map["csr"] + 0x800*mapaddr) | self.shadow_base, + self.add_csr_region(name, (self.soc_mem_map["csr"] + 0x800*mapaddr), self.csr_data_width, csrs) # Check and add Memory regions for name, memory, mapaddr, mmap in self.csrbankarray.srams: self.check_csr_range(name, 0x800*mapaddr) self.add_csr_region(name + "_" + memory.name_override, - (self.soc_mem_map["csr"] + 0x800*mapaddr) | self.shadow_base, + (self.soc_mem_map["csr"] + 0x800*mapaddr), self.csr_data_width, memory) # Add CSRs / Config items to constants @@ -464,6 +482,26 @@ class SoCCore(Module): self.comb += self.cpu.interrupt[_id].eq(module.ev.irq) self.constants[_name.upper() + "_INTERRUPT"] = _id + + # API retro-compatibility layer ---------------------------------------------------------------- + # Allow user to build the design the old API for ~3 months after the API change is introduced. + # Adds warning and artificical delay to encourage user to update. + + def add_retro_compat(self, kwargs): + # 2019-10-09 : deprecate shadow_base, introduce io_regions + if "shadow_base" in kwargs.keys(): + deprecated_warning(": shadow_base replaced by IO regions.") + self.retro_compat_shadow_base = kwargs.get("shadow_base", 0x80000000) + self.config["SHADOW_BASE"] = self.retro_compat_shadow_base + + def __getattr__(self, name): + # 2019-10-09: deprecate shadow_base, introduce io_regions + if name == "shadow_base": + deprecated_warning(": shadow_base replaced by IO regions.") + return self.retro_compat_shadow_base + else: + return Module.__getattr__(self, name) + # SoCCore arguments -------------------------------------------------------------------------------- def soc_core_args(parser):