soc/integration: use dicts for constants/mem_regions/csr_regions to cleanup/simplify iterations on theses
This commit is contained in:
parent
7b72148c4e
commit
8be5824e25
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 --------------------------------------------------------------------------------
|
||||
|
||||
|
|
Loading…
Reference in New Issue