diff --git a/litex/soc/integration/export.py b/litex/soc/integration/export.py index 23f4809d6..d38c32d65 100644 --- a/litex/soc/integration/export.py +++ b/litex/soc/integration/export.py @@ -136,7 +136,7 @@ def get_soc_header(constants, with_access_functions=True): r += "\n#endif\n" return r -def _get_rw_functions_c(reg_name, reg_base, nwords, busword, read_only, with_access_functions): +def _get_rw_functions_c(reg_name, reg_base, nwords, busword, alignment, read_only, with_access_functions): r = "" addr_str = "CSR_{}_ADDR".format(reg_name.upper()) @@ -146,7 +146,7 @@ def _get_rw_functions_c(reg_name, reg_base, nwords, busword, read_only, with_acc size = nwords*busword//8 if size > 8: - # FIXME: maybe implement some "memcpy-like" semantics for larger blobs? + # downstream should select appropriate `csr_[rd|wr]_buf_uintX()` pair! return r elif size > 4: ctype = "uint64_t" @@ -157,13 +157,28 @@ def _get_rw_functions_c(reg_name, reg_base, nwords, busword, read_only, with_acc else: ctype = "uint8_t" + stride = alignment//8; if with_access_functions: r += "static inline {} {}_read(void) {{\n".format(ctype, reg_name) - r += "\treturn _csr_rd((unsigned long *){}, {});\n}}\n".format(addr_str, size) + if nwords > 1: + r += "\t{} r = csr_read_simple({}L);\n".format(ctype, hex(reg_base)) + for sub in range(1, nwords): + r += "\tr <<= {};\n".format(busword) + r += "\tr |= csr_read_simple({}L);\n".format(hex(reg_base+sub*stride)) + r += "\treturn r;\n}\n" + else: + r += "\treturn csr_read_simple({}L);\n}}\n".format(hex(reg_base)) if not read_only: r += "static inline void {}_write({} v) {{\n".format(reg_name, ctype) - r += "\t_csr_wr((unsigned long *){}, v, {});\n}}\n".format(addr_str, size) + for sub in range(nwords): + shift = (nwords-sub-1)*busword + if shift: + v_shift = "v >> {}".format(shift) + else: + v_shift = "v" + r += "\tcsr_write_simple({}, {}L);\n".format(v_shift, hex(reg_base+sub*stride)) + r += "}\n" return r @@ -176,14 +191,8 @@ def get_csr_header(regions, constants, with_access_functions=True): if with_access_functions: r += "#include \n" r += "#ifdef CSR_ACCESSORS_DEFINED\n" - r += "extern void csr_wr_uint8(uint8_t v, unsigned long a);\n" - r += "extern void csr_wr_uint16(uint16_t v, unsigned long a);\n" - r += "extern void csr_wr_uint32(uint32_t v, unsigned long a);\n" - r += "extern void csr_wr_uint64(uint64_t v, unsigned long a);\n" - r += "extern uint8_t csr_rd_uint8(unsigned long a);\n" - r += "extern uint16_t csr_rd_uint16(unsigned long a);\n" - r += "extern uint32_t csr_rd_uint32(unsigned long a);\n" - r += "extern uint64_t csr_rd_uint64(unsigned long a);\n" + r += "extern void csr_write_simple(unsigned long v, unsigned long a);\n" + r += "extern unsigned long csr_read_simple(unsigned long a);\n" r += "#else /* ! CSR_ACCESSORS_DEFINED */\n" r += "#include \n" r += "#endif /* ! CSR_ACCESSORS_DEFINED */\n" @@ -194,7 +203,7 @@ def get_csr_header(regions, constants, with_access_functions=True): 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, + 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"): diff --git a/litex/soc/software/include/hw/common.h b/litex/soc/software/include/hw/common.h index 801ec9790..708f30750 100644 --- a/litex/soc/software/include/hw/common.h +++ b/litex/soc/software/include/hw/common.h @@ -3,9 +3,8 @@ #include -/* To overwrite CSR accessors, define extern, non-inlined versions - * of csr_rd_uint[8|16|32|64]() and csr_wr_uint[8|16|32|64](), and - * define CSR_ACCESSORS_DEFINED. +/* To overwrite CSR subregister accessors, define extern, non-inlined versions + * of csr_[read|write]_simple(), and define CSR_ACCESSORS_DEFINED. */ #ifndef CSR_ACCESSORS_DEFINED @@ -35,12 +34,23 @@ * #endif */ -/* CSR data width (subregister width) in bytes, for direct comparson to sizeof() */ +/* CSR data width (subreg. width) in bytes, for direct comparson to sizeof() */ #define CSR_DW_BYTES (CONFIG_CSR_DATA_WIDTH/8) -/* CSR subregisters are embedded inside native CPU word aligned locations: */ +/* CSR subregisters (a.k.a. "simple CSRs") are embedded inside native CPU-word + * aligned locations: */ #define MMPTR(a) (*((volatile unsigned long *)(a))) +static inline void csr_write_simple(unsigned long v, unsigned long a) +{ + MMPTR(a) = v; +} + +static inline unsigned long csr_read_simple(unsigned long a) +{ + return MMPTR(a); +} + /* Number of subregs required for various total byte sizes, by subreg width: * NOTE: 1, 2, 4, and 8 bytes represent uint[8|16|32|64]_t C types; However, * CSRs of intermediate byte sizes (24, 40, 48, and 56) are NOT padded