qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [PATCH 051/111] m68k: correct divs.w and divu.w


From: Bryce Lanham
Subject: [Qemu-devel] [PATCH 051/111] m68k: correct divs.w and divu.w
Date: Wed, 17 Aug 2011 15:46:56 -0500

From: Laurent Vivier <address@hidden>

- the source register to be divided is a 32bit,
   so don't extend the 16bit value sign
- don't modify the destination operand on overflow
- don't modify N and Z flags on overflow
  (documentation says "undefined" but real 68040 is
   doing like this)

Signed-off-by: Laurent Vivier <address@hidden>
---
 target-m68k/op_helper.c |   46 ++++++++++++++++++++++++++--------------------
 target-m68k/translate.c |   26 +++++++++++++++++---------
 2 files changed, 43 insertions(+), 29 deletions(-)

diff --git a/target-m68k/op_helper.c b/target-m68k/op_helper.c
index a6c8148..c270259 100644
--- a/target-m68k/op_helper.c
+++ b/target-m68k/op_helper.c
@@ -213,17 +213,20 @@ void HELPER(divu)(CPUState *env, uint32_t word)
     /* 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 (word && quot > 0xffff)
-        flags |= CCF_V;
-    if (quot == 0)
-        flags |= CCF_Z;
-    else if ((int32_t)quot < 0)
-        flags |= CCF_N;
-    /* Don't modify destination if overflow occured.  */
-    if ((flags & CCF_V) == 0) {
-        env->div1 = quot;
-        env->div2 = rem;
+    if (word && quot > 0xffff) {
+       /* real 68040 keep Z and N on overflow,
+         * whereas documentation says "undefined"
+         */
+        flags |= CCF_V | (env->cc_dest & (CCF_Z|CCF_N));
+    } else {
+        if (quot == 0)
+            flags |= CCF_Z;
+        else if ((int16_t)quot < 0)
+            flags |= CCF_N;
     }
+
+    env->div1 = quot;
+    env->div2 = rem;
     env->cc_dest = flags;
 }
 
@@ -242,17 +245,20 @@ void HELPER(divs)(CPUState *env, uint32_t word)
     quot = num / den;
     rem = num % den;
     flags = 0;
-    if (word && quot != (int16_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;
+    if (word && quot != (int16_t)quot) {
+       /* real 68040 keep Z and N on overflow,
+         * whereas documentation says "undefined"
+         */
+        flags |= CCF_V | (env->cc_dest & (CCF_Z|CCF_N));
+    } else {
+        if (quot == 0)
+            flags |= CCF_Z;
+        else if ((int16_t)quot < 0)
+            flags |= CCF_N;
     }
+
+    env->div1 = quot;
+    env->div2 = rem;
     env->cc_dest = flags;
 }
 
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index f5e56bc..52da485 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -993,32 +993,40 @@ DISAS_INSN(mulw)
 
 DISAS_INSN(divw)
 {
-    TCGv reg;
+    TCGv dest;
     TCGv tmp;
     TCGv src;
     int sign;
+    int l1;
 
     sign = (insn & 0x100) != 0;
-    reg = DREG(insn, 9);
-    if (sign) {
-        tcg_gen_ext16s_i32(QREG_DIV1, reg);
-    } else {
-        tcg_gen_ext16u_i32(QREG_DIV1, reg);
-    }
+
+    /* dest.l / src.w */
+
+    dest = DREG(insn, 9);
+    tcg_gen_mov_i32(QREG_DIV1, dest);
+
     SRC_EA(src, OS_WORD, sign, NULL);
     tcg_gen_mov_i32(QREG_DIV2, src);
+
+    /* div1 / div2 */
+
     if (sign) {
         gen_helper_divs(cpu_env, tcg_const_i32(1));
     } else {
         gen_helper_divu(cpu_env, tcg_const_i32(1));
     }
 
+    s->cc_op = CC_OP_FLAGS;
+
+    l1 = gen_new_label();
+    gen_jmpcc(s, 9 /* V */, l1);
     tmp = tcg_temp_new();
     src = tcg_temp_new();
     tcg_gen_ext16u_i32(tmp, QREG_DIV1);
     tcg_gen_shli_i32(src, QREG_DIV2, 16);
-    tcg_gen_or_i32(reg, tmp, src);
-    s->cc_op = CC_OP_FLAGS;
+    tcg_gen_or_i32(dest, tmp, src);
+    gen_set_label(l1);
 }
 
 DISAS_INSN(divl)
-- 
1.7.2.3




reply via email to

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