Message ID | 20220310112725.570053-43-richard.henderson@linaro.org |
---|---|
State | Superseded |
Headers | show |
Series | target/nios2: Shadow register set, EIC and VIC | expand |
Something is wrong when translating rdprs in an interrupt handler when CRS is 0x1. I'm hitting "../tcg/tcg.c:3466: tcg_reg_alloc_mov: Assertion `ts->val_type == TEMP_VAL_REG' failed." When stopped on that assertion I can see that : - ts->val_type = TEMP_VAL_DEAD - op->opc = INDEX_op_mov_i32 - ots->name = "pc" - cpu->ctrl[0] = 0x5f9 (that's STATUS so CRS = 1) - pc = 0xa2d5c so, it looks related to an assignment to PC a little after rdprs. When running with -d in_asm,op_ind,op_opt: ---------------- IN: 0x000a2d5c: ldw r16,4(et) 0x000a2d60: rdprs sp,sp,0 0x000a2d64: ldw r4,8(et) 0x000a2d68: callr r16 OP before indirect lowering: ld_i32 tmp0,env,$0xfffffffffffffff0 brcond_i32 tmp0,$0x0,lt,$L0 dead: 0 ---- 000a2d5c add_i32 tmp0,et,$0x4 dead: 2 qemu_ld_i32 r16,tmp0,leul,0 sync: 0 dead: 1 ---- 000a2d60 call rdprs,$0x2,$1,sp,env,$0x1b sync: 0 dead: 0 2 ---- 000a2d64 add_i32 tmp0,et,$0x8 dead: 1 2 qemu_ld_i32 r4,tmp0,leul,0 sync: 0 dead: 0 1 ---- 000a2d68 and_i32 tmp0,r16,$0x3 dead: 2 brcond_i32 tmp0,$0x0,ne,$L1 dead: 0 1 mov_i32 pc,r16 sync: 0 dead: 0 1 mov_i32 ra,$0xa2d6c sync: 0 dead: 0 1 call lookup_tb_ptr,$0x6,$1,tmp7,env dead: 1 goto_ptr tmp7 dead: 0 set_label $L1 st_i32 r16,env,$0x2038 dead: 0 mov_i32 pc,$0xa2d68 sync: 0 dead: 0 1 call raise_exception,$0xa,$0,env,$0x7 dead: 0 1 set_label $L0 exit_tb $0x7f1878027e43 OP after optimization and liveness analysis: ld_i32 tmp0,env,$0xfffffffffffffff0 pref=0xffff brcond_i32 tmp0,$0x0,lt,$L0 dead: 0 ---- 000a2d5c ld_i32 tmp34,crs,$0x60 pref=0xf038 add_i32 tmp0,tmp34,$0x4 dead: 2 pref=0xff3f qemu_ld_i32 tmp26,tmp0,leul,0 dead: 1 pref=0xf038 st_i32 tmp26,crs,$0x40 ---- 000a2d60 call rdprs,$0x2,$1,tmp37,env,$0x1b dead: 2 pref=none st_i32 tmp37,crs,$0x6c dead: 0 ---- 000a2d64 add_i32 tmp0,tmp34,$0x8 dead: 1 2 pref=0xff3f qemu_ld_i32 tmp14,tmp0,leul,0 dead: 1 pref=0xffff st_i32 tmp14,crs,$0x10 dead: 0 ---- 000a2d68 and_i32 tmp0,tmp26,$0x3 dead: 1 2 pref=0xffff brcond_i32 tmp0,$0x0,ne,$L1 dead: 0 1 mov_i32 pc,tmp26 sync: 0 dead: 0 1 pref=0xffff st_i32 $0xa2d6c,crs,$0x7c dead: 0 1 call lookup_tb_ptr,$0x6,$1,tmp7,env dead: 1 pref=none goto_ptr tmp7 dead: 0 set_label $L1 ld_i32 tmp26,crs,$0x40 dead: 1 pref=0xffff st_i32 tmp26,env,$0x2038 dead: 0 mov_i32 pc,$0xa2d68 sync: 0 dead: 0 1 pref=0xffff call raise_exception,$0xa,$0,env,$0x7 dead: 0 1 set_label $L0 exit_tb $0x7f1878027e43
On 3/15/22 09:26, Amir Gonnen wrote: > Something is wrong when translating rdprs in an interrupt handler when CRS is 0x1. > I'm hitting "../tcg/tcg.c:3466: tcg_reg_alloc_mov: Assertion `ts->val_type == TEMP_VAL_REG' failed." > > When stopped on that assertion I can see that : > - ts->val_type = TEMP_VAL_DEAD > - op->opc = INDEX_op_mov_i32 > - ots->name = "pc" > - cpu->ctrl[0] = 0x5f9 (that's STATUS so CRS = 1) > - pc = 0xa2d5c > > so, it looks related to an assignment to PC a little after rdprs. Ok, thanks for the report. Yes, it's a bug in the indirection lowering. r~
diff --git a/target/nios2/cpu.h b/target/nios2/cpu.h index e32bebe9b7..26d4dcfe12 100644 --- a/target/nios2/cpu.h +++ b/target/nios2/cpu.h @@ -220,6 +220,7 @@ struct ArchCPU { bool diverr_present; bool mmu_present; + bool eic_present; uint32_t pid_num_bits; uint32_t tlb_num_ways; diff --git a/target/nios2/helper.h b/target/nios2/helper.h index 6f5ec60b0d..1648d76ade 100644 --- a/target/nios2/helper.h +++ b/target/nios2/helper.h @@ -24,6 +24,8 @@ DEF_HELPER_FLAGS_3(divu, TCG_CALL_NO_WG, i32, env, i32, i32) #if !defined(CONFIG_USER_ONLY) DEF_HELPER_3(eret, noreturn, env, i32, i32) +DEF_HELPER_FLAGS_2(rdprs, TCG_CALL_NO_WG, i32, env, i32) +DEF_HELPER_3(wrprs, void, env, i32, i32) DEF_HELPER_2(mmu_write_tlbacc, void, env, i32) DEF_HELPER_2(mmu_write_tlbmisc, void, env, i32) DEF_HELPER_2(mmu_write_pteaddr, void, env, i32) diff --git a/target/nios2/op_helper.c b/target/nios2/op_helper.c index 849867becd..e5e70268da 100644 --- a/target/nios2/op_helper.c +++ b/target/nios2/op_helper.c @@ -83,4 +83,16 @@ void helper_eret(CPUNios2State *env, uint32_t new_status, uint32_t new_pc) env->pc = new_pc; cpu_loop_exit(cs); } + +uint32_t helper_rdprs(CPUNios2State *env, uint32_t regno) +{ + unsigned prs = FIELD_EX32(env->ctrl[CR_STATUS], CR_STATUS, PRS); + return env->shadow_regs[prs][regno]; +} + +void helper_wrprs(CPUNios2State *env, uint32_t regno, uint32_t val) +{ + unsigned prs = FIELD_EX32(env->ctrl[CR_STATUS], CR_STATUS, PRS); + env->shadow_regs[prs][regno] = val; +} #endif /* !CONFIG_USER_ONLY */ diff --git a/target/nios2/translate.c b/target/nios2/translate.c index 525df7b023..2b2f528e00 100644 --- a/target/nios2/translate.c +++ b/target/nios2/translate.c @@ -103,6 +103,7 @@ typedef struct DisasContext { bool crs0; TCGv sink; const ControlRegState *cr_state; + bool eic_present; } DisasContext; static TCGv cpu_R[NUM_GP_REGS]; @@ -326,6 +327,27 @@ gen_i_math_logic(andhi, andi, 0, instr.imm16.u << 16) gen_i_math_logic(orhi , ori, 1, instr.imm16.u << 16) gen_i_math_logic(xorhi, xori, 1, instr.imm16.u << 16) +/* 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); @@ -387,7 +409,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 */ @@ -587,6 +609,26 @@ 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)); +#endif +} + /* Comparison instructions */ static void gen_cmpxx(DisasContext *dc, uint32_t code, uint32_t flags) { @@ -711,7 +753,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 */ @@ -812,6 +854,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->eic_present = cpu->eic_present; dc->crs0 = FIELD_EX32(dc->base.tb->flags, TBFLAGS, CRS0); /* Bound the number of insns to execute to those left on the page. */
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. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- target/nios2/cpu.h | 1 + target/nios2/helper.h | 2 ++ target/nios2/op_helper.c | 12 ++++++++++ target/nios2/translate.c | 47 ++++++++++++++++++++++++++++++++++++++-- 4 files changed, 60 insertions(+), 2 deletions(-)