soft float support
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Sun, 13 Mar 2005 18:50:23 +0000 (18:50 +0000)
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Sun, 13 Mar 2005 18:50:23 +0000 (18:50 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1337 c046a42c-6fe2-441c-8c8c-71466251a162

cpu-all.h
target-arm/cpu.h
target-arm/op.c
target-arm/op_helper.c

index afc9ae1..25f9cea 100644 (file)
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -119,7 +119,7 @@ static inline void tswap64s(uint64_t *s)
 /* NOTE: arm FPA is horrible as double 32 bit words are stored in big
    endian ! */
 typedef union {
-    double d;
+    float64 d;
 #if defined(WORDS_BIGENDIAN) || (defined(__arm__) && !defined(__VFP_FP__))
     struct {
         uint32_t upper;
@@ -268,27 +268,27 @@ static inline void stq_p(void *ptr, uint64_t v)
 
 /* float access */
 
-static inline float ldfl_p(void *ptr)
+static inline float32 ldfl_p(void *ptr)
 {
     union {
-        float f;
+        float32 f;
         uint32_t i;
     } u;
     u.i = ldl_p(ptr);
     return u.f;
 }
 
-static inline void stfl_p(void *ptr, float v)
+static inline void stfl_p(void *ptr, float32 v)
 {
     union {
-        float f;
+        float32 f;
         uint32_t i;
     } u;
     u.f = v;
     stl_p(ptr, u.i);
 }
 
-static inline double ldfq_p(void *ptr)
+static inline float64 ldfq_p(void *ptr)
 {
     CPU_DoubleU u;
     u.l.lower = ldl_p(ptr);
@@ -296,7 +296,7 @@ static inline double ldfq_p(void *ptr)
     return u.d;
 }
 
-static inline void stfq_p(void *ptr, double v)
+static inline void stfq_p(void *ptr, float64 v)
 {
     CPU_DoubleU u;
     u.d = v;
@@ -397,27 +397,27 @@ static inline void stq_p(void *ptr, uint64_t v)
 
 /* float access */
 
-static inline float ldfl_p(void *ptr)
+static inline float32 ldfl_p(void *ptr)
 {
     union {
-        float f;
+        float32 f;
         uint32_t i;
     } u;
     u.i = ldl_p(ptr);
     return u.f;
 }
 
-static inline void stfl_p(void *ptr, float v)
+static inline void stfl_p(void *ptr, float32 v)
 {
     union {
-        float f;
+        float32 f;
         uint32_t i;
     } u;
     u.f = v;
     stl_p(ptr, u.i);
 }
 
-static inline double ldfq_p(void *ptr)
+static inline float64 ldfq_p(void *ptr)
 {
     CPU_DoubleU u;
     u.l.upper = ldl_p(ptr);
@@ -425,7 +425,7 @@ static inline double ldfq_p(void *ptr)
     return u.d;
 }
 
-static inline void stfq_p(void *ptr, double v)
+static inline void stfq_p(void *ptr, float64 v)
 {
     CPU_DoubleU u;
     u.d = v;
@@ -472,24 +472,24 @@ static inline void stq_p(void *ptr, uint64_t v)
 
 /* float access */
 
-static inline float ldfl_p(void *ptr)
+static inline float32 ldfl_p(void *ptr)
 {
-    return *(float *)ptr;
+    return *(float32 *)ptr;
 }
 
-static inline double ldfq_p(void *ptr)
+static inline float64 ldfq_p(void *ptr)
 {
-    return *(double *)ptr;
+    return *(float64 *)ptr;
 }
 
-static inline void stfl_p(void *ptr, float v)
+static inline void stfl_p(void *ptr, float32 v)
 {
-    *(float *)ptr = v;
+    *(float32 *)ptr = v;
 }
 
-static inline void stfq_p(void *ptr, double v)
+static inline void stfq_p(void *ptr, float64 v)
 {
-    *(double *)ptr = v;
+    *(float64 *)ptr = v;
 }
 #endif
 
index a5f4f94..cf11c2f 100644 (file)
@@ -24,6 +24,8 @@
 
 #include "cpu-defs.h"
 
+#include "softfloat.h"
+
 #define EXCP_UDEF            1   /* undefined instruction */
 #define EXCP_SWI             2   /* software interrupt */
 #define EXCP_PREFETCH_ABORT  3
@@ -70,8 +72,8 @@ typedef struct CPUARMState {
     /* VFP coprocessor state.  */
     struct {
         union {
-            float s[32];
-            double d[16];
+            float32 s[32];
+            float64 d[16];
         } regs;
 
         /* We store these fpcsr fields separately for convenience.  */
@@ -81,9 +83,10 @@ typedef struct CPUARMState {
         uint32_t fpscr;
 
         /* Temporary variables if we don't have spare fp regs.  */
-        float tmp0s, tmp1s;
-        double tmp0d, tmp1d;
-
+        float32 tmp0s, tmp1s;
+        float64 tmp0d, tmp1d;
+        
+        float_status fp_status;
     } vfp;
 
     /* user data */
index 6c608f1..42ee4f9 100644 (file)
@@ -864,19 +864,19 @@ void OPPROTO op_undef_insn(void)
 
 #define VFP_OP(name, p) void OPPROTO op_vfp_##name##p(void)
 
-#define VFP_BINOP(name, op) \
+#define VFP_BINOP(name) \
 VFP_OP(name, s)             \
 {                           \
-    FT0s = FT0s op FT1s;    \
+    FT0s = float32_ ## name (FT0s, FT1s, &env->vfp.fp_status);    \
 }                           \
 VFP_OP(name, d)             \
 {                           \
-    FT0d = FT0d op FT1d;    \
+    FT0d = float64_ ## name (FT0d, FT1d, &env->vfp.fp_status);    \
 }
-VFP_BINOP(add, +)
-VFP_BINOP(sub, -)
-VFP_BINOP(mul, *)
-VFP_BINOP(div, /)
+VFP_BINOP(add)
+VFP_BINOP(sub)
+VFP_BINOP(mul)
+VFP_BINOP(div)
 #undef VFP_BINOP
 
 #define VFP_HELPER(name)  \
@@ -898,41 +898,51 @@ VFP_HELPER(cmpe)
    without looking at the rest of the value.  */
 VFP_OP(neg, s)
 {
-    FT0s = -FT0s;
+    FT0s = float32_chs(FT0s);
 }
 
 VFP_OP(neg, d)
 {
-    FT0d = -FT0d;
+    FT0d = float64_chs(FT0d);
 }
 
 VFP_OP(F1_ld0, s)
 {
-    FT1s = 0.0f;
+    union {
+        uint32_t i;
+        float32 s;
+    } v;
+    v.i = 0;
+    FT1s = v.s;
 }
 
 VFP_OP(F1_ld0, d)
 {
-    FT1d = 0.0;
+    union {
+        uint64_t i;
+        float64 d;
+    } v;
+    v.i = 0;
+    FT1d = v.d;
 }
 
 /* Helper routines to perform bitwise copies between float and int.  */
-static inline float vfp_itos(uint32_t i)
+static inline float32 vfp_itos(uint32_t i)
 {
     union {
         uint32_t i;
-        float s;
+        float32 s;
     } v;
 
     v.i = i;
     return v.s;
 }
 
-static inline uint32_t vfp_stoi(float s)
+static inline uint32_t vfp_stoi(float32 s)
 {
     union {
         uint32_t i;
-        float s;
+        float32 s;
     } v;
 
     v.s = s;
@@ -942,111 +952,106 @@ static inline uint32_t vfp_stoi(float s)
 /* Integer to float conversion.  */
 VFP_OP(uito, s)
 {
-    FT0s = (float)(uint32_t)vfp_stoi(FT0s);
+    FT0s = uint32_to_float32(vfp_stoi(FT0s), &env->vfp.fp_status);
 }
 
 VFP_OP(uito, d)
 {
-    FT0d = (double)(uint32_t)vfp_stoi(FT0s);
+    FT0d = uint32_to_float64(vfp_stoi(FT0s), &env->vfp.fp_status);
 }
 
 VFP_OP(sito, s)
 {
-    FT0s = (float)(int32_t)vfp_stoi(FT0s);
+    FT0s = int32_to_float32(vfp_stoi(FT0s), &env->vfp.fp_status);
 }
 
 VFP_OP(sito, d)
 {
-    FT0d = (double)(int32_t)vfp_stoi(FT0s);
+    FT0d = int32_to_float64(vfp_stoi(FT0s), &env->vfp.fp_status);
 }
 
 /* Float to integer conversion.  */
 VFP_OP(toui, s)
 {
-    FT0s = vfp_itos((uint32_t)FT0s);
+    FT0s = vfp_itos(float32_to_uint32(FT0s, &env->vfp.fp_status));
 }
 
 VFP_OP(toui, d)
 {
-    FT0s = vfp_itos((uint32_t)FT0d);
+    FT0s = vfp_itos(float64_to_uint32(FT0d, &env->vfp.fp_status));
 }
 
 VFP_OP(tosi, s)
 {
-    FT0s = vfp_itos((int32_t)FT0s);
+    FT0s = vfp_itos(float32_to_int32(FT0s, &env->vfp.fp_status));
 }
 
 VFP_OP(tosi, d)
 {
-    FT0s = vfp_itos((int32_t)FT0d);
+    FT0s = vfp_itos(float64_to_int32(FT0d, &env->vfp.fp_status));
 }
 
 /* TODO: Set rounding mode properly.  */
 VFP_OP(touiz, s)
 {
-    FT0s = vfp_itos((uint32_t)FT0s);
+    FT0s = vfp_itos(float32_to_uint32_round_to_zero(FT0s, &env->vfp.fp_status));
 }
 
 VFP_OP(touiz, d)
 {
-    FT0s = vfp_itos((uint32_t)FT0d);
+    FT0s = vfp_itos(float64_to_uint32_round_to_zero(FT0d, &env->vfp.fp_status));
 }
 
 VFP_OP(tosiz, s)
 {
-    FT0s = vfp_itos((int32_t)FT0s);
+    FT0s = vfp_itos(float32_to_int32_round_to_zero(FT0s, &env->vfp.fp_status));
 }
 
 VFP_OP(tosiz, d)
 {
-    FT0s = vfp_itos((int32_t)FT0d);
+    FT0s = vfp_itos(float64_to_int32_round_to_zero(FT0d, &env->vfp.fp_status));
 }
 
 /* floating point conversion */
 VFP_OP(fcvtd, s)
 {
-    FT0d = (double)FT0s;
+    FT0d = float32_to_float64(FT0s, &env->vfp.fp_status);
 }
 
 VFP_OP(fcvts, d)
 {
-    FT0s = (float)FT0d;
+    FT0s = float64_to_float32(FT0d, &env->vfp.fp_status);
 }
 
 /* Get and Put values from registers.  */
 VFP_OP(getreg_F0, d)
 {
-  FT0d = *(double *)((char *) env + PARAM1);
+  FT0d = *(float64 *)((char *) env + PARAM1);
 }
 
 VFP_OP(getreg_F0, s)
 {
-  FT0s = *(float *)((char *) env + PARAM1);
+  FT0s = *(float32 *)((char *) env + PARAM1);
 }
 
 VFP_OP(getreg_F1, d)
 {
-  FT1d = *(double *)((char *) env + PARAM1);
+  FT1d = *(float64 *)((char *) env + PARAM1);
 }
 
 VFP_OP(getreg_F1, s)
 {
-  FT1s = *(float *)((char *) env + PARAM1);
+  FT1s = *(float32 *)((char *) env + PARAM1);
 }
 
 VFP_OP(setreg_F0, d)
 {
-  *(double *)((char *) env + PARAM1) = FT0d;
+  *(float64 *)((char *) env + PARAM1) = FT0d;
 }
 
 VFP_OP(setreg_F0, s)
 {
-  *(float *)((char *) env + PARAM1) = FT0s;
-}
-
-VFP_OP(foobar, d)
-{
-  FT0d = env->vfp.regs.s[3];
+  *(float32 *)((char *) env + PARAM1) = FT0s;
 }
 
 void OPPROTO op_vfp_movl_T0_fpscr(void)
index 38c97fe..a39e44a 100644 (file)
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-
-#include <math.h>
-#include <fenv.h>
 #include "exec.h"
 
-/* If the host doesn't define C99 math intrinsics then use the normal
-   operators.  This may generate excess exceptions, but it's probably
-   near enough for most things.  */
-#ifndef isless
-#define isless(x, y) (x < y)
-#endif
-#ifndef isgreater
-#define isgreater(x, y) (x > y)
-#endif
-#ifndef isunordered
-#define isunordered(x, y) (!((x < y) || (x >= y)))
-#endif
-
 void raise_exception(int tt)
 {
     env->exception_index = tt;
@@ -59,119 +43,88 @@ void cpu_unlock(void)
 
 void do_vfp_abss(void)
 {
-  FT0s = fabsf(FT0s);
+    FT0s = float32_abs(FT0s);
 }
 
 void do_vfp_absd(void)
 {
-  FT0d = fabs(FT0d);
+    FT0d = float64_abs(FT0d);
 }
 
 void do_vfp_sqrts(void)
 {
-  FT0s = sqrtf(FT0s);
+    FT0s = float32_sqrt(FT0s, &env->vfp.fp_status);
 }
 
 void do_vfp_sqrtd(void)
 {
-  FT0d = sqrt(FT0d);
+    FT0d = float64_sqrt(FT0d, &env->vfp.fp_status);
 }
 
-/* We use an == operator first to generate teh correct floating point
-   exception.  Subsequent comparisons use the exception-safe macros.  */
-#define DO_VFP_cmp(p)                     \
+/* XXX: check quiet/signaling case */
+#define DO_VFP_cmp(p, size)               \
 void do_vfp_cmp##p(void)                  \
 {                                         \
     uint32_t flags;                       \
-    if (FT0##p == FT1##p)                 \
-        flags = 0xc;                      \
-    else if (isless (FT0##p, FT1##p))     \
-        flags = 0x8;                      \
-    else if (isgreater (FT0##p, FT1##p))  \
-        flags = 0x2;                      \
-    else /* unordered */                  \
-        flags = 0x3;                      \
+    switch(float ## size ## _compare_quiet(FT0##p, FT1##p, &env->vfp.fp_status)) {\
+    case 0: flags = 0xc; break;\
+    case -1: flags = 0x8; break;\
+    case 1: flags = 0x2; break;\
+    default: case 2: flags = 0x3; break;\
+    }\
     env->vfp.fpscr = (flags << 28) | (env->vfp.fpscr & 0x0fffffff); \
     FORCE_RET();                          \
-}
-DO_VFP_cmp(s)
-DO_VFP_cmp(d)
-#undef DO_VFP_cmp
-
-/* We use a > operator first to get FP exceptions right.  */
-#define DO_VFP_cmpe(p)                      \
+}\
+\
 void do_vfp_cmpe##p(void)                   \
 {                                           \
-    uint32_t flags;                         \
-    if (FT0##p > FT1##p)                    \
-        flags = 0x2;                        \
-    else if (isless (FT0##p, FT1##p))       \
-        flags = 0x8;                        \
-    else if (isunordered (FT0##p, FT1##p))  \
-        flags = 0x3;                        \
-    else /* equal */                        \
-        flags = 0xc;                        \
+    uint32_t flags;                       \
+    switch(float ## size ## _compare(FT0##p, FT1##p, &env->vfp.fp_status)) {\
+    case 0: flags = 0xc; break;\
+    case -1: flags = 0x8; break;\
+    case 1: flags = 0x2; break;\
+    default: case 2: flags = 0x3; break;\
+    }\
     env->vfp.fpscr = (flags << 28) | (env->vfp.fpscr & 0x0fffffff); \
-    FORCE_RET();                            \
+    FORCE_RET();                          \
 }
-DO_VFP_cmpe(s)
-DO_VFP_cmpe(d)
-#undef DO_VFP_cmpe
+DO_VFP_cmp(s, 32)
+DO_VFP_cmp(d, 64)
+#undef DO_VFP_cmp
 
 /* Convert host exception flags to vfp form.  */
-int vfp_exceptbits_from_host(int host_bits)
+static inline int vfp_exceptbits_from_host(int host_bits)
 {
     int target_bits = 0;
 
-#ifdef FE_INVALID
-    if (host_bits & FE_INVALID)
+    if (host_bits & float_flag_invalid)
         target_bits |= 1;
-#endif
-#ifdef FE_DIVBYZERO
-    if (host_bits & FE_DIVBYZERO)
+    if (host_bits & float_flag_divbyzero)
         target_bits |= 2;
-#endif
-#ifdef FE_OVERFLOW
-    if (host_bits & FE_OVERFLOW)
+    if (host_bits & float_flag_overflow)
         target_bits |= 4;
-#endif
-#ifdef FE_UNDERFLOW
-    if (host_bits & FE_UNDERFLOW)
+    if (host_bits & float_flag_underflow)
         target_bits |= 8;
-#endif
-#ifdef FE_INEXACT
-    if (host_bits & FE_INEXACT)
+    if (host_bits & float_flag_inexact)
         target_bits |= 0x10;
-#endif
-    /* C doesn't define an inexact exception.  */
     return target_bits;
 }
 
 /* Convert vfp exception flags to target form.  */
-int vfp_host_exceptbits_to_host(int target_bits)
+static inline int vfp_exceptbits_to_host(int target_bits)
 {
     int host_bits = 0;
 
-#ifdef FE_INVALID
     if (target_bits & 1)
-        host_bits |= FE_INVALID;
-#endif
-#ifdef FE_DIVBYZERO
+        host_bits |= float_flag_invalid;
     if (target_bits & 2)
-        host_bits |= FE_DIVBYZERO;
-#endif
-#ifdef FE_OVERFLOW
+        host_bits |= float_flag_divbyzero;
     if (target_bits & 4)
-        host_bits |= FE_OVERFLOW;
-#endif
-#ifdef FE_UNDERFLOW
+        host_bits |= float_flag_overflow;
     if (target_bits & 8)
-        host_bits |= FE_UNDERFLOW;
-#endif
-#ifdef FE_INEXACT
+        host_bits |= float_flag_underflow;
     if (target_bits & 0x10)
-        host_bits |= FE_INEXACT;
-#endif
+        host_bits |= float_flag_inexact;
     return host_bits;
 }
 
@@ -190,31 +143,23 @@ void do_vfp_set_fpscr(void)
         i = (T0 >> 22) & 3;
         switch (i) {
         case 0:
-            i = FE_TONEAREST;
+            i = float_round_nearest_even;
             break;
         case 1:
-            i = FE_UPWARD;
+            i = float_round_up;
             break;
         case 2:
-            i = FE_DOWNWARD;
+            i = float_round_down;
             break;
         case 3:
-            i = FE_TOWARDZERO;
+            i = float_round_to_zero;
             break;
         }
-        fesetround (i);
+        set_float_rounding_mode(i, &env->vfp.fp_status);
     }
 
-    /* Clear host exception flags.  */
-    feclearexcept(FE_ALL_EXCEPT);
-
-#ifdef feenableexcept
-    if (changed & 0x1f00) {
-        i = vfp_exceptbits_to_host((T0 >> 8) & 0x1f);
-        feenableexcept (i);
-        fedisableexcept (FE_ALL_EXCEPT & ~i);
-    }
-#endif
+    i = vfp_exceptbits_to_host((T0 >> 8) & 0x1f);
+    set_float_exception_flags(i, &env->vfp.fp_status);
     /* XXX: FZ and DN are not implemented.  */
 }
 
@@ -224,6 +169,6 @@ void do_vfp_get_fpscr(void)
 
     T0 = (env->vfp.fpscr & 0xffc8ffff) | (env->vfp.vec_len << 16)
           | (env->vfp.vec_stride << 20);
-    i = fetestexcept(FE_ALL_EXCEPT);
+    i = get_float_exception_flags(&env->vfp.fp_status);
     T0 |= vfp_exceptbits_from_host(i);
 }