Skip to content

Commit

Permalink
soc/integration: use dicts for constants/mem_regions/csr_regions to c…
Browse files Browse the repository at this point in the history
…leanup/simplify iterations on theses
  • Loading branch information
enjoy-digital committed Sep 30, 2019
1 parent 7b72148 commit 8be5824
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 106 deletions.
35 changes: 8 additions & 27 deletions litex/soc/integration/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,18 +66,11 @@ def add_software_package(self, name, src_dir=None):
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)))
Expand All @@ -91,7 +84,7 @@ def define(k, v):
"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"
Expand All @@ -110,13 +103,13 @@ def define(k, v):
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()
Expand All @@ -131,27 +124,15 @@ def define(k, v):
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:
Expand Down
18 changes: 18 additions & 0 deletions litex/soc/integration/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

from migen import *

# Helpers ----------------------------------------------------------------------------------------

def mem_decoder(address, size=0x10000000):
address &= ~0x80000000
size = 2**log2_int(size, False)
Expand Down Expand Up @@ -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
70 changes: 29 additions & 41 deletions litex/soc/integration/export.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,6 @@

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):
Expand Down Expand Up @@ -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

Expand All @@ -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 = ""

Expand Down Expand Up @@ -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:
Expand All @@ -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"):
Expand All @@ -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
Expand All @@ -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": {},
Expand All @@ -233,34 +220,35 @@ 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)


# 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)
Expand Down
62 changes: 24 additions & 38 deletions litex/soc/integration/soc_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,18 +100,16 @@ def __init__(self, platform, clk_freq,
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 = []
Expand All @@ -131,6 +129,7 @@ def __init__(self, platform, clk_freq,
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 != []
Expand Down Expand Up @@ -352,12 +351,11 @@ def add_csr_master(self, csrm):
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)
Expand All @@ -367,34 +365,23 @@ def register_rom(self, interface, rom_size=0xa000):
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:
Expand All @@ -418,11 +405,10 @@ def build(self, *args, **kwargs):

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):
Expand Down Expand Up @@ -459,11 +445,11 @@ def do_finalize(self):

# 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"):
Expand All @@ -475,7 +461,7 @@ def do_finalize(self):
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 --------------------------------------------------------------------------------

Expand Down

0 comments on commit 8be5824

Please sign in to comment.