soc_core/cpu: add io_regions and deprecate shadow_base (with API retro-compat)
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Wed, 9 Oct 2019 08:14:14 +0000 (10:14 +0200)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Wed, 9 Oct 2019 08:15:42 +0000 (10:15 +0200)
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
litex/soc/cores/cpu/minerva/core.py
litex/soc/cores/cpu/mor1kx/core.py
litex/soc/cores/cpu/picorv32/core.py
litex/soc/cores/cpu/rocket/core.py
litex/soc/cores/cpu/vexriscv/core.py
litex/soc/integration/builder.py
litex/soc/integration/export.py
litex/soc/integration/soc_core.py

index 4122dd6a0190213541ef14f2629e7667cf0061e0..47d65fa0aaccaaefa3d345af9de41bd4f1aae453 100644 (file)
@@ -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):
index bcb3172b6c59615fd239f6bfdb1e72b26b66dabe..3cda5a1957e3a915e036610759dbe0289d9fa421 100644 (file)
@@ -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):
index b595d81a3db42bf35002a8d53d41dd01cde4c9b5..16a43e89363e2c660bb9d9b13f5a54c77fc04240 100644 (file)
@@ -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
index 70adc3b4fa470c37ab75a00dd17eeb565a6e137a..c9b3af5fd03ddb415af0b6be1fac09c7707e005b 100644 (file)
@@ -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):
index b7e28f67a0937691cc87878dc65587d6e8d4f8a8..4f46ae2b20854f1b81d1c3ee7540dab8d2c14450 100644 (file)
@@ -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):
index 3ae10fb86321f029f37184055ebe3e0d1ee5c8b7..375dd9a9e5c917c1c2c4a2720cb3edfa197efce7 100644 (file)
@@ -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):
index c1adcd190c376d61a61172963733a231e07efcf4..6119d056e03c0755a5d3c405489eccee5c4f07d4 100644 (file)
@@ -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"),
index ef1d37a4de669fa6b25fbd8512ae632c855a4681..08014a49f7bf02c0f202080e5ac842cd4b5df4ce 100644 (file)
@@ -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):
index d991d703fb36e4dccbdad61a87f9d83d9cb786dd..94aa037b22287fb843ad4b5e1b796b4cc53a8618 100644 (file)
@@ -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):