summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/mips_int.c9
-rw-r--r--target-mips/cpu.h3
-rw-r--r--target-mips/helper.h1
-rw-r--r--target-mips/op_helper.c20
-rw-r--r--target-mips/translate.c12
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: