software, integration/export: (re-)expose CSR subregister accessors
authorGabriel Somlo <gsomlo@gmail.com>
Wed, 29 Jan 2020 15:54:30 +0000 (10:54 -0500)
committerGabriel Somlo <gsomlo@gmail.com>
Wed, 29 Jan 2020 19:29:24 +0000 (14:29 -0500)
Expose a pair of `csr_[read|write]_simple()` subregister accessors, and
restore the way dedicated accessors are generated in "generated/csr.h"
to use hard-coded combinations of shifts and subregister accessor calls.

This restores downstream ability to override CSR handling at the
subregister accessor level.

Signed-off-by: Gabriel Somlo <gsomlo@gmail.com>
litex/soc/integration/export.py
litex/soc/software/include/hw/common.h

index 23f4809d681b0c046ed8a12103451d752a090182..d38c32d65f1f065e0b6d37e7b0668b89ab21a220 100644 (file)
@@ -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 <stdint.h>\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 <hw/common.h>\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"):
index 801ec9790eb310cf50550455911252d4f9de1700..708f30750457f8cdbaa8840d4a41e769fdddf97f 100644 (file)
@@ -3,9 +3,8 @@
 
 #include <stdint.h>
 
-/* 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
  * #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