diff options
author | Richard Henderson | 2022-06-02 15:30:24 +0200 |
---|---|---|
committer | Richard Henderson | 2022-06-02 15:30:24 +0200 |
commit | 1e62a82574fc28e64deca589a23cf55ada2e1a7d (patch) | |
tree | ebad6eeb763631e6fd846e2a5dd54bcb415b1eec /target | |
parent | Merge tag 'pull-testing-next-010622-3' of https://github.com/stsquad/qemu int... (diff) | |
parent | target/m68k: Mark helper_raise_exception as noreturn (diff) | |
download | qemu-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.c | 7 | ||||
-rw-r--r-- | target/m68k/cpu.h | 8 | ||||
-rw-r--r-- | target/m68k/helper.h | 14 | ||||
-rw-r--r-- | target/m68k/op_helper.c | 173 | ||||
-rw-r--r-- | target/m68k/translate.c | 192 |
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); } |