@@ -90,6 +90,9 @@ typedef struct CPUM68KState {
uint32_t div1;
uint32_t div2;
+ /* Upper 32 bits of a 64bit operand for quad MUL/DIV. */
+ uint32_t quadh;
+
/* MMU status. */
struct {
uint32_t ar;
@@ -3,6 +3,12 @@ DEF_HELPER_1(ff1, i32, i32)
DEF_HELPER_2(sats, i32, i32, i32)
DEF_HELPER_2(divu, void, env, i32)
DEF_HELPER_2(divs, void, env, i32)
+DEF_HELPER_1(divu64, void, env)
+DEF_HELPER_1(divs64, void, env)
+DEF_HELPER_3(mulu32_cc, i32, env, i32, i32)
+DEF_HELPER_3(muls32_cc, i32, env, i32, i32)
+DEF_HELPER_3(mulu64, i32, env, i32, i32)
+DEF_HELPER_3(muls64, i32, env, i32, i32)
DEF_HELPER_3(addx_cc, i32, env, i32, i32)
DEF_HELPER_3(subx_cc, i32, env, i32, i32)
DEF_HELPER_3(shl_cc, i32, env, i32, i32)
@@ -244,3 +244,146 @@ void HELPER(divs)(CPUM68KState *env, uint32_t word)
env->div2 = rem;
env->cc_dest = flags;
}
+
+void HELPER(divu64)(CPUM68KState *env)
+{
+ uint32_t num;
+ uint32_t den;
+ uint64_t quot;
+ uint32_t rem;
+ uint32_t flags;
+ uint64_t quad;
+
+ num = env->div1;
+ den = env->div2;
+ /* ??? This needs to make sure the throwing location is accurate. */
+ if (den == 0) {
+ raise_exception(env, EXCP_DIV0);
+ }
+ quad = num | ((uint64_t)env->quadh << 32);
+ quot = quad / den;
+ rem = quad % den;
+ if (quot > 0xffffffffULL) {
+ flags = (env->cc_dest & ~CCF_C) | CCF_V;
+ } else {
+ flags = 0;
+ if (quot == 0) {
+ flags |= CCF_Z;
+ } else if ((int32_t)quot < 0) {
+ flags |= CCF_N;
+ }
+ env->div1 = quot;
+ env->quadh = rem;
+ }
+ env->cc_dest = flags;
+}
+
+void HELPER(divs64)(CPUM68KState *env)
+{
+ uint32_t num;
+ int32_t den;
+ int64_t quot;
+ int32_t rem;
+ int32_t flags;
+ int64_t quad;
+
+ num = env->div1;
+ den = env->div2;
+ if (den == 0) {
+ raise_exception(env, EXCP_DIV0);
+ }
+ quad = num | ((int64_t)env->quadh << 32);
+ quot = quad / (int64_t)den;
+ rem = quad % (int64_t)den;
+
+ if ((quot & 0xffffffff80000000ULL) &&
+ (quot & 0xffffffff80000000ULL) != 0xffffffff80000000ULL) {
+ flags = (env->cc_dest & ~CCF_C) | CCF_V;
+ } else {
+ flags = 0;
+ if (quot == 0) {
+ flags |= CCF_Z;
+ } else if ((int32_t)quot < 0) {
+ flags |= CCF_N;
+ }
+ env->div1 = quot;
+ env->quadh = rem;
+ }
+ env->cc_dest = flags;
+}
+
+uint32_t HELPER(mulu32_cc)(CPUM68KState *env, uint32_t op1, uint32_t op2)
+{
+ uint64_t res = (uint32_t)op1 * op2;
+ uint32_t flags;
+
+ flags = 0;
+ if (res >> 32) {
+ flags |= CCF_V;
+ }
+ if ((uint32_t)res == 0) {
+ flags |= CCF_Z;
+ }
+ if ((int32_t)res < 0) {
+ flags |= CCF_N;
+ }
+ env->cc_dest = flags;
+
+ return res;
+}
+
+uint32_t HELPER(muls32_cc)(CPUM68KState *env, uint32_t op1, uint32_t op2)
+{
+ int64_t res = (int32_t)op1 * (int32_t)op2;
+ uint32_t flags;
+
+ flags = 0;
+ if (res != (int64_t)(int32_t)res) {
+ flags |= CCF_V;
+ }
+ if ((uint32_t)res == 0) {
+ flags |= CCF_Z;
+ }
+ if ((int32_t)res < 0) {
+ flags |= CCF_N;
+ }
+ env->cc_dest = flags;
+
+ return res;
+}
+
+uint32_t HELPER(mulu64)(CPUM68KState *env, uint32_t op1, uint32_t op2)
+{
+ uint64_t res = (uint64_t)op1 * op2;
+ uint32_t flags;
+
+ env->quadh = res >> 32;
+ flags = 0;
+ if (res == 0) {
+ flags |= CCF_Z;
+ }
+ if ((int64_t)res < 0) {
+ flags |= CCF_N;
+ }
+ env->cc_dest = flags;
+
+ return res;
+}
+
+uint32_t HELPER(muls64)(CPUM68KState *env, uint32_t op1, uint32_t op2)
+{
+ int64_t res = (uint64_t)(int32_t)op1 * (int32_t)op2;
+ uint32_t flags;
+
+ env->quadh = res >> 32;
+ flags = 0;
+ if (res == 0) {
+ flags |= CCF_Z;
+ }
+ if (res < 0) {
+ flags |= CCF_N;
+ }
+ env->cc_dest = flags;
+
+ return res;
+}
@@ -7,5 +7,6 @@ DEFO32(CC_SRC, cc_src)
DEFO32(CC_X, cc_x)
DEFO32(DIV1, div1)
DEFO32(DIV2, div2)
+DEFO32(QUADH, quadh)
DEFO32(MACSR, macsr)
DEFO32(MAC_MASK, mac_mask)
@@ -1122,8 +1122,27 @@ DISAS_INSN(divl)
uint16_t ext;
ext = read_im16(env, s);
- if (ext & 0x87f8) {
- gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED);
+ if (ext & 0x400) {
+ if (!m68k_feature(s->env, M68K_FEATURE_QUAD_MULDIV)) {
+ gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED);
+ return;
+ }
+ num = DREG(ext, 12);
+ reg = DREG(ext, 0);
+ tcg_gen_mov_i32(QREG_DIV1, num);
+ tcg_gen_mov_i32(QREG_QUADH, reg);
+ SRC_EA(env, den, OS_LONG, 0, NULL);
+ tcg_gen_mov_i32(QREG_DIV2, den);
+ if (ext & 0x0800) {
+ gen_helper_divs64(cpu_env);
+ } else {
+ gen_helper_divu64(cpu_env);
+ }
+ tcg_gen_mov_i32(num, QREG_DIV1);
+ if (!TCGV_EQUAL(num, reg)) {
+ tcg_gen_mov_i32(reg, QREG_QUADH);
+ }
+ set_cc_op(s, CC_OP_FLAGS);
return;
}
num = DREG(ext, 12);
@@ -1136,10 +1155,12 @@ DISAS_INSN(divl)
} else {
gen_helper_divu(cpu_env, tcg_const_i32(0));
}
- if ((ext & 7) == ((ext >> 12) & 7)) {
+ if (TCGV_EQUAL(num, reg) ||
+ m68k_feature(s->env, M68K_FEATURE_LONG_MULDIV)) {
/* div */
- tcg_gen_mov_i32 (reg, QREG_DIV1);
- } else {
+ tcg_gen_mov_i32(num, QREG_DIV1);
+ }
+ if (!TCGV_EQUAL(num, reg)) {
/* rem */
tcg_gen_mov_i32 (reg, QREG_DIV2);
}
@@ -1887,21 +1908,45 @@ DISAS_INSN(mull)
TCGv reg;
TCGv src1;
TCGv dest;
+ TCGv regh;
/* The upper 32 bits of the product are discarded, so
muls.l and mulu.l are functionally equivalent. */
ext = read_im16(env, s);
- if (ext & 0x87ff) {
- gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED);
+ if (ext & 0x400) {
+ if (!m68k_feature(s->env, M68K_FEATURE_QUAD_MULDIV)) {
+ gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED);
+ return;
+ }
+ reg = DREG(ext, 12);
+ regh = DREG(ext, 0);
+ SRC_EA(env, src1, OS_LONG, 0, NULL);
+ dest = tcg_temp_new();
+ if (ext & 0x800) {
+ gen_helper_muls64(dest, cpu_env, src1, reg);
+ } else {
+ gen_helper_mulu64(dest, cpu_env, src1, reg);
+ }
+ tcg_gen_mov_i32(reg, dest);
+ tcg_gen_mov_i32(regh, QREG_QUADH);
+ set_cc_op(s, CC_OP_FLAGS);
return;
}
reg = DREG(ext, 12);
SRC_EA(env, src1, OS_LONG, 0, NULL);
dest = tcg_temp_new();
- tcg_gen_mul_i32(dest, src1, reg);
- tcg_gen_mov_i32(reg, dest);
- /* Unlike m68k, coldfire always clears the overflow bit. */
+ if (m68k_feature(s->env, M68K_FEATURE_M68000)) {
+ if (ext & 0x800) {
+ gen_helper_muls32_cc(dest, cpu_env, src1, reg);
+ } else {
+ gen_helper_mulu32_cc(dest, cpu_env, src1, reg);
+ }
+ set_cc_op(s, CC_OP_FLAGS);
+ } else {
+ tcg_gen_mul_i32(dest, src1, reg);
+ }
gen_logic_cc(s, dest, OS_LONG);
+ tcg_gen_mov_i32(reg, dest);
}
DISAS_INSN(link)
Signed-off-by: Laurent Vivier <laurent@vivier.eu> --- target-m68k/cpu.h | 3 + target-m68k/helper.h | 6 ++ target-m68k/op_helper.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++++ target-m68k/qregs.def | 1 + target-m68k/translate.c | 65 ++++++++++++++++++---- 5 files changed, 208 insertions(+), 10 deletions(-)