Patchwork [2/6] target-alpha: Split up FPCR value into separate fields.

login
register
mail settings
Submitter Richard Henderson
Date Dec. 31, 2009, 8:41 p.m.
Message ID <d6e7d7108cd62d7096122ea123f8e226de4c06dc.1262645165.git.rth@twiddle.net>
Download mbox | patch
Permalink /patch/42219/
State New
Headers show

Comments

Richard Henderson - Dec. 31, 2009, 8:41 p.m.
The fpcr_exc_status, fpcr_exc_mask, and fpcr_dyn_round fields
are stored in <softfloat.h> format for convenience during
regular execution.

Revert the addition of float_exception_mask to float_status,
added in ba0e276db4b51bd2255a5d5ff8902c70d32ade40.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 fpu/softfloat.h       |    1 -
 target-alpha/cpu.h    |   24 ++++++--
 target-alpha/helper.c |  167 +++++++++++++++++++++++++++++++++----------------
 3 files changed, 131 insertions(+), 61 deletions(-)

Patch

diff --git a/fpu/softfloat.h b/fpu/softfloat.h
index 9d82694..636591b 100644
--- a/fpu/softfloat.h
+++ b/fpu/softfloat.h
@@ -187,7 +187,6 @@  typedef struct float_status {
     signed char float_detect_tininess;
     signed char float_rounding_mode;
     signed char float_exception_flags;
-    signed char float_exception_mask;
 #ifdef FLOATX80
     signed char floatx80_rounding_precision;
 #endif
diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h
index c0dff4b..4722415 100644
--- a/target-alpha/cpu.h
+++ b/target-alpha/cpu.h
@@ -145,6 +145,10 @@  enum {
 #define FPCR_UNFD		(1ULL << 61)
 #define FPCR_UNDZ		(1ULL << 60)
 #define FPCR_DYN_SHIFT		58
+#define FPCR_DYN_CHOPPED	(0ULL << FPCR_DYN_SHIFT)
+#define FPCR_DYN_MINUS		(1ULL << FPCR_DYN_SHIFT)
+#define FPCR_DYN_NORMAL		(2ULL << FPCR_DYN_SHIFT)
+#define FPCR_DYN_PLUS		(3ULL << FPCR_DYN_SHIFT)
 #define FPCR_DYN_MASK		(3ULL << FPCR_DYN_SHIFT)
 #define FPCR_IOV		(1ULL << 57)
 #define FPCR_INE		(1ULL << 56)
@@ -341,17 +345,27 @@  struct pal_handler_t {
 
 struct CPUAlphaState {
     uint64_t ir[31];
-    float64  fir[31];
-    float_status fp_status;
-    uint64_t fpcr;
+    float64 fir[31];
     uint64_t pc;
     uint64_t lock;
     uint32_t pcc[2];
     uint64_t ipr[IPR_LAST];
     uint64_t ps;
     uint64_t unique;
-    int saved_mode; /* Used for HW_LD / HW_ST */
-    int intr_flag; /* For RC and RS */
+    float_status fp_status;
+    /* The following fields make up the FPCR, but in FP_STATUS format.  */
+    uint8_t fpcr_exc_status;
+    uint8_t fpcr_exc_mask;
+    uint8_t fpcr_dyn_round;
+    uint8_t fpcr_flush_to_zero;
+    uint8_t fpcr_dnz;
+    uint8_t fpcr_dnod;
+    uint8_t fpcr_undz;
+
+    /* Used for HW_LD / HW_ST */
+    uint8_t saved_mode;
+    /* For RC and RS */
+    uint8_t intr_flag;
 
 #if TARGET_LONG_BITS > HOST_LONG_BITS
     /* temporary fixed-point registers
diff --git a/target-alpha/helper.c b/target-alpha/helper.c
index be7d37b..57830e4 100644
--- a/target-alpha/helper.c
+++ b/target-alpha/helper.c
@@ -27,79 +27,136 @@ 
 
 uint64_t cpu_alpha_load_fpcr (CPUState *env)
 {
-    uint64_t ret = 0;
-    int flags, mask;
-
-    flags = env->fp_status.float_exception_flags;
-    ret |= (uint64_t) flags << 52;
-    if (flags)
-        ret |= FPCR_SUM;
-    env->ipr[IPR_EXC_SUM] &= ~0x3E;
-    env->ipr[IPR_EXC_SUM] |= flags << 1;
-
-    mask = env->fp_status.float_exception_mask;
-    if (mask & float_flag_invalid)
-        ret |= FPCR_INVD;
-    if (mask & float_flag_divbyzero)
-        ret |= FPCR_DZED;
-    if (mask & float_flag_overflow)
-        ret |= FPCR_OVFD;
-    if (mask & float_flag_underflow)
-        ret |= FPCR_UNFD;
-    if (mask & float_flag_inexact)
-        ret |= FPCR_INED;
-
-    switch (env->fp_status.float_rounding_mode) {
+    uint64_t r = 0;
+    uint8_t t;
+
+    t = env->fpcr_exc_status;
+    if (t) {
+        r = FPCR_SUM;
+        if (t & float_flag_invalid) {
+            r |= FPCR_INV;
+        }
+        if (t & float_flag_divbyzero) {
+            r |= FPCR_DZE;
+        }
+        if (t & float_flag_overflow) {
+            r |= FPCR_OVF;
+        }
+        if (t & float_flag_underflow) {
+            r |= FPCR_UNF;
+        }
+        if (t & float_flag_inexact) {
+            r |= FPCR_INE;
+        }
+    }
+
+    t = env->fpcr_exc_mask;
+    if (t & float_flag_invalid) {
+        r |= FPCR_INVD;
+    }
+    if (t & float_flag_divbyzero) {
+        r |= FPCR_DZED;
+    }
+    if (t & float_flag_overflow) {
+        r |= FPCR_OVFD;
+    }
+    if (t & float_flag_underflow) {
+        r |= FPCR_UNFD;
+    }
+    if (t & float_flag_inexact) {
+        r |= FPCR_INED;
+    }
+
+    switch (env->fpcr_dyn_round) {
     case float_round_nearest_even:
-        ret |= 2ULL << FPCR_DYN_SHIFT;
+        r |= FPCR_DYN_NORMAL;
         break;
     case float_round_down:
-        ret |= 1ULL << FPCR_DYN_SHIFT;
+        r |= FPCR_DYN_MINUS;
         break;
     case float_round_up:
-        ret |= 3ULL << FPCR_DYN_SHIFT;
+        r |= FPCR_DYN_PLUS;
         break;
     case float_round_to_zero:
+        r |= FPCR_DYN_CHOPPED;
         break;
     }
-    return ret;
+
+    if (env->fpcr_dnz) {
+        r |= FPCR_DNZ;
+    }
+    if (env->fpcr_dnod) {
+        r |= FPCR_DNOD;
+    }
+    if (env->fpcr_undz) {
+        r |= FPCR_UNDZ;
+    }
+
+    return r;
 }
 
 void cpu_alpha_store_fpcr (CPUState *env, uint64_t val)
 {
-    int round_mode, mask;
+    uint8_t t;
 
-    set_float_exception_flags((val >> 52) & 0x3F, &env->fp_status);
+    t = 0;
+    if (val & FPCR_INV) {
+        t |= float_flag_invalid;
+    }
+    if (val & FPCR_DZE) {
+        t |= float_flag_divbyzero;
+    }
+    if (val & FPCR_OVF) {
+        t |= float_flag_overflow;
+    }
+    if (val & FPCR_UNF) {
+        t |= float_flag_underflow;
+    }
+    if (val & FPCR_INE) {
+        t |= float_flag_inexact;
+    }
+    env->fpcr_exc_status = t;
 
-    mask = 0;
-    if (val & FPCR_INVD)
-        mask |= float_flag_invalid;
-    if (val & FPCR_DZED)
-        mask |= float_flag_divbyzero;
-    if (val & FPCR_OVFD)
-        mask |= float_flag_overflow;
-    if (val & FPCR_UNFD)
-        mask |= float_flag_underflow;
-    if (val & FPCR_INED)
-        mask |= float_flag_inexact;
-    env->fp_status.float_exception_mask = mask;
+    t = 0;
+    if (val & FPCR_INVD) {
+        t |= float_flag_invalid;
+    }
+    if (val & FPCR_DZED) {
+        t |= float_flag_divbyzero;
+    }
+    if (val & FPCR_OVFD) {
+        t |= float_flag_overflow;
+    }
+    if (val & FPCR_UNFD) {
+        t |= float_flag_underflow;
+    }
+    if (val & FPCR_INED) {
+        t |= float_flag_inexact;
+    }
+    env->fpcr_exc_mask = t;
 
-    switch ((val >> FPCR_DYN_SHIFT) & 3) {
-    case 0:
-        round_mode = float_round_to_zero;
+    switch (val & FPCR_DYN_MASK) {
+    case FPCR_DYN_CHOPPED:
+        t = float_round_to_zero;
         break;
-    case 1:
-        round_mode = float_round_down;
+    case FPCR_DYN_MINUS:
+        t = float_round_down;
         break;
-    case 2:
-        round_mode = float_round_nearest_even;
+    case FPCR_DYN_NORMAL:
+        t = float_round_nearest_even;
         break;
-    case 3:
-    default: /* this avoids a gcc (< 4.4) warning */
-        round_mode = float_round_up;
+    case FPCR_DYN_PLUS:
+        t = float_round_up;
         break;
     }
-    set_float_rounding_mode(round_mode, &env->fp_status);
+    env->fpcr_dyn_round = t;
+
+    env->fpcr_flush_to_zero
+      = (val & (FPCR_UNDZ|FPCR_UNFD)) == (FPCR_UNDZ|FPCR_UNFD);
+
+    env->fpcr_dnz = (val & FPCR_DNZ) != 0;
+    env->fpcr_dnod = (val & FPCR_DNOD) != 0;
+    env->fpcr_undz = (val & FPCR_UNDZ) != 0;
 }
 
 #if defined(CONFIG_USER_ONLY)