diff --git a/qemu/target-m68k/cpu.h b/qemu/target-m68k/cpu.h index 2f418565..66a69f0d 100644 --- a/qemu/target-m68k/cpu.h +++ b/qemu/target-m68k/cpu.h @@ -97,10 +97,6 @@ typedef struct CPUM68KState { uint32_t macsr; uint32_t mac_mask; - /* Temporary storage for DIV helpers. */ - uint32_t div1; - uint32_t div2; - /* MMU status. */ struct { uint32_t ar; diff --git a/qemu/target-m68k/helper.h b/qemu/target-m68k/helper.h index 22437d30..5acc7633 100644 --- a/qemu/target-m68k/helper.h +++ b/qemu/target-m68k/helper.h @@ -3,8 +3,12 @@ DEF_HELPER_4(uc_tracecode, void, i32, i32, ptr, i64) 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_2(divu, void, env, i32) -DEF_HELPER_2(divs, void, env, 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_3(shl_cc, i32, env, i32, i32) DEF_HELPER_3(shr_cc, i32, env, i32, i32) DEF_HELPER_3(sar_cc, i32, env, i32, i32) diff --git a/qemu/target-m68k/op_helper.c b/qemu/target-m68k/op_helper.c index e470fac0..5f439a2a 100644 --- a/qemu/target-m68k/op_helper.c +++ b/qemu/target-m68k/op_helper.c @@ -157,12 +157,17 @@ bool m68k_cpu_exec_interrupt(CPUState *cs, int interrupt_request) return false; } -static void raise_exception(CPUM68KState *env, int tt) +static void raise_exception_ra(CPUM68KState *env, int tt, uintptr_t raddr) { CPUState *cs = CPU(m68k_env_get_cpu(env)); cs->exception_index = tt; - cpu_loop_exit(cs); + cpu_loop_exit_restore(cs, raddr); +} + +static void raise_exception(CPUM68KState *env, int tt) +{ + raise_exception_ra(env, tt, 0); } void HELPER(raise_exception)(CPUM68KState *env, uint32_t tt) @@ -170,51 +175,179 @@ void HELPER(raise_exception)(CPUM68KState *env, uint32_t tt) raise_exception(env, tt); } -void HELPER(divu)(CPUM68KState *env, uint32_t word) +void HELPER(divuw)(CPUM68KState *env, int destr, uint32_t den) { - uint32_t num; - uint32_t den; - uint32_t quot; + uint32_t num = env->dregs[destr]; + uint32_t quot, rem; + + if (den == 0) { + raise_exception_ra(env, EXCP_DIV0, GETPC()); + } + quot = num / den; + rem = num % den; + + env->cc_c = 0; /* always cleared, even if overflow */ + if (quot > 0xffff) { + env->cc_v = -1; + /* real 68040 keeps N and unset Z on overflow, + * whereas documentation says "undefined" + */ + env->cc_z = 1; + return; + } + env->dregs[destr] = deposit32(quot, 16, 16, rem); + env->cc_z = (int16_t)quot; + env->cc_n = (int16_t)quot; + env->cc_v = 0; +} + +void HELPER(divsw)(CPUM68KState *env, int destr, int32_t den) +{ + int32_t num = env->dregs[destr]; + uint32_t quot, rem; + + if (den == 0) { + raise_exception_ra(env, EXCP_DIV0, 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 */ + /* real 68040 keeps N and unset Z on overflow, + * whereas documentation says "undefined" + */ + env->cc_z = 1; + return; + } + env->dregs[destr] = deposit32(quot, 16, 16, rem); + env->cc_z = (int16_t)quot; + env->cc_n = (int16_t)quot; + env->cc_v = 0; +} + +void HELPER(divul)(CPUM68KState *env, int numr, int regr, uint32_t den) +{ + uint32_t num = env->dregs[numr]; + uint32_t quot, rem; + + if (den == 0) { + raise_exception_ra(env, EXCP_DIV0, GETPC()); + } + quot = num / den; + rem = num % den; + + env->cc_c = 0; + env->cc_z = quot; + env->cc_n = quot; + env->cc_v = 0; + + if (m68k_feature(env, M68K_FEATURE_CF_ISA_A)) { + if (numr == regr) { + env->dregs[numr] = quot; + } else { + env->dregs[regr] = rem; + } + } else { + env->dregs[regr] = rem; + env->dregs[numr] = quot; + } +} + +void HELPER(divsl)(CPUM68KState *env, int numr, int regr, int32_t den) +{ + int32_t num = env->dregs[numr]; + int32_t quot, rem; + + if (den == 0) { + raise_exception_ra(env, EXCP_DIV0, GETPC()); + } + quot = num / den; + rem = num % den; + + env->cc_c = 0; + env->cc_z = quot; + env->cc_n = quot; + env->cc_v = 0; + + if (m68k_feature(env, M68K_FEATURE_CF_ISA_A)) { + if (numr == regr) { + env->dregs[numr] = quot; + } else { + env->dregs[regr] = rem; + } + } else { + env->dregs[regr] = rem; + env->dregs[numr] = quot; + } +} + +void HELPER(divull)(CPUM68KState *env, int numr, int regr, uint32_t den) +{ + uint64_t num = deposit64(env->dregs[numr], 32, 32, env->dregs[regr]); + uint64_t quot; uint32_t rem; - num = env->div1; - den = env->div2; - /* ??? This needs to make sure the throwing location is accurate. */ if (den == 0) { - raise_exception(env, EXCP_DIV0); + raise_exception_ra(env, EXCP_DIV0, GETPC()); } quot = num / den; rem = num % den; - env->cc_v = (word && quot > 0xffff ? -1 : 0); + env->cc_c = 0; /* always cleared, even if overflow */ + if (quot > 0xffffffffULL) { + env->cc_v = -1; + /* real 68040 keeps N and unset Z on overflow, + * whereas documentation says "undefined" + */ + env->cc_z = 1; + return; + } env->cc_z = quot; env->cc_n = quot; - env->cc_c = 0; + env->cc_v = 0; - env->div1 = quot; - env->div2 = rem; + /* + * If Dq and Dr are the same, the quotient is returned. + * therefore we set Dq last. + */ + + env->dregs[regr] = rem; + env->dregs[numr] = quot; } -void HELPER(divs)(CPUM68KState *env, uint32_t word) +void HELPER(divsll)(CPUM68KState *env, int numr, int regr, int32_t den) { - int32_t num; - int32_t den; - int32_t quot; + int64_t num = deposit64(env->dregs[numr], 32, 32, env->dregs[regr]); + int64_t quot; int32_t rem; - num = env->div1; - den = env->div2; if (den == 0) { - raise_exception(env, EXCP_DIV0); + raise_exception_ra(env, EXCP_DIV0, GETPC()); } quot = num / den; rem = num % den; - env->cc_v = (word && quot != (int16_t)quot ? -1 : 0); + env->cc_c = 0; /* always cleared, even if overflow */ + if (quot != (int32_t)quot) { + env->cc_v = -1; + /* real 68040 keeps N and unset Z on overflow, + * whereas documentation says "undefined" + */ + env->cc_z = 1; + return; + } env->cc_z = quot; env->cc_n = quot; - env->cc_c = 0; + env->cc_v = 0; - env->div1 = quot; - env->div2 = rem; + /* + * If Dq and Dr are the same, the quotient is returned. + * therefore we set Dq last. + */ + + env->dregs[regr] = rem; + env->dregs[numr] = quot; } diff --git a/qemu/target-m68k/qregs.def b/qemu/target-m68k/qregs.def index a79d554f..fe6037db 100644 --- a/qemu/target-m68k/qregs.def +++ b/qemu/target-m68k/qregs.def @@ -7,7 +7,5 @@ DEFO32(CC_N, cc_n) DEFO32(CC_V, cc_v) DEFO32(CC_Z, cc_z) DEFO32(CC_X, cc_x) -DEFO32(DIV1, div1) -DEFO32(DIV2, div2) DEFO32(MACSR, macsr) DEFO32(MAC_MASK, mac_mask) diff --git a/qemu/tcg/tcg.h b/qemu/tcg/tcg.h index ffabb253..ea609ded 100644 --- a/qemu/tcg/tcg.h +++ b/qemu/tcg/tcg.h @@ -919,8 +919,6 @@ struct TCGContext { TCGv QREG_CC_N; TCGv QREG_CC_V; TCGv QREG_CC_Z; - TCGv QREG_DIV1; - TCGv QREG_DIV2; TCGv QREG_MACSR; TCGv QREG_MAC_MASK; TCGv NULL_QREG;