soc/integration: use dicts for constants/mem_regions/csr_regions to cleanup/simplify iterations on theses

This commit is contained in:
Florent Kermarrec 2019-09-30 10:59:36 +02:00
parent 7b72148c4e
commit 8be5824e25
4 changed files with 79 additions and 106 deletions

View 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:

View 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

View 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)

View 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 --------------------------------------------------------------------------------