1 /* 2 * UAE - The Un*x Amiga Emulator 3 * 4 * MC68881 emulation 5 * 6 * Conversion routines for hosts knowing floating point format. 7 * 8 * Copyright 1996 Herman ten Brugge 9 * Modified 2005 Peter Keunecke 10 */ 11 12 #include <math.h> 13 14 #define FPCR_ROUNDING_MODE 0x00000030 15 #define FPCR_ROUND_NEAR 0x00000000 16 #define FPCR_ROUND_ZERO 0x00000010 17 #define FPCR_ROUND_MINF 0x00000020 18 #define FPCR_ROUND_PINF 0x00000030 19 20 #define FPCR_ROUNDING_PRECISION 0x000000c0 21 #define FPCR_PRECISION_SINGLE 0x00000040 22 #define FPCR_PRECISION_DOUBLE 0x00000080 23 #define FPCR_PRECISION_EXTENDED 0x00000000 24 25 extern void to_single(fpdata *fpd, uae_u32 value); 26 extern void to_double(fpdata *fpd, uae_u32 wrd1, uae_u32 wrd2); 27 extern void to_exten(fpdata *fpd, uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3); 28 extern const TCHAR *fp_print(fpdata *fpd); 29 30 #if 0 31 STATIC_INLINE void exten_zeronormalize(uae_u32 *pwrd1, uae_u32 *pwrd2, uae_u32 *pwrd3) 32 { 33 uae_u32 wrd1 = *pwrd1; 34 uae_u32 wrd2 = *pwrd2; 35 uae_u32 wrd3 = *pwrd3; 36 int exp = (wrd1 >> 16) & 0x7fff; 37 // Force zero if mantissa is zero but exponent is non-zero 38 // M68k FPU automatically convert them to plain zeros. 39 // x86 FPU considers them invalid values 40 if (exp != 0 && exp != 0x7fff && !wrd2 && !wrd3) { 41 *pwrd1 = (wrd1 & 0x80000000); 42 } 43 } 44 45 #if USE_LONG_DOUBLE 46 STATIC_INLINE void to_exten_x(fptype *fp, uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3) 47 { 48 // force correct long double alignment 49 union 50 { 51 long double lf; 52 uae_u32 longarray[3]; 53 } uld; 54 exten_zeronormalize(&wrd1, &wrd2, &wrd3); 55 // little endian order 56 uld.longarray[0] = wrd3; 57 uld.longarray[1] = wrd2; 58 uld.longarray[2] = wrd1 >> 16; 59 long double *longdoublewords = (long double *)uld.longarray; 60 *fp = *longdoublewords; 61 } 62 #define HAVE_to_exten 63 64 STATIC_INLINE void from_exten_x(fptype fp, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3) 65 { 66 uae_u32 *longarray = (uae_u32 *)&fp; 67 uae_u16 *finalword = (uae_u16 *)(((uae_u8*)&fp) + 8); 68 69 *wrd1 = finalword[0] << 16; 70 *wrd2 = longarray[1]; 71 *wrd3 = longarray[0]; // little endian 72 } 73 #define HAVE_from_exten 74 #endif /* USE_LONG_DOUBLE */ 75 76 #if defined(X86_MSVC_ASSEMBLY_FPU) 77 #ifndef HAVE_to_single 78 #define HAVE_to_single 79 STATIC_INLINE double to_single_x (uae_u32 longvalue) 80 { 81 double floatfake; 82 83 __asm { 84 fld dword ptr longvalue; 85 fstp qword ptr floatfake; 86 } 87 return floatfake; 88 } 89 #endif 90 91 #ifndef HAVE_from_single 92 #define HAVE_from_single 93 STATIC_INLINE uae_u32 from_single_x (double floatfake) 94 { 95 uae_u32 longvalue; 96 97 __asm { 98 fld qword ptr floatfake; 99 fstp dword ptr longvalue; 100 } 101 return longvalue; 102 } 103 #endif 104 105 #ifndef HAVE_to_exten 106 #define HAVE_to_exten 107 STATIC_INLINE void to_exten_x(fptype *fp, uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3) 108 { 109 uae_u32 longarray[3]; 110 double extenfake; 111 112 exten_normalize(&wrd1, &wrd2, &wrd3); 113 longarray[0] = wrd3; // littlen endian 114 longarray[1] = wrd2; 115 longarray[2] = wrd2 >> 16; 116 117 __asm { 118 fld tbyte ptr longarray; 119 fstp qword ptr extenfake; 120 } 121 *fp = extenfake; 122 } 123 #endif 124 125 #ifndef HAVE_from_exten 126 #define HAVE_from_exten 127 STATIC_INLINE void from_exten_x(fptype fp, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3) 128 { 129 fptype src = fp; 130 uae_u32 longarray[3], *srcarray = (uae_u32 *)&src; 131 __asm { 132 fld qword ptr src; 133 fstp tbyte ptr longarray; 134 } 135 *wrd1 = (longarray[2] & 0xffff) <<16; 136 *wrd2 = longarray[1]; 137 *wrd3 = longarray[0]; // little endian 138 if (!srcarray[0] && (srcarray[1] == 0x7ff00000 || srcarray[1] == 0xfff00000)) 139 *wrd2 = 0; // The MSB of the mantissa was set wrongly for infinity, causing a NaN 140 } 141 #endif 142 #endif /* X86_MSVC_ASSEMBLY */ 143 144 #ifndef HAVE_to_single 145 #define HAVE_to_single 146 STATIC_INLINE double to_single_x (uae_u32 value) 147 { 148 union { 149 float f; 150 uae_u32 u; 151 } val; 152 153 val.u = value; 154 return val.f; 155 } 156 #endif 157 158 #ifndef HAVE_from_single 159 #define HAVE_from_single 160 STATIC_INLINE uae_u32 from_single_x (double src) 161 { 162 union { 163 float f; 164 uae_u32 u; 165 } val; 166 167 val.f = (float) src; 168 return val.u; 169 } 170 #endif 171 172 #ifndef HAVE_to_double 173 #define HAVE_to_double 174 STATIC_INLINE double to_double_x(uae_u32 wrd1, uae_u32 wrd2) 175 { 176 union { 177 double d; 178 uae_u32 u[2]; 179 } val; 180 181 #ifdef WORDS_BIGENDIAN 182 val.u[0] = wrd1; 183 val.u[1] = wrd2; 184 #else 185 val.u[1] = wrd1; 186 val.u[0] = wrd2; 187 #endif 188 return val.d; 189 } 190 #endif 191 192 #ifndef HAVE_from_double 193 #define HAVE_from_double 194 STATIC_INLINE void from_double_x(double src, uae_u32 * wrd1, uae_u32 * wrd2) 195 { 196 uae_u32 *longarray = (uae_u32 *)&src; 197 198 *wrd1 = longarray[1]; // little endian 199 *wrd2 = longarray[0]; 200 } 201 #endif 202 203 #ifndef HAVE_to_exten 204 #define HAVE_to_exten 205 STATIC_INLINE void to_exten_x(fptype *fp, uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3) 206 { 207 double frac; 208 exten_zeronormalize(&wrd1, &wrd2, &wrd3); 209 if ((wrd1 & 0x7fff0000) == 0 && wrd2 == 0 && wrd3 == 0) { 210 *fp = (wrd1 & 0x80000000) ? -0.0 : +0.0; 211 return; 212 } 213 frac = ((double)wrd2 + ((double)wrd3 / twoto32)) / 2147483648.0; 214 if (wrd1 & 0x80000000) 215 frac = -frac; 216 *fp = ldexp (frac, ((wrd1 >> 16) & 0x7fff) - 16383); 217 } 218 #endif 219 220 #ifndef HAVE_from_exten 221 #define HAVE_from_exten 222 STATIC_INLINE void from_exten_x(fptype fp, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3) 223 { 224 int expon; 225 double frac; 226 fptype v; 227 228 v = fp; 229 if (v == 0.0) { 230 *wrd1 = signbit(v) ? 0x80000000 : 0; 231 *wrd2 = 0; 232 *wrd3 = 0; 233 return; 234 } 235 if (v < 0) { 236 *wrd1 = 0x80000000; 237 v = -v; 238 } else { 239 *wrd1 = 0; 240 } 241 frac = frexp (v, &expon); 242 frac += 0.5 / (twoto32 * twoto32); 243 if (frac >= 1.0) { 244 frac /= 2.0; 245 expon++; 246 } 247 *wrd1 |= (((expon + 16383 - 1) & 0x7fff) << 16); 248 *wrd2 = (uae_u32) (frac * twoto32); 249 *wrd3 = (uae_u32) ((frac * twoto32 - *wrd2) * twoto32); 250 } 251 #endif 252 #endif 253