@@ -266,6 +266,8 @@ hwaddr nios2_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
G_NORETURN void nios2_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
MMUAccessType access_type, int mmu_idx,
uintptr_t retaddr);
+G_NORETURN void nios2_cpu_loop_exit_advance(CPUNios2State *env,
+ uintptr_t retaddr);
void do_nios2_semihosting(CPUNios2State *env);
@@ -39,6 +39,8 @@ void cpu_loop(CPUNios2State *env)
break;
case EXCP_DIV:
+ /* Match kernel's handle_diverror_c(). */
+ env->pc -= 4;
force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTDIV, env->pc);
break;
@@ -49,12 +51,6 @@ void cpu_loop(CPUNios2State *env)
break;
case EXCP_TRAP:
- /*
- * TODO: This advance should be done in the translator, as
- * hardware produces an advanced pc as part of all exceptions.
- */
- env->pc += 4;
-
switch (env->error_code) {
case 0:
qemu_log_mask(CPU_LOG_INT, "\nSyscall\n");
@@ -49,7 +49,7 @@ static void do_exception(Nios2CPU *cpu, uint32_t exception_addr,
cr_es = CR_BSTATUS;
}
env->ctrl[cr_es] = old_status;
- env->regs[r_ea] = env->pc + 4;
+ env->regs[r_ea] = env->pc;
if (cpu->mmu_present) {
new_status |= CR_STATUS_EH;
@@ -113,7 +113,7 @@ static void do_eic_irq(Nios2CPU *cpu)
}
env->shadow_regs[new_rs][R_SSTATUS] = old_status;
}
- env->shadow_regs[new_rs][R_EA] = env->pc + 4;
+ env->shadow_regs[new_rs][R_EA] = env->pc;
}
env->ctrl[CR_STATUS] = new_status;
@@ -187,6 +187,8 @@ void nios2_cpu_do_interrupt(CPUState *cs)
switch (cs->exception_index) {
case EXCP_IRQ:
+ /* Note that PC is advanced for interrupts as well. */
+ env->pc += 4;
if (cpu->eic_present) {
do_eic_irq(cpu);
} else {
@@ -249,7 +251,6 @@ void nios2_cpu_do_interrupt(CPUState *cs)
break;
case EXCP_SEMIHOST:
- env->pc += 4;
do_nios2_semihosting(env);
break;
@@ -291,7 +292,7 @@ void nios2_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
env->ctrl[CR_BADADDR] = addr;
cs->exception_index = EXCP_UNALIGN;
- cpu_loop_exit_restore(cs, retaddr);
+ nios2_cpu_loop_exit_advance(env, retaddr);
}
bool nios2_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
@@ -330,7 +331,7 @@ bool nios2_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
cs->exception_index = (access_type == MMU_INST_FETCH
? EXCP_SUPERA_X : EXCP_SUPERA_D);
env->ctrl[CR_BADADDR] = address;
- cpu_loop_exit_restore(cs, retaddr);
+ nios2_cpu_loop_exit_advance(env, retaddr);
}
}
@@ -367,5 +368,5 @@ bool nios2_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
cs->exception_index = excp;
env->ctrl[CR_BADADDR] = address;
- cpu_loop_exit_restore(cs, retaddr);
+ nios2_cpu_loop_exit_advance(env, retaddr);
}
@@ -31,6 +31,20 @@ void helper_raise_exception(CPUNios2State *env, uint32_t index)
cpu_loop_exit(cs);
}
+void nios2_cpu_loop_exit_advance(CPUNios2State *env, uintptr_t retaddr)
+{
+ CPUState *cs = env_cpu(env);
+
+ /*
+ * Note that PC is advanced for all hardware exceptions.
+ * Do this here, rather than in restore_state_to_opc(),
+ * lest we affect QEMU internal exceptions, like EXCP_DEBUG.
+ */
+ cpu_restore_state(cs, retaddr, true);
+ env->pc += 4;
+ cpu_loop_exit(cs);
+}
+
static void maybe_raise_div(CPUNios2State *env, uintptr_t ra)
{
Nios2CPU *cpu = env_archcpu(env);
@@ -38,7 +52,7 @@ static void maybe_raise_div(CPUNios2State *env, uintptr_t ra)
if (cpu->diverr_present) {
cs->exception_index = EXCP_DIV;
- cpu_loop_exit_restore(cs, ra);
+ nios2_cpu_loop_exit_advance(env, ra);
}
}
@@ -69,7 +83,7 @@ void helper_eret(CPUNios2State *env, uint32_t new_status, uint32_t new_pc)
if (unlikely(new_pc & 3)) {
env->ctrl[CR_BADADDR] = new_pc;
cs->exception_index = EXCP_UNALIGND;
- cpu_loop_exit_restore(cs, GETPC());
+ nios2_cpu_loop_exit_advance(env, GETPC());
}
/*
@@ -202,10 +202,10 @@ static TCGv dest_gpr(DisasContext *dc, unsigned reg)
#endif
}
-static void t_gen_helper_raise_exception(DisasContext *dc,
- uint32_t index)
+static void t_gen_helper_raise_exception(DisasContext *dc, uint32_t index)
{
- tcg_gen_movi_tl(cpu_pc, dc->pc);
+ /* Note that PC is advanced for all hardware exceptions. */
+ tcg_gen_movi_tl(cpu_pc, dc->base.pc_next);
gen_helper_raise_exception(cpu_env, tcg_constant_i32(index));
dc->base.is_jmp = DISAS_NORETURN;
}