diff --git a/qemu/target-mips/helper.c b/qemu/target-mips/helper.c index ef86d223..2e241e41 100644 --- a/qemu/target-mips/helper.c +++ b/qemu/target-mips/helper.c @@ -543,35 +543,31 @@ void mips_cpu_do_interrupt(CPUState *cs) set_hflags_for_handler(env); break; case EXCP_EXT_INTERRUPT: - cause = 0; - if (env->CP0_Cause & (1 << CP0Ca_IV)) - offset = 0x200; + if (env->CP0_Cause & (1 << CP0Ca_IV)) { + uint32_t spacing = (env->CP0_IntCtl >> CP0IntCtl_VS) & 0x1f; - if (env->CP0_Config3 & ((1 << CP0C3_VInt) | (1 << CP0C3_VEIC))) { - /* Vectored Interrupts. */ - unsigned int spacing; - unsigned int vector; - unsigned int pending = (env->CP0_Cause & CP0Ca_IP_mask) >> 8; + if ((env->CP0_Status & (1 << CP0St_BEV)) || spacing == 0) { + offset = 0x200; + } else { + uint32_t vector = 0; + uint32_t pending = (env->CP0_Cause & CP0Ca_IP_mask) >> CP0Ca_IP; - pending &= env->CP0_Status >> 8; - /* Compute the Vector Spacing. */ - spacing = (env->CP0_IntCtl >> CP0IntCtl_VS) & ((1 << 6) - 1); - spacing <<= 5; + if (env->CP0_Config3 & (1 << CP0C3_VEIC)) { + /* For VEIC mode, the external interrupt controller feeds + * the vector through the CP0Cause IP lines. */ + vector = pending; + } else { + /* Vectored Interrupts + * Mask with Status.IM7-IM0 to get enabled interrupts. */ + pending &= (env->CP0_Status >> CP0St_IM) & 0xff; + /* Find the highest-priority interrupt. */ + while (pending >>= 1) { + vector++; - if (env->CP0_Config3 & (1 << CP0C3_VInt)) { - /* For VInt mode, the MIPS computes the vector internally. */ - for (vector = 7; vector > 0; vector--) { - if (pending & (1 << vector)) { - /* Found it. */ - break; } } - } else { - /* For VEIC mode, the external interrupt controller feeds the - vector through the CP0Cause IP lines. */ - vector = pending; + offset = 0x200 + (vector * (spacing << 5)); } - offset = 0x200 + vector * spacing; } goto set_EPC; case EXCP_LTLBL: diff --git a/qemu/target-mips/op_helper.c b/qemu/target-mips/op_helper.c index 27e667a7..fee8fe53 100644 --- a/qemu/target-mips/op_helper.c +++ b/qemu/target-mips/op_helper.c @@ -1432,7 +1432,6 @@ void helper_mttc0_status(CPUMIPSState *env, target_ulong arg1) void helper_mtc0_intctl(CPUMIPSState *env, target_ulong arg1) { - /* vectored interrupts not implemented, no performance counters. */ env->CP0_IntCtl = (env->CP0_IntCtl & ~0x000003e0) | (arg1 & 0x000003e0); } @@ -1473,7 +1472,6 @@ target_ulong helper_mftc0_ebase(CPUMIPSState *env) void helper_mtc0_ebase(CPUMIPSState *env, target_ulong arg1) { - /* vectored interrupts not implemented */ env->CP0_EBase = (env->CP0_EBase & ~0x3FFFF000) | (arg1 & 0x3FFFF000); }