summaryrefslogtreecommitdiffstats
path: root/target
diff options
context:
space:
mode:
authorRichard Henderson2022-06-02 15:30:24 +0200
committerRichard Henderson2022-06-02 15:30:24 +0200
commit1e62a82574fc28e64deca589a23cf55ada2e1a7d (patch)
treeebad6eeb763631e6fd846e2a5dd54bcb415b1eec /target
parentMerge tag 'pull-testing-next-010622-3' of https://github.com/stsquad/qemu int... (diff)
parenttarget/m68k: Mark helper_raise_exception as noreturn (diff)
downloadqemu-1e62a82574fc28e64deca589a23cf55ada2e1a7d.tar.gz
qemu-1e62a82574fc28e64deca589a23cf55ada2e1a7d.tar.xz
qemu-1e62a82574fc28e64deca589a23cf55ada2e1a7d.zip
Merge tag 'm68k-for-7.1-pull-request' of https://github.com/vivier/qemu-m68k into staging
m68k pull request 20220602 - Fixes and cleanup - Implement TRAP opcodes - Enable halt on 68060 # -----BEGIN PGP SIGNATURE----- # # iQJGBAABCAAwFiEEzS913cjjpNwuT1Fz8ww4vT8vvjwFAmKYpeQSHGxhdXJlbnRA # dml2aWVyLmV1AAoJEPMMOL0/L748U+AP/i6EYidZmelIEqOwZTwwzxreF5bTZmAP # v0Hxt3Tef3PWJpLnoCXCsd4othCO3PgHcwtrLff+bkWRl0Wt5CYcq+tTu2im7fIN # zM7RSO00Pt/va7Ss7Ej8d5P5l7uuFqcBFytnitbsNrvHNK4cQ9PVmOkPnJZe0lYt # vA3pUk7giE1KV+/s78Z4VD5CbvwpTRQpDCPDvba7oIP2E9mOELajKtYGh7gvPthx # hrG2L5Ou4rYWxJkpZ0mNyYvoPuGRmzgPImdaDMTPLjEYNJMnnqGCRm+ANtzNk+jy # d/fE/xJ41xvPAt4Q29yCp0vITuRF468M/elp5hQr/rHc6xtitLCi57FhduY9PuL/ # zCMXytgFtnU1C9XhDI/FtQhQxpvEKkZmEJRrAnsuHQKLrHlGoofjBU3whHqfx1zG # qw/cdYqx/RUKKxvmoTbk76doaqfVQvBIx2nB6CsHF3pqOpQETK5TYeId49GCkwgR # 4DmBPL1RZZpkYxi1KEKprcJWMj1l29UTa2dJ+kt9T2YACRm7MYQurP8OCGoHFIX4 # MOr3vdxaqSRU+mE2lWLZWupkZyzFrG/khHSB7A9htTomgbfZLfc0YkHX5kOkHQNq # k4ymLpf16F94aau568HVQO8UZV+1FedtRwJL2EWVqkzKri9rSCCeI8I27HVLjwLP # YzrHwsMVsjgl # =T1g0 # -----END PGP SIGNATURE----- # gpg: Signature made Thu 02 Jun 2022 04:58:28 AM PDT # gpg: using RSA key CD2F75DDC8E3A4DC2E4F5173F30C38BD3F2FBE3C # gpg: issuer "laurent@vivier.eu" # gpg: Good signature from "Laurent Vivier <lvivier@redhat.com>" [undefined] # gpg: aka "Laurent Vivier <laurent@vivier.eu>" [undefined] # gpg: aka "Laurent Vivier (Red Hat) <lvivier@redhat.com>" [undefined] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: CD2F 75DD C8E3 A4DC 2E4F 5173 F30C 38BD 3F2F BE3C * tag 'm68k-for-7.1-pull-request' of https://github.com/vivier/qemu-m68k: target/m68k: Mark helper_raise_exception as noreturn linux-user/strace: Adjust get_thread_area for m68k linux-user/strace: Use is_error in print_syscall_err tests/tcg/m68k: Add trap.c target/m68k: Implement FTRAPcc target/m68k: Implement TRAPV target/m68k: Implement TPF in terms of TRAPcc target/m68k: Implement TRAPcc target/m68k: Fix stack frame for EXCP_ILLEGAL target/m68k: Fix address argument for EXCP_TRACE target/m68k: Fix pc, c flag, and address argument for EXCP_DIV0 target/m68k: Fix address argument for EXCP_CHK target/m68k: Remove retaddr in m68k_interrupt_all linux-user/m68k: Handle EXCP_TRAP1 through EXCP_TRAP15 target/m68k: Fix coding style in m68k_interrupt_all target/m68k: Switch over exception type in m68k_interrupt_all target/m68k: Raise the TRAPn exception with the correct pc target/m68k: Enable halt insn for 68060 target/m68k: Clear mach in m68k_cpu_disas_set_info Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'target')
-rw-r--r--target/m68k/cpu.c7
-rw-r--r--target/m68k/cpu.h8
-rw-r--r--target/m68k/helper.h14
-rw-r--r--target/m68k/op_helper.c173
-rw-r--r--target/m68k/translate.c192
5 files changed, 250 insertions, 144 deletions
diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c
index c7aeb7da9c..5bbefda575 100644
--- a/target/m68k/cpu.c
+++ b/target/m68k/cpu.c
@@ -75,12 +75,8 @@ static void m68k_cpu_reset(DeviceState *dev)
static void m68k_cpu_disas_set_info(CPUState *s, disassemble_info *info)
{
- M68kCPU *cpu = M68K_CPU(s);
- CPUM68KState *env = &cpu->env;
info->print_insn = print_insn_m68k;
- if (m68k_feature(env, M68K_FEATURE_M68000)) {
- info->mach = bfd_mach_m68040;
- }
+ info->mach = 0;
}
/* CPU models */
@@ -162,6 +158,7 @@ static void m68020_cpu_initfn(Object *obj)
m68k_set_feature(env, M68K_FEATURE_CHK2);
m68k_set_feature(env, M68K_FEATURE_MSP);
m68k_set_feature(env, M68K_FEATURE_UNALIGNED_DATA);
+ m68k_set_feature(env, M68K_FEATURE_TRAPCC);
}
/*
diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h
index 9b3bf7a448..4d8f48e8c7 100644
--- a/target/m68k/cpu.h
+++ b/target/m68k/cpu.h
@@ -122,6 +122,12 @@ typedef struct CPUArchState {
/* MMU status. */
struct {
+ /*
+ * Holds the "address" value in between raising an exception
+ * and creation of the exception stack frame.
+ * Used for both Format 7 exceptions (Access, i.e. mmu)
+ * and Format 2 exceptions (chk, div0, trapcc, etc).
+ */
uint32_t ar;
uint32_t ssw;
/* 68040 */
@@ -528,6 +534,8 @@ enum m68k_features {
M68K_FEATURE_MOVEC,
/* Unaligned data accesses (680[2346]0) */
M68K_FEATURE_UNALIGNED_DATA,
+ /* TRAPcc insn. (680[2346]0, and CPU32) */
+ M68K_FEATURE_TRAPCC,
};
static inline int m68k_feature(CPUM68KState *env, int feature)
diff --git a/target/m68k/helper.h b/target/m68k/helper.h
index 0a6b4146f6..c9bed2b884 100644
--- a/target/m68k/helper.h
+++ b/target/m68k/helper.h
@@ -1,12 +1,12 @@
DEF_HELPER_1(bitrev, i32, i32)
DEF_HELPER_1(ff1, i32, i32)
DEF_HELPER_FLAGS_2(sats, TCG_CALL_NO_RWG_SE, i32, i32, i32)
-DEF_HELPER_3(divuw, void, env, int, i32)
-DEF_HELPER_3(divsw, void, env, int, s32)
-DEF_HELPER_4(divul, void, env, int, int, i32)
-DEF_HELPER_4(divsl, void, env, int, int, s32)
-DEF_HELPER_4(divull, void, env, int, int, i32)
-DEF_HELPER_4(divsll, void, env, int, int, s32)
+DEF_HELPER_4(divuw, void, env, int, i32, int)
+DEF_HELPER_4(divsw, void, env, int, s32, int)
+DEF_HELPER_5(divul, void, env, int, int, i32, int)
+DEF_HELPER_5(divsl, void, env, int, int, s32, int)
+DEF_HELPER_5(divull, void, env, int, int, i32, int)
+DEF_HELPER_5(divsll, void, env, int, int, s32, int)
DEF_HELPER_2(set_sr, void, env, i32)
DEF_HELPER_3(cf_movec_to, void, env, i32, i32)
DEF_HELPER_3(m68k_movec_to, void, env, i32, i32)
@@ -109,7 +109,7 @@ DEF_HELPER_3(set_mac_extu, void, env, i32, i32)
DEF_HELPER_2(flush_flags, void, env, i32)
DEF_HELPER_2(set_ccr, void, env, i32)
DEF_HELPER_FLAGS_1(get_ccr, TCG_CALL_NO_WG_SE, i32, env)
-DEF_HELPER_2(raise_exception, void, env, i32)
+DEF_HELPER_2(raise_exception, noreturn, env, i32)
DEF_HELPER_FLAGS_3(bfffo_reg, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32)
diff --git a/target/m68k/op_helper.c b/target/m68k/op_helper.c
index 8decc61240..d9937ca8dc 100644
--- a/target/m68k/op_helper.c
+++ b/target/m68k/op_helper.c
@@ -217,11 +217,6 @@ static void cf_interrupt_all(CPUM68KState *env, int is_hw)
cpu_loop_exit(cs);
return;
}
- if (cs->exception_index >= EXCP_TRAP0
- && cs->exception_index <= EXCP_TRAP15) {
- /* Move the PC after the trap instruction. */
- retaddr += 2;
- }
}
vector = cs->exception_index << 2;
@@ -292,22 +287,15 @@ static void m68k_interrupt_all(CPUM68KState *env, int is_hw)
{
CPUState *cs = env_cpu(env);
uint32_t sp;
- uint32_t retaddr;
uint32_t vector;
uint16_t sr, oldsr;
- retaddr = env->pc;
-
if (!is_hw) {
switch (cs->exception_index) {
case EXCP_RTE:
/* Return from an exception. */
m68k_rte(env);
return;
- case EXCP_TRAP0 ... EXCP_TRAP15:
- /* Move the PC after the trap instruction. */
- retaddr += 2;
- break;
}
}
@@ -342,7 +330,8 @@ static void m68k_interrupt_all(CPUM68KState *env, int is_hw)
sp &= ~1;
}
- if (cs->exception_index == EXCP_ACCESS) {
+ switch (cs->exception_index) {
+ case EXCP_ACCESS:
if (env->mmu.fault) {
cpu_abort(cs, "DOUBLE MMU FAULT\n");
}
@@ -393,36 +382,48 @@ static void m68k_interrupt_all(CPUM68KState *env, int is_hw)
sp -= 4;
cpu_stl_mmuidx_ra(env, sp, env->mmu.ar, MMU_KERNEL_IDX, 0);
- do_stack_frame(env, &sp, 7, oldsr, 0, retaddr);
+ do_stack_frame(env, &sp, 7, oldsr, 0, env->pc);
env->mmu.fault = false;
if (qemu_loglevel_mask(CPU_LOG_INT)) {
qemu_log(" "
"ssw: %08x ea: %08x sfc: %d dfc: %d\n",
env->mmu.ssw, env->mmu.ar, env->sfc, env->dfc);
}
- } else if (cs->exception_index == EXCP_ADDRESS) {
- do_stack_frame(env, &sp, 2, oldsr, 0, retaddr);
- } else if (cs->exception_index == EXCP_ILLEGAL ||
- cs->exception_index == EXCP_DIV0 ||
- cs->exception_index == EXCP_CHK ||
- cs->exception_index == EXCP_TRAPCC ||
- cs->exception_index == EXCP_TRACE) {
- /* FIXME: addr is not only env->pc */
- do_stack_frame(env, &sp, 2, oldsr, env->pc, retaddr);
- } else if (is_hw && oldsr & SR_M &&
- cs->exception_index >= EXCP_SPURIOUS &&
- cs->exception_index <= EXCP_INT_LEVEL_7) {
- do_stack_frame(env, &sp, 0, oldsr, 0, retaddr);
- oldsr = sr;
- env->aregs[7] = sp;
- cpu_m68k_set_sr(env, sr &= ~SR_M);
- sp = env->aregs[7];
- if (!m68k_feature(env, M68K_FEATURE_UNALIGNED_DATA)) {
- sp &= ~1;
+ break;
+
+ case EXCP_ILLEGAL:
+ do_stack_frame(env, &sp, 0, oldsr, 0, env->pc);
+ break;
+
+ case EXCP_ADDRESS:
+ do_stack_frame(env, &sp, 2, oldsr, 0, env->pc);
+ break;
+
+ case EXCP_CHK:
+ case EXCP_DIV0:
+ case EXCP_TRACE:
+ case EXCP_TRAPCC:
+ do_stack_frame(env, &sp, 2, oldsr, env->mmu.ar, env->pc);
+ break;
+
+ case EXCP_SPURIOUS ... EXCP_INT_LEVEL_7:
+ if (is_hw && (oldsr & SR_M)) {
+ do_stack_frame(env, &sp, 0, oldsr, 0, env->pc);
+ oldsr = sr;
+ env->aregs[7] = sp;
+ cpu_m68k_set_sr(env, sr & ~SR_M);
+ sp = env->aregs[7];
+ if (!m68k_feature(env, M68K_FEATURE_UNALIGNED_DATA)) {
+ sp &= ~1;
+ }
+ do_stack_frame(env, &sp, 1, oldsr, 0, env->pc);
+ break;
}
- do_stack_frame(env, &sp, 1, oldsr, 0, retaddr);
- } else {
- do_stack_frame(env, &sp, 0, oldsr, 0, retaddr);
+ /* fall through */
+
+ default:
+ do_stack_frame(env, &sp, 0, oldsr, 0, env->pc);
+ break;
}
env->aregs[7] = sp;
@@ -531,7 +532,8 @@ bool m68k_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
#endif /* !CONFIG_USER_ONLY */
-static void raise_exception_ra(CPUM68KState *env, int tt, uintptr_t raddr)
+G_NORETURN static void
+raise_exception_ra(CPUM68KState *env, int tt, uintptr_t raddr)
{
CPUState *cs = env_cpu(env);
@@ -539,7 +541,7 @@ static void raise_exception_ra(CPUM68KState *env, int tt, uintptr_t raddr)
cpu_loop_exit_restore(cs, raddr);
}
-static void raise_exception(CPUM68KState *env, int tt)
+G_NORETURN static void raise_exception(CPUM68KState *env, int tt)
{
raise_exception_ra(env, tt, 0);
}
@@ -549,18 +551,42 @@ void HELPER(raise_exception)(CPUM68KState *env, uint32_t tt)
raise_exception(env, tt);
}
-void HELPER(divuw)(CPUM68KState *env, int destr, uint32_t den)
+G_NORETURN static void
+raise_exception_format2(CPUM68KState *env, int tt, int ilen, uintptr_t raddr)
+{
+ CPUState *cs = env_cpu(env);
+
+ cs->exception_index = tt;
+
+ /* Recover PC and CC_OP for the beginning of the insn. */
+ cpu_restore_state(cs, raddr, true);
+
+ /* Flags are current in env->cc_*, or are undefined. */
+ env->cc_op = CC_OP_FLAGS;
+
+ /*
+ * Remember original pc in mmu.ar, for the Format 2 stack frame.
+ * Adjust PC to end of the insn.
+ */
+ env->mmu.ar = env->pc;
+ env->pc += ilen;
+
+ cpu_loop_exit(cs);
+}
+
+void HELPER(divuw)(CPUM68KState *env, int destr, uint32_t den, int ilen)
{
uint32_t num = env->dregs[destr];
uint32_t quot, rem;
+ env->cc_c = 0; /* always cleared, even if div0 */
+
if (den == 0) {
- raise_exception_ra(env, EXCP_DIV0, GETPC());
+ raise_exception_format2(env, EXCP_DIV0, ilen, GETPC());
}
quot = num / den;
rem = num % den;
- env->cc_c = 0; /* always cleared, even if overflow */
if (quot > 0xffff) {
env->cc_v = -1;
/*
@@ -576,18 +602,19 @@ void HELPER(divuw)(CPUM68KState *env, int destr, uint32_t den)
env->cc_v = 0;
}
-void HELPER(divsw)(CPUM68KState *env, int destr, int32_t den)
+void HELPER(divsw)(CPUM68KState *env, int destr, int32_t den, int ilen)
{
int32_t num = env->dregs[destr];
uint32_t quot, rem;
+ env->cc_c = 0; /* always cleared, even if overflow/div0 */
+
if (den == 0) {
- raise_exception_ra(env, EXCP_DIV0, GETPC());
+ raise_exception_format2(env, EXCP_DIV0, ilen, GETPC());
}
quot = num / den;
rem = num % den;
- env->cc_c = 0; /* always cleared, even if overflow */
if (quot != (int16_t)quot) {
env->cc_v = -1;
/* nothing else is modified */
@@ -604,18 +631,20 @@ void HELPER(divsw)(CPUM68KState *env, int destr, int32_t den)
env->cc_v = 0;
}
-void HELPER(divul)(CPUM68KState *env, int numr, int regr, uint32_t den)
+void HELPER(divul)(CPUM68KState *env, int numr, int regr,
+ uint32_t den, int ilen)
{
uint32_t num = env->dregs[numr];
uint32_t quot, rem;
+ env->cc_c = 0; /* always cleared, even if div0 */
+
if (den == 0) {
- raise_exception_ra(env, EXCP_DIV0, GETPC());
+ raise_exception_format2(env, EXCP_DIV0, ilen, GETPC());
}
quot = num / den;
rem = num % den;
- env->cc_c = 0;
env->cc_z = quot;
env->cc_n = quot;
env->cc_v = 0;
@@ -632,18 +661,20 @@ void HELPER(divul)(CPUM68KState *env, int numr, int regr, uint32_t den)
}
}
-void HELPER(divsl)(CPUM68KState *env, int numr, int regr, int32_t den)
+void HELPER(divsl)(CPUM68KState *env, int numr, int regr,
+ int32_t den, int ilen)
{
int32_t num = env->dregs[numr];
int32_t quot, rem;
+ env->cc_c = 0; /* always cleared, even if overflow/div0 */
+
if (den == 0) {
- raise_exception_ra(env, EXCP_DIV0, GETPC());
+ raise_exception_format2(env, EXCP_DIV0, ilen, GETPC());
}
quot = num / den;
rem = num % den;
- env->cc_c = 0;
env->cc_z = quot;
env->cc_n = quot;
env->cc_v = 0;
@@ -660,19 +691,21 @@ void HELPER(divsl)(CPUM68KState *env, int numr, int regr, int32_t den)
}
}
-void HELPER(divull)(CPUM68KState *env, int numr, int regr, uint32_t den)
+void HELPER(divull)(CPUM68KState *env, int numr, int regr,
+ uint32_t den, int ilen)
{
uint64_t num = deposit64(env->dregs[numr], 32, 32, env->dregs[regr]);
uint64_t quot;
uint32_t rem;
+ env->cc_c = 0; /* always cleared, even if overflow/div0 */
+
if (den == 0) {
- raise_exception_ra(env, EXCP_DIV0, GETPC());
+ raise_exception_format2(env, EXCP_DIV0, ilen, GETPC());
}
quot = num / den;
rem = num % den;
- env->cc_c = 0; /* always cleared, even if overflow */
if (quot > 0xffffffffULL) {
env->cc_v = -1;
/*
@@ -695,19 +728,21 @@ void HELPER(divull)(CPUM68KState *env, int numr, int regr, uint32_t den)
env->dregs[numr] = quot;
}
-void HELPER(divsll)(CPUM68KState *env, int numr, int regr, int32_t den)
+void HELPER(divsll)(CPUM68KState *env, int numr, int regr,
+ int32_t den, int ilen)
{
int64_t num = deposit64(env->dregs[numr], 32, 32, env->dregs[regr]);
int64_t quot;
int32_t rem;
+ env->cc_c = 0; /* always cleared, even if overflow/div0 */
+
if (den == 0) {
- raise_exception_ra(env, EXCP_DIV0, GETPC());
+ raise_exception_format2(env, EXCP_DIV0, ilen, GETPC());
}
quot = num / den;
rem = num % den;
- env->cc_c = 0; /* always cleared, even if overflow */
if (quot != (int32_t)quot) {
env->cc_v = -1;
/*
@@ -1066,18 +1101,7 @@ void HELPER(chk)(CPUM68KState *env, int32_t val, int32_t ub)
env->cc_c = 0 <= ub ? val < 0 || val > ub : val > ub && val < 0;
if (val < 0 || val > ub) {
- CPUState *cs = env_cpu(env);
-
- /* Recover PC and CC_OP for the beginning of the insn. */
- cpu_restore_state(cs, GETPC(), true);
-
- /* flags have been modified by gen_flush_flags() */
- env->cc_op = CC_OP_FLAGS;
- /* Adjust PC to end of the insn. */
- env->pc += 2;
-
- cs->exception_index = EXCP_CHK;
- cpu_loop_exit(cs);
+ raise_exception_format2(env, EXCP_CHK, 2, GETPC());
}
}
@@ -1098,17 +1122,6 @@ void HELPER(chk2)(CPUM68KState *env, int32_t val, int32_t lb, int32_t ub)
env->cc_c = lb <= ub ? val < lb || val > ub : val > ub && val < lb;
if (env->cc_c) {
- CPUState *cs = env_cpu(env);
-
- /* Recover PC and CC_OP for the beginning of the insn. */
- cpu_restore_state(cs, GETPC(), true);
-
- /* flags have been modified by gen_flush_flags() */
- env->cc_op = CC_OP_FLAGS;
- /* Adjust PC to end of the insn. */
- env->pc += 4;
-
- cs->exception_index = EXCP_CHK;
- cpu_loop_exit(cs);
+ raise_exception_format2(env, EXCP_CHK, 4, GETPC());
}
}
diff --git a/target/m68k/translate.c b/target/m68k/translate.c
index 4026572ed8..8f3c298ad0 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)
@@ -1601,6 +1618,7 @@ DISAS_INSN(divw)
int sign;
TCGv src;
TCGv destr;
+ TCGv ilen;
/* divX.w <EA>,Dn 32/16 -> 16r:16q */
@@ -1609,20 +1627,20 @@ DISAS_INSN(divw)
/* dest.l / src.w */
SRC_EA(env, src, OS_WORD, sign, NULL);
- destr = tcg_const_i32(REG(insn, 9));
+ destr = tcg_constant_i32(REG(insn, 9));
+ ilen = tcg_constant_i32(s->pc - s->base.pc_next);
if (sign) {
- gen_helper_divsw(cpu_env, destr, src);
+ gen_helper_divsw(cpu_env, destr, src, ilen);
} else {
- gen_helper_divuw(cpu_env, destr, src);
+ gen_helper_divuw(cpu_env, destr, src, ilen);
}
- tcg_temp_free(destr);
set_cc_op(s, CC_OP_FLAGS);
}
DISAS_INSN(divl)
{
- TCGv num, reg, den;
+ TCGv num, reg, den, ilen;
int sign;
uint16_t ext;
@@ -1639,15 +1657,14 @@ DISAS_INSN(divl)
/* divX.l <EA>, Dr:Dq 64/32 -> 32r:32q */
SRC_EA(env, den, OS_LONG, 0, NULL);
- num = tcg_const_i32(REG(ext, 12));
- reg = tcg_const_i32(REG(ext, 0));
+ num = tcg_constant_i32(REG(ext, 12));
+ reg = tcg_constant_i32(REG(ext, 0));
+ ilen = tcg_constant_i32(s->pc - s->base.pc_next);
if (sign) {
- gen_helper_divsll(cpu_env, num, reg, den);
+ gen_helper_divsll(cpu_env, num, reg, den, ilen);
} else {
- gen_helper_divull(cpu_env, num, reg, den);
+ gen_helper_divull(cpu_env, num, reg, den, ilen);
}
- tcg_temp_free(reg);
- tcg_temp_free(num);
set_cc_op(s, CC_OP_FLAGS);
return;
}
@@ -1656,15 +1673,14 @@ DISAS_INSN(divl)
/* divXl.l <EA>, Dr:Dq 32/32 -> 32r:32q */
SRC_EA(env, den, OS_LONG, 0, NULL);
- num = tcg_const_i32(REG(ext, 12));
- reg = tcg_const_i32(REG(ext, 0));
+ num = tcg_constant_i32(REG(ext, 12));
+ reg = tcg_constant_i32(REG(ext, 0));
+ ilen = tcg_constant_i32(s->pc - s->base.pc_next);
if (sign) {
- gen_helper_divsl(cpu_env, num, reg, den);
+ gen_helper_divsl(cpu_env, num, reg, den, ilen);
} else {
- gen_helper_divul(cpu_env, num, reg, den);
+ gen_helper_divul(cpu_env, num, reg, den, ilen);
}
- tcg_temp_free(reg);
- tcg_temp_free(num);
set_cc_op(s, CC_OP_FLAGS);
}
@@ -3059,22 +3075,6 @@ DISAS_INSN(addsubq)
tcg_temp_free(dest);
}
-DISAS_INSN(tpf)
-{
- switch (insn & 7) {
- case 2: /* One extension word. */
- s->pc += 2;
- break;
- case 3: /* Two extension words. */
- s->pc += 4;
- break;
- case 4: /* No extension words. */
- break;
- default:
- disas_undef(env, s, insn);
- }
-}
-
DISAS_INSN(branch)
{
int32_t offset;
@@ -3097,13 +3097,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);
}
}
@@ -4860,7 +4860,62 @@ DISAS_INSN(wdebug)
DISAS_INSN(trap)
{
- gen_exception(s, s->base.pc_next, EXCP_TRAP0 + (insn & 0xf));
+ gen_exception(s, s->pc, EXCP_TRAP0 + (insn & 0xf));
+}
+
+static void do_trapcc(DisasContext *s, DisasCompare *c)
+{
+ if (c->tcond != TCG_COND_NEVER) {
+ TCGLabel *over = NULL;
+
+ update_cc_op(s);
+
+ if (c->tcond != TCG_COND_ALWAYS) {
+ /* Jump over if !c. */
+ over = gen_new_label();
+ tcg_gen_brcond_i32(tcg_invert_cond(c->tcond), c->v1, c->v2, over);
+ }
+
+ tcg_gen_movi_i32(QREG_PC, s->pc);
+ gen_raise_exception_format2(s, EXCP_TRAPCC, s->base.pc_next);
+
+ if (over != NULL) {
+ gen_set_label(over);
+ s->base.is_jmp = DISAS_NEXT;
+ }
+ }
+ free_cond(c);
+}
+
+DISAS_INSN(trapcc)
+{
+ DisasCompare c;
+
+ /* Consume and discard the immediate operand. */
+ switch (extract32(insn, 0, 3)) {
+ case 2: /* trapcc.w */
+ (void)read_im16(env, s);
+ break;
+ case 3: /* trapcc.l */
+ (void)read_im32(env, s);
+ break;
+ case 4: /* trapcc (no operand) */
+ break;
+ default:
+ /* trapcc registered with only valid opmodes */
+ g_assert_not_reached();
+ }
+
+ gen_cc_cond(&c, s, extract32(insn, 8, 4));
+ do_trapcc(s, &c);
+}
+
+DISAS_INSN(trapv)
+{
+ DisasCompare c;
+
+ gen_cc_cond(&c, s, 9); /* V set */
+ do_trapcc(s, &c);
}
static void gen_load_fcr(DisasContext *s, TCGv res, int reg)
@@ -5486,9 +5541,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)
@@ -5511,6 +5566,34 @@ DISAS_INSN(fscc)
tcg_temp_free(tmp);
}
+DISAS_INSN(ftrapcc)
+{
+ DisasCompare c;
+ uint16_t ext;
+ int cond;
+
+ ext = read_im16(env, s);
+ cond = ext & 0x3f;
+
+ /* Consume and discard the immediate operand. */
+ switch (extract32(insn, 0, 3)) {
+ case 2: /* ftrapcc.w */
+ (void)read_im16(env, s);
+ break;
+ case 3: /* ftrapcc.l */
+ (void)read_im32(env, s);
+ break;
+ case 4: /* ftrapcc (no operand) */
+ break;
+ default:
+ /* ftrapcc registered with only valid opmodes */
+ g_assert_not_reached();
+ }
+
+ gen_fcc_cond(&c, s, cond);
+ do_trapcc(s, &c);
+}
+
#if defined(CONFIG_SOFTMMU)
DISAS_INSN(frestore)
{
@@ -6003,6 +6086,7 @@ void register_m68k_insns (CPUM68KState *env)
INSN(tas, 4ac0, ffc0, M68000);
#if defined(CONFIG_SOFTMMU)
INSN(halt, 4ac8, ffff, CF_ISA_A);
+ INSN(halt, 4ac8, ffff, M68060);
#endif
INSN(pulse, 4acc, ffff, CF_ISA_A);
BASE(illegal, 4afc, ffff);
@@ -6026,6 +6110,7 @@ void register_m68k_insns (CPUM68KState *env)
BASE(nop, 4e71, ffff);
INSN(rtd, 4e74, ffff, RTD);
BASE(rts, 4e75, ffff);
+ INSN(trapv, 4e76, ffff, M68000);
INSN(rtr, 4e77, ffff, M68000);
BASE(jump, 4e80, ffc0);
BASE(jump, 4ec0, ffc0);
@@ -6034,7 +6119,10 @@ void register_m68k_insns (CPUM68KState *env)
INSN(scc, 50c0, f0f8, CF_ISA_A); /* Scc.B Dx */
INSN(scc, 50c0, f0c0, M68000); /* Scc.B <EA> */
INSN(dbcc, 50c8, f0f8, M68000);
- INSN(tpf, 51f8, fff8, CF_ISA_A);
+ INSN(trapcc, 50fa, f0fe, TRAPCC); /* opmode 010, 011 */
+ INSN(trapcc, 50fc, f0ff, TRAPCC); /* opmode 100 */
+ INSN(trapcc, 51fa, fffe, CF_ISA_A); /* TPF (trapf) opmode 010, 011 */
+ INSN(trapcc, 51fc, ffff, CF_ISA_A); /* TPF (trapf) opmode 100 */
/* Branch instructions. */
BASE(branch, 6000, f000);
@@ -6132,6 +6220,8 @@ void register_m68k_insns (CPUM68KState *env)
INSN(fbcc, f280, ffc0, CF_FPU);
INSN(fpu, f200, ffc0, FPU);
INSN(fscc, f240, ffc0, FPU);
+ INSN(ftrapcc, f27a, fffe, FPU); /* opmode 010, 011 */
+ INSN(ftrapcc, f27c, ffff, FPU); /* opmode 100 */
INSN(fbcc, f280, ff80, FPU);
#if defined(CONFIG_SOFTMMU)
INSN(frestore, f340, ffc0, CF_FPU);
@@ -6159,6 +6249,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 +6284,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 +6319,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 +6335,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);
}