From: Ruinalnd ChuanTzu Tsai <ruinl...@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 <dy...@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