aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--target-mips/translate.c21
1 files changed, 18 insertions, 3 deletions
diff --git a/target-mips/translate.c b/target-mips/translate.c
index fb3c980c18..72692efe08 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -463,6 +463,7 @@ typedef struct DisasContext {
struct TranslationBlock *tb;
target_ulong pc, saved_pc;
uint32_t opcode;
+ int singlestep_enabled;
/* Routine used to access memory */
int mem_idx;
uint32_t hflags, saved_hflags;
@@ -2459,12 +2460,17 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
{
TranslationBlock *tb;
tb = ctx->tb;
- if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
+ if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) &&
+ likely(!ctx->singlestep_enabled)) {
tcg_gen_goto_tb(n);
gen_save_pc(dest);
tcg_gen_exit_tb((long)tb + n);
} else {
gen_save_pc(dest);
+ if (ctx->singlestep_enabled) {
+ save_cpu_state(ctx, 0);
+ gen_helper_0i(raise_exception, EXCP_DEBUG);
+ }
tcg_gen_exit_tb(0);
}
}
@@ -8263,6 +8269,10 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
/* unconditional branch to register */
MIPS_DEBUG("branch to register");
tcg_gen_mov_tl(cpu_PC, btarget);
+ if (ctx->singlestep_enabled) {
+ save_cpu_state(ctx, 0);
+ gen_helper_0i(raise_exception, EXCP_DEBUG);
+ }
tcg_gen_exit_tb(0);
break;
default:
@@ -8292,6 +8302,7 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE - 16;
ctx.pc = pc_start;
ctx.saved_pc = -1;
+ ctx.singlestep_enabled = env->singlestep_enabled;
ctx.tb = tb;
ctx.bstate = BS_NONE;
/* Restore delay slot state from the tb context. */
@@ -8347,7 +8358,11 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
ctx.pc += 4;
num_insns++;
- if (env->singlestep_enabled)
+ /* Execute a branch and its delay slot as a single instruction.
+ This is what GDB expects and is consistent with what the
+ hardware does (e.g. if a delay slot instruction faults, the
+ reported PC is the PC of the branch). */
+ if (env->singlestep_enabled && (ctx.hflags & MIPS_HFLAG_BMASK) == 0)
break;
if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0)
@@ -8364,7 +8379,7 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
}
if (tb->cflags & CF_LAST_IO)
gen_io_end();
- if (env->singlestep_enabled) {
+ if (env->singlestep_enabled && ctx.bstate != BS_BRANCH) {
save_cpu_state(&ctx, ctx.bstate == BS_NONE);
gen_helper_0i(raise_exception, EXCP_DEBUG);
} else {