|
|
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: #ifndef FPP_H
13: #define FPP_H
14:
15: #define __USE_ISOC9X /* We might be able to pick up a NaN */
16:
17: #include <math.h>
18: #include <float.h>
19: #include <fenv.h>
20:
21: //#pragma STDC FENV_ACCESS on
22:
23: #define USE_HOST_ROUNDING
24:
25: #define FPCR_ROUNDING_MODE 0x00000030
26: #define FPCR_ROUND_NEAR 0x00000000
27: #define FPCR_ROUND_ZERO 0x00000010
28: #define FPCR_ROUND_MINF 0x00000020
29: #define FPCR_ROUND_PINF 0x00000030
30:
31: #define FPCR_ROUNDING_PRECISION 0x000000c0
32: #define FPCR_PRECISION_SINGLE 0x00000040
33: #define FPCR_PRECISION_DOUBLE 0x00000080
34: #define FPCR_PRECISION_EXTENDED 0x00000000
35:
36: extern uae_u32 fpp_get_fpsr (void);
37: extern void fpsr_set_exception(uae_u32 exception);
38:
39: static int fp_rnd_prec = 80;
40:
41: /* Functions for setting host/library modes and getting status */
42: STATIC_INLINE void init_fp_mode(void) {
43:
44: }
45: STATIC_INLINE void set_fp_mode(uae_u32 mode_control)
46: {
47: switch(mode_control & FPCR_ROUNDING_PRECISION) {
48: case FPCR_PRECISION_EXTENDED: // X
49: fp_rnd_prec = 80;
50: break;
51: case FPCR_PRECISION_SINGLE: // S
52: fp_rnd_prec = 32;
53: break;
54: case FPCR_PRECISION_DOUBLE: // D
55: default: // undefined
56: fp_rnd_prec = 64;
57: break;
58: }
59: #ifdef USE_HOST_ROUNDING
60: switch(mode_control & FPCR_ROUNDING_MODE) {
61: case FPCR_ROUND_NEAR: // to neareset
62: fesetround(FE_TONEAREST);
63: break;
64: case FPCR_ROUND_ZERO: // to zero
65: fesetround(FE_TOWARDZERO);
66: break;
67: case FPCR_ROUND_MINF: // to minus
68: fesetround(FE_DOWNWARD);
69: break;
70: case FPCR_ROUND_PINF: // to plus
71: fesetround(FE_UPWARD);
72: break;
73: }
74: return;
75: #endif
76: }
77: STATIC_INLINE void get_fp_status(uae_u32 *status)
78: {
79: int exp_flags = fetestexcept(FE_ALL_EXCEPT);
80: if (exp_flags) {
81: if (exp_flags & FE_INEXACT)
82: *status |= 0x0200;
83: if (exp_flags & FE_DIVBYZERO)
84: *status |= 0x0400;
85: if (exp_flags & FE_UNDERFLOW)
86: *status |= 0x0800;
87: if (exp_flags & FE_OVERFLOW)
88: *status |= 0x1000;
89: if (exp_flags & FE_INVALID)
90: *status |= 0x2000;
91: }
92: /* FIXME: how to detect SNAN? */
93: }
94: STATIC_INLINE void clear_fp_status(void)
95: {
96: feclearexcept (FE_ALL_EXCEPT);
97: }
98:
99: /* Helper functions */
100: STATIC_INLINE const char *fp_print(fptype *fx)
101: {
102: static char fs[32];
103: bool n, d;
104:
105: n = signbit(*fx) ? 1 : 0;
106: d = isnormal(*fx) ? 0 : 1;
107:
108: if (isinf(*fx)) {
109: sprintf(fs, "%c%s", n?'-':'+', "inf");
110: } else if (isnan(*fx)) {
111: sprintf(fs, "%c%s", n?'-':'+', "nan");
112: } else {
113: if (n)
114: *fx *= -1.0;
115: #ifdef USE_LONG_DOUBLE
116: sprintf(fs, "%c%#.16Le%s%s", n?'-':'+', *fx, "", d?"D":"");
117: #else
118: sprintf(fs, "%c%#.16e%s%s", n?'-':'+', *fx, "", d?"D":"");
119: #endif
120: }
121:
122: return fs;
123: }
124:
125: /* Functions for detecting float type */
126: STATIC_INLINE bool fp_is_snan(fptype *fp)
127: {
128: return 0; /* FIXME: how to detect SNAN */
129: }
130: STATIC_INLINE void fp_unset_snan(fptype *fp)
131: {
132: /* FIXME: how to unset SNAN */
133: }
134: STATIC_INLINE bool fp_is_nan (fptype *fp)
135: {
136: return isnan(*fp) != 0;
137: }
138: STATIC_INLINE bool fp_is_infinity (fptype *fp)
139: {
140: return isinf(*fp) != 0;
141: }
142: STATIC_INLINE bool fp_is_zero(fptype *fp)
143: {
144: return (*fp == 0.0);
145: }
146: STATIC_INLINE bool fp_is_neg(fptype *fp)
147: {
148: return signbit(*fp) != 0;
149: }
150: STATIC_INLINE bool fp_is_denormal(fptype *fp)
151: {
152: return false;
153: //return (isnormal(*fp) == 0); /* FIXME: how to differ denormal/unnormal? */
154: }
155: STATIC_INLINE bool fp_is_unnormal(fptype *fp)
156: {
157: return false;
158: //return (isnormal(*fp) == 0); /* FIXME: how to differ denormal/unnormal? */
159: }
160:
161: /* Function for normalizing unnormals FIXME: how to do this with native floats? */
162: STATIC_INLINE void fp_normalize(fptype *fp)
163: {
164: }
165:
166: /* Functions for converting between float formats */
167: /* FIXME: how to preserve/fix denormals and unnormals? */
168:
169: STATIC_INLINE void to_single(fptype *fp, uae_u32 wrd1)
170: {
171: union {
172: float f;
173: uae_u32 u;
174: } val;
175:
176: val.u = wrd1;
177: *fp = (fptype) val.f;
178: }
179: STATIC_INLINE uae_u32 from_single(fptype *fp)
180: {
181: union {
182: float f;
183: uae_u32 u;
184: } val;
185:
186: val.f = (float) *fp;
187: return val.u;
188: }
189:
190: STATIC_INLINE void to_double(fptype *fp, uae_u32 wrd1, uae_u32 wrd2)
191: {
192: union {
193: double d;
194: uae_u32 u[2];
195: } val;
196:
197: #ifdef WORDS_BIGENDIAN
198: val.u[0] = wrd1;
199: val.u[1] = wrd2;
200: #else
201: val.u[1] = wrd1;
202: val.u[0] = wrd2;
203: #endif
204: *fp = (fptype) val.d;
205: }
206: STATIC_INLINE void from_double(fptype *fp, uae_u32 *wrd1, uae_u32 *wrd2)
207: {
208: union {
209: double d;
210: uae_u32 u[2];
211: } val;
212:
213: val.d = (double) *fp;
214: #ifdef WORDS_BIGENDIAN
215: *wrd1 = val.u[0];
216: *wrd2 = val.u[1];
217: #else
218: *wrd1 = val.u[1];
219: *wrd2 = val.u[0];
220: #endif
221: }
222: #ifdef USE_LONG_DOUBLE
223: STATIC_INLINE void to_exten(fptype *fp, uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3)
224: {
225: union {
226: long double ld;
227: uae_u32 u[3];
228: } val;
229:
230: #if WORDS_BIGENDIAN
231: val.u[0] = (wrd1 & 0xffff0000) | ((wrd2 & 0xffff0000) >> 16);
232: val.u[1] = (wrd2 & 0x0000ffff) | ((wrd3 & 0xffff0000) >> 16);
233: val.u[2] = (wrd3 & 0x0000ffff) << 16;
234: #else
235: val.u[0] = wrd3;
236: val.u[1] = wrd2;
237: val.u[2] = wrd1 >> 16;
238: #endif
239: *fp = val.ld;
240: }
241: STATIC_INLINE void from_exten(fptype *fp, uae_u32 *wrd1, uae_u32 *wrd2, uae_u32 *wrd3)
242: {
243: union {
244: long double ld;
245: uae_u32 u[3];
246: } val;
247:
248: val.ld = *fp;
249: #if WORDS_BIGENDIAN
250: *wrd1 = val.u[0] & 0xffff0000;
251: *wrd2 = ((val.u[0] & 0x0000ffff) << 16) | ((val.u[1] & 0xffff0000) >> 16);
252: *wrd3 = ((val.u[1] & 0x0000ffff) << 16) | ((val.u[2] & 0xffff0000) >> 16);
253: #else
254: *wrd3 = val.u[0];
255: *wrd2 = val.u[1];
256: *wrd1 = val.u[2] << 16;
257: #endif
258: }
259: #else // if !USE_LONG_DOUBLE
260: static const double twoto32 = 4294967296.0;
261: STATIC_INLINE void to_exten(fptype *fp, uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3)
262: {
263: double frac;
264: if ((wrd1 & 0x7fff0000) == 0 && wrd2 == 0 && wrd3 == 0) {
265: *fp = (wrd1 & 0x80000000) ? -0.0 : +0.0;
266: return;
267: }
268: frac = ((double)wrd2 + ((double)wrd3 / twoto32)) / 2147483648.0;
269: if (wrd1 & 0x80000000)
270: frac = -frac;
271: *fp = ldexp (frac, ((wrd1 >> 16) & 0x7fff) - 16383);
272: }
273: STATIC_INLINE void from_exten(fptype *fp, uae_u32 *wrd1, uae_u32 *wrd2, uae_u32 *wrd3)
274: {
275: int expon;
276: double frac;
277: fptype v;
278:
279: v = *fp;
280: if (v == 0.0) {
281: *wrd1 = signbit(v) ? 0x80000000 : 0;
282: *wrd2 = 0;
283: *wrd3 = 0;
284: return;
285: }
286: if (v < 0) {
287: *wrd1 = 0x80000000;
288: v = -v;
289: } else {
290: *wrd1 = 0;
291: }
292: frac = frexp (v, &expon);
293: frac += 0.5 / (twoto32 * twoto32);
294: if (frac >= 1.0) {
295: frac /= 2.0;
296: expon++;
297: }
298: *wrd1 |= (((expon + 16383 - 1) & 0x7fff) << 16);
299: *wrd2 = (uae_u32) (frac * twoto32);
300: *wrd3 = (uae_u32) ((frac * twoto32 - *wrd2) * twoto32);
301: }
302: #endif // !USE_LONG_DOUBLE
303: STATIC_INLINE void to_exten_fmovem(fptype *fp, uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3)
304: {
305: to_exten(fp, wrd1, wrd2, wrd3);
306: }
307: STATIC_INLINE void from_exten_fmovem(fptype *fp, uae_u32 *wrd1, uae_u32 *wrd2, uae_u32 *wrd3)
308: {
309: from_exten(fp, wrd1, wrd2, wrd3);
310: }
311:
312: STATIC_INLINE void to_pack (fptype *fp, uae_u32 *wrd)
313: {
314: char *cp;
315: char str[100];
316:
317: if (((wrd[0] >> 16) & 0x7fff) == 0x7fff) {
318: // infinity has extended exponent and all 0 packed fraction
319: // nans are copies bit by bit
320: to_exten(fp, wrd[0], wrd[1], wrd[2]);
321: return;
322: }
323: if (!(wrd[0] & 0xf) && !wrd[1] && !wrd[2]) {
324: // exponent is not cared about, if mantissa is zero
325: wrd[0] &= 0x80000000;
326: to_exten(fp, wrd[0], wrd[1], wrd[2]);
327: return;
328: }
329:
330: cp = str;
331: if (wrd[0] & 0x80000000)
332: *cp++ = '-';
333: *cp++ = (wrd[0] & 0xf) + '0';
334: *cp++ = '.';
335: *cp++ = ((wrd[1] >> 28) & 0xf) + '0';
336: *cp++ = ((wrd[1] >> 24) & 0xf) + '0';
337: *cp++ = ((wrd[1] >> 20) & 0xf) + '0';
338: *cp++ = ((wrd[1] >> 16) & 0xf) + '0';
339: *cp++ = ((wrd[1] >> 12) & 0xf) + '0';
340: *cp++ = ((wrd[1] >> 8) & 0xf) + '0';
341: *cp++ = ((wrd[1] >> 4) & 0xf) + '0';
342: *cp++ = ((wrd[1] >> 0) & 0xf) + '0';
343: *cp++ = ((wrd[2] >> 28) & 0xf) + '0';
344: *cp++ = ((wrd[2] >> 24) & 0xf) + '0';
345: *cp++ = ((wrd[2] >> 20) & 0xf) + '0';
346: *cp++ = ((wrd[2] >> 16) & 0xf) + '0';
347: *cp++ = ((wrd[2] >> 12) & 0xf) + '0';
348: *cp++ = ((wrd[2] >> 8) & 0xf) + '0';
349: *cp++ = ((wrd[2] >> 4) & 0xf) + '0';
350: *cp++ = ((wrd[2] >> 0) & 0xf) + '0';
351: *cp++ = 'E';
352: if (wrd[0] & 0x40000000)
353: *cp++ = '-';
354: *cp++ = ((wrd[0] >> 24) & 0xf) + '0';
355: *cp++ = ((wrd[0] >> 20) & 0xf) + '0';
356: *cp++ = ((wrd[0] >> 16) & 0xf) + '0';
357: *cp = 0;
358:
359: #ifdef USE_LONG_DOUBLE
360: sscanf (str, "%Le", fp);
361: #else
362: sscanf (str, "%le", fp);
363: #endif
364: }
365: STATIC_INLINE void from_pack (fptype *fp, uae_u32 *wrd, int kfactor)
366: {
367: int i, j, t;
368: int exp;
369: int ndigits;
370: char *cp, *strp;
371: char str[100];
372:
373: if (fp_is_nan (fp)) {
374: // copy bit by bit, handle signaling nan
375: from_exten(fp, &wrd[0], &wrd[1], &wrd[2]);
376: return;
377: }
378: if (fp_is_infinity (fp)) {
379: // extended exponent and all 0 packed fraction
380: from_exten(fp, &wrd[0], &wrd[1], &wrd[2]);
381: wrd[1] = wrd[2] = 0;
382: return;
383: }
384:
385: wrd[0] = wrd[1] = wrd[2] = 0;
386:
387: #ifdef USE_LONG_DOUBLE
388: sprintf (str, "%#.17Le", *fp);
389: #else
390: sprintf (str, "%#.17e", *fp);
391: #endif
392:
393: // get exponent
394: cp = str;
395: while (*cp != 'e') {
396: if (*cp == 0)
397: return;
398: cp++;
399: }
400: cp++;
401: if (*cp == '+')
402: cp++;
403: exp = atoi (cp);
404:
405: // remove trailing zeros
406: cp = str;
407: while (*cp != 'e')
408: cp++;
409: cp[0] = 0;
410: cp--;
411: while (cp > str && *cp == '0') {
412: *cp = 0;
413: cp--;
414: }
415:
416: cp = str;
417: // get sign
418: if (*cp == '-') {
419: cp++;
420: wrd[0] = 0x80000000;
421: } else if (*cp == '+') {
422: cp++;
423: }
424: strp = cp;
425:
426: if (kfactor <= 0) {
427: ndigits = abs (exp) + (-kfactor) + 1;
428: } else {
429: if (kfactor > 17) {
430: kfactor = 17;
431: fpsr_set_exception(0x00002000); // OPERR
432: }
433: ndigits = kfactor;
434: }
435:
436: if (ndigits < 0)
437: ndigits = 0;
438: if (ndigits > 16)
439: ndigits = 16;
440:
441: // remove decimal point
442: strp[1] = strp[0];
443: strp++;
444: // add trailing zeros
445: i = strlen (strp);
446: cp = strp + i;
447: while (i < ndigits) {
448: *cp++ = '0';
449: i++;
450: }
451: i = ndigits + 1;
452: while (i < 17) {
453: strp[i] = 0;
454: i++;
455: }
456: *cp = 0;
457: i = ndigits - 1;
458: // need to round?
459: if (i >= 0 && strp[i + 1] >= '5') {
460: while (i >= 0) {
461: strp[i]++;
462: if (strp[i] <= '9')
463: break;
464: if (i == 0) {
465: strp[i] = '1';
466: exp++;
467: } else {
468: strp[i] = '0';
469: }
470: i--;
471: }
472: }
473: strp[ndigits] = 0;
474:
475: // store first digit of mantissa
476: cp = strp;
477: wrd[0] |= *cp++ - '0';
478:
479: // store rest of mantissa
480: for (j = 1; j < 3; j++) {
481: for (i = 0; i < 8; i++) {
482: wrd[j] <<= 4;
483: if (*cp >= '0' && *cp <= '9')
484: wrd[j] |= *cp++ - '0';
485: }
486: }
487:
488: // exponent
489: if (exp < 0) {
490: wrd[0] |= 0x40000000;
491: exp = -exp;
492: }
493: if (exp > 9999) // ??
494: exp = 9999;
495: if (exp > 999) {
496: int d = exp / 1000;
497: wrd[0] |= d << 12;
498: exp -= d * 1000;
499: fpsr_set_exception(0x00002000); // OPERR
500: }
501: i = 100;
502: t = 0;
503: while (i >= 1) {
504: int d = exp / i;
505: t <<= 4;
506: t |= d;
507: exp -= d * i;
508: i /= 10;
509: }
510: wrd[0] |= t << 16;
511: }
512:
513: #ifndef USE_HOST_ROUNDING
514: #ifdef USE_LONG_DOUBLE
515: #define fp_round_to_minus_infinity(x) floorl(x)
516: #define fp_round_to_plus_infinity(x) ceill(x)
517: #define fp_round_to_zero(x) ((x) >= 0.0 ? floorl(x) : ceill(x))
518: #define fp_round_to_nearest(x) roundl(x)
519: #else // if !USE_LONG_DOUBLE
520: #define fp_round_to_minus_infinity(x) floor(x)
521: #define fp_round_to_plus_infinity(x) ceil(x)
522: #define fp_round_to_zero(x) ((x) >= 0.0 ? floor(x) : ceil(x))
523: #define fp_round_to_nearest(x) round(x)
524: #endif // !USE_LONG_DOUBLE
525: #endif // USE_HOST_ROUNDING
526:
527: STATIC_INLINE uae_s64 to_int(fptype *src, int size)
528: {
529: static fptype fxsizes[6] =
530: {
531: -128.0, 127.0,
532: -32768.0, 32767.0,
533: -2147483648.0, 2147483647.0
534: };
535:
536: if (*src < fxsizes[size * 2 + 0])
537: *src = fxsizes[size * 2 + 0];
538: if (*src > fxsizes[size * 2 + 1])
539: *src = fxsizes[size * 2 + 1];
540: #ifdef USE_HOST_ROUNDING
541: #ifdef USE_LONG_DOUBLE
542: return lrintl(*src);
543: #else
544: return lrint(*src);
545: #endif
546: #else
547: switch (regs.fpcr & FPCR_ROUNDING_MODE)
548: {
549: case FPCR_ROUND_ZERO:
550: return fp_round_to_zero (*src);
551: case FPCR_ROUND_MINF:
552: return fp_round_to_minus_infinity (*src);
553: case FPCR_ROUND_NEAR:
554: return fp_round_to_nearest (*src);
555: case FPCR_ROUND_PINF:
556: return fp_round_to_plus_infinity (*src);
557: default:
558: return (int) *src;
559: }
560: #endif
561: }
562: STATIC_INLINE fptype from_int(uae_s32 src)
563: {
564: return (fptype) src;
565: }
566:
567: /* Functions for returning exception state data */
568: /* (almost impossible to emulate using native floats) */
569: STATIC_INLINE fptype fp_get_internal_overflow(void)
570: {
571: return 0.0;
572: }
573: STATIC_INLINE fptype fp_get_internal_underflow(void)
574: {
575: return 0.0;
576: }
577: STATIC_INLINE fptype fp_get_internal(void)
578: {
579: return 0.0;
580: }
581: STATIC_INLINE fptype fp_get_internal_round(void)
582: {
583: return 0.0;
584: }
585: STATIC_INLINE fptype fp_get_internal_round_all(void)
586: {
587: return 0.0;
588: }
589: STATIC_INLINE fptype fp_get_internal_round_exten(void)
590: {
591: return 0.0;
592: }
593: STATIC_INLINE uae_u32 fp_get_internal_grs(void)
594: {
595: return 0.0;
596: }
597:
598: /* Function for denormalizing */
599: STATIC_INLINE void fp_denormalize(fptype *fp, int esign)
600: {
601: // do nothing
602: }
603:
604: /* Functions for rounding */
605:
606: // round to float with extended precision exponent
607: STATIC_INLINE void fp_round32(fptype *fp)
608: {
609: int expon;
610: float mant;
611: #ifdef USE_LONG_DOUBLE
612: mant = (float)(frexpl(*fp, &expon) * 2.0);
613: *fp = ldexpl((fptype)mant, expon - 1);
614: #else
615: mant = (float)(frexp(*fp, &expon) * 2.0);
616: *fp = ldexp((fptype)mant, expon - 1);
617: #endif
618: }
619:
620: // round to double with extended precision exponent
621: STATIC_INLINE void fp_round64(fptype *fp)
622: {
623: int expon;
624: double mant;
625: #ifdef USE_LONG_DOUBLE
626: mant = (double)(frexpl(*fp, &expon) * 2.0);
627: *fp = ldexpl((fptype)mant, expon - 1);
628: #else
629: mant = (double)(frexp(*fp, &expon) * 2.0);
630: *fp = ldexp((fptype)mant, expon - 1);
631: #endif
632: }
633:
634: // round to float
635: STATIC_INLINE void fp_round_single(fptype *fp)
636: {
637: *fp = (float) *fp;
638: }
639:
640: // round to double
641: STATIC_INLINE void fp_round_double(fptype *fp)
642: {
643: *fp = (double) *fp;
644: }
645:
646: // round to selected precision
647: STATIC_INLINE void fp_round(fptype *fp)
648: {
649: switch(fp_rnd_prec) {
650: case 32:
651: *fp = (float) *fp;
652: break;
653: case 64:
654: *fp = (double) *fp;
655: break;
656: default:
657: break;
658: }
659: }
660:
661:
662: /* Arithmetic functions */
663:
664: #ifdef USE_LONG_DOUBLE
665:
666: STATIC_INLINE void fp_move(fptype *a, fptype *b)
667: {
668: *a = *b;
669: fp_round(a);
670: }
671: STATIC_INLINE void fp_move_single(fptype *a, fptype *b)
672: {
673: *a = *b;
674: fp_round_single(a);
675: }
676: STATIC_INLINE void fp_move_double(fptype *a, fptype *b)
677: {
678: *a = *b;
679: fp_round_double(a);
680: }
681: STATIC_INLINE void fp_int(fptype *a, fptype *b)
682: {
683: #ifdef USE_HOST_ROUNDING
684: *a = rintl(*b);
685: #else
686: switch (regs.fpcr & FPCR_ROUNDING_MODE)
687: {
688: case FPCR_ROUND_NEAR:
689: *a = fp_round_to_nearest(*b);
690: break;
691: case FPCR_ROUND_ZERO:
692: *a = fp_round_to_zero(*b);
693: break;
694: case FPCR_ROUND_MINF:
695: *a = fp_round_to_minus_infinity(*b);
696: break;
697: case FPCR_ROUND_PINF:
698: *a = fp_round_to_plus_infinity(*b);
699: break;
700: default: /* never reached */
701: break;
702: }
703: #endif
704: fp_round(a);
705: }
706: STATIC_INLINE void fp_sinh(fptype *a, fptype *b)
707: {
708: *a = sinhl(*b);
709: fp_round(a);
710: }
711: STATIC_INLINE void fp_intrz(fptype *a, fptype *b)
712: {
713: #ifdef USE_HOST_ROUNDING
714: *a = truncl(*b);
715: #else
716: *a = fp_round_to_zero (*b);
717: #endif
718: fp_round(a);
719: }
720: STATIC_INLINE void fp_sqrt(fptype *a, fptype *b)
721: {
722: *a = sqrtl(*b);
723: fp_round(a);
724: }
725: STATIC_INLINE void fp_sqrt_single(fptype *a, fptype *b)
726: {
727: *a = sqrtl(*b);
728: fp_round_single(a);
729: }
730: STATIC_INLINE void fp_sqrt_double(fptype *a, fptype *b)
731: {
732: *a = sqrtl(*b);
733: fp_round_double(a);
734: }
735: STATIC_INLINE void fp_lognp1(fptype *a, fptype *b)
736: {
737: *a = log1pl(*b);
738: fp_round(a);
739: }
740: STATIC_INLINE void fp_etoxm1(fptype *a, fptype *b)
741: {
742: *a = expm1l(*b);
743: fp_round(a);
744: }
745: STATIC_INLINE void fp_tanh(fptype *a, fptype *b)
746: {
747: *a = tanhl(*b);
748: fp_round(a);
749: }
750: STATIC_INLINE void fp_atan(fptype *a, fptype *b)
751: {
752: *a = atanl(*b);
753: fp_round(a);
754: }
755: STATIC_INLINE void fp_asin(fptype *a, fptype *b)
756: {
757: *a = asinl(*b);
758: fp_round(a);
759: }
760: STATIC_INLINE void fp_atanh(fptype *a, fptype *b)
761: {
762: *a = atanhl(*b);
763: fp_round(a);
764: }
765: STATIC_INLINE void fp_sin(fptype *a, fptype *b)
766: {
767: *a = sinl(*b);
768: fp_round(a);
769: }
770: STATIC_INLINE void fp_tan(fptype *a, fptype *b)
771: {
772: *a = tanl(*b);
773: fp_round(a);
774: }
775: STATIC_INLINE void fp_etox(fptype *a, fptype *b)
776: {
777: *a = expl(*b);
778: fp_round(a);
779: }
780: STATIC_INLINE void fp_twotox(fptype *a, fptype *b)
781: {
782: *a = powl(2.0, *b);
783: fp_round(a);
784: }
785: STATIC_INLINE void fp_tentox(fptype *a, fptype *b)
786: {
787: *a = powl(10.0, *b);
788: fp_round(a);
789: }
790: STATIC_INLINE void fp_logn(fptype *a, fptype *b)
791: {
792: *a = logl(*b);
793: fp_round(a);
794: }
795: STATIC_INLINE void fp_log10(fptype *a, fptype *b)
796: {
797: *a = log10l(*b);
798: fp_round(a);
799: }
800: STATIC_INLINE void fp_log2(fptype *a, fptype *b)
801: {
802: *a = log2l(*b);
803: fp_round(a);
804: }
805: STATIC_INLINE void fp_abs(fptype *a, fptype *b)
806: {
807: *a = fabsl(*b);
808: fp_round(a);
809: }
810: STATIC_INLINE void fp_abs_single(fptype *a, fptype *b)
811: {
812: *a = fabsl(*b);
813: fp_round_single(a);
814: }
815: STATIC_INLINE void fp_abs_double(fptype *a, fptype *b)
816: {
817: *a = fabsl(*b);
818: fp_round_double(a);
819: }
820: STATIC_INLINE void fp_cosh(fptype *a, fptype *b)
821: {
822: *a = coshl(*b);
823: fp_round(a);
824: }
825: STATIC_INLINE void fp_neg(fptype *a, fptype *b)
826: {
827: *a = -(*b);
828: fp_round(a);
829: }
830: STATIC_INLINE void fp_neg_single(fptype *a, fptype *b)
831: {
832: *a = -(*b);
833: fp_round_single(a);
834: }
835: STATIC_INLINE void fp_neg_double(fptype *a, fptype *b)
836: {
837: *a = -(*b);
838: fp_round_double(a);
839: }
840: STATIC_INLINE void fp_acos(fptype *a, fptype *b)
841: {
842: *a = acosl(*b);
843: fp_round(a);
844: }
845: STATIC_INLINE void fp_cos(fptype *a, fptype *b)
846: {
847: *a = cosl(*b);
848: fp_round(a);
849: }
850: STATIC_INLINE void fp_getexp(fptype *a, fptype *b)
851: {
852: int expon;
853: frexpl(*b, &expon);
854: *a = (long double) (expon - 1);
855: fp_round(a);
856: }
857: STATIC_INLINE void fp_getman(fptype *a, fptype *b)
858: {
859: int expon;
860: *a = frexpl(*b, &expon) * 2.0;
861: fp_round(a);
862: }
863: STATIC_INLINE void fp_div(fptype *a, fptype *b)
864: {
865: *a /= *b;
866: fp_round(a);
867: }
868: STATIC_INLINE void fp_div_single(fptype *a, fptype *b)
869: {
870: *a /= *b;
871: fp_round_single(a);
872: }
873: STATIC_INLINE void fp_div_double(fptype *a, fptype *b)
874: {
875: *a /= *b;
876: fp_round_double(a);
877: }
878: STATIC_INLINE void fp_mod(fptype *a, fptype *b, uae_u64 *q, uae_s8 *s)
879: {
880: fptype quot;
881: #ifdef USE_HOST_ROUNDING
882: quot = truncl(*a / *b);
883: #else
884: quot = fp_round_to_zero(*a / *b);
885: #endif
886: if (quot < 0.0) {
887: *s = 1;
888: quot = -quot;
889: } else {
890: *s = 0;
891: }
892: *q = (uae_u64)quot;
893: *a = fmodl(*a, *b);
894: fp_round(a);
895: }
896: STATIC_INLINE void fp_add(fptype *a, fptype *b)
897: {
898: *a += *b;
899: fp_round(a);
900: }
901: STATIC_INLINE void fp_add_single(fptype *a, fptype *b)
902: {
903: *a += *b;
904: fp_round_single(a);
905: }
906: STATIC_INLINE void fp_add_double(fptype *a, fptype *b)
907: {
908: *a += *b;
909: fp_round_double(a);
910: }
911: STATIC_INLINE void fp_mul(fptype *a, fptype *b)
912: {
913: *a *= *b;
914: fp_round(a);
915: }
916: STATIC_INLINE void fp_mul_single(fptype *a, fptype *b)
917: {
918: *a *= *b;
919: fp_round_single(a);
920: }
921: STATIC_INLINE void fp_mul_double(fptype *a, fptype *b)
922: {
923: *a *= *b;
924: fp_round_double(a);
925: }
926: STATIC_INLINE void fp_sgldiv(fptype *a, fptype *b)
927: {
928: fptype z;
929: float mant;
930: int expon;
931: z = *a / *b;
932:
933: mant = (float)(frexpl(z, &expon) * 2.0);
934: *a = ldexpl((fptype)mant, expon - 1);
935: }
936: STATIC_INLINE void fp_rem(fptype *a, fptype *b, uae_u64 *q, uae_s8 *s)
937: {
938: fptype quot;
939: #ifdef USE_HOST_ROUNDING
940: quot = roundl(*a / *b);
941: #else
942: quot = fp_round_to_nearest(*a / *b);
943: #endif
944: if (quot < 0.0) {
945: *s = 1;
946: quot = -quot;
947: } else {
948: *s = 0;
949: }
950: *q = (uae_u64)quot;
951: *a = remainderl(*a, *b);
952: fp_round(a);
953: }
954: STATIC_INLINE void fp_scale(fptype *a, fptype *b)
955: {
956: *a = ldexpl(*a, (int) *b);
957: fp_round(a);
958: }
959: STATIC_INLINE void fp_sglmul(fptype *a, fptype *b)
960: {
961: fptype z;
962: float mant;
963: int expon;
964: /* FIXME: truncate mantissa of a and b to single precision */
965: z = *a * (*b);
966:
967: mant = (float)(frexpl(z, &expon) * 2.0);
968: *a = ldexpl((fptype)mant, expon - 1);
969: }
970: STATIC_INLINE void fp_sub(fptype *a, fptype *b)
971: {
972: *a -= *b;
973: fp_round(a);
974: }
975: STATIC_INLINE void fp_sub_single(fptype *a, fptype *b)
976: {
977: *a -= *b;
978: fp_round_single(a);
979: }
980: STATIC_INLINE void fp_sub_double(fptype *a, fptype *b)
981: {
982: *a -= *b;
983: fp_round_double(a);
984: }
985: STATIC_INLINE void fp_cmp(fptype *a, fptype *b)
986: {
987: *a = (*a - *b); /* FIXME: comparing is different from subtraction */
988: }
989: STATIC_INLINE void fp_tst(fptype *a, fptype *b)
990: {
991: *a = *b; /* FIXME: test b */
992: }
993:
994: #else // if !USE_LONG_DOUBLE
995:
996: STATIC_INLINE void fp_move(fptype *a, fptype *b)
997: {
998: *a = *b;
999: fp_round(a);
1000: }
1001: STATIC_INLINE void fp_move_single(fptype *a, fptype *b)
1002: {
1003: *a = *b;
1004: fp_round_single(a);
1005: }
1006: STATIC_INLINE void fp_move_double(fptype *a, fptype *b)
1007: {
1008: *a = *b;
1009: fp_round_double(a);
1010: }
1011: STATIC_INLINE void fp_int(fptype *a, fptype *b)
1012: {
1013: #ifdef USE_HOST_ROUNDING
1014: *a = rint(*b);
1015: #else
1016: switch (regs.fpcr & FPCR_ROUNDING_MODE)
1017: {
1018: case FPCR_ROUND_NEAR:
1019: *a = fp_round_to_nearest(*b);
1020: break;
1021: case FPCR_ROUND_ZERO:
1022: *a = fp_round_to_zero(*b);
1023: break;
1024: case FPCR_ROUND_MINF:
1025: *a = fp_round_to_minus_infinity(*b);
1026: break;
1027: case FPCR_ROUND_PINF:
1028: *a = fp_round_to_plus_infinity(*b);
1029: break;
1030: default: /* never reached */
1031: break;
1032: }
1033: #endif
1034: fp_round(a);
1035: }
1036: STATIC_INLINE void fp_sinh(fptype *a, fptype *b)
1037: {
1038: *a = sinh(*b);
1039: fp_round(a);
1040: }
1041: STATIC_INLINE void fp_intrz(fptype *a, fptype *b)
1042: {
1043: #ifdef USE_HOST_ROUNDING
1044: *a = trunc(*b);
1045: #else
1046: *a = fp_round_to_zero (*b);
1047: #endif
1048: fp_round(a);
1049: }
1050: STATIC_INLINE void fp_sqrt(fptype *a, fptype *b)
1051: {
1052: *a = sqrt(*b);
1053: fp_round(a);
1054: }
1055: STATIC_INLINE void fp_sqrt_single(fptype *a, fptype *b)
1056: {
1057: *a = sqrt(*b);
1058: fp_round_single(a);
1059: }
1060: STATIC_INLINE void fp_sqrt_double(fptype *a, fptype *b)
1061: {
1062: *a = sqrt(*b);
1063: fp_round_double(a);
1064: }
1065: STATIC_INLINE void fp_lognp1(fptype *a, fptype *b)
1066: {
1067: *a = log1p(*b);
1068: fp_round(a);
1069: }
1070: STATIC_INLINE void fp_etoxm1(fptype *a, fptype *b)
1071: {
1072: *a = expm1(*b);
1073: fp_round(a);
1074: }
1075: STATIC_INLINE void fp_tanh(fptype *a, fptype *b)
1076: {
1077: *a = tanh(*b);
1078: fp_round(a);
1079: }
1080: STATIC_INLINE void fp_atan(fptype *a, fptype *b)
1081: {
1082: *a = atan(*b);
1083: fp_round(a);
1084: }
1085: STATIC_INLINE void fp_asin(fptype *a, fptype *b)
1086: {
1087: *a = asin(*b);
1088: fp_round(a);
1089: }
1090: STATIC_INLINE void fp_atanh(fptype *a, fptype *b)
1091: {
1092: *a = atanh(*b);
1093: fp_round(a);
1094: }
1095: STATIC_INLINE void fp_sin(fptype *a, fptype *b)
1096: {
1097: *a = sin(*b);
1098: fp_round(a);
1099: }
1100: STATIC_INLINE void fp_tan(fptype *a, fptype *b)
1101: {
1102: *a = tan(*b);
1103: fp_round(a);
1104: }
1105: STATIC_INLINE void fp_etox(fptype *a, fptype *b)
1106: {
1107: *a = exp(*b);
1108: fp_round(a);
1109: }
1110: STATIC_INLINE void fp_twotox(fptype *a, fptype *b)
1111: {
1112: *a = pow(2.0, *b);
1113: fp_round(a);
1114: }
1115: STATIC_INLINE void fp_tentox(fptype *a, fptype *b)
1116: {
1117: *a = pow(10.0, *b);
1118: fp_round(a);
1119: }
1120: STATIC_INLINE void fp_logn(fptype *a, fptype *b)
1121: {
1122: *a = log(*b);
1123: fp_round(a);
1124: }
1125: STATIC_INLINE void fp_log10(fptype *a, fptype *b)
1126: {
1127: *a = log10(*b);
1128: fp_round(a);
1129: }
1130: STATIC_INLINE void fp_log2(fptype *a, fptype *b)
1131: {
1132: *a = log2(*b);
1133: fp_round(a);
1134: }
1135: STATIC_INLINE void fp_abs(fptype *a, fptype *b)
1136: {
1137: *a = fabs(*b);
1138: fp_round(a);
1139: }
1140: STATIC_INLINE void fp_abs_single(fptype *a, fptype *b)
1141: {
1142: *a = fabs(*b);
1143: fp_round_single(a);
1144: }
1145: STATIC_INLINE void fp_abs_double(fptype *a, fptype *b)
1146: {
1147: *a = fabs(*b);
1148: fp_round_double(a);
1149: }
1150: STATIC_INLINE void fp_cosh(fptype *a, fptype *b)
1151: {
1152: *a = cosh(*b);
1153: fp_round(a);
1154: }
1155: STATIC_INLINE void fp_neg(fptype *a, fptype *b)
1156: {
1157: *a = -(*b);
1158: fp_round(a);
1159: }
1160: STATIC_INLINE void fp_neg_single(fptype *a, fptype *b)
1161: {
1162: *a = -(*b);
1163: fp_round_single(a);
1164: }
1165: STATIC_INLINE void fp_neg_double(fptype *a, fptype *b)
1166: {
1167: *a = -(*b);
1168: fp_round_double(a);
1169: }
1170: STATIC_INLINE void fp_acos(fptype *a, fptype *b)
1171: {
1172: *a = acos(*b);
1173: fp_round(a);
1174: }
1175: STATIC_INLINE void fp_cos(fptype *a, fptype *b)
1176: {
1177: *a = cos(*b);
1178: fp_round(a);
1179: }
1180: STATIC_INLINE void fp_getexp(fptype *a, fptype *b)
1181: {
1182: int expon;
1183: frexp(*b, &expon);
1184: *a = (long double) (expon - 1);
1185: fp_round(a);
1186: }
1187: STATIC_INLINE void fp_getman(fptype *a, fptype *b)
1188: {
1189: int expon;
1190: *a = frexp(*b, &expon) * 2.0;
1191: fp_round(a);
1192: }
1193: STATIC_INLINE void fp_div(fptype *a, fptype *b)
1194: {
1195: *a /= *b;
1196: fp_round(a);
1197: }
1198: STATIC_INLINE void fp_div_single(fptype *a, fptype *b)
1199: {
1200: *a /= *b;
1201: fp_round_single(a);
1202: }
1203: STATIC_INLINE void fp_div_double(fptype *a, fptype *b)
1204: {
1205: *a /= *b;
1206: fp_round_double(a);
1207: }
1208: STATIC_INLINE void fp_mod(fptype *a, fptype *b, uae_u64 *q, uae_s8 *s)
1209: {
1210: fptype quot;
1211: #ifdef USE_HOST_ROUNDING
1212: quot = trunc(*a / *b);
1213: #else
1214: quot = fp_round_to_zero(*a / *b);
1215: #endif
1216: if (quot < 0.0) {
1217: *s = 1;
1218: quot = -quot;
1219: } else {
1220: *s = 0;
1221: }
1222: *q = (uae_u64)quot;
1223: *a = fmod(*a, *b);
1224: fp_round(a);
1225: }
1226: STATIC_INLINE void fp_add(fptype *a, fptype *b)
1227: {
1228: *a += *b;
1229: fp_round(a);
1230: }
1231: STATIC_INLINE void fp_add_single(fptype *a, fptype *b)
1232: {
1233: *a += *b;
1234: fp_round_single(a);
1235: }
1236: STATIC_INLINE void fp_add_double(fptype *a, fptype *b)
1237: {
1238: *a += *b;
1239: fp_round_double(a);
1240: }
1241: STATIC_INLINE void fp_mul(fptype *a, fptype *b)
1242: {
1243: *a *= *b;
1244: fp_round(a);
1245: }
1246: STATIC_INLINE void fp_mul_single(fptype *a, fptype *b)
1247: {
1248: *a *= *b;
1249: fp_round_single(a);
1250: }
1251: STATIC_INLINE void fp_mul_double(fptype *a, fptype *b)
1252: {
1253: *a *= *b;
1254: fp_round_double(a);
1255: }
1256: STATIC_INLINE void fp_sgldiv(fptype *a, fptype *b)
1257: {
1258: fptype z;
1259: float mant;
1260: int expon;
1261: z = *a / *b;
1262:
1263: mant = (float)(frexp(z, &expon) * 2.0);
1264: *a = ldexp((fptype)mant, expon - 1);
1265: }
1266: STATIC_INLINE void fp_rem(fptype *a, fptype *b, uae_u64 *q, uae_s8 *s)
1267: {
1268: fptype quot;
1269: #ifdef USE_HOST_ROUNDING
1270: quot = round(*a / *b);
1271: #else
1272: quot = fp_round_to_nearest(*a / *b);
1273: #endif
1274: if (quot < 0.0) {
1275: *s = 1;
1276: quot = -quot;
1277: } else {
1278: *s = 0;
1279: }
1280: *q = (uae_u64)quot;
1281: *a = remainder(*a, *b);
1282: fp_round(a);
1283: }
1284: STATIC_INLINE void fp_scale(fptype *a, fptype *b)
1285: {
1286: *a = ldexp(*a, (int) *b);
1287: fp_round(a);
1288: }
1289: STATIC_INLINE void fp_sglmul(fptype *a, fptype *b)
1290: {
1291: fptype z;
1292: float mant;
1293: int expon;
1294: /* FIXME: truncate mantissa of a and b to single precision */
1295: z = *a * (*b);
1296:
1297: mant = (float)(frexp(z, &expon) * 2.0);
1298: *a = ldexp((fptype)mant, expon - 1);
1299: }
1300: STATIC_INLINE void fp_sub(fptype *a, fptype *b)
1301: {
1302: *a -= *b;
1303: fp_round(a);
1304: }
1305: STATIC_INLINE void fp_sub_single(fptype *a, fptype *b)
1306: {
1307: *a -= *b;
1308: fp_round_single(a);
1309: }
1310: STATIC_INLINE void fp_sub_double(fptype *a, fptype *b)
1311: {
1312: *a -= *b;
1313: fp_round_double(a);
1314: }
1315: STATIC_INLINE void fp_cmp(fptype *a, fptype *b)
1316: {
1317: *a = (*a - *b); /* FIXME: comparing is different from subtraction */
1318: }
1319: STATIC_INLINE void fp_tst(fptype *a, fptype *b)
1320: {
1321: *a = *b; /* FIXME: test b */
1322: }
1323:
1324: #endif // !USE_LONG_DOUBLE
1325:
1326: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.