qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 09/17] m68k: add 64bit divide.


From: Laurent Vivier
Subject: [Qemu-devel] [PATCH 09/17] m68k: add 64bit divide.
Date: Sat, 30 May 2009 00:41:53 +0200

This patch modifies "divl" to support 64bit operands (QUAD_MULDIV
feature).

Signed-off-by: Andreas Schwab <address@hidden>
Signed-off-by: Laurent Vivier <address@hidden>
---
 target-m68k/cpu.h       |    3 ++
 target-m68k/helpers.h   |    2 +
 target-m68k/op_helper.c |   77 ++++++++++++++++++++++++++++++++++++++++++++--
 target-m68k/qregs.def   |    1 +
 target-m68k/translate.c |   29 +++++++++++++++--
 5 files changed, 104 insertions(+), 8 deletions(-)

diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h
index 240d75f..fa0b055 100644
--- a/target-m68k/cpu.h
+++ b/target-m68k/cpu.h
@@ -91,6 +91,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/helpers.h b/target-m68k/helpers.h
index cb8a0c7..a158aee 100644
--- a/target-m68k/helpers.h
+++ b/target-m68k/helpers.h
@@ -5,6 +5,8 @@ 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(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 a339a17..2d75b50 100644
--- a/target-m68k/op_helper.c
+++ b/target-m68k/op_helper.c
@@ -194,8 +194,11 @@ void HELPER(divu)(CPUState *env, uint32_t word)
         flags |= CCF_Z;
     else if ((int32_t)quot < 0)
         flags |= CCF_N;
-    env->div1 = quot;
-    env->div2 = rem;
+    /* Don't modify destination if overflow occured.  */
+    if ((flags & CCF_V) == 0) {
+        env->div1 = quot;
+        env->div2 = rem;
+    }
     env->cc_dest = flags;
 }
 
@@ -220,7 +223,73 @@ void HELPER(divs)(CPUState *env, uint32_t word)
         flags |= CCF_Z;
     else if (quot < 0)
         flags |= CCF_N;
-    env->div1 = quot;
-    env->div2 = rem;
+    /* Don't modify destination if overflow occured.  */
+    if ((flags & CCF_V) == 0) {
+        env->div1 = quot;
+        env->div2 = rem;
+    }
+    env->cc_dest = flags;
+}
+
+void HELPER(divu64)(CPUState *env)
+{
+    uint32_t num;
+    uint32_t den;
+    uint32_t quot;
+    uint32_t rem;
+    uint32_t flags;
+
+    num = env->div1;
+    den = env->div2;
+    /* ??? This needs to make sure the throwing location is accurate.  */
+    if (den == 0)
+        raise_exception(EXCP_DIV0);
+    quot = (num | ((uint64_t)env->quadh << 32)) / den;
+    rem = (num | ((uint64_t)env->quadh << 32)) % den;
+    flags = 0;
+    /* Avoid using a PARAM1 of zero.  This breaks dyngen because it uses
+       the address of a symbol, and gcc knows symbols can't have address
+       zero.  */
+    if (quot > 0xffffffff)
+        flags |= CCF_V;
+    if (quot == 0)
+        flags |= CCF_Z;
+    else if ((int64_t)quot < 0)
+        flags |= CCF_N;
+    /* Don't modify destination if overflow occured.  */
+    if ((flags & CCF_V) == 0) {
+        env->div1 = quot;
+        env->div2 = rem;
+    }
+    env->cc_dest = flags;
+}
+
+void HELPER(divs64)(CPUState *env)
+{
+    int32_t num;
+    int32_t den;
+    int32_t quot;
+    int32_t rem;
+    int32_t flags;
+
+    num = env->div1;
+    den = env->div2;
+    if (den == 0)
+        raise_exception(EXCP_DIV0);
+    quot = (num | ((int64_t)env->quadh << 32)) / den;
+    rem = (num | ((int64_t)env->quadh << 32)) % den;
+    rem = num % den;
+    flags = 0;
+    if (quot != (int32_t)quot)
+        flags |= CCF_V;
+    if (quot == 0)
+        flags |= CCF_Z;
+    else if (quot < 0)
+        flags |= CCF_N;
+    /* Don't modify destination if overflow occured.  */
+    if ((flags & CCF_V) == 0) {
+        env->div1 = quot;
+        env->div2 = rem;
+    }
     env->cc_dest = flags;
 }
diff --git a/target-m68k/qregs.def b/target-m68k/qregs.def
index 49400c4..76e0236 100644
--- a/target-m68k/qregs.def
+++ b/target-m68k/qregs.def
@@ -7,6 +7,7 @@ DEFO32(CC_SRC, cc_src)
 DEFO32(CC_X, cc_x)
 DEFO32(DIV1, div1)
 DEFO32(DIV2, div2)
+DEFO32(QUADH, quadh)
 DEFO32(EXCEPTION, exception_index)
 DEFO32(HALTED, halted)
 DEFO32(MACSR, macsr)
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index c869cf9..d0e223c 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -1025,8 +1025,26 @@ DISAS_INSN(divl)
 
     ext = lduw_code(s->pc);
     s->pc += 2;
-    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(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_DIV2);
+        s->cc_op = CC_OP_FLAGS;
         return;
     }
     num = DREG(ext, 12);
@@ -1039,10 +1057,12 @@ DISAS_INSN(divl)
     } else {
         gen_helper_divu(cpu_env, tcg_const_i32(0));
     }
-    if ((ext & 7) == ((ext >> 12) & 7)) {
+    if (((ext & 7) == ((ext >> 12) & 7)) ||
+        m68k_feature(s->env, M68K_FEATURE_LONG_MULDIV)) {
         /* div */
         tcg_gen_mov_i32 (reg, QREG_DIV1);
-    } else {
+    }
+    if ((ext & 7) != ((ext >> 12) & 7)) {
         /* rem */
         tcg_gen_mov_i32 (reg, QREG_DIV2);
     }
@@ -3013,6 +3033,7 @@ void register_m68k_insns (CPUM68KState *env)
     INSN(illegal,   4afc, ffff, M68000);
     INSN(mull,      4c00, ffc0, CF_ISA_A);
     INSN(divl,      4c40, ffc0, CF_ISA_A);
+    INSN(divl,      4c40, ffc0, LONG_MULDIV);
     INSN(sats,      4c80, fff8, CF_ISA_B);
     INSN(trap,      4e40, fff0, CF_ISA_A);
     INSN(trap,      4e40, fff0, M68000);
-- 
1.5.6.5





reply via email to

[Prev in Thread] Current Thread [Next in Thread]