- fprintf(logfile, "%s enter: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " %s exception\n",
- __func__, env->active_tc.PC, env->CP0_EPC, name);
- }
- if (env->exception_index == EXCP_EXT_INTERRUPT &&
- (env->hflags & MIPS_HFLAG_DM))
- env->exception_index = EXCP_DINT;
- offset = 0x180;
- switch (env->exception_index) {
- case EXCP_DSS:
- env->CP0_Debug |= 1 << CP0DB_DSS;
- /* Debug single step cannot be raised inside a delay slot and
- resume will always occur on the next instruction
- (but we assume the pc has always been updated during
- code translation). */
- env->CP0_DEPC = env->active_tc.PC;
- goto enter_debug_mode;
- case EXCP_DINT:
- env->CP0_Debug |= 1 << CP0DB_DINT;
- goto set_DEPC;
- case EXCP_DIB:
- env->CP0_Debug |= 1 << CP0DB_DIB;
- goto set_DEPC;
- case EXCP_DBp:
- env->CP0_Debug |= 1 << CP0DB_DBp;
- goto set_DEPC;
- case EXCP_DDBS:
- env->CP0_Debug |= 1 << CP0DB_DDBS;
- goto set_DEPC;
- case EXCP_DDBL:
- env->CP0_Debug |= 1 << CP0DB_DDBL;
- set_DEPC:
- if (env->hflags & MIPS_HFLAG_BMASK) {
- /* If the exception was raised from a delay slot,
- come back to the jump. */
- env->CP0_DEPC = env->active_tc.PC - 4;
- env->hflags &= ~MIPS_HFLAG_BMASK;
- } else {
- env->CP0_DEPC = env->active_tc.PC;
- }
+ isa_mode = !!(env->hflags & MIPS_HFLAG_M16);
+ bad_pc = env->active_tc.PC | isa_mode;
+ if (env->hflags & MIPS_HFLAG_BMASK) {
+ /* If the exception was raised from a delay slot, come back to
+ the jump. */
+ bad_pc -= (env->hflags & MIPS_HFLAG_B16 ? 2 : 4);
+ }
+
+ return bad_pc;
+}
+
+#if !defined(CONFIG_USER_ONLY)
+static void set_hflags_for_handler (CPUMIPSState *env)
+{
+ /* Exception handlers are entered in 32-bit mode. */
+ env->hflags &= ~(MIPS_HFLAG_M16);
+ /* ...except that microMIPS lets you choose. */
+ if (env->insn_flags & ASE_MICROMIPS) {
+ env->hflags |= (!!(env->CP0_Config3
+ & (1 << CP0C3_ISA_ON_EXC))
+ << MIPS_HFLAG_M16_SHIFT);
+ }
+}
+#endif
+
+void mips_cpu_do_interrupt(CPUState *cs)
+{
+ MIPSCPU *cpu = MIPS_CPU(cs);
+ CPUMIPSState *env = &cpu->env;
+#if !defined(CONFIG_USER_ONLY)
+ target_ulong offset;
+ int cause = -1;
+ const char *name;
+
+ if (qemu_log_enabled() && env->exception_index != EXCP_EXT_INTERRUPT) {
+ if (env->exception_index < 0 || env->exception_index > EXCP_LAST)
+ name = "unknown";
+ else
+ name = excp_names[env->exception_index];
+
+ qemu_log("%s enter: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " %s exception\n",
+ __func__, env->active_tc.PC, env->CP0_EPC, name);
+ }
+ if (env->exception_index == EXCP_EXT_INTERRUPT &&
+ (env->hflags & MIPS_HFLAG_DM))
+ env->exception_index = EXCP_DINT;
+ offset = 0x180;
+ switch (env->exception_index) {
+ case EXCP_DSS:
+ env->CP0_Debug |= 1 << CP0DB_DSS;
+ /* Debug single step cannot be raised inside a delay slot and
+ resume will always occur on the next instruction
+ (but we assume the pc has always been updated during
+ code translation). */
+ env->CP0_DEPC = env->active_tc.PC | !!(env->hflags & MIPS_HFLAG_M16);
+ goto enter_debug_mode;
+ case EXCP_DINT:
+ env->CP0_Debug |= 1 << CP0DB_DINT;
+ goto set_DEPC;
+ case EXCP_DIB:
+ env->CP0_Debug |= 1 << CP0DB_DIB;
+ goto set_DEPC;
+ case EXCP_DBp:
+ env->CP0_Debug |= 1 << CP0DB_DBp;
+ goto set_DEPC;
+ case EXCP_DDBS:
+ env->CP0_Debug |= 1 << CP0DB_DDBS;
+ goto set_DEPC;
+ case EXCP_DDBL:
+ env->CP0_Debug |= 1 << CP0DB_DDBL;
+ set_DEPC:
+ env->CP0_DEPC = exception_resume_pc(env);
+ env->hflags &= ~MIPS_HFLAG_BMASK;