qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [PATCH 030/126] target-s390: Send signals for divide


From: Richard Henderson
Subject: [Qemu-devel] [PATCH 030/126] target-s390: Send signals for divide
Date: Sun, 9 Sep 2012 14:04:48 -0700

Signed-off-by: Richard Henderson <address@hidden>
---
 target-s390x/cpu.h         |  2 ++
 target-s390x/int_helper.c  | 51 ++++++++++++++++++++++++++++++++++++++++------
 target-s390x/misc_helper.c | 22 ++++++++++++++++++++
 3 files changed, 69 insertions(+), 6 deletions(-)

diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
index 52ab5ea..7d89a6f 100644
--- a/target-s390x/cpu.h
+++ b/target-s390x/cpu.h
@@ -934,5 +934,7 @@ uint32_t set_cc_nz_f64(float64 v);
 
 /* misc_helper.c */
 void program_interrupt(CPUS390XState *env, uint32_t code, int ilc);
+void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp,
+                                     uintptr_t retaddr);
 
 #endif
diff --git a/target-s390x/int_helper.c b/target-s390x/int_helper.c
index fe1cb87..f2f420c 100644
--- a/target-s390x/int_helper.c
+++ b/target-s390x/int_helper.c
@@ -38,22 +38,54 @@ uint64_t HELPER(mul128)(CPUS390XState *env, uint64_t v1, 
uint64_t v2)
 }
 
 /* 64/32 -> 32 signed division */
-int64_t HELPER(divs32)(CPUS390XState *env, int64_t a, int64_t b)
+int64_t HELPER(divs32)(CPUS390XState *env, int64_t a, int64_t b64)
 {
-    env->retxl = a % (int32_t)b;
-    return a / (int32_t)b;
+    int32_t ret, b = b64;
+    int64_t q;
+
+    if (b == 0) {
+        runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC());
+    }
+
+    ret = q = a / b;
+    env->retxl = a % b;
+
+    /* Catch non-representable quotient.  */
+    if (ret != q) {
+        runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC());
+    }
+
+    return ret;
 }
 
 /* 64/32 -> 32 unsigned division */
-uint64_t HELPER(divu32)(CPUS390XState *env, uint64_t a, uint64_t b)
+uint64_t HELPER(divu32)(CPUS390XState *env, uint64_t a, uint64_t b64)
 {
-    env->retxl = a % (uint32_t)b;
-    return a / (uint32_t)b;
+    uint32_t ret, b = b64;
+    uint64_t q;
+
+    if (b == 0) {
+        runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC());
+    }
+
+    ret = q = a / b;
+    env->retxl = a % b;
+
+    /* Catch non-representable quotient.  */
+    if (ret != q) {
+        runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC());
+    }
+
+    return ret;
 }
 
 /* 64/64 -> 64 signed division */
 int64_t HELPER(divs64)(CPUS390XState *env, int64_t a, int64_t b)
 {
+    /* Catch divide by zero, and non-representable quotient (MIN / -1).  */
+    if (b == 0 || (b == -1 && a == (1ll << 63))) {
+        runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC());
+    }
     env->retxl = a % b;
     return a / b;
 }
@@ -63,6 +95,10 @@ uint64_t HELPER(divu64)(CPUS390XState *env, uint64_t ah, 
uint64_t al,
                         uint64_t b)
 {
     uint64_t ret;
+    /* Signal divide by zero.  */
+    if (b == 0) {
+        runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC());
+    }
     if (ah == 0) {
         /* 64 -> 64/64 case */
         env->retxl = al % b;
@@ -75,6 +111,9 @@ uint64_t HELPER(divu64)(CPUS390XState *env, uint64_t ah, 
uint64_t al,
         __uint128_t q = a / b;
         env->retxl = a % b;
         ret = q;
+        if (ret != q) {
+            runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC());
+        }
 #else
         /* 32-bit hosts would need special wrapper functionality - just abort 
if
            we encounter such a case; it's very unlikely anyways. */
diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c
index 1502f15..32b75f2 100644
--- a/target-s390x/misc_helper.c
+++ b/target-s390x/misc_helper.c
@@ -69,6 +69,28 @@
     do { } while (0)
 #endif
 
+void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp,
+                                     uintptr_t retaddr)
+{
+    TranslationBlock *tb;
+    int t;
+
+    env->exception_index = EXCP_PGM;
+    env->int_pgm_code = excp;
+
+    /* Use the (ultimate) callers address to find the insn that trapped.  */
+    tb = tb_find_pc(retaddr);
+    assert(tb != NULL);
+    cpu_restore_state(tb, env, retaddr);
+
+    /* Advance past the insn.  */
+    t = cpu_ldub_code(env, env->psw.addr);
+    env->int_pgm_ilc = t = get_ilc(t);
+    env->psw.addr += 2 * t;
+
+    cpu_loop_exit(env);
+}
+
 void HELPER(exception)(CPUS390XState *env, uint32_t excp)
 {
     HELPER_LOG("%s: exception %d\n", __func__, excp);
-- 
1.7.11.4




reply via email to

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