qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [PULL 055/130] target-ppc: Add ISA2.06 divde[o] Instruction


From: Alexander Graf
Subject: [Qemu-devel] [PULL 055/130] target-ppc: Add ISA2.06 divde[o] Instructions
Date: Fri, 7 Mar 2014 00:33:02 +0100

From: Tom Musta <address@hidden>

This patch adds the Divide Doubleword Extended instructions.
The implementation builds on the unsigned helper provided in
the previous patch.

Signed-off-by: Tom Musta <address@hidden>
Reviewed-by: Richard Henderson <address@hidden>
Signed-off-by: Alexander Graf <address@hidden>
---
 include/qemu/host-utils.h | 14 ++++++++++++++
 target-ppc/helper.h       |  1 +
 target-ppc/int_helper.c   | 23 +++++++++++++++++++++++
 target-ppc/translate.c    |  5 ++++-
 util/host-utils.c         | 37 +++++++++++++++++++++++++++++++++++++
 5 files changed, 79 insertions(+), 1 deletion(-)

diff --git a/include/qemu/host-utils.h b/include/qemu/host-utils.h
index 402b53f..d4f21c9 100644
--- a/include/qemu/host-utils.h
+++ b/include/qemu/host-utils.h
@@ -57,10 +57,24 @@ static inline int divu128(uint64_t *plow, uint64_t *phigh, 
uint64_t divisor)
         return result > UINT64_MAX;
     }
 }
+
+static inline int divs128(int64_t *plow, int64_t *phigh, int64_t divisor)
+{
+    if (divisor == 0) {
+        return 1;
+    } else {
+        __int128_t dividend = ((__int128_t)*phigh << 64) | *plow;
+        __int128_t result = dividend / divisor;
+        *plow = result;
+        *phigh = dividend % divisor;
+        return result != *plow;
+    }
+}
 #else
 void muls64(uint64_t *phigh, uint64_t *plow, int64_t a, int64_t b);
 void mulu64(uint64_t *phigh, uint64_t *plow, uint64_t a, uint64_t b);
 int divu128(uint64_t *plow, uint64_t *phigh, uint64_t divisor);
+int divs128(int64_t *plow, int64_t *phigh, int64_t divisor);
 #endif
 
 /**
diff --git a/target-ppc/helper.h b/target-ppc/helper.h
index 9865e17..a09a618 100644
--- a/target-ppc/helper.h
+++ b/target-ppc/helper.h
@@ -32,6 +32,7 @@ DEF_HELPER_5(lscbx, tl, env, tl, i32, i32, i32)
 #if defined(TARGET_PPC64)
 DEF_HELPER_3(mulldo, i64, env, i64, i64)
 DEF_HELPER_4(divdeu, i64, env, i64, i64, i32)
+DEF_HELPER_4(divde, i64, env, i64, i64, i32)
 #endif
 
 DEF_HELPER_FLAGS_1(cntlzw, TCG_CALL_NO_RWG_SE, tl, tl)
diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c
index 6f3d8fd..920dba7 100644
--- a/target-ppc/int_helper.c
+++ b/target-ppc/int_helper.c
@@ -65,6 +65,29 @@ uint64_t helper_divdeu(CPUPPCState *env, uint64_t ra, 
uint64_t rb, uint32_t oe)
     return rt;
 }
 
+uint64_t helper_divde(CPUPPCState *env, uint64_t rau, uint64_t rbu, uint32_t 
oe)
+{
+    int64_t rt = 0;
+    int64_t ra = (int64_t)rau;
+    int64_t rb = (int64_t)rbu;
+    int overflow = divs128(&rt, &ra, rb);
+
+    if (unlikely(overflow)) {
+        rt = 0; /* Undefined */
+    }
+
+    if (oe) {
+
+        if (unlikely(overflow)) {
+            env->so = env->ov = 1;
+        } else {
+            env->ov = 0;
+        }
+    }
+
+    return rt;
+}
+
 #endif
 
 
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 55f259b..7751b29 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -1049,7 +1049,8 @@ GEN_INT_ARITH_DIVD(divdo, 0x1F, 1, 1);
 
 GEN_DIVE(divdeu, divdeu, 0);
 GEN_DIVE(divdeuo, divdeu, 1);
-
+GEN_DIVE(divde, divde, 0);
+GEN_DIVE(divdeo, divde, 1);
 #endif
 
 /* mulhw  mulhw. */
@@ -9727,6 +9728,8 @@ GEN_INT_ARITH_DIVD(divdo, 0x1F, 1, 1),
 
 GEN_HANDLER_E(divdeu, 0x1F, 0x09, 0x0C, 0, PPC_NONE, PPC2_DIVE_ISA206),
 GEN_HANDLER_E(divdeuo, 0x1F, 0x09, 0x1C, 0, PPC_NONE, PPC2_DIVE_ISA206),
+GEN_HANDLER_E(divde, 0x1F, 0x09, 0x0D, 0, PPC_NONE, PPC2_DIVE_ISA206),
+GEN_HANDLER_E(divdeo, 0x1F, 0x09, 0x1D, 0, PPC_NONE, PPC2_DIVE_ISA206),
 
 #undef GEN_INT_ARITH_MUL_HELPER
 #define GEN_INT_ARITH_MUL_HELPER(name, opc3)                                  \
diff --git a/util/host-utils.c b/util/host-utils.c
index 37c1706..ee57ef5 100644
--- a/util/host-utils.c
+++ b/util/host-utils.c
@@ -124,4 +124,41 @@ int divu128(uint64_t *plow, uint64_t *phigh, uint64_t 
divisor)
         return 0;
     }
 }
+
+int divs128(int64_t *plow, int64_t *phigh, int64_t divisor)
+{
+    int sgn_dvdnd = *phigh < 0;
+    int sgn_divsr = divisor < 0;
+    int overflow = 0;
+
+    if (sgn_dvdnd) {
+        *plow = ~(*plow);
+        *phigh = ~(*phigh);
+        if (*plow == (int64_t)-1) {
+            *plow = 0;
+            (*phigh)++;
+         } else {
+            (*plow)++;
+         }
+    }
+
+    if (sgn_divsr) {
+        divisor = 0 - divisor;
+    }
+
+    overflow = divu128((uint64_t *)plow, (uint64_t *)phigh, (uint64_t)divisor);
+
+    if (sgn_dvdnd  ^ sgn_divsr) {
+        *plow = 0 - *plow;
+    }
+
+    if (!overflow) {
+        if ((*plow < 0) ^ (sgn_dvdnd ^ sgn_divsr)) {
+            overflow = 1;
+        }
+    }
+
+    return overflow;
+}
+
 #endif /* !CONFIG_INT128 */
-- 
1.8.1.4




reply via email to

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