Merge pull request #1953 from enjoy-digital/export_csr_c_rework
Simplify/Cleanup C exports and disable Fields accessors generation by default.
This commit is contained in:
commit
8a83585b85
|
@ -252,7 +252,10 @@ class Builder:
|
||||||
csr_contents = export.get_csr_header(
|
csr_contents = export.get_csr_header(
|
||||||
regions = self.soc.csr_regions,
|
regions = self.soc.csr_regions,
|
||||||
constants = self.soc.constants,
|
constants = self.soc.constants,
|
||||||
csr_base = self.soc.mem_regions["csr"].origin)
|
csr_base = self.soc.mem_regions["csr"].origin,
|
||||||
|
with_access_functions = True,
|
||||||
|
with_fields_access_functions = False,
|
||||||
|
)
|
||||||
write_to_file(os.path.join(self.generated_dir, "csr.h"), csr_contents)
|
write_to_file(os.path.join(self.generated_dir, "csr.h"), csr_contents)
|
||||||
|
|
||||||
# Generate Git SHA1 of tools to git.h
|
# Generate Git SHA1 of tools to git.h
|
||||||
|
|
|
@ -194,24 +194,30 @@ def get_soc_header(constants, with_access_functions=True):
|
||||||
return r
|
return r
|
||||||
|
|
||||||
def _get_csr_addr(csr_base, addr, with_csr_base_define=True):
|
def _get_csr_addr(csr_base, addr, with_csr_base_define=True):
|
||||||
|
"""
|
||||||
|
Generate the CSR address string.
|
||||||
|
"""
|
||||||
if with_csr_base_define:
|
if with_csr_base_define:
|
||||||
return f"(CSR_BASE + {hex(addr)}L)"
|
return f"(CSR_BASE + {hex(addr)}L)"
|
||||||
else:
|
else:
|
||||||
return f"{hex(csr_base + addr)}L"
|
return f"{hex(csr_base + addr)}L"
|
||||||
|
|
||||||
def _get_rw_functions_c(reg_name, reg_base, nwords, busword, alignment, read_only, csr_base, with_csr_base_define, with_access_functions):
|
def _generate_csr_definitions_c(reg_name, reg_base, nwords, csr_base, with_csr_base_define):
|
||||||
r = ""
|
"""
|
||||||
|
Generate C code for CSR address and size definitions.
|
||||||
|
"""
|
||||||
addr_str = f"CSR_{reg_name.upper()}_ADDR"
|
addr_str = f"CSR_{reg_name.upper()}_ADDR"
|
||||||
size_str = f"CSR_{reg_name.upper()}_SIZE"
|
size_str = f"CSR_{reg_name.upper()}_SIZE"
|
||||||
r += f"#define {addr_str} {_get_csr_addr(csr_base, reg_base, with_csr_base_define)}\n"
|
definitions = f"#define {addr_str} {_get_csr_addr(csr_base, reg_base, with_csr_base_define)}\n"
|
||||||
|
definitions += f"#define {size_str} {nwords}\n"
|
||||||
|
return definitions
|
||||||
|
|
||||||
r += f"#define {size_str} {nwords}\n"
|
def _determine_ctype_and_stride_c(size, alignment):
|
||||||
|
"""
|
||||||
size = nwords*busword//8
|
Determine the C type and stride based on the size.
|
||||||
|
"""
|
||||||
if size > 8:
|
if size > 8:
|
||||||
# Downstream should select appropriate `csr_[rd|wr]_buf_uintX()` pair!
|
return None, None
|
||||||
return r
|
|
||||||
elif size > 4:
|
elif size > 4:
|
||||||
ctype = "uint64_t"
|
ctype = "uint64_t"
|
||||||
elif size > 2:
|
elif size > 2:
|
||||||
|
@ -220,59 +226,129 @@ def _get_rw_functions_c(reg_name, reg_base, nwords, busword, alignment, read_onl
|
||||||
ctype = "uint16_t"
|
ctype = "uint16_t"
|
||||||
else:
|
else:
|
||||||
ctype = "uint8_t"
|
ctype = "uint8_t"
|
||||||
|
stride = alignment // 8
|
||||||
|
return ctype, stride
|
||||||
|
|
||||||
stride = alignment//8;
|
def _generate_read_function_c(reg_name, reg_base, nwords, busword, ctype, stride, csr_base, with_csr_base_define):
|
||||||
if with_access_functions:
|
"""
|
||||||
r += f"static inline {ctype} {reg_name}_read(void) {{\n"
|
Generate C code for the read function of a CSR.
|
||||||
|
"""
|
||||||
|
read_function = f"static inline {ctype} {reg_name}_read(void) {{\n"
|
||||||
if nwords > 1:
|
if nwords > 1:
|
||||||
r += f"\t{ctype} r = csr_read_simple({_get_csr_addr(csr_base, reg_base, with_csr_base_define)});\n"
|
read_function += f"\t{ctype} r = csr_read_simple({_get_csr_addr(csr_base, reg_base, with_csr_base_define)});\n"
|
||||||
for sub in range(1, nwords):
|
for sub in range(1, nwords):
|
||||||
r += f"\tr <<= {busword};\n"
|
read_function += f"\tr <<= {busword};\n"
|
||||||
r += f"\tr |= csr_read_simple({_get_csr_addr(csr_base, reg_base+sub*stride, with_csr_base_define)});\n"
|
read_function += f"\tr |= csr_read_simple({_get_csr_addr(csr_base, reg_base + sub * stride, with_csr_base_define)});\n"
|
||||||
r += "\treturn r;\n}\n"
|
read_function += "\treturn r;\n}\n"
|
||||||
else:
|
else:
|
||||||
r += f"\treturn csr_read_simple({_get_csr_addr(csr_base, reg_base, with_csr_base_define)});\n}}\n"
|
read_function += f"\treturn csr_read_simple({_get_csr_addr(csr_base, reg_base, with_csr_base_define)});\n}}\n"
|
||||||
|
return read_function
|
||||||
|
|
||||||
if not read_only:
|
def _generate_write_function_c(reg_name, reg_base, nwords, busword, ctype, stride, csr_base, with_csr_base_define):
|
||||||
r += f"static inline void {reg_name}_write({ctype} v) {{\n"
|
"""
|
||||||
|
Generate C code for the write function of a CSR.
|
||||||
|
"""
|
||||||
|
write_function = f"static inline void {reg_name}_write({ctype} v) {{\n"
|
||||||
for sub in range(nwords):
|
for sub in range(nwords):
|
||||||
shift = (nwords-sub-1)*busword
|
shift = (nwords - sub - 1) * busword
|
||||||
if shift:
|
v_shift = f"v >> {shift}" if shift else "v"
|
||||||
v_shift = "v >> {}".format(shift)
|
write_function += f"\tcsr_write_simple({v_shift}, {_get_csr_addr(csr_base, reg_base + sub * stride, with_csr_base_define)});\n"
|
||||||
else:
|
write_function += "}\n"
|
||||||
v_shift = "v"
|
return write_function
|
||||||
r += f"\tcsr_write_simple({v_shift}, {_get_csr_addr(csr_base, reg_base+sub*stride, with_csr_base_define)});\n"
|
|
||||||
r += "}\n"
|
|
||||||
return r
|
|
||||||
|
|
||||||
|
def _get_rw_functions_c(reg_name, reg_base, nwords, busword, alignment, read_only, csr_base, with_csr_base_define, with_access_functions):
|
||||||
|
"""
|
||||||
|
Generate C code for CSR read/write functions and definitions.
|
||||||
|
"""
|
||||||
|
result = _generate_csr_definitions_c(reg_name, reg_base, nwords, csr_base, with_csr_base_define)
|
||||||
|
size = nwords * busword // 8
|
||||||
|
|
||||||
|
ctype, stride = _determine_ctype_and_stride_c(size, alignment)
|
||||||
|
if ctype is None:
|
||||||
|
return result
|
||||||
|
|
||||||
def get_csr_header(regions, constants, csr_base=None, with_csr_base_define=True, with_access_functions=True):
|
|
||||||
alignment = constants.get("CONFIG_CSR_ALIGNMENT", 32)
|
|
||||||
r = generated_banner("//")
|
|
||||||
if with_access_functions: # FIXME
|
|
||||||
r += "#include <generated/soc.h>\n"
|
|
||||||
r += "#ifndef __GENERATED_CSR_H\n#define __GENERATED_CSR_H\n"
|
|
||||||
if with_access_functions:
|
if with_access_functions:
|
||||||
r += "#include <stdint.h>\n"
|
result += _generate_read_function_c(reg_name, reg_base, nwords, busword, ctype, stride, csr_base, with_csr_base_define)
|
||||||
r += "#include <system.h>\n"
|
if not read_only:
|
||||||
r += "#ifndef CSR_ACCESSORS_DEFINED\n"
|
result += _generate_write_function_c(reg_name, reg_base, nwords, busword, ctype, stride, csr_base, with_csr_base_define)
|
||||||
r += "#include <hw/common.h>\n"
|
|
||||||
r += "#endif /* ! CSR_ACCESSORS_DEFINED */\n"
|
return result
|
||||||
_csr_base = regions[next(iter(regions))].origin
|
|
||||||
csr_base = csr_base if csr_base is not None else _csr_base
|
def _generate_csr_header_includes_c(with_access_functions):
|
||||||
|
"""
|
||||||
|
Generate the necessary include directives for the CSR header file.
|
||||||
|
"""
|
||||||
|
includes = "#include <generated/soc.h>\n"
|
||||||
|
includes += "#ifndef __GENERATED_CSR_H\n"
|
||||||
|
includes += "#define __GENERATED_CSR_H\n"
|
||||||
|
if with_access_functions:
|
||||||
|
includes += "#include <stdint.h>\n"
|
||||||
|
includes += "#include <system.h>\n"
|
||||||
|
includes += "#ifndef CSR_ACCESSORS_DEFINED\n"
|
||||||
|
includes += "#include <hw/common.h>\n"
|
||||||
|
includes += "#endif /* ! CSR_ACCESSORS_DEFINED */\n"
|
||||||
|
return includes
|
||||||
|
|
||||||
|
def _generate_csr_base_define_c(csr_base, with_csr_base_define):
|
||||||
|
"""
|
||||||
|
Generate the CSR base address define directive.
|
||||||
|
"""
|
||||||
if with_csr_base_define:
|
if with_csr_base_define:
|
||||||
r += "\n#ifndef CSR_BASE\n"
|
return f"\n#ifndef CSR_BASE\n#define CSR_BASE {hex(csr_base)}L\n#endif\n"
|
||||||
r += f"#define CSR_BASE {hex(csr_base)}L\n"
|
return ""
|
||||||
r += "#endif\n"
|
|
||||||
for name, region in regions.items():
|
def _generate_field_definitions_c(csr, name, with_fields_access_functions):
|
||||||
origin = region.origin - _csr_base
|
"""
|
||||||
base_define = with_csr_base_define and (not isinstance(region, MockCSRRegion))
|
Generate definitions for CSR fields.
|
||||||
r += "\n/* "+name+" */\n"
|
"""
|
||||||
r += f"#define CSR_{name.upper()}_BASE {_get_csr_addr(csr_base, origin, base_define)}\n"
|
field_defs = ""
|
||||||
|
for field in csr.fields.fields:
|
||||||
|
offset = str(field.offset)
|
||||||
|
size = str(field.size)
|
||||||
|
field_defs += f"#define CSR_{name.upper()}_{csr.name.upper()}_{field.name.upper()}_OFFSET {offset}\n"
|
||||||
|
field_defs += f"#define CSR_{name.upper()}_{csr.name.upper()}_{field.name.upper()}_SIZE {size}\n"
|
||||||
|
if with_fields_access_functions:
|
||||||
|
field_defs += _generate_field_accessors_c(name, csr, field)
|
||||||
|
return field_defs
|
||||||
|
|
||||||
|
def _generate_field_accessors_c(name, csr, field):
|
||||||
|
"""
|
||||||
|
Generate access functions for CSR fields if the CSR size is <= 32 bits.
|
||||||
|
"""
|
||||||
|
accessors = ""
|
||||||
|
if csr.size <= 32:
|
||||||
|
reg_name = name + "_" + csr.name.lower()
|
||||||
|
field_name = reg_name + "_" + field.name.lower()
|
||||||
|
offset = str(field.offset)
|
||||||
|
size = str(field.size)
|
||||||
|
accessors += f"static inline uint32_t {field_name}_extract(uint32_t oldword) {{\n"
|
||||||
|
accessors += f"\tuint32_t mask = 0x{(1 << int(size)) - 1:x};\n"
|
||||||
|
accessors += f"\treturn ((oldword >> {offset}) & mask);\n}}\n"
|
||||||
|
accessors += f"static inline uint32_t {field_name}_read(void) {{\n"
|
||||||
|
accessors += f"\tuint32_t word = {reg_name}_read();\n"
|
||||||
|
accessors += f"\treturn {field_name}_extract(word);\n}}\n"
|
||||||
|
if not getattr(csr, "read_only", False):
|
||||||
|
accessors += f"static inline uint32_t {field_name}_replace(uint32_t oldword, uint32_t plain_value) {{\n"
|
||||||
|
accessors += f"\tuint32_t mask = 0x{(1 << int(size)) - 1:x};\n"
|
||||||
|
accessors += f"\treturn (oldword & (~(mask << {offset}))) | ((mask & plain_value) << {offset});\n}}\n"
|
||||||
|
accessors += f"static inline void {field_name}_write(uint32_t plain_value) {{\n"
|
||||||
|
accessors += f"\tuint32_t oldword = {reg_name}_read();\n"
|
||||||
|
accessors += f"\tuint32_t newword = {field_name}_replace(oldword, plain_value);\n"
|
||||||
|
accessors += f"\t{reg_name}_write(newword);\n}}\n"
|
||||||
|
return accessors
|
||||||
|
|
||||||
|
def _generate_csr_region_definitions_c(name, region, origin, alignment, csr_base, with_csr_base_define, with_access_functions, with_fields_access_functions):
|
||||||
|
"""
|
||||||
|
Generate CSR address and size definitions for a region.
|
||||||
|
"""
|
||||||
|
base_define = with_csr_base_define and not isinstance(region, MockCSRRegion)
|
||||||
|
region_defs = f"\n/* {name} */\n"
|
||||||
|
region_defs += f"#define CSR_{name.upper()}_BASE {_get_csr_addr(csr_base, origin, base_define)}\n"
|
||||||
|
|
||||||
if not isinstance(region.obj, Memory):
|
if not isinstance(region.obj, Memory):
|
||||||
for csr in region.obj:
|
for csr in region.obj:
|
||||||
nr = (csr.size + region.busword - 1)//region.busword
|
nr = (csr.size + region.busword - 1) // region.busword
|
||||||
r += _get_rw_functions_c(
|
region_defs += _get_rw_functions_c(
|
||||||
reg_name = name + "_" + csr.name,
|
reg_name = name + "_" + csr.name,
|
||||||
reg_base = origin,
|
reg_base = origin,
|
||||||
nwords = nr,
|
nwords = nr,
|
||||||
|
@ -283,36 +359,34 @@ def get_csr_header(regions, constants, csr_base=None, with_csr_base_define=True,
|
||||||
with_csr_base_define = base_define,
|
with_csr_base_define = base_define,
|
||||||
with_access_functions = with_access_functions,
|
with_access_functions = with_access_functions,
|
||||||
)
|
)
|
||||||
origin += alignment//8*nr
|
origin += alignment // 8 * nr
|
||||||
if hasattr(csr, "fields"):
|
if hasattr(csr, "fields"):
|
||||||
for field in csr.fields.fields:
|
region_defs += _generate_field_definitions_c(csr, name, with_access_functions and with_fields_access_functions)
|
||||||
offset = str(field.offset)
|
return region_defs
|
||||||
size = str(field.size)
|
|
||||||
r += f"#define CSR_{name.upper()}_{csr.name.upper()}_{field.name.upper()}_OFFSET {offset}\n"
|
def get_csr_header(regions, constants, csr_base=None, with_csr_base_define=True, with_access_functions=True, with_fields_access_functions=True):
|
||||||
r += f"#define CSR_{name.upper()}_{csr.name.upper()}_{field.name.upper()}_SIZE {size}\n"
|
"""
|
||||||
if with_access_functions and csr.size <= 32: # FIXME: Implement extract/read functions for csr.size > 32-bit.
|
Generate the CSR header file content.
|
||||||
reg_name = name + "_" + csr.name.lower()
|
"""
|
||||||
field_name = reg_name + "_" + field.name.lower()
|
alignment = constants.get("CONFIG_CSR_ALIGNMENT", 32)
|
||||||
r += "static inline uint32_t " + field_name + "_extract(uint32_t oldword) {\n"
|
r = generated_banner("//")
|
||||||
r += f"\tuint32_t mask = 0x{(1<<int(size))-1:x};\n"
|
|
||||||
r += "\treturn ( (oldword >> " + offset + ") & mask );\n}\n"
|
r += _generate_csr_header_includes_c(with_access_functions)
|
||||||
r += "static inline uint32_t " + field_name + "_read(void) {\n"
|
|
||||||
r += "\tuint32_t word = " + reg_name + "_read();\n"
|
_csr_base = regions[next(iter(regions))].origin
|
||||||
r += "\treturn " + field_name + "_extract(word);\n"
|
csr_base = csr_base if csr_base is not None else _csr_base
|
||||||
r += "}\n"
|
|
||||||
if not getattr(csr, "read_only", False):
|
r += _generate_csr_base_define_c(csr_base, with_csr_base_define)
|
||||||
r += "static inline uint32_t " + field_name + "_replace(uint32_t oldword, uint32_t plain_value) {\n"
|
|
||||||
r += f"\tuint32_t mask = 0x{(1<<int(size))-1:x};\n"
|
for name, region in regions.items():
|
||||||
r += "\treturn (oldword & (~(mask << " + offset + "))) | (mask & plain_value)<< " + offset + " ;\n}\n"
|
origin = region.origin - _csr_base
|
||||||
r += "static inline void " + field_name + "_write(uint32_t plain_value) {\n"
|
r += _generate_csr_region_definitions_c(name, region, origin, alignment, csr_base, with_csr_base_define, with_access_functions, with_fields_access_functions)
|
||||||
r += "\tuint32_t oldword = " + reg_name + "_read();\n"
|
|
||||||
r += "\tuint32_t newword = " + field_name + "_replace(oldword, plain_value);\n"
|
|
||||||
r += "\t" + reg_name + "_write(newword);\n"
|
|
||||||
r += "}\n"
|
|
||||||
|
|
||||||
r += "\n#endif\n"
|
r += "\n#endif\n"
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
# C I2C Export -------------------------------------------------------------------------------------
|
||||||
|
|
||||||
def get_i2c_header(i2c_init_values):
|
def get_i2c_header(i2c_init_values):
|
||||||
i2c_devs, i2c_init = i2c_init_values
|
i2c_devs, i2c_init = i2c_init_values
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue