target/nios2: Implement rdprs, wrprs

Implement these out of line, so that tcg global temps
(aka the architectural registers) are synced back to
tcg storage as required.  This makes sure that we get
the proper results when status.PRS == status.CRS.

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Message-Id: <20220421151735.31996-55-richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2022-04-21 08:17:25 -07:00
parent 945a5bd3f8
commit 3a03087019
4 changed files with 74 additions and 2 deletions

View file

@ -130,6 +130,7 @@ typedef struct DisasContext {
uint32_t tb_flags;
TCGv sink;
const ControlRegState *cr_state;
bool eic_present;
} DisasContext;
static TCGv cpu_R[NUM_GP_REGS];
@ -387,6 +388,27 @@ gen_i_math_logic(andhi, andi, 0, imm_shifted)
gen_i_math_logic(orhi , ori, 1, imm_shifted)
gen_i_math_logic(xorhi, xori, 1, imm_shifted)
/* rB <- prs.rA + sigma(IMM16) */
static void rdprs(DisasContext *dc, uint32_t code, uint32_t flags)
{
if (!dc->eic_present) {
t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
return;
}
if (!gen_check_supervisor(dc)) {
return;
}
#ifdef CONFIG_USER_ONLY
g_assert_not_reached();
#else
I_TYPE(instr, code);
TCGv dest = dest_gpr(dc, instr.b);
gen_helper_rdprs(dest, cpu_env, tcg_constant_i32(instr.a));
tcg_gen_addi_tl(dest, dest, instr.imm16.s);
#endif
}
/* Prototype only, defined below */
static void handle_r_type_instr(DisasContext *dc, uint32_t code,
uint32_t flags);
@ -448,7 +470,7 @@ static const Nios2Instruction i_type_instructions[] = {
INSTRUCTION_FLG(gen_stx, MO_SL), /* stwio */
INSTRUCTION_FLG(gen_bxx, TCG_COND_LTU), /* bltu */
INSTRUCTION_FLG(gen_ldx, MO_UL), /* ldwio */
INSTRUCTION_UNIMPLEMENTED(), /* rdprs */
INSTRUCTION(rdprs), /* rdprs */
INSTRUCTION_ILLEGAL(),
INSTRUCTION_FLG(handle_r_type_instr, 0), /* R-Type */
INSTRUCTION_NOP(), /* flushd */
@ -648,6 +670,36 @@ static void wrctl(DisasContext *dc, uint32_t code, uint32_t flags)
#endif
}
/* prs.rC <- rA */
static void wrprs(DisasContext *dc, uint32_t code, uint32_t flags)
{
if (!dc->eic_present) {
t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
return;
}
if (!gen_check_supervisor(dc)) {
return;
}
#ifdef CONFIG_USER_ONLY
g_assert_not_reached();
#else
R_TYPE(instr, code);
gen_helper_wrprs(cpu_env, tcg_constant_i32(instr.c),
load_gpr(dc, instr.a));
/*
* The expected write to PRS[r0] is 0, from CRS[r0].
* If not, and CRS == PRS (which we cannot tell from here),
* we may now have a non-zero value in our current r0.
* By ending the TB, we re-evaluate tb_flags and find out.
*/
if (instr.c == 0
&& (instr.a != 0 || !FIELD_EX32(dc->tb_flags, TBFLAGS, R0_0))) {
dc->base.is_jmp = DISAS_UPDATE;
}
#endif
}
/* Comparison instructions */
static void gen_cmpxx(DisasContext *dc, uint32_t code, uint32_t flags)
{
@ -793,7 +845,7 @@ static const Nios2Instruction r_type_instructions[] = {
INSTRUCTION_ILLEGAL(),
INSTRUCTION(slli), /* slli */
INSTRUCTION(sll), /* sll */
INSTRUCTION_UNIMPLEMENTED(), /* wrprs */
INSTRUCTION(wrprs), /* wrprs */
INSTRUCTION_ILLEGAL(),
INSTRUCTION(or), /* or */
INSTRUCTION(mulxsu), /* mulxsu */
@ -895,6 +947,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->tb_flags = dc->base.tb->flags;
dc->eic_present = cpu->eic_present;
/* Bound the number of insns to execute to those left on the page. */
page_insns = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;