[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH for-2.5 26/30] m68k: add mull/divl
From: |
Laurent Vivier |
Subject: |
[Qemu-devel] [PATCH for-2.5 26/30] m68k: add mull/divl |
Date: |
Sun, 9 Aug 2015 22:13:45 +0200 |
Signed-off-by: Laurent Vivier <address@hidden>
---
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(-)
diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h
index 6d1a140..a261680 100644
--- a/target-m68k/cpu.h
+++ b/target-m68k/cpu.h
@@ -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;
diff --git a/target-m68k/helper.h b/target-m68k/helper.h
index 9b54ebf..de4d84d 100644
--- a/target-m68k/helper.h
+++ b/target-m68k/helper.h
@@ -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)
diff --git a/target-m68k/op_helper.c b/target-m68k/op_helper.c
index 71641bf..8ecbf8a 100644
--- a/target-m68k/op_helper.c
+++ b/target-m68k/op_helper.c
@@ -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;
+}
diff --git a/target-m68k/qregs.def b/target-m68k/qregs.def
index 204663e..aba6c9a 100644
--- a/target-m68k/qregs.def
+++ b/target-m68k/qregs.def
@@ -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)
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 67527fe..ad11457 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -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)
--
2.4.3
- [Qemu-devel] [PATCH for-2.5 22/30] m68k: add cas instruction, (continued)
- [Qemu-devel] [PATCH for-2.5 28/30] m68k: shift/rotate bytes and words, Laurent Vivier, 2015/08/09
- [Qemu-devel] [PATCH for-2.5 26/30] m68k: add mull/divl,
Laurent Vivier <=
- [Qemu-devel] [PATCH for-2.5 29/30] m68k: add rol/rox/ror/roxr, Laurent Vivier, 2015/08/09
- [Qemu-devel] [PATCH for-2.5 30/30] m68k: add bitfield instructions, Laurent Vivier, 2015/08/09
- Re: [Qemu-devel] [PATCH for-2.5 00/30] 680x0 instructions emulation, Richard Henderson, 2015/08/12