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----- 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>
This commit is contained in:
commit
1e62a82574
@ -47,16 +47,19 @@ void cpu_loop(CPUM68KState *env)
|
||||
force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPN, env->pc);
|
||||
break;
|
||||
case EXCP_CHK:
|
||||
force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTOVF, env->pc);
|
||||
case EXCP_TRAPCC:
|
||||
force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTOVF, env->mmu.ar);
|
||||
break;
|
||||
case EXCP_DIV0:
|
||||
force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTDIV, env->pc);
|
||||
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;
|
||||
n = env->dregs[0];
|
||||
env->pc += 2;
|
||||
ret = do_syscall(env,
|
||||
n,
|
||||
env->dregs[1],
|
||||
@ -76,7 +79,11 @@ void cpu_loop(CPUM68KState *env)
|
||||
case EXCP_INTERRUPT:
|
||||
/* just indicate that signals should be handled asap */
|
||||
break;
|
||||
case EXCP_TRAP0 + 1 ... EXCP_TRAP0 + 14:
|
||||
force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLTRP, env->pc);
|
||||
break;
|
||||
case EXCP_DEBUG:
|
||||
case EXCP_TRAP15:
|
||||
force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc);
|
||||
break;
|
||||
case EXCP_ATOMIC:
|
||||
|
@ -689,7 +689,7 @@ print_syscall_err(abi_long ret)
|
||||
const char *errstr;
|
||||
|
||||
qemu_log(" = ");
|
||||
if (ret < 0) {
|
||||
if (is_error(ret)) {
|
||||
errstr = target_strerror(-ret);
|
||||
if (errstr) {
|
||||
qemu_log("-1 errno=%d (%s)", (int)-ret, errstr);
|
||||
|
@ -384,8 +384,13 @@
|
||||
{ TARGET_NR_getsockopt, "getsockopt" , NULL, NULL, NULL },
|
||||
#endif
|
||||
#ifdef TARGET_NR_get_thread_area
|
||||
#if defined(TARGET_I386) && defined(TARGET_ABI32)
|
||||
{ TARGET_NR_get_thread_area, "get_thread_area", "%s(0x"TARGET_ABI_FMT_lx")",
|
||||
NULL, NULL },
|
||||
#elif defined(TARGET_M68K)
|
||||
{ TARGET_NR_get_thread_area, "get_thread_area" , "%s()",
|
||||
NULL, print_syscall_ret_addr },
|
||||
#endif
|
||||
#endif
|
||||
#ifdef TARGET_NR_gettid
|
||||
{ TARGET_NR_gettid, "gettid" , "%s()", NULL, NULL },
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -3,5 +3,8 @@
|
||||
# m68k specific tweaks - specifically masking out broken tests
|
||||
#
|
||||
|
||||
VPATH += $(SRC_PATH)/tests/tcg/m68k
|
||||
TESTS += trap
|
||||
|
||||
# On m68k Linux supports 4k and 8k pages (but 8k is currently broken)
|
||||
EXTRA_RUNS+=run-test-mmap-4096 # run-test-mmap-8192
|
||||
|
129
tests/tcg/m68k/trap.c
Normal file
129
tests/tcg/m68k/trap.c
Normal file
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Test m68k trap addresses.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE 1
|
||||
#include <signal.h>
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
|
||||
static int expect_sig;
|
||||
static int expect_si_code;
|
||||
static void *expect_si_addr;
|
||||
static greg_t expect_mc_pc;
|
||||
static volatile int got_signal;
|
||||
|
||||
static void sig_handler(int sig, siginfo_t *si, void *puc)
|
||||
{
|
||||
ucontext_t *uc = puc;
|
||||
mcontext_t *mc = &uc->uc_mcontext;
|
||||
|
||||
assert(sig == expect_sig);
|
||||
assert(si->si_code == expect_si_code);
|
||||
assert(si->si_addr == expect_si_addr);
|
||||
assert(mc->gregs[R_PC] == expect_mc_pc);
|
||||
|
||||
got_signal = 1;
|
||||
}
|
||||
|
||||
#define FMT_INS [ad] "a"(&expect_si_addr), [pc] "a"(&expect_mc_pc)
|
||||
#define FMT0_STR(S) \
|
||||
"move.l #1f, (%[ad])\n\tmove.l #1f, (%[pc])\n" S "\n1:\n"
|
||||
#define FMT2_STR(S) \
|
||||
"move.l #0f, (%[ad])\n\tmove.l #1f, (%[pc])\n" S "\n1:\n"
|
||||
|
||||
#define CHECK_SIG do { assert(got_signal); got_signal = 0; } while (0)
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct sigaction act = {
|
||||
.sa_sigaction = sig_handler,
|
||||
.sa_flags = SA_SIGINFO
|
||||
};
|
||||
int t0, t1;
|
||||
|
||||
sigaction(SIGILL, &act, NULL);
|
||||
sigaction(SIGTRAP, &act, NULL);
|
||||
sigaction(SIGFPE, &act, NULL);
|
||||
|
||||
expect_sig = SIGFPE;
|
||||
expect_si_code = FPE_INTOVF;
|
||||
asm volatile(FMT2_STR("0:\tchk %0, %1") : : "d"(0), "d"(-1), FMT_INS);
|
||||
CHECK_SIG;
|
||||
|
||||
#if 0
|
||||
/* FIXME: chk2 not correctly translated. */
|
||||
int bounds[2] = { 0, 1 };
|
||||
asm volatile(FMT2_STR("0:\tchk2.l %0, %1")
|
||||
: : "m"(bounds), "d"(2), FMT_INS);
|
||||
CHECK_SIG;
|
||||
#endif
|
||||
|
||||
asm volatile(FMT2_STR("cmp.l %0, %1\n0:\ttrapv")
|
||||
: : "d"(INT_MIN), "d"(1), FMT_INS);
|
||||
CHECK_SIG;
|
||||
|
||||
asm volatile(FMT2_STR("cmp.l %0, %0\n0:\ttrapeq")
|
||||
: : "d"(0), FMT_INS);
|
||||
CHECK_SIG;
|
||||
|
||||
asm volatile(FMT2_STR("cmp.l %0, %0\n0:\ttrapeq.w #0x1234")
|
||||
: : "d"(0), FMT_INS);
|
||||
CHECK_SIG;
|
||||
|
||||
asm volatile(FMT2_STR("cmp.l %0, %0\n0:\ttrapeq.l #0x12345678")
|
||||
: : "d"(0), FMT_INS);
|
||||
CHECK_SIG;
|
||||
|
||||
asm volatile(FMT2_STR("fcmp.x %0, %0\n0:\tftrapeq")
|
||||
: : "f"(0.0L), FMT_INS);
|
||||
CHECK_SIG;
|
||||
|
||||
expect_si_code = FPE_INTDIV;
|
||||
|
||||
asm volatile(FMT2_STR("0:\tdivs.w %1, %0")
|
||||
: "=d"(t0) : "d"(0), "0"(1), FMT_INS);
|
||||
CHECK_SIG;
|
||||
|
||||
asm volatile(FMT2_STR("0:\tdivsl.l %2, %1:%0")
|
||||
: "=d"(t0), "=d"(t1) : "d"(0), "0"(1), FMT_INS);
|
||||
CHECK_SIG;
|
||||
|
||||
expect_sig = SIGILL;
|
||||
expect_si_code = ILL_ILLTRP;
|
||||
asm volatile(FMT0_STR("trap #1") : : FMT_INS);
|
||||
CHECK_SIG;
|
||||
asm volatile(FMT0_STR("trap #2") : : FMT_INS);
|
||||
CHECK_SIG;
|
||||
asm volatile(FMT0_STR("trap #3") : : FMT_INS);
|
||||
CHECK_SIG;
|
||||
asm volatile(FMT0_STR("trap #4") : : FMT_INS);
|
||||
CHECK_SIG;
|
||||
asm volatile(FMT0_STR("trap #5") : : FMT_INS);
|
||||
CHECK_SIG;
|
||||
asm volatile(FMT0_STR("trap #6") : : FMT_INS);
|
||||
CHECK_SIG;
|
||||
asm volatile(FMT0_STR("trap #7") : : FMT_INS);
|
||||
CHECK_SIG;
|
||||
asm volatile(FMT0_STR("trap #8") : : FMT_INS);
|
||||
CHECK_SIG;
|
||||
asm volatile(FMT0_STR("trap #9") : : FMT_INS);
|
||||
CHECK_SIG;
|
||||
asm volatile(FMT0_STR("trap #10") : : FMT_INS);
|
||||
CHECK_SIG;
|
||||
asm volatile(FMT0_STR("trap #11") : : FMT_INS);
|
||||
CHECK_SIG;
|
||||
asm volatile(FMT0_STR("trap #12") : : FMT_INS);
|
||||
CHECK_SIG;
|
||||
asm volatile(FMT0_STR("trap #13") : : FMT_INS);
|
||||
CHECK_SIG;
|
||||
asm volatile(FMT0_STR("trap #14") : : FMT_INS);
|
||||
CHECK_SIG;
|
||||
|
||||
expect_sig = SIGTRAP;
|
||||
expect_si_code = TRAP_BRKPT;
|
||||
asm volatile(FMT0_STR("trap #15") : : FMT_INS);
|
||||
CHECK_SIG;
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user