soc/integration: use dicts for constants/mem_regions/csr_regions to cleanup/simplify...
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Mon, 30 Sep 2019 08:59:36 +0000 (10:59 +0200)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Mon, 30 Sep 2019 08:59:36 +0000 (10:59 +0200)
litex/soc/integration/builder.py
litex/soc/integration/common.py
litex/soc/integration/export.py
litex/soc/integration/soc_core.py

index fe0fbbc72e539dba35077863b076252c750724c8..1120e4ccbb23ac05be5e3ed43929175479eb6129 100644 (file)
@@ -66,18 +66,11 @@ class Builder:
         self.software_packages.append((name, src_dir))
 
     def _generate_includes(self):
-        cpu_type = self.soc.cpu_type
-        memory_regions = self.soc.get_memory_regions()
-        flash_boot_address = getattr(self.soc, "flash_boot_address", None)
-        shadow_base = getattr(self.soc, "shadow_base", None)
-        csr_regions = self.soc.get_csr_regions()
-        constants = self.soc.get_constants()
-
-        buildinc_dir = os.path.join(self.output_dir, "software", "include")
+        buildinc_dir  = os.path.join(self.output_dir, "software", "include")
         generated_dir = os.path.join(buildinc_dir, "generated")
         os.makedirs(generated_dir, exist_ok=True)
 
-        if cpu_type is not None:
+        if self.soc.cpu_type is not None:
             variables_contents = []
             def define(k, v):
                 variables_contents.append("{}={}\n".format(k, _makefile_escape(v)))
@@ -91,7 +84,7 @@ class Builder:
                 "COPY_TO_MAIN_RAM" : "0",
                 "EXECUTE_IN_PLACE" : "0"
             }
-            if "main_ram" in (m[0] for m in memory_regions):
+            if "main_ram" in self.soc.mem_regions.keys():
                 exec_profiles["COPY_TO_MAIN_RAM"] = "1"
             else:
                 exec_profiles["EXECUTE_IN_PLACE"] = "1"
@@ -110,13 +103,13 @@ class Builder:
                 cpu_interface.get_linker_output_format(self.soc.cpu))
             write_to_file(
                 os.path.join(generated_dir, "regions.ld"),
-                cpu_interface.get_linker_regions(memory_regions))
+                cpu_interface.get_linker_regions(self.soc.mem_regions))
         write_to_file(
             os.path.join(generated_dir, "mem.h"),
-            cpu_interface.get_mem_header(memory_regions, flash_boot_address, shadow_base))
+            cpu_interface.get_mem_header(self.soc.mem_regions))
         write_to_file(
             os.path.join(generated_dir, "csr.h"),
-            cpu_interface.get_csr_header(csr_regions, constants))
+            cpu_interface.get_csr_header(self.soc.csr_regions, self.soc.constants))
         write_to_file(
             os.path.join(generated_dir, "git.h"),
             cpu_interface.get_git_header()
@@ -131,27 +124,15 @@ class Builder:
                         self.soc.sdram.controller.settings.timing))
 
     def _generate_csr_map(self, csr_json=None, csr_csv=None):
-        memory_regions = self.soc.get_memory_regions()
-        csr_regions = self.soc.get_csr_regions()
-        constants = self.soc.get_constants()
-
-        shadow_base = getattr(self.soc, "shadow_base", None)
-        if shadow_base:
-            constants.append(('shadow_base',  shadow_base))
-
-        flash_boot_address = getattr(self.soc, "flash_boot_address", None)
-        if flash_boot_address:
-            constants.append(('flash_boot_address',  flash_boot_address))
-
         if csr_json is not None:
             csr_dir = os.path.dirname(os.path.realpath(csr_json))
             os.makedirs(csr_dir, exist_ok=True)
-            write_to_file(csr_json, cpu_interface.get_csr_json(csr_regions, constants, memory_regions))
+            write_to_file(csr_json, cpu_interface.get_csr_json(self.soc.csr_regions, self.soc.constants, self.soc.mem_regions))
 
         if csr_csv is not None:
             csr_dir = os.path.dirname(os.path.realpath(csr_csv))
             os.makedirs(csr_dir, exist_ok=True)
-            write_to_file(csr_csv, cpu_interface.get_csr_csv(csr_regions, constants, memory_regions))
+            write_to_file(csr_csv, cpu_interface.get_csr_csv(self.soc.csr_regions, self.soc.constants, self.soc.mem_regions))
 
     def _prepare_software(self):
         for name, src_dir in self.software_packages:
index 991680a60b43959bb659940e5d41a19331958f2b..0a34d59d1d889258408c1cf69b354ba1b66928f0 100644 (file)
@@ -10,6 +10,8 @@ import datetime
 
 from migen import *
 
+# Helpers ----------------------------------------------------------------------------------------
+
 def mem_decoder(address, size=0x10000000):
     address &= ~0x80000000
     size = 2**log2_int(size, False)
@@ -68,3 +70,19 @@ def get_mem_data(filename_or_regions, endianness="big", mem_size=None):
                     data[int(base, 16)//4 + i] = struct.unpack(">I", w)[0]
                 i += 1
     return data
+
+# SoC primitives -----------------------------------------------------------------------------------
+
+def SoCConstant(value):
+    return value
+
+class SoCMemRegion:
+    def __init__(self, origin, length):
+        self.origin = origin
+        self.length = length
+
+class SoCCSRRegion:
+    def __init__(self, origin, busword, obj):
+        self.origin  = origin
+        self.busword = busword
+        self.obj     = obj
index 74c1ea24357b67b587e3f205397886780d2f4b18..ef1d37a4de669fa6b25fbd8512ae632c855a4681 100644 (file)
@@ -23,15 +23,6 @@ from litex.soc.interconnect.csr import CSRStatus
 
 from litex.build.tools import generated_banner
 
-# Helpers ----------------------------------------------------------------------------------------
-
-# FIXME: use OrderedDict for constants?
-def get_constant(name, constants):
-    for n, v in constants:
-        if n == name:
-            return v
-    return None
-
 # CPU files ----------------------------------------------------------------------------------------
 
 def get_cpu_mak(cpu, compile_software):
@@ -98,8 +89,8 @@ def get_linker_output_format(cpu):
 
 def get_linker_regions(regions):
     r = "MEMORY {\n"
-    for name, origin, length in regions:
-        r += "\t{} : ORIGIN = 0x{:08x}, LENGTH = 0x{:08x}\n".format(name, origin, length)
+    for name, region in regions.items():
+        r += "\t{} : ORIGIN = 0x{:08x}, LENGTH = 0x{:08x}\n".format(name, region.origin, region.length)
     r += "}\n"
     return r
 
@@ -115,20 +106,15 @@ def get_git_header():
     r += "#endif\n"
     return r
 
-def get_mem_header(regions, flash_boot_address, shadow_base):
+def get_mem_header(regions):
     r = generated_banner("//")
     r += "#ifndef __GENERATED_MEM_H\n#define __GENERATED_MEM_H\n\n"
-    for name, base, size in regions:
+    for name, region in regions.items():
         r += "#define {name}_BASE 0x{base:08x}L\n#define {name}_SIZE 0x{size:08x}\n\n".format(
-            name=name.upper(), base=base, size=size)
-    if flash_boot_address is not None:
-        r += "#define FLASH_BOOT_ADDRESS 0x{:08x}L\n\n".format(flash_boot_address)
-    if shadow_base is not None:
-        r += "#define SHADOW_BASE 0x{:08x}L\n\n".format(shadow_base)
+            name=name.upper(), base=region.origin, size=region.length)
     r += "#endif\n"
     return r
 
-
 def _get_rw_functions_c(reg_name, reg_base, nwords, busword, alignment, read_only, with_access_functions):
     r = ""
 
@@ -171,7 +157,7 @@ def _get_rw_functions_c(reg_name, reg_base, nwords, busword, alignment, read_onl
 
 
 def get_csr_header(regions, constants, with_access_functions=True, with_shadow_base=True, shadow_base=0x80000000):
-    alignment = get_constant("CONFIG_CSR_ALIGNMENT", constants)
+    alignment = constants.get("CONFIG_CSR_ALIGNMENT", 32)
     r = generated_banner("//")
     r += "#ifndef __GENERATED_CSR_H\n#define __GENERATED_CSR_H\n"
     if with_access_functions:
@@ -186,15 +172,16 @@ def get_csr_header(regions, constants, with_access_functions=True, with_shadow_b
         r += "#else /* ! CSR_ACCESSORS_DEFINED */\n"
         r += "#include <hw/common.h>\n"
         r += "#endif /* ! CSR_ACCESSORS_DEFINED */\n"
-    for name, origin, busword, obj in regions:
+    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(obj, Memory):
-            for csr in obj:
-                nr = (csr.size + busword - 1)//busword
-                r += _get_rw_functions_c(name + "_" + csr.name, origin, nr, busword, alignment,
+        if not isinstance(region.obj, Memory):
+            for csr in region.obj:
+                nr = (csr.size + region.busword - 1)//region.busword
+                r += _get_rw_functions_c(name + "_" + csr.name, origin, nr, region.busword, alignment,
                     isinstance(csr, CSRStatus), with_access_functions)
                 origin += alignment//8*nr
                 if hasattr(csr, "fields"):
@@ -203,7 +190,7 @@ def get_csr_header(regions, constants, with_access_functions=True, with_shadow_b
                         r += "#define CSR_"+name.upper()+"_"+csr.name.upper()+"_"+field.name.upper()+"_SIZE "+str(field.size)+"\n"
 
     r += "\n/* constants */\n"
-    for name, value in constants:
+    for name, value in constants.items():
         if value is None:
             r += "#define "+name+"\n"
             continue
@@ -223,8 +210,8 @@ def get_csr_header(regions, constants, with_access_functions=True, with_shadow_b
 
 # JSON Export --------------------------------------------------------------------------------------
 
-def get_csr_json(csr_regions=[], constants=[], memory_regions=[]):
-    alignment = 32 if constants is None else get_constant("CONFIG_CSR_ALIGNMENT", constants)
+def get_csr_json(csr_regions={}, constants={}, mem_regions={}):
+    alignment = constants.get("CONFIG_CSR_ALIGNMENT", 32)
 
     d = {
         "csr_bases":     {},
@@ -233,25 +220,26 @@ def get_csr_json(csr_regions=[], constants=[], memory_regions=[]):
         "memories":      {},
     }
 
-    for name, origin, busword, obj in csr_regions:
-        d["csr_bases"][name] = origin
-        if not isinstance(obj, Memory):
-            for csr in obj:
-                size = (csr.size + busword - 1)//busword
+    for name, region in csr_regions.items():
+        d["csr_bases"][name] = region.origin
+        region_origin = region.origin
+        if not isinstance(region.obj, Memory):
+            for csr in region.obj:
+                size = (csr.size + region.busword - 1)//region.busword
                 d["csr_registers"][name + "_" + csr.name] = {
-                    "addr": origin,
+                    "addr": region_origin,
                     "size": size,
                     "type": "ro" if isinstance(csr, CSRStatus) else "rw"
                 }
-                origin += alignment//8*size
+                region_origin += alignment//8*size
 
-    for name, value in constants:
+    for name, value in constants.items():
         d["constants"][name.lower()] = value.lower() if isinstance(value, str) else value
 
-    for name, origin, length in memory_regions:
+    for name, region in mem_regions.items():
         d["memories"][name.lower()] = {
-            "base": origin,
-            "size": length
+            "base": region.origin,
+            "size": region.length
         }
 
     return json.dumps(d, indent=4)
@@ -259,8 +247,8 @@ def get_csr_json(csr_regions=[], constants=[], memory_regions=[]):
 
 # CSV Export --------------------------------------------------------------------------------------
 
-def get_csr_csv(csr_regions=[], constants=[], memory_regions=[]):
-    d = json.loads(get_csr_json(csr_regions, constants, memory_regions))
+def get_csr_csv(csr_regions={}, constants={}, mem_regions={}):
+    d = json.loads(get_csr_json(csr_regions, constants, mem_regions))
     r = generated_banner("#")
     for name, value in d["csr_bases"].items():
         r += "csr_base,{},0x{:08x},,\n".format(name, value)
index b3f1ae4003fdc61c5b49e5a1306dc23e236dc909..33be3dab446fbfe6ccece4c45904837be3d25fc9 100644 (file)
@@ -100,18 +100,16 @@ class SoCCore(Module):
         self.platform = platform
         self.clk_freq = clk_freq
 
-        # config dictionary (store all SoC's parameters to be exported to software)
-        self.config = dict()
-
-        # SoC's register/interrupt/memory mappings (default or user defined + dynamically allocateds)
+        # SoC's CSR/Mem/Interrupt mapping (default or user defined + dynamically allocateds)
         self.soc_csr_map       = {}
         self.soc_interrupt_map = {}
         self.soc_mem_map       = self.mem_map
 
-        # Regions / Constants lists
-        self._memory_regions = []  # (name, origin, length)
-        self._csr_regions    = []  # (name, origin, busword, csr_list/Memory)
-        self._constants      = []  # (name, value)
+        # SoC's Config/Constants/Regions
+        self.config      = {}
+        self.constants   = {}
+        self.mem_regions = {}
+        self.csr_regions = {}
 
         # Wishbone masters/slaves lists
         self._wb_masters = []
@@ -131,6 +129,7 @@ class SoCCore(Module):
         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 != []
@@ -352,12 +351,11 @@ class SoCCore(Module):
     def add_memory_region(self, name, origin, length):
         def in_this_region(addr):
             return addr >= origin and addr < origin + length
-        for n, o, l in self._memory_regions:
-            l = 2**log2_int(l, False)
-            if n == name or in_this_region(o) or in_this_region(o+l-1):
+        for n, r in self.mem_regions.items():
+            r.length = 2**log2_int(r.length, False)
+            if n == name or in_this_region(r.origin) or in_this_region(r.origin + r.length - 1):
                 raise ValueError("Memory region conflict between {} and {}".format(n, name))
-
-        self._memory_regions.append((name, origin, length))
+        self.mem_regions[name] = SoCMemRegion(origin, length)
 
     def register_mem(self, name, address, interface, size=0x10000000):
         self.add_wb_slave(address, interface, size)
@@ -367,34 +365,23 @@ class SoCCore(Module):
         self.add_wb_slave(self.soc_mem_map["rom"], interface, rom_size)
         self.add_memory_region("rom", self.cpu.reset_address, rom_size)
 
-    def get_memory_regions(self):
-        return self._memory_regions
-
     def check_csr_range(self, name, addr):
         if addr >= 1<<(self.csr_address_width+2):
             raise ValueError("{} CSR out of range, increase csr_address_width".format(name))
 
     def check_csr_region(self, name, origin):
-        for n, o, l, obj in self._csr_regions:
-            if n == name or o == origin:
+        for n, r in self.csr_regions.items():
+            if n == name or r.origin == origin:
                 raise ValueError("CSR region conflict between {} and {}".format(n, name))
 
     def add_csr_region(self, name, origin, busword, obj):
         self.check_csr_region(name, origin)
-        self._csr_regions.append((name, origin, busword, obj))
-
-    def get_csr_regions(self):
-        return self._csr_regions
+        self.csr_regions[name] = SoCCSRRegion(origin, busword, obj)
 
     def add_constant(self, name, value=None):
-        self._constants.append((name, value))
-
-    def get_constants(self):
-        r = []
-        for _name, _id in sorted(self.soc_interrupt_map.items()):
-            r.append((_name.upper() + "_INTERRUPT", _id))
-        r += self._constants
-        return r
+        if name in self.constants.keys():
+            raise ValueError("Constant {} already declared.".format(name))
+        self.constants[name] = SoCConstant(value)
 
     def get_csr_dev_address(self, name, memory):
         if memory is not None:
@@ -418,11 +405,10 @@ class SoCCore(Module):
 
     def do_finalize(self):
         # Verify CPU has required memories
-        registered_mems = {regions[0] for regions in self._memory_regions}
         if self.cpu_type is not None:
-            for mem in "rom", "sram":
-                if mem not in registered_mems:
-                    raise FinalizeError("CPU needs \"{}\" to be registered with SoC.register_mem()".format(mem))
+            for name in "rom", "sram":
+                if name not in self.mem_regions.keys():
+                    raise FinalizeError("CPU needs \"{}\" to be registered with SoC.register_mem()".format(name))
 
         # Add the Wishbone Masters/Slaves interconnect
         if len(self._wb_masters):
@@ -459,11 +445,11 @@ class SoCCore(Module):
 
         # Add CSRs / Config items to constants
         for name, constant in self.csrbankarray.constants:
-            self._constants.append(((name + "_" + constant.name).upper(), constant.value.value))
+            self.add_constant(name + "_" + constant.name, constant.value.value)
         for name, value in sorted(self.config.items(), key=itemgetter(0)):
-            self._constants.append(("CONFIG_" + name.upper(), value))
+            self.add_constant("CONFIG_" + name.upper(), value)
             if isinstance(value, str):
-                self._constants.append(("CONFIG_" + name.upper() + "_" + value, 1))
+                self.add_constant("CONFIG_" + name.upper() + "_" + value)
 
         # Connect interrupts
         if hasattr(self, "cpu"):
@@ -475,7 +461,7 @@ class SoCCore(Module):
                         module = getattr(self, _name)
                         assert hasattr(module, 'ev'), "Submodule %s does not have EventManager (xx.ev) module" % _name
                         self.comb += self.cpu.interrupt[_id].eq(module.ev.irq)
-
+                    self.constants[_name.upper() + "_INTERRUPT"] = _id
 
 # SoCCore arguments --------------------------------------------------------------------------------