From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1NI2kN-0001rD-PS for qemu-devel@nongnu.org; Tue, 08 Dec 2009 11:17:07 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1NI2kJ-0001ov-S5 for qemu-devel@nongnu.org; Tue, 08 Dec 2009 11:17:07 -0500 Received: from [199.232.76.173] (port=40705 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NI2kJ-0001on-DM for qemu-devel@nongnu.org; Tue, 08 Dec 2009 11:17:03 -0500 Received: from mx20.gnu.org ([199.232.41.8]:51957) by monty-python.gnu.org with esmtps (TLS-1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1NI2kJ-0001V4-71 for qemu-devel@nongnu.org; Tue, 08 Dec 2009 11:17:03 -0500 Received: from mail.codesourcery.com ([38.113.113.100]) by mx20.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1NI2kI-0000ud-Gn for qemu-devel@nongnu.org; Tue, 08 Dec 2009 11:17:02 -0500 From: Nathan Froyd Date: Tue, 8 Dec 2009 08:06:23 -0800 Message-Id: <1260288392-20804-3-git-send-email-froydnj@codesourcery.com> In-Reply-To: <1260288392-20804-1-git-send-email-froydnj@codesourcery.com> References: <1260288392-20804-1-git-send-email-froydnj@codesourcery.com> Subject: [Qemu-devel] [PATCH 02/11] target-mips: change interrupt bits to be mips16-aware List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org We need to stash the operating mode into the low bit of the error PC and restore it on return from interrupts. Signed-off-by: Nathan Froyd --- target-mips/helper.c | 51 +++++++++++++++++++++++++++------------------- target-mips/op_helper.c | 17 ++++++++++++-- 2 files changed, 44 insertions(+), 24 deletions(-) diff --git a/target-mips/helper.c b/target-mips/helper.c index 1e7e016..903987b 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -369,6 +369,24 @@ static const char * const excp_names[EXCP_LAST + 1] = { [EXCP_CACHE] = "cache error", }; +#if !defined(CONFIG_USER_ONLY) +static target_ulong exception_resume_pc (CPUState *env) +{ + target_ulong bad_pc; + target_ulong isa_mode; + + 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; +} +#endif + void do_interrupt (CPUState *env) { #if !defined(CONFIG_USER_ONLY) @@ -396,7 +414,7 @@ void do_interrupt (CPUState *env) 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->CP0_DEPC = env->active_tc.PC | !!(env->hflags & MIPS_HFLAG_M16); goto enter_debug_mode; case EXCP_DINT: env->CP0_Debug |= 1 << CP0DB_DINT; @@ -413,14 +431,8 @@ void do_interrupt (CPUState *env) 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; - } + env->CP0_DEPC = exception_resume_pc(env); + env->hflags &= ~MIPS_HFLAG_BMASK; enter_debug_mode: env->hflags |= MIPS_HFLAG_DM | MIPS_HFLAG_64 | MIPS_HFLAG_CP0; env->hflags &= ~(MIPS_HFLAG_KSU); @@ -428,6 +440,8 @@ void do_interrupt (CPUState *env) if (!(env->CP0_Status & (1 << CP0St_EXL))) env->CP0_Cause &= ~(1 << CP0Ca_BD); env->active_tc.PC = (int32_t)0xBFC00480; + /* Exception handlers are entered in 32-bit mode. */ + env->hflags &= ~(MIPS_HFLAG_M16); break; case EXCP_RESET: cpu_reset(env); @@ -439,20 +453,16 @@ void do_interrupt (CPUState *env) case EXCP_NMI: env->CP0_Status |= (1 << CP0St_NMI); set_error_EPC: - if (env->hflags & MIPS_HFLAG_BMASK) { - /* If the exception was raised from a delay slot, - come back to the jump. */ - env->CP0_ErrorEPC = env->active_tc.PC - 4; - env->hflags &= ~MIPS_HFLAG_BMASK; - } else { - env->CP0_ErrorEPC = env->active_tc.PC; - } + env->CP0_ErrorEPC = exception_resume_pc(env); + env->hflags &= ~MIPS_HFLAG_BMASK; env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV); env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0; env->hflags &= ~(MIPS_HFLAG_KSU); if (!(env->CP0_Status & (1 << CP0St_EXL))) env->CP0_Cause &= ~(1 << CP0Ca_BD); env->active_tc.PC = (int32_t)0xBFC00000; + /* Exception handlers are entered in 32-bit mode. */ + env->hflags &= ~(MIPS_HFLAG_M16); break; case EXCP_EXT_INTERRUPT: cause = 0; @@ -554,13 +564,10 @@ void do_interrupt (CPUState *env) } set_EPC: if (!(env->CP0_Status & (1 << CP0St_EXL))) { + env->CP0_EPC = exception_resume_pc(env); if (env->hflags & MIPS_HFLAG_BMASK) { - /* If the exception was raised from a delay slot, - come back to the jump. */ - env->CP0_EPC = env->active_tc.PC - 4; env->CP0_Cause |= (1 << CP0Ca_BD); } else { - env->CP0_EPC = env->active_tc.PC; env->CP0_Cause &= ~(1 << CP0Ca_BD); } env->CP0_Status |= (1 << CP0St_EXL); @@ -574,6 +581,8 @@ void do_interrupt (CPUState *env) env->active_tc.PC = (int32_t)(env->CP0_EBase & ~0x3ff); } env->active_tc.PC += offset; + /* Exception handlers are entered in 32-bit mode. */ + env->hflags &= ~(MIPS_HFLAG_M16); env->CP0_Cause = (env->CP0_Cause & ~(0x1f << CP0Ca_EC)) | (cause << CP0Ca_EC); break; default: diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index be75af5..cccfd8e 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -1684,14 +1684,24 @@ static void debug_post_eret (void) } } +static void set_pc (target_ulong error_pc) +{ + env->active_tc.PC = error_pc & ~(target_ulong)1; + if (error_pc & 1) { + env->hflags |= MIPS_HFLAG_M16; + } else { + env->hflags &= ~(MIPS_HFLAG_M16); + } +} + void helper_eret (void) { debug_pre_eret(); if (env->CP0_Status & (1 << CP0St_ERL)) { - env->active_tc.PC = env->CP0_ErrorEPC; + set_pc(env->CP0_ErrorEPC); env->CP0_Status &= ~(1 << CP0St_ERL); } else { - env->active_tc.PC = env->CP0_EPC; + set_pc(env->CP0_EPC); env->CP0_Status &= ~(1 << CP0St_EXL); } compute_hflags(env); @@ -1702,7 +1712,8 @@ void helper_eret (void) void helper_deret (void) { debug_pre_eret(); - env->active_tc.PC = env->CP0_DEPC; + set_pc(env->CP0_DEPC); + env->hflags &= MIPS_HFLAG_DM; compute_hflags(env); debug_post_eret(); -- 1.6.3.2