On Fri, Aug 6, 2021 at 3:58 AM Ruinland Chuan-Tzu Tsai <ruinl...@andestech.com> wrote: > > 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[] > + ) {
Can you run `checkpatch.pl` on each patch? That will catch issues like this. > + > + 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; This should be a seperate patch. > + > /* 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]; This should be a seperate patch > 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" Don't do this. It it is unused then just remove it. > 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; Why declare this at all? > + #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]; > + } Cool! This looks like it's going in the right direction. Alistair > + #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 > >