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