aboutsummaryrefslogtreecommitdiff
path: root/target/sh4/translate.c
diff options
context:
space:
mode:
authorAurelien Jarno <aurelien@aurel32.net>2017-05-17 00:48:18 +0200
committerAurelien Jarno <aurelien@aurel32.net>2017-05-30 21:00:56 +0200
commitbe53081a619443dc4512039d89345475ef7d9a46 (patch)
tree9dce7b4becd3a8cf2ed86b627513817c87ebdb08 /target/sh4/translate.c
parent5c6f3eb7db478fe988d8419c191fe388c6cf5194 (diff)
target/sh4: fix RTE instruction delay slot
The ReTurn from Exception (RTE) instruction loads the system register (SR) with the saved system register (SSR). It has a delay slot, and behaves specially according to the SH4 manual: The SR value accessed by the instruction in the RTE delay slot is the value restored from SSR by the RTE instruction. The SR and MD values defined prior to RTE execution are used to fetch the instruction in the RTE delay slot. The instruction in the delay slot being often a NOP, it doesn't cause any issue most of the time except in some rare cases where the NOP is being splitted in a different TB (for example when the TCG op buffer is full). In that case the NOP is fetched with the user permissions and causes an instruction TLB protection violation exception. This patches fixes that by introducing a new delay slot flag for the RTE instruction. Given it's a privileged instruction, the RTE delay slot instruction is always fetched in privileged mode. It is therefore enough to to check for this flag in cpu_mmu_index. Reviewed-by: Richard Henderson <rth@twiddle.net> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Diffstat (limited to 'target/sh4/translate.c')
-rw-r--r--target/sh4/translate.c8
1 files changed, 6 insertions, 2 deletions
diff --git a/target/sh4/translate.c b/target/sh4/translate.c
index aba316f593..8bc132b27b 100644
--- a/target/sh4/translate.c
+++ b/target/sh4/translate.c
@@ -185,6 +185,9 @@ void superh_cpu_dump_state(CPUState *cs, FILE *f,
} else if (env->flags & DELAY_SLOT_CONDITIONAL) {
cpu_fprintf(f, "in conditional delay slot (delayed_pc=0x%08x)\n",
env->delayed_pc);
+ } else if (env->flags & DELAY_SLOT_RTE) {
+ cpu_fprintf(f, "in rte delay slot (delayed_pc=0x%08x)\n",
+ env->delayed_pc);
}
}
@@ -427,8 +430,9 @@ static void _decode_opc(DisasContext * ctx)
CHECK_NOT_DELAY_SLOT
gen_write_sr(cpu_ssr);
tcg_gen_mov_i32(cpu_delayed_pc, cpu_spc);
- ctx->envflags |= DELAY_SLOT;
+ ctx->envflags |= DELAY_SLOT_RTE;
ctx->delayed_pc = (uint32_t) - 1;
+ ctx->bstate = BS_STOP;
return;
case 0x0058: /* sets */
tcg_gen_ori_i32(cpu_sr, cpu_sr, (1u << SR_S));
@@ -1804,7 +1808,7 @@ static void decode_opc(DisasContext * ctx)
ctx->bstate = BS_BRANCH;
if (old_flags & DELAY_SLOT_CONDITIONAL) {
gen_delayed_conditional_jump(ctx);
- } else if (old_flags & DELAY_SLOT) {
+ } else {
gen_jump(ctx);
}