aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--linux-user/m68k/cpu_loop.c3
-rw-r--r--target/m68k/op_helper.c2
-rw-r--r--target/m68k/translate.c49
3 files changed, 36 insertions, 18 deletions
diff --git a/linux-user/m68k/cpu_loop.c b/linux-user/m68k/cpu_loop.c
index 6598bce..fcf9220 100644
--- a/linux-user/m68k/cpu_loop.c
+++ b/linux-user/m68k/cpu_loop.c
@@ -52,6 +52,9 @@ void cpu_loop(CPUM68KState *env)
case EXCP_DIV0:
force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTDIV, env->mmu.ar);
break;
+ case EXCP_TRACE:
+ force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_TRACE, env->mmu.ar);
+ break;
case EXCP_TRAP0:
{
abi_long ret;
diff --git a/target/m68k/op_helper.c b/target/m68k/op_helper.c
index 729ee0e..3cb71c9 100644
--- a/target/m68k/op_helper.c
+++ b/target/m68k/op_helper.c
@@ -397,13 +397,13 @@ static void m68k_interrupt_all(CPUM68KState *env, int is_hw)
case EXCP_ILLEGAL:
case EXCP_TRAPCC:
- case EXCP_TRACE:
/* FIXME: addr is not only env->pc */
do_stack_frame(env, &sp, 2, oldsr, env->pc, env->pc);
break;
case EXCP_CHK:
case EXCP_DIV0:
+ case EXCP_TRACE:
do_stack_frame(env, &sp, 2, oldsr, env->mmu.ar, env->pc);
break;
diff --git a/target/m68k/translate.c b/target/m68k/translate.c
index 6075f49..38b72d2 100644
--- a/target/m68k/translate.c
+++ b/target/m68k/translate.c
@@ -114,6 +114,7 @@ typedef struct DisasContext {
DisasContextBase base;
CPUM68KState *env;
target_ulong pc;
+ target_ulong pc_prev;
CCOp cc_op; /* Current CC operation */
int cc_op_synced;
TCGv_i64 mactmp;
@@ -298,6 +299,21 @@ static void gen_raise_exception(int nr)
tcg_temp_free_i32(tmp);
}
+static void gen_raise_exception_format2(DisasContext *s, int nr,
+ target_ulong this_pc)
+{
+ /*
+ * Pass the address of the insn to the exception handler,
+ * for recording in the Format $2 (6-word) stack frame.
+ * Re-use mmu.ar for the purpose, since that's only valid
+ * after tlb_fill.
+ */
+ tcg_gen_st_i32(tcg_constant_i32(this_pc), cpu_env,
+ offsetof(CPUM68KState, mmu.ar));
+ gen_raise_exception(nr);
+ s->base.is_jmp = DISAS_NORETURN;
+}
+
static void gen_exception(DisasContext *s, uint32_t dest, int nr)
{
update_cc_op(s);
@@ -1494,12 +1510,13 @@ static void gen_exit_tb(DisasContext *s)
} while (0)
/* Generate a jump to an immediate address. */
-static void gen_jmp_tb(DisasContext *s, int n, uint32_t dest)
+static void gen_jmp_tb(DisasContext *s, int n, target_ulong dest,
+ target_ulong src)
{
if (unlikely(s->ss_active)) {
update_cc_op(s);
tcg_gen_movi_i32(QREG_PC, dest);
- gen_raise_exception(EXCP_TRACE);
+ gen_raise_exception_format2(s, EXCP_TRACE, src);
} else if (translator_use_goto_tb(&s->base, dest)) {
tcg_gen_goto_tb(n);
tcg_gen_movi_i32(QREG_PC, dest);
@@ -1548,9 +1565,9 @@ DISAS_INSN(dbcc)
tcg_gen_addi_i32(tmp, tmp, -1);
gen_partset_reg(OS_WORD, reg, tmp);
tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, -1, l1);
- gen_jmp_tb(s, 1, base + offset);
+ gen_jmp_tb(s, 1, base + offset, s->base.pc_next);
gen_set_label(l1);
- gen_jmp_tb(s, 0, s->pc);
+ gen_jmp_tb(s, 0, s->pc, s->base.pc_next);
}
DISAS_INSN(undef_mac)
@@ -3096,13 +3113,13 @@ DISAS_INSN(branch)
/* Bcc */
TCGLabel *l1 = gen_new_label();
gen_jmpcc(s, ((insn >> 8) & 0xf) ^ 1, l1);
- gen_jmp_tb(s, 1, base + offset);
+ gen_jmp_tb(s, 1, base + offset, s->base.pc_next);
gen_set_label(l1);
- gen_jmp_tb(s, 0, s->pc);
+ gen_jmp_tb(s, 0, s->pc, s->base.pc_next);
} else {
/* Unconditional branch. */
update_cc_op(s);
- gen_jmp_tb(s, 0, base + offset);
+ gen_jmp_tb(s, 0, base + offset, s->base.pc_next);
}
}
@@ -5485,9 +5502,9 @@ DISAS_INSN(fbcc)
l1 = gen_new_label();
update_cc_op(s);
gen_fjmpcc(s, insn & 0x3f, l1);
- gen_jmp_tb(s, 0, s->pc);
+ gen_jmp_tb(s, 0, s->pc, s->base.pc_next);
gen_set_label(l1);
- gen_jmp_tb(s, 1, base + offset);
+ gen_jmp_tb(s, 1, base + offset, s->base.pc_next);
}
DISAS_INSN(fscc)
@@ -6159,6 +6176,8 @@ static void m68k_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu)
dc->env = env;
dc->pc = dc->base.pc_first;
+ /* This value will always be filled in properly before m68k_tr_tb_stop. */
+ dc->pc_prev = 0xdeadbeef;
dc->cc_op = CC_OP_DYNAMIC;
dc->cc_op_synced = 1;
dc->done_mac = 0;
@@ -6192,6 +6211,7 @@ static void m68k_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
do_writebacks(dc);
do_release(dc);
+ dc->pc_prev = dc->base.pc_next;
dc->base.pc_next = dc->pc;
if (dc->base.is_jmp == DISAS_NEXT) {
@@ -6226,17 +6246,12 @@ static void m68k_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
break;
case DISAS_TOO_MANY:
update_cc_op(dc);
- if (dc->ss_active) {
- tcg_gen_movi_i32(QREG_PC, dc->pc);
- gen_raise_exception(EXCP_TRACE);
- } else {
- gen_jmp_tb(dc, 0, dc->pc);
- }
+ gen_jmp_tb(dc, 0, dc->pc, dc->pc_prev);
break;
case DISAS_JUMP:
/* We updated CC_OP and PC in gen_jmp/gen_jmp_im. */
if (dc->ss_active) {
- gen_raise_exception(EXCP_TRACE);
+ gen_raise_exception_format2(dc, EXCP_TRACE, dc->pc_prev);
} else {
tcg_gen_lookup_and_goto_ptr();
}
@@ -6247,7 +6262,7 @@ static void m68k_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
* other state that may require returning to the main loop.
*/
if (dc->ss_active) {
- gen_raise_exception(EXCP_TRACE);
+ gen_raise_exception_format2(dc, EXCP_TRACE, dc->pc_prev);
} else {
tcg_gen_exit_tb(NULL, 0);
}