Commit 53cd6637924a83481038b2266c59dc1e1ff7bb11

Authored by bellard
1 parent 7a0e1f41

soft float support


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1337 c046a42c-6fe2-441c-8c8c-71466251a162
cpu-all.h
... ... @@ -119,7 +119,7 @@ static inline void tswap64s(uint64_t *s)
119 119 /* NOTE: arm FPA is horrible as double 32 bit words are stored in big
120 120 endian ! */
121 121 typedef union {
122   - double d;
  122 + float64 d;
123 123 #if defined(WORDS_BIGENDIAN) || (defined(__arm__) && !defined(__VFP_FP__))
124 124 struct {
125 125 uint32_t upper;
... ... @@ -268,27 +268,27 @@ static inline void stq_p(void *ptr, uint64_t v)
268 268  
269 269 /* float access */
270 270  
271   -static inline float ldfl_p(void *ptr)
  271 +static inline float32 ldfl_p(void *ptr)
272 272 {
273 273 union {
274   - float f;
  274 + float32 f;
275 275 uint32_t i;
276 276 } u;
277 277 u.i = ldl_p(ptr);
278 278 return u.f;
279 279 }
280 280  
281   -static inline void stfl_p(void *ptr, float v)
  281 +static inline void stfl_p(void *ptr, float32 v)
282 282 {
283 283 union {
284   - float f;
  284 + float32 f;
285 285 uint32_t i;
286 286 } u;
287 287 u.f = v;
288 288 stl_p(ptr, u.i);
289 289 }
290 290  
291   -static inline double ldfq_p(void *ptr)
  291 +static inline float64 ldfq_p(void *ptr)
292 292 {
293 293 CPU_DoubleU u;
294 294 u.l.lower = ldl_p(ptr);
... ... @@ -296,7 +296,7 @@ static inline double ldfq_p(void *ptr)
296 296 return u.d;
297 297 }
298 298  
299   -static inline void stfq_p(void *ptr, double v)
  299 +static inline void stfq_p(void *ptr, float64 v)
300 300 {
301 301 CPU_DoubleU u;
302 302 u.d = v;
... ... @@ -397,27 +397,27 @@ static inline void stq_p(void *ptr, uint64_t v)
397 397  
398 398 /* float access */
399 399  
400   -static inline float ldfl_p(void *ptr)
  400 +static inline float32 ldfl_p(void *ptr)
401 401 {
402 402 union {
403   - float f;
  403 + float32 f;
404 404 uint32_t i;
405 405 } u;
406 406 u.i = ldl_p(ptr);
407 407 return u.f;
408 408 }
409 409  
410   -static inline void stfl_p(void *ptr, float v)
  410 +static inline void stfl_p(void *ptr, float32 v)
411 411 {
412 412 union {
413   - float f;
  413 + float32 f;
414 414 uint32_t i;
415 415 } u;
416 416 u.f = v;
417 417 stl_p(ptr, u.i);
418 418 }
419 419  
420   -static inline double ldfq_p(void *ptr)
  420 +static inline float64 ldfq_p(void *ptr)
421 421 {
422 422 CPU_DoubleU u;
423 423 u.l.upper = ldl_p(ptr);
... ... @@ -425,7 +425,7 @@ static inline double ldfq_p(void *ptr)
425 425 return u.d;
426 426 }
427 427  
428   -static inline void stfq_p(void *ptr, double v)
  428 +static inline void stfq_p(void *ptr, float64 v)
429 429 {
430 430 CPU_DoubleU u;
431 431 u.d = v;
... ... @@ -472,24 +472,24 @@ static inline void stq_p(void *ptr, uint64_t v)
472 472  
473 473 /* float access */
474 474  
475   -static inline float ldfl_p(void *ptr)
  475 +static inline float32 ldfl_p(void *ptr)
476 476 {
477   - return *(float *)ptr;
  477 + return *(float32 *)ptr;
478 478 }
479 479  
480   -static inline double ldfq_p(void *ptr)
  480 +static inline float64 ldfq_p(void *ptr)
481 481 {
482   - return *(double *)ptr;
  482 + return *(float64 *)ptr;
483 483 }
484 484  
485   -static inline void stfl_p(void *ptr, float v)
  485 +static inline void stfl_p(void *ptr, float32 v)
486 486 {
487   - *(float *)ptr = v;
  487 + *(float32 *)ptr = v;
488 488 }
489 489  
490   -static inline void stfq_p(void *ptr, double v)
  490 +static inline void stfq_p(void *ptr, float64 v)
491 491 {
492   - *(double *)ptr = v;
  492 + *(float64 *)ptr = v;
493 493 }
494 494 #endif
495 495  
... ...
target-arm/cpu.h
... ... @@ -24,6 +24,8 @@
24 24  
25 25 #include "cpu-defs.h"
26 26  
  27 +#include "softfloat.h"
  28 +
27 29 #define EXCP_UDEF 1 /* undefined instruction */
28 30 #define EXCP_SWI 2 /* software interrupt */
29 31 #define EXCP_PREFETCH_ABORT 3
... ... @@ -70,8 +72,8 @@ typedef struct CPUARMState {
70 72 /* VFP coprocessor state. */
71 73 struct {
72 74 union {
73   - float s[32];
74   - double d[16];
  75 + float32 s[32];
  76 + float64 d[16];
75 77 } regs;
76 78  
77 79 /* We store these fpcsr fields separately for convenience. */
... ... @@ -81,9 +83,10 @@ typedef struct CPUARMState {
81 83 uint32_t fpscr;
82 84  
83 85 /* Temporary variables if we don't have spare fp regs. */
84   - float tmp0s, tmp1s;
85   - double tmp0d, tmp1d;
86   -
  86 + float32 tmp0s, tmp1s;
  87 + float64 tmp0d, tmp1d;
  88 +
  89 + float_status fp_status;
87 90 } vfp;
88 91  
89 92 /* user data */
... ...
target-arm/op.c
... ... @@ -864,19 +864,19 @@ void OPPROTO op_undef_insn(void)
864 864  
865 865 #define VFP_OP(name, p) void OPPROTO op_vfp_##name##p(void)
866 866  
867   -#define VFP_BINOP(name, op) \
  867 +#define VFP_BINOP(name) \
868 868 VFP_OP(name, s) \
869 869 { \
870   - FT0s = FT0s op FT1s; \
  870 + FT0s = float32_ ## name (FT0s, FT1s, &env->vfp.fp_status); \
871 871 } \
872 872 VFP_OP(name, d) \
873 873 { \
874   - FT0d = FT0d op FT1d; \
  874 + FT0d = float64_ ## name (FT0d, FT1d, &env->vfp.fp_status); \
875 875 }
876   -VFP_BINOP(add, +)
877   -VFP_BINOP(sub, -)
878   -VFP_BINOP(mul, *)
879   -VFP_BINOP(div, /)
  876 +VFP_BINOP(add)
  877 +VFP_BINOP(sub)
  878 +VFP_BINOP(mul)
  879 +VFP_BINOP(div)
880 880 #undef VFP_BINOP
881 881  
882 882 #define VFP_HELPER(name) \
... ... @@ -898,41 +898,51 @@ VFP_HELPER(cmpe)
898 898 without looking at the rest of the value. */
899 899 VFP_OP(neg, s)
900 900 {
901   - FT0s = -FT0s;
  901 + FT0s = float32_chs(FT0s);
902 902 }
903 903  
904 904 VFP_OP(neg, d)
905 905 {
906   - FT0d = -FT0d;
  906 + FT0d = float64_chs(FT0d);
907 907 }
908 908  
909 909 VFP_OP(F1_ld0, s)
910 910 {
911   - FT1s = 0.0f;
  911 + union {
  912 + uint32_t i;
  913 + float32 s;
  914 + } v;
  915 + v.i = 0;
  916 + FT1s = v.s;
912 917 }
913 918  
914 919 VFP_OP(F1_ld0, d)
915 920 {
916   - FT1d = 0.0;
  921 + union {
  922 + uint64_t i;
  923 + float64 d;
  924 + } v;
  925 + v.i = 0;
  926 + FT1d = v.d;
917 927 }
918 928  
919 929 /* Helper routines to perform bitwise copies between float and int. */
920   -static inline float vfp_itos(uint32_t i)
  930 +static inline float32 vfp_itos(uint32_t i)
921 931 {
922 932 union {
923 933 uint32_t i;
924   - float s;
  934 + float32 s;
925 935 } v;
926 936  
927 937 v.i = i;
928 938 return v.s;
929 939 }
930 940  
931   -static inline uint32_t vfp_stoi(float s)
  941 +static inline uint32_t vfp_stoi(float32 s)
932 942 {
933 943 union {
934 944 uint32_t i;
935   - float s;
  945 + float32 s;
936 946 } v;
937 947  
938 948 v.s = s;
... ... @@ -942,111 +952,106 @@ static inline uint32_t vfp_stoi(float s)
942 952 /* Integer to float conversion. */
943 953 VFP_OP(uito, s)
944 954 {
945   - FT0s = (float)(uint32_t)vfp_stoi(FT0s);
  955 + FT0s = uint32_to_float32(vfp_stoi(FT0s), &env->vfp.fp_status);
946 956 }
947 957  
948 958 VFP_OP(uito, d)
949 959 {
950   - FT0d = (double)(uint32_t)vfp_stoi(FT0s);
  960 + FT0d = uint32_to_float64(vfp_stoi(FT0s), &env->vfp.fp_status);
951 961 }
952 962  
953 963 VFP_OP(sito, s)
954 964 {
955   - FT0s = (float)(int32_t)vfp_stoi(FT0s);
  965 + FT0s = int32_to_float32(vfp_stoi(FT0s), &env->vfp.fp_status);
956 966 }
957 967  
958 968 VFP_OP(sito, d)
959 969 {
960   - FT0d = (double)(int32_t)vfp_stoi(FT0s);
  970 + FT0d = int32_to_float64(vfp_stoi(FT0s), &env->vfp.fp_status);
961 971 }
962 972  
963 973 /* Float to integer conversion. */
964 974 VFP_OP(toui, s)
965 975 {
966   - FT0s = vfp_itos((uint32_t)FT0s);
  976 + FT0s = vfp_itos(float32_to_uint32(FT0s, &env->vfp.fp_status));
967 977 }
968 978  
969 979 VFP_OP(toui, d)
970 980 {
971   - FT0s = vfp_itos((uint32_t)FT0d);
  981 + FT0s = vfp_itos(float64_to_uint32(FT0d, &env->vfp.fp_status));
972 982 }
973 983  
974 984 VFP_OP(tosi, s)
975 985 {
976   - FT0s = vfp_itos((int32_t)FT0s);
  986 + FT0s = vfp_itos(float32_to_int32(FT0s, &env->vfp.fp_status));
977 987 }
978 988  
979 989 VFP_OP(tosi, d)
980 990 {
981   - FT0s = vfp_itos((int32_t)FT0d);
  991 + FT0s = vfp_itos(float64_to_int32(FT0d, &env->vfp.fp_status));
982 992 }
983 993  
984 994 /* TODO: Set rounding mode properly. */
985 995 VFP_OP(touiz, s)
986 996 {
987   - FT0s = vfp_itos((uint32_t)FT0s);
  997 + FT0s = vfp_itos(float32_to_uint32_round_to_zero(FT0s, &env->vfp.fp_status));
988 998 }
989 999  
990 1000 VFP_OP(touiz, d)
991 1001 {
992   - FT0s = vfp_itos((uint32_t)FT0d);
  1002 + FT0s = vfp_itos(float64_to_uint32_round_to_zero(FT0d, &env->vfp.fp_status));
993 1003 }
994 1004  
995 1005 VFP_OP(tosiz, s)
996 1006 {
997   - FT0s = vfp_itos((int32_t)FT0s);
  1007 + FT0s = vfp_itos(float32_to_int32_round_to_zero(FT0s, &env->vfp.fp_status));
998 1008 }
999 1009  
1000 1010 VFP_OP(tosiz, d)
1001 1011 {
1002   - FT0s = vfp_itos((int32_t)FT0d);
  1012 + FT0s = vfp_itos(float64_to_int32_round_to_zero(FT0d, &env->vfp.fp_status));
1003 1013 }
1004 1014  
1005 1015 /* floating point conversion */
1006 1016 VFP_OP(fcvtd, s)
1007 1017 {
1008   - FT0d = (double)FT0s;
  1018 + FT0d = float32_to_float64(FT0s, &env->vfp.fp_status);
1009 1019 }
1010 1020  
1011 1021 VFP_OP(fcvts, d)
1012 1022 {
1013   - FT0s = (float)FT0d;
  1023 + FT0s = float64_to_float32(FT0d, &env->vfp.fp_status);
1014 1024 }
1015 1025  
1016 1026 /* Get and Put values from registers. */
1017 1027 VFP_OP(getreg_F0, d)
1018 1028 {
1019   - FT0d = *(double *)((char *) env + PARAM1);
  1029 + FT0d = *(float64 *)((char *) env + PARAM1);
1020 1030 }
1021 1031  
1022 1032 VFP_OP(getreg_F0, s)
1023 1033 {
1024   - FT0s = *(float *)((char *) env + PARAM1);
  1034 + FT0s = *(float32 *)((char *) env + PARAM1);
1025 1035 }
1026 1036  
1027 1037 VFP_OP(getreg_F1, d)
1028 1038 {
1029   - FT1d = *(double *)((char *) env + PARAM1);
  1039 + FT1d = *(float64 *)((char *) env + PARAM1);
1030 1040 }
1031 1041  
1032 1042 VFP_OP(getreg_F1, s)
1033 1043 {
1034   - FT1s = *(float *)((char *) env + PARAM1);
  1044 + FT1s = *(float32 *)((char *) env + PARAM1);
1035 1045 }
1036 1046  
1037 1047 VFP_OP(setreg_F0, d)
1038 1048 {
1039   - *(double *)((char *) env + PARAM1) = FT0d;
  1049 + *(float64 *)((char *) env + PARAM1) = FT0d;
1040 1050 }
1041 1051  
1042 1052 VFP_OP(setreg_F0, s)
1043 1053 {
1044   - *(float *)((char *) env + PARAM1) = FT0s;
1045   -}
1046   -
1047   -VFP_OP(foobar, d)
1048   -{
1049   - FT0d = env->vfp.regs.s[3];
  1054 + *(float32 *)((char *) env + PARAM1) = FT0s;
1050 1055 }
1051 1056  
1052 1057 void OPPROTO op_vfp_movl_T0_fpscr(void)
... ...
target-arm/op_helper.c
... ... @@ -17,24 +17,8 @@
17 17 * License along with this library; if not, write to the Free Software
18 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 19 */
20   -
21   -#include <math.h>
22   -#include <fenv.h>
23 20 #include "exec.h"
24 21  
25   -/* If the host doesn't define C99 math intrinsics then use the normal
26   - operators. This may generate excess exceptions, but it's probably
27   - near enough for most things. */
28   -#ifndef isless
29   -#define isless(x, y) (x < y)
30   -#endif
31   -#ifndef isgreater
32   -#define isgreater(x, y) (x > y)
33   -#endif
34   -#ifndef isunordered
35   -#define isunordered(x, y) (!((x < y) || (x >= y)))
36   -#endif
37   -
38 22 void raise_exception(int tt)
39 23 {
40 24 env->exception_index = tt;
... ... @@ -59,119 +43,88 @@ void cpu_unlock(void)
59 43  
60 44 void do_vfp_abss(void)
61 45 {
62   - FT0s = fabsf(FT0s);
  46 + FT0s = float32_abs(FT0s);
63 47 }
64 48  
65 49 void do_vfp_absd(void)
66 50 {
67   - FT0d = fabs(FT0d);
  51 + FT0d = float64_abs(FT0d);
68 52 }
69 53  
70 54 void do_vfp_sqrts(void)
71 55 {
72   - FT0s = sqrtf(FT0s);
  56 + FT0s = float32_sqrt(FT0s, &env->vfp.fp_status);
73 57 }
74 58  
75 59 void do_vfp_sqrtd(void)
76 60 {
77   - FT0d = sqrt(FT0d);
  61 + FT0d = float64_sqrt(FT0d, &env->vfp.fp_status);
78 62 }
79 63  
80   -/* We use an == operator first to generate teh correct floating point
81   - exception. Subsequent comparisons use the exception-safe macros. */
82   -#define DO_VFP_cmp(p) \
  64 +/* XXX: check quiet/signaling case */
  65 +#define DO_VFP_cmp(p, size) \
83 66 void do_vfp_cmp##p(void) \
84 67 { \
85 68 uint32_t flags; \
86   - if (FT0##p == FT1##p) \
87   - flags = 0xc; \
88   - else if (isless (FT0##p, FT1##p)) \
89   - flags = 0x8; \
90   - else if (isgreater (FT0##p, FT1##p)) \
91   - flags = 0x2; \
92   - else /* unordered */ \
93   - flags = 0x3; \
  69 + switch(float ## size ## _compare_quiet(FT0##p, FT1##p, &env->vfp.fp_status)) {\
  70 + case 0: flags = 0xc; break;\
  71 + case -1: flags = 0x8; break;\
  72 + case 1: flags = 0x2; break;\
  73 + default: case 2: flags = 0x3; break;\
  74 + }\
94 75 env->vfp.fpscr = (flags << 28) | (env->vfp.fpscr & 0x0fffffff); \
95 76 FORCE_RET(); \
96   -}
97   -DO_VFP_cmp(s)
98   -DO_VFP_cmp(d)
99   -#undef DO_VFP_cmp
100   -
101   -/* We use a > operator first to get FP exceptions right. */
102   -#define DO_VFP_cmpe(p) \
  77 +}\
  78 +\
103 79 void do_vfp_cmpe##p(void) \
104 80 { \
105   - uint32_t flags; \
106   - if (FT0##p > FT1##p) \
107   - flags = 0x2; \
108   - else if (isless (FT0##p, FT1##p)) \
109   - flags = 0x8; \
110   - else if (isunordered (FT0##p, FT1##p)) \
111   - flags = 0x3; \
112   - else /* equal */ \
113   - flags = 0xc; \
  81 + uint32_t flags; \
  82 + switch(float ## size ## _compare(FT0##p, FT1##p, &env->vfp.fp_status)) {\
  83 + case 0: flags = 0xc; break;\
  84 + case -1: flags = 0x8; break;\
  85 + case 1: flags = 0x2; break;\
  86 + default: case 2: flags = 0x3; break;\
  87 + }\
114 88 env->vfp.fpscr = (flags << 28) | (env->vfp.fpscr & 0x0fffffff); \
115   - FORCE_RET(); \
  89 + FORCE_RET(); \
116 90 }
117   -DO_VFP_cmpe(s)
118   -DO_VFP_cmpe(d)
119   -#undef DO_VFP_cmpe
  91 +DO_VFP_cmp(s, 32)
  92 +DO_VFP_cmp(d, 64)
  93 +#undef DO_VFP_cmp
120 94  
121 95 /* Convert host exception flags to vfp form. */
122   -int vfp_exceptbits_from_host(int host_bits)
  96 +static inline int vfp_exceptbits_from_host(int host_bits)
123 97 {
124 98 int target_bits = 0;
125 99  
126   -#ifdef FE_INVALID
127   - if (host_bits & FE_INVALID)
  100 + if (host_bits & float_flag_invalid)
128 101 target_bits |= 1;
129   -#endif
130   -#ifdef FE_DIVBYZERO
131   - if (host_bits & FE_DIVBYZERO)
  102 + if (host_bits & float_flag_divbyzero)
132 103 target_bits |= 2;
133   -#endif
134   -#ifdef FE_OVERFLOW
135   - if (host_bits & FE_OVERFLOW)
  104 + if (host_bits & float_flag_overflow)
136 105 target_bits |= 4;
137   -#endif
138   -#ifdef FE_UNDERFLOW
139   - if (host_bits & FE_UNDERFLOW)
  106 + if (host_bits & float_flag_underflow)
140 107 target_bits |= 8;
141   -#endif
142   -#ifdef FE_INEXACT
143   - if (host_bits & FE_INEXACT)
  108 + if (host_bits & float_flag_inexact)
144 109 target_bits |= 0x10;
145   -#endif
146   - /* C doesn't define an inexact exception. */
147 110 return target_bits;
148 111 }
149 112  
150 113 /* Convert vfp exception flags to target form. */
151   -int vfp_host_exceptbits_to_host(int target_bits)
  114 +static inline int vfp_exceptbits_to_host(int target_bits)
152 115 {
153 116 int host_bits = 0;
154 117  
155   -#ifdef FE_INVALID
156 118 if (target_bits & 1)
157   - host_bits |= FE_INVALID;
158   -#endif
159   -#ifdef FE_DIVBYZERO
  119 + host_bits |= float_flag_invalid;
160 120 if (target_bits & 2)
161   - host_bits |= FE_DIVBYZERO;
162   -#endif
163   -#ifdef FE_OVERFLOW
  121 + host_bits |= float_flag_divbyzero;
164 122 if (target_bits & 4)
165   - host_bits |= FE_OVERFLOW;
166   -#endif
167   -#ifdef FE_UNDERFLOW
  123 + host_bits |= float_flag_overflow;
168 124 if (target_bits & 8)
169   - host_bits |= FE_UNDERFLOW;
170   -#endif
171   -#ifdef FE_INEXACT
  125 + host_bits |= float_flag_underflow;
172 126 if (target_bits & 0x10)
173   - host_bits |= FE_INEXACT;
174   -#endif
  127 + host_bits |= float_flag_inexact;
175 128 return host_bits;
176 129 }
177 130  
... ... @@ -190,31 +143,23 @@ void do_vfp_set_fpscr(void)
190 143 i = (T0 >> 22) & 3;
191 144 switch (i) {
192 145 case 0:
193   - i = FE_TONEAREST;
  146 + i = float_round_nearest_even;
194 147 break;
195 148 case 1:
196   - i = FE_UPWARD;
  149 + i = float_round_up;
197 150 break;
198 151 case 2:
199   - i = FE_DOWNWARD;
  152 + i = float_round_down;
200 153 break;
201 154 case 3:
202   - i = FE_TOWARDZERO;
  155 + i = float_round_to_zero;
203 156 break;
204 157 }
205   - fesetround (i);
  158 + set_float_rounding_mode(i, &env->vfp.fp_status);
206 159 }
207 160  
208   - /* Clear host exception flags. */
209   - feclearexcept(FE_ALL_EXCEPT);
210   -
211   -#ifdef feenableexcept
212   - if (changed & 0x1f00) {
213   - i = vfp_exceptbits_to_host((T0 >> 8) & 0x1f);
214   - feenableexcept (i);
215   - fedisableexcept (FE_ALL_EXCEPT & ~i);
216   - }
217   -#endif
  161 + i = vfp_exceptbits_to_host((T0 >> 8) & 0x1f);
  162 + set_float_exception_flags(i, &env->vfp.fp_status);
218 163 /* XXX: FZ and DN are not implemented. */
219 164 }
220 165  
... ... @@ -224,6 +169,6 @@ void do_vfp_get_fpscr(void)
224 169  
225 170 T0 = (env->vfp.fpscr & 0xffc8ffff) | (env->vfp.vec_len << 16)
226 171 | (env->vfp.vec_stride << 20);
227   - i = fetestexcept(FE_ALL_EXCEPT);
  172 + i = get_float_exception_flags(&env->vfp.fp_status);
228 173 T0 |= vfp_exceptbits_from_host(i);
229 174 }
... ...