diff options
-rw-r--r-- | hw/mips_int.c | 9 | ||||
-rw-r--r-- | target-mips/cpu.h | 3 | ||||
-rw-r--r-- | target-mips/helper.h | 1 | ||||
-rw-r--r-- | target-mips/op_helper.c | 20 | ||||
-rw-r--r-- | target-mips/translate.c | 12 |
5 files changed, 30 insertions, 15 deletions
diff --git a/hw/mips_int.c b/hw/mips_int.c index 80488baeba..477f6abf95 100644 --- a/hw/mips_int.c +++ b/hw/mips_int.c @@ -54,3 +54,12 @@ void cpu_mips_irq_init_cpu(CPUState *env) env->irq[i] = qi[i]; } } + +void cpu_mips_soft_irq(CPUState *env, int irq, int level) +{ + if (irq < 0 || irq > 2) { + return; + } + + qemu_set_irq(env->irq[irq], level); +} diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 157885082a..b8e6feefc2 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -597,6 +597,9 @@ void cpu_mips_store_compare (CPUState *env, uint32_t value); void cpu_mips_start_count(CPUState *env); void cpu_mips_stop_count(CPUState *env); +/* mips_int.c */ +void cpu_mips_soft_irq(CPUState *env, int irq, int level); + /* helper.c */ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, int mmu_idx, int is_softmmu); diff --git a/target-mips/helper.h b/target-mips/helper.h index a6ba75dfbc..cb13fb2352 100644 --- a/target-mips/helper.h +++ b/target-mips/helper.h @@ -2,7 +2,6 @@ DEF_HELPER_2(raise_exception_err, void, i32, int) DEF_HELPER_1(raise_exception, void, i32) -DEF_HELPER_0(interrupt_restart, void) #ifdef TARGET_MIPS64 DEF_HELPER_3(ldl, tl, tl, tl, int) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index c9632248a0..a619b72610 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -46,18 +46,6 @@ void helper_raise_exception (uint32_t exception) helper_raise_exception_err(exception, 0); } -void helper_interrupt_restart (void) -{ - if (!(env->CP0_Status & (1 << CP0St_EXL)) && - !(env->CP0_Status & (1 << CP0St_ERL)) && - !(env->hflags & MIPS_HFLAG_DM) && - (env->CP0_Status & (1 << CP0St_IE)) && - (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask)) { - env->CP0_Cause &= ~(0x1f << CP0Ca_EC); - helper_raise_exception(EXCP_EXT_INTERRUPT); - } -} - #if !defined(CONFIG_USER_ONLY) static void do_restore_state (void *pc_ptr) { @@ -1346,6 +1334,7 @@ void helper_mtc0_cause (target_ulong arg1) { uint32_t mask = 0x00C00300; uint32_t old = env->CP0_Cause; + int i; if (env->insn_flags & ISA_MIPS32R2) mask |= 1 << CP0Ca_DC; @@ -1358,6 +1347,13 @@ void helper_mtc0_cause (target_ulong arg1) else cpu_mips_start_count(env); } + + /* Set/reset software interrupts */ + for (i = 0 ; i < 2 ; i++) { + if ((old ^ env->CP0_Cause) & (1 << (CP0Ca_IP + i))) { + cpu_mips_soft_irq(env, i, env->CP0_Cause & (1 << (CP0Ca_IP + i))); + } + } } void helper_mtc0_ebase (target_ulong arg1) diff --git a/target-mips/translate.c b/target-mips/translate.c index 7168273381..6c72dee1ba 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -5190,7 +5190,17 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, TCGv arg, int reg, int switch (sel) { case 0: save_cpu_state(ctx, 1); + /* Mark as an IO operation because we may trigger a software + interrupt. */ + if (use_icount) { + gen_io_start(); + } gen_helper_mtc0_cause(arg); + if (use_icount) { + gen_io_end(); + } + /* Stop translation as we may have triggered an intetrupt */ + ctx->bstate = BS_STOP; rn = "Cause"; break; default: @@ -12365,7 +12375,6 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, } else { switch (ctx.bstate) { case BS_STOP: - gen_helper_interrupt_restart(); gen_goto_tb(&ctx, 0, ctx.pc); break; case BS_NONE: @@ -12373,7 +12382,6 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, gen_goto_tb(&ctx, 0, ctx.pc); break; case BS_EXCP: - gen_helper_interrupt_restart(); tcg_gen_exit_tb(0); break; case BS_BRANCH: |