qemu-riscv
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[RFC PATCH v4 2/4] Adding basic custom/vendor CSR handling mechanism


From: Ruinland Chuan-Tzu Tsai
Subject: [RFC PATCH v4 2/4] Adding basic custom/vendor CSR handling mechanism
Date: Fri, 6 Aug 2021 01:56:24 +0800

From: Ruinalnd ChuanTzu Tsai <ruinland@andestech.com>

For now we add a custom CSR handling mechanism to handle non-standard CSR read
or write.

The write_stub() and read_zero() are provided for quick placeholder usage if
such CSRs' behavior are expected to fail-over in its user code.

Signed-off-by: Dylan Jhong <dylan@andestech.com>
---
 target/riscv/cpu.c             | 23 ++++++++++
 target/riscv/cpu.h             | 31 ++++++++++++-
 target/riscv/cpu_bits.h        |  4 ++
 target/riscv/csr.c             | 83 ++++++++++++++++++++++++++++------
 target/riscv/custom_cpu_bits.h |  8 ++++
 5 files changed, 134 insertions(+), 15 deletions(-)
 create mode 100644 target/riscv/custom_cpu_bits.h

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 7401325..3a638b5 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -144,6 +144,29 @@ static void set_resetvec(CPURISCVState *env, target_ulong 
resetvec)
 #endif
 }
 
+#if defined(CONFIG_RISCV_CUSTOM)
+static void setup_custom_csr(CPURISCVState *env,
+                             riscv_custom_csr_operations csr_map_struct[]
+                             ) {
+
+    env->custom_csr_map = g_hash_table_new_full(g_direct_hash, \
+                                                g_direct_equal, \
+                                                NULL, NULL);
+
+
+    int i;
+    for (i = 0; i < MAX_CUSTOM_CSR_NUM; i++) {
+        if (csr_map_struct[i].csrno != 0) {
+            g_hash_table_insert(env->custom_csr_map,
+                GINT_TO_POINTER(csr_map_struct[i].csrno),
+                &csr_map_struct[i].csr_opset);
+        } else {
+            break;
+        }
+    }
+}
+#endif
+
 static void riscv_any_cpu_init(Object *obj)
 {
     CPURISCVState *env = &RISCV_CPU(obj)->env;
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 0edb282..52df9bb 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -239,6 +239,16 @@ struct CPURISCVState {
 
     /* Fields from here on are preserved across CPU reset. */
     QEMUTimer *timer; /* Internal timer */
+
+    /*
+     * The reason why we have an opset map for custom CSRs and a seperated
+     * storage map is that we might have heterogeneous architecture, in which
+     * different harts have different custom CSRs.
+     * Custom CSR opset map
+     */
+    GHashTable *custom_csr_map;
+    /* Custom CSR val holder */
+    void *custom_csr_val;
 };
 
 OBJECT_DECLARE_TYPE(RISCVCPU, RISCVCPUClass,
@@ -485,17 +495,36 @@ typedef struct {
     riscv_csr_op_fn op;
 } riscv_csr_operations;
 
+typedef struct {
+    int csrno;
+    riscv_csr_operations csr_opset;
+    } riscv_custom_csr_operations;
+
+/*
+ * The reason why we have an abstraction here is that : We could have CSR
+ * number M on hart A is an alias of CSR number N on hart B. So we make a
+ * CSR number to value address map.
+ */
+typedef struct  {
+    int csrno;
+    target_ulong val;
+    } riscv_custom_csr_vals;
+
 /* CSR function table constants */
 enum {
-    CSR_TABLE_SIZE = 0x1000
+    CSR_TABLE_SIZE = 0x1000,
+    MAX_CUSTOM_CSR_NUM = 100
 };
 
 /* CSR function table */
+extern int andes_custom_csr_size;
+extern riscv_custom_csr_operations andes_custom_csr_table[MAX_CUSTOM_CSR_NUM];
 extern riscv_csr_operations csr_ops[CSR_TABLE_SIZE];
 
 void riscv_get_csr_ops(int csrno, riscv_csr_operations *ops);
 void riscv_set_csr_ops(int csrno, riscv_csr_operations *ops);
 
+
 void riscv_cpu_register_gdb_regs_for_features(CPUState *cs);
 
 #endif /* RISCV_CPU_H */
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index caf4599..de77242 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -593,3 +593,7 @@
 #define MIE_SSIE                           (1 << IRQ_S_SOFT)
 #define MIE_USIE                           (1 << IRQ_U_SOFT)
 #endif
+
+#if defined(CONFIG_RISCV_CUSTOM)
+#include "custom_cpu_bits.h"
+#endif
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index fd2e636..1c4dc94 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -137,7 +137,8 @@ static int ctr32(CPURISCVState *env, int csrno)
     return ctr(env, csrno);
 }
 
-#if !defined(CONFIG_USER_ONLY)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-function"
 static int any(CPURISCVState *env, int csrno)
 {
     return 0;
@@ -152,6 +153,25 @@ static int any32(CPURISCVState *env, int csrno)
     return any(env, csrno);
 
 }
+#pragma GCC diagnostic pop
+
+/* Machine Information Registers */
+static int read_zero(CPURISCVState *env, int csrno, target_ulong *val)
+{
+    return *val = 0;
+}
+
+/*
+ * XXX: This is just a write stub for developing custom CSR handler,
+ * if the behavior of writting such CSR is not presentable in QEMU and doesn't
+ * affect the functionality, just stub it.
+ */
+static int write_stub(CPURISCVState *env, int csrno, target_ulong val)
+{
+    return 0;
+}
+
+#if !defined(CONFIG_USER_ONLY)
 
 static int smode(CPURISCVState *env, int csrno)
 {
@@ -435,11 +455,6 @@ static const char valid_vm_1_10_64[16] = {
     [VM_1_10_SV57] = 1
 };
 
-/* Machine Information Registers */
-static int read_zero(CPURISCVState *env, int csrno, target_ulong *val)
-{
-    return *val = 0;
-}
 
 static int read_mhartid(CPURISCVState *env, int csrno, target_ulong *val)
 {
@@ -1264,6 +1279,18 @@ static int write_pmpaddr(CPURISCVState *env, int csrno, 
target_ulong val)
 
 #endif
 
+
+#if defined(CONFIG_RISCV_CUSTOM)
+/* Custom CSR related routines and data structures */
+
+static gpointer is_custom_csr(CPURISCVState *env, int csrno)
+{
+    gpointer ret;
+    ret = g_hash_table_lookup(env->custom_csr_map, GINT_TO_POINTER(csrno));
+    return ret;
+}
+#endif
+
 /*
  * riscv_csrrw - read and/or update control and status register
  *
@@ -1273,12 +1300,19 @@ static int write_pmpaddr(CPURISCVState *env, int csrno, 
target_ulong val)
  * csrrc  <->  riscv_csrrw(env, csrno, ret_value, 0, value);
  */
 
+
+
 int riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value,
                 target_ulong new_value, target_ulong write_mask)
 {
     int ret;
     target_ulong old_value;
     RISCVCPU *cpu = env_archcpu(env);
+    #if !defined(CONFIG_RISCV_CUSTOM)
+    riscv_csr_operations *csrop = &csr_ops[csrno];
+    #else
+    riscv_csr_operations *csrop;
+    #endif
 
     /* check privileges and return -1 if check fails */
 #if !defined(CONFIG_USER_ONLY)
@@ -1300,6 +1334,7 @@ int riscv_csrrw(CPURISCVState *env, int csrno, 
target_ulong *ret_value,
         (!env->debugger && (effective_priv < get_field(csrno, 0x300)))) {
         return -RISCV_EXCP_ILLEGAL_INST;
     }
+
 #endif
 
     /* ensure the CSR extension is enabled. */
@@ -1307,27 +1342,43 @@ int riscv_csrrw(CPURISCVState *env, int csrno, 
target_ulong *ret_value,
         return -RISCV_EXCP_ILLEGAL_INST;
     }
 
+    /* try handle_custom_csr */
+
+    #if defined(CONFIG_RISCV_CUSTOM)
+    if (unlikely(env->custom_csr_map != NULL)) {
+        riscv_csr_operations *custom_csr_opset = (riscv_csr_operations *)
+            is_custom_csr(env, csrno);
+        if (NULL != custom_csr_opset) {
+            csrop = custom_csr_opset;
+            } else {
+            csrop = &csr_ops[csrno];
+            }
+        } else {
+        csrop = &csr_ops[csrno];
+        }
+    #endif
+
     /* check predicate */
-    if (!csr_ops[csrno].predicate) {
+    if (!csrop->predicate) {
         return -RISCV_EXCP_ILLEGAL_INST;
     }
-    ret = csr_ops[csrno].predicate(env, csrno);
+    ret = csrop->predicate(env, csrno);
     if (ret < 0) {
         return ret;
     }
 
     /* execute combined read/write operation if it exists */
-    if (csr_ops[csrno].op) {
-        return csr_ops[csrno].op(env, csrno, ret_value, new_value, write_mask);
+    if (csrop->op) {
+        return csrop->op(env, csrno, ret_value, new_value, write_mask);
     }
 
     /* if no accessor exists then return failure */
-    if (!csr_ops[csrno].read) {
+    if (!csrop->read) {
         return -RISCV_EXCP_ILLEGAL_INST;
     }
 
     /* read old value */
-    ret = csr_ops[csrno].read(env, csrno, &old_value);
+    ret = csrop->read(env, csrno, &old_value);
     if (ret < 0) {
         return ret;
     }
@@ -1335,8 +1386,8 @@ int riscv_csrrw(CPURISCVState *env, int csrno, 
target_ulong *ret_value,
     /* write value if writable and write mask set, otherwise drop writes */
     if (write_mask) {
         new_value = (old_value & ~write_mask) | (new_value & write_mask);
-        if (csr_ops[csrno].write) {
-            ret = csr_ops[csrno].write(env, csrno, new_value);
+        if (csrop->write) {
+            ret = csrop->write(env, csrno, new_value);
             if (ret < 0) {
                 return ret;
             }
@@ -1369,6 +1420,10 @@ int riscv_csrrw_debug(CPURISCVState *env, int csrno, 
target_ulong *ret_value,
     return ret;
 }
 
+#if defined(CONFIG_RISCV_CUSTOM)
+/* Include the custom CSR table here. */
+#endif
+
 /* Control and Status Register function table */
 riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
     /* User Floating-Point CSRs */
diff --git a/target/riscv/custom_cpu_bits.h b/target/riscv/custom_cpu_bits.h
new file mode 100644
index 0000000..5df31f8
--- /dev/null
+++ b/target/riscv/custom_cpu_bits.h
@@ -0,0 +1,8 @@
+/*
+ * RISC-V cpu bits for custom CSR logic.
+ *
+ * Copyright (c) 2021 Andes Technology Corp.
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/* This file is intentionally left blank at this commit. */
-- 
2.32.0




reply via email to

[Prev in Thread] Current Thread [Next in Thread]