[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH for-7.1 v6 41/51] target/nios2: Introduce shadow register sets
From: |
Richard Henderson |
Subject: |
[PATCH for-7.1 v6 41/51] target/nios2: Introduce shadow register sets |
Date: |
Wed, 16 Mar 2022 22:05:28 -0700 |
Do not actually enable them so far, but add all of the
plumbing to address them. Do not enable them for user-only.
Add an env->regs pointer that handles the indirection to
the current register set. The naming of the pointer hides
the difference between old and new, user-only and sysemu.
>From the notes on wrprs, which states that r0 must be initialized
before use in shadow register sets, infer that R_ZERO is *not*
hardwired to zero in shadow register sets. Adjust load_gpr and
dest_gpr to reflect this. At the same time we might as well
special case crs == 0 to avoid the indirection through env->regs
during translation as well. Given that this is intended to be
the most common case for non-interrupt handlers.
Init env->regs at reset.
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
target/nios2/cpu.h | 24 +++++++++++++++++
target/nios2/cpu.c | 4 ++-
target/nios2/translate.c | 58 +++++++++++++++++++++++++++++++---------
3 files changed, 72 insertions(+), 14 deletions(-)
diff --git a/target/nios2/cpu.h b/target/nios2/cpu.h
index d5255e9e76..e32bebe9b7 100644
--- a/target/nios2/cpu.h
+++ b/target/nios2/cpu.h
@@ -60,6 +60,11 @@ struct Nios2CPUClass {
#define NUM_GP_REGS 32
#define NUM_CR_REGS 32
+#ifndef CONFIG_USER_ONLY
+/* 63 shadow register sets; index 0 is the primary register set. */
+#define NUM_REG_SETS 64
+#endif
+
/* General purpose register aliases */
enum {
R_ZERO = 0,
@@ -178,7 +183,13 @@ FIELD(CR_TLBMISC, EE, 24, 1)
#define EXCP_MPUD 17
struct CPUArchState {
+#ifdef CONFIG_USER_ONLY
uint32_t regs[NUM_GP_REGS];
+#else
+ uint32_t shadow_regs[NUM_REG_SETS][NUM_GP_REGS];
+ /* Pointer into shadow_regs for the current register set. */
+ uint32_t *regs;
+#endif
uint32_t ctrl[NUM_CR_REGS];
uint32_t pc;
@@ -229,6 +240,14 @@ static inline bool nios2_cr_reserved(const ControlRegState
*s)
return (s->writable | s->readonly) == 0;
}
+static inline void nios2_update_crs(CPUNios2State *env)
+{
+#ifndef CONFIG_USER_ONLY
+ unsigned crs = FIELD_EX32(env->ctrl[CR_STATUS], CR_STATUS, CRS);
+ env->regs = env->shadow_regs[crs];
+#endif
+}
+
void nios2_tcg_init(void);
void nios2_cpu_do_interrupt(CPUState *cs);
void dump_mmu(CPUNios2State *env);
@@ -271,12 +290,17 @@ typedef Nios2CPU ArchCPU;
#include "exec/cpu-all.h"
+FIELD(TBFLAGS, CRS0, 0, 1) /* Set if CRS == 0. */
+FIELD(TBFLAGS, U, 1, 1) /* Overlaps CR_STATUS_U */
+
static inline void cpu_get_tb_cpu_state(CPUNios2State *env, target_ulong *pc,
target_ulong *cs_base, uint32_t *flags)
{
*pc = env->pc;
*cs_base = 0;
*flags = env->ctrl[CR_STATUS] & CR_STATUS_U;
+ *flags |= (env->ctrl[CR_STATUS] & R_CR_STATUS_CRS_MASK
+ ? 0 : R_TBFLAGS_CRS0_MASK);
}
#endif /* NIOS2_CPU_H */
diff --git a/target/nios2/cpu.c b/target/nios2/cpu.c
index 07306efc35..7545abc68e 100644
--- a/target/nios2/cpu.c
+++ b/target/nios2/cpu.c
@@ -53,15 +53,17 @@ static void nios2_cpu_reset(DeviceState *dev)
ncc->parent_reset(dev);
- memset(env->regs, 0, sizeof(env->regs));
memset(env->ctrl, 0, sizeof(env->ctrl));
env->pc = cpu->reset_addr;
#if defined(CONFIG_USER_ONLY)
/* Start in user mode with interrupts enabled. */
env->ctrl[CR_STATUS] = CR_STATUS_RSIE | CR_STATUS_U | CR_STATUS_PIE;
+ memset(env->regs, 0, sizeof(env->regs));
#else
env->ctrl[CR_STATUS] = CR_STATUS_RSIE;
+ nios2_update_crs(env);
+ memset(env->shadow_regs, 0, sizeof(env->shadow_regs));
#endif
}
diff --git a/target/nios2/translate.c b/target/nios2/translate.c
index 1e784c8a37..525df7b023 100644
--- a/target/nios2/translate.c
+++ b/target/nios2/translate.c
@@ -100,12 +100,16 @@ typedef struct DisasContext {
DisasContextBase base;
target_ulong pc;
int mem_idx;
+ bool crs0;
TCGv sink;
const ControlRegState *cr_state;
} DisasContext;
static TCGv cpu_R[NUM_GP_REGS];
static TCGv cpu_pc;
+#ifndef CONFIG_USER_ONLY
+static TCGv cpu_crs_R[NUM_GP_REGS];
+#endif
typedef struct Nios2Instruction {
void (*handler)(DisasContext *dc, uint32_t code, uint32_t flags);
@@ -127,22 +131,36 @@ static uint8_t get_opxcode(uint32_t code)
static TCGv load_gpr(DisasContext *dc, unsigned reg)
{
assert(reg < NUM_GP_REGS);
- if (unlikely(reg == R_ZERO)) {
- return tcg_constant_tl(0);
+ if (dc->crs0) {
+ if (unlikely(reg == R_ZERO)) {
+ return tcg_constant_tl(0);
+ }
+ return cpu_R[reg];
}
- return cpu_R[reg];
+#ifdef CONFIG_USER_ONLY
+ g_assert_not_reached();
+#else
+ return cpu_crs_R[reg];
+#endif
}
static TCGv dest_gpr(DisasContext *dc, unsigned reg)
{
assert(reg < NUM_GP_REGS);
- if (unlikely(reg == R_ZERO)) {
- if (dc->sink == NULL) {
- dc->sink = tcg_temp_new();
+ if (dc->crs0) {
+ if (unlikely(reg == R_ZERO)) {
+ if (dc->sink == NULL) {
+ dc->sink = tcg_temp_new();
+ }
+ return dc->sink;
}
- return dc->sink;
+ return cpu_R[reg];
}
- return cpu_R[reg];
+#ifdef CONFIG_USER_ONLY
+ g_assert_not_reached();
+#else
+ return cpu_crs_R[reg];
+#endif
}
static void t_gen_helper_raise_exception(DisasContext *dc,
@@ -198,7 +216,7 @@ static void gen_excp(DisasContext *dc, uint32_t code,
uint32_t flags)
static bool gen_check_supervisor(DisasContext *dc)
{
- if (dc->base.tb->flags & CR_STATUS_U) {
+ if (dc->base.tb->flags & R_TBFLAGS_U_MASK) {
/* CPU in user mode, privileged instruction called, stop. */
t_gen_helper_raise_exception(dc, EXCP_SUPERI);
return false;
@@ -794,6 +812,7 @@ static void nios2_tr_init_disas_context(DisasContextBase
*dcbase, CPUState *cs)
dc->mem_idx = cpu_mmu_index(env, false);
dc->cr_state = cpu->cr_state;
+ dc->crs0 = FIELD_EX32(dc->base.tb->flags, TBFLAGS, CRS0);
/* Bound the number of insns to execute to those left on the page. */
page_insns = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
@@ -927,13 +946,26 @@ void nios2_cpu_dump_state(CPUState *cs, FILE *f, int
flags)
void nios2_tcg_init(void)
{
- int i;
+#ifndef CONFIG_USER_ONLY
+ TCGv_ptr crs = tcg_global_mem_new_ptr(cpu_env,
+ offsetof(CPUNios2State, regs),
"crs");
- for (i = 0; i < NUM_GP_REGS; i++) {
- cpu_R[i] = tcg_global_mem_new(cpu_env,
- offsetof(CPUNios2State, regs[i]),
+ for (int i = 0; i < NUM_GP_REGS; i++) {
+ cpu_crs_R[i] = tcg_global_mem_new(crs, 4 * i, gr_regnames[i]);
+ }
+
+#define offsetof_regs0(N) offsetof(CPUNios2State, shadow_regs[0][N])
+#else
+#define offsetof_regs0(N) offsetof(CPUNios2State, regs[N])
+#endif
+
+ for (int i = 0; i < NUM_GP_REGS; i++) {
+ cpu_R[i] = tcg_global_mem_new(cpu_env, offsetof_regs0(i),
gr_regnames[i]);
}
+
+#undef offsetof_regs0
+
cpu_pc = tcg_global_mem_new(cpu_env,
offsetof(CPUNios2State, pc), "pc");
}
--
2.25.1
- Re: [PATCH for-7.1 v6 35/51] target/nios2: Create gen_jumpr, (continued)
- [PATCH for-7.1 v6 36/51] target/nios2: Hoist set of is_jmp into gen_goto_tb, Richard Henderson, 2022/03/17
- [PATCH for-7.1 v6 39/51] target/nios2: Implement Misaligned destination exception, Richard Henderson, 2022/03/17
- [PATCH for-7.1 v6 38/51] target/nios2: Use tcg_gen_lookup_and_goto_ptr, Richard Henderson, 2022/03/17
- [PATCH for-7.1 v6 40/51] linux-user/nios2: Handle various SIGILL exceptions, Richard Henderson, 2022/03/17
- [PATCH for-7.1 v6 41/51] target/nios2: Introduce shadow register sets,
Richard Henderson <=
- [PATCH for-7.1 v6 42/51] target/nios2: Implement rdprs, wrprs, Richard Henderson, 2022/03/17
- [PATCH for-7.1 v6 43/51] target/nios2: Update helper_eret for shadow registers, Richard Henderson, 2022/03/17
- [PATCH for-7.1 v6 44/51] target/nios2: Implement EIC interrupt processing, Richard Henderson, 2022/03/17
- [PATCH for-7.1 v6 46/51] hw/nios2: Introduce Nios2MachineState, Richard Henderson, 2022/03/17