--- previous/src/cpu/md-fpp.h 2018/04/24 19:25:47 1.1 +++ previous/src/cpu/md-fpp.h 2018/04/24 19:31:51 1.1.1.4 @@ -1,4 +1,4 @@ - /* +/* * UAE - The Un*x Amiga Emulator * * MC68881 emulation @@ -9,6 +9,19 @@ * Modified 2005 Peter Keunecke */ +#ifndef FPP_H +#define FPP_H + +#define __USE_ISOC9X /* We might be able to pick up a NaN */ + +#include +#include +#include + +//#pragma STDC FENV_ACCESS on + +#define USE_HOST_ROUNDING + #define FPCR_ROUNDING_MODE 0x00000030 #define FPCR_ROUND_NEAR 0x00000000 #define FPCR_ROUND_ZERO 0x00000010 @@ -20,188 +33,1291 @@ #define FPCR_PRECISION_DOUBLE 0x00000080 #define FPCR_PRECISION_EXTENDED 0x00000000 -#if USE_LONG_DOUBLE -STATIC_INLINE long double to_exten(uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3) -{ - uae_u32 longarray[] = {wrd3,wrd2,((wrd1>>16)&0xffff)}; // little endian - register long double *longdoublewords = (long double *)longarray; +extern uae_u32 fpp_get_fpsr (void); +extern void fpsr_set_exception(uae_u32 exception); - return(*longdoublewords); -} -#define HAVE_to_exten +static int fp_rnd_prec = 80; -STATIC_INLINE void from_exten(long double src, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3) +/* Functions for setting host/library modes and getting status */ +STATIC_INLINE void set_fp_mode(uae_u32 mode_control) { - register uae_u32 *longarray = (uae_u32 *)&src; - register uae_u16 *finalword = (uae_u16 *)(&src + 8); - - *wrd1 = ((uae_u32)*finalword)<<16; - *wrd2 = longarray[1]; - *wrd3 = longarray[0]; // little endian + switch(mode_control & FPCR_ROUNDING_PRECISION) { + case FPCR_PRECISION_EXTENDED: // X + fp_rnd_prec = 80; + break; + case FPCR_PRECISION_SINGLE: // S + fp_rnd_prec = 32; + break; + case FPCR_PRECISION_DOUBLE: // D + default: // undefined + fp_rnd_prec = 64; + break; + } +#ifdef USE_HOST_ROUNDING + switch(mode_control & FPCR_ROUNDING_MODE) { + case FPCR_ROUND_NEAR: // to neareset + fesetround(FE_TONEAREST); + break; + case FPCR_ROUND_ZERO: // to zero + fesetround(FE_TOWARDZERO); + break; + case FPCR_ROUND_MINF: // to minus + fesetround(FE_DOWNWARD); + break; + case FPCR_ROUND_PINF: // to plus + fesetround(FE_UPWARD); + break; + } + return; +#endif } -#define HAVE_from_exten -#endif /* USE_LONG_DOUBLE */ - -#if defined(X86_MSVC_ASSEMBLY) -#ifndef HAVE_to_single -#define HAVE_to_single -STATIC_INLINE double to_single (uae_u32 longvalue) +STATIC_INLINE void get_fp_status(uae_u32 *status) { - double floatfake; - - __asm { - fld dword ptr longvalue; - fstp qword ptr floatfake; + int exp_flags = fetestexcept(FE_ALL_EXCEPT); + if (exp_flags) { + if (exp_flags & FE_INEXACT) + *status |= 0x0200; + if (exp_flags & FE_DIVBYZERO) + *status |= 0x0400; + if (exp_flags & FE_UNDERFLOW) + *status |= 0x0800; + if (exp_flags & FE_OVERFLOW) + *status |= 0x1000; + if (exp_flags & FE_INVALID) + *status |= 0x2000; } - return(floatfake); + /* FIXME: how to detect SNAN? */ } -#endif - -#ifndef HAVE_from_single -#define HAVE_from_single -STATIC_INLINE uae_u32 from_single (double floatfake) +STATIC_INLINE void clear_fp_status(void) { - uae_u32 longvalue; - - __asm { - fld qword ptr floatfake; - fstp dword ptr longvalue; - } - return(longvalue); + feclearexcept (FE_ALL_EXCEPT); } -#endif -#ifndef HAVE_to_exten -#define HAVE_to_exten -STATIC_INLINE double to_exten(uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3) +/* Helper functions */ +STATIC_INLINE const char *fp_print(fptype *fx) { - uae_u32 longarray[] = {wrd3,wrd2,((wrd1>>16)&0xffff)}; // little endian - double extenfake; - - __asm { - fld tbyte ptr longarray; - fstp qword ptr extenfake; + static char fs[32]; + bool n, d; + + n = signbit(*fx) ? 1 : 0; + d = isnormal(*fx) ? 0 : 1; + + if (isinf(*fx)) { + sprintf(fs, "%c%s", n?'-':'+', "inf"); + } else if (isnan(*fx)) { + sprintf(fs, "%c%s", n?'-':'+', "nan"); + } else { + if (n) + *fx *= -1.0; +#ifdef USE_LONG_DOUBLE + sprintf(fs, "%c%#.16Le%s%s", n?'-':'+', *fx, "", d?"D":""); +#else + sprintf(fs, "%c%#.16e%s%s", n?'-':'+', *fx, "", d?"D":""); +#endif } - return(extenfake); + + return fs; } -#endif -#ifndef HAVE_from_exten -#define HAVE_from_exten -STATIC_INLINE void from_exten(double src, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3) +/* Functions for detecting float type */ +STATIC_INLINE bool fp_is_snan(fptype *fp) { - uae_u32 longarray[3], *srcarray = (uae_u32 *)&src; + return 0; /* FIXME: how to detect SNAN */ +} +STATIC_INLINE void fp_unset_snan(fptype *fp) +{ + /* FIXME: how to unset SNAN */ +} +STATIC_INLINE bool fp_is_nan (fptype *fp) +{ + return isnan(*fp) != 0; +} +STATIC_INLINE bool fp_is_infinity (fptype *fp) +{ + return isinf(*fp) != 0; +} +STATIC_INLINE bool fp_is_zero(fptype *fp) +{ + return (*fp == 0.0); +} +STATIC_INLINE bool fp_is_neg(fptype *fp) +{ + return signbit(*fp) != 0; +} +STATIC_INLINE bool fp_is_denormal(fptype *fp) +{ + return false; + //return (isnormal(*fp) == 0); /* FIXME: how to differ denormal/unnormal? */ +} +STATIC_INLINE bool fp_is_unnormal(fptype *fp) +{ + return false; + //return (isnormal(*fp) == 0); /* FIXME: how to differ denormal/unnormal? */ +} - __asm { - fld qword ptr src; - fstp tbyte ptr longarray; - } - *wrd1 = (longarray[2] & 0xffff) <<16; - *wrd2 = longarray[1]; - *wrd3 = longarray[0]; // little endian - if (!srcarray[0] && (srcarray[1]==0x7ff00000 || srcarray[1]==0xfff00000)) - *wrd2 = 0; // The MSB of the mantissa was set wrongly for infinity, causing a NaN +/* Function for normalizing unnormals FIXME: how to do this with native floats? */ +STATIC_INLINE void fp_normalize(fptype *fp) +{ } -#endif -#endif /* X86_MSVC_ASSEMBLY */ -#ifndef HAVE_to_single -#define HAVE_to_single -STATIC_INLINE double to_single (uae_u32 value) +/* Functions for converting between float formats */ +/* FIXME: how to preserve/fix denormals and unnormals? */ + +STATIC_INLINE void to_single(fptype *fp, uae_u32 wrd1) { union { - float f; - uae_u32 u; + float f; + uae_u32 u; } val; - - val.u = value; - return val.f; + + val.u = wrd1; + *fp = (fptype) val.f; } -#endif - -#ifndef HAVE_from_single -#define HAVE_from_single -STATIC_INLINE uae_u32 from_single (double src) +STATIC_INLINE uae_u32 from_single(fptype *fp) { union { - float f; - uae_u32 u; + float f; + uae_u32 u; } val; - - val.f = (float) src; + + val.f = (float) *fp; return val.u; } -#endif -#ifndef HAVE_to_double -#define HAVE_to_double -STATIC_INLINE double to_double(uae_u32 wrd1, uae_u32 wrd2) +STATIC_INLINE void to_double(fptype *fp, uae_u32 wrd1, uae_u32 wrd2) { union { - double d; - uae_u32 u[2]; + double d; + uae_u32 u[2]; } val; - - val.u[0] = wrd2; // little endian + +#ifdef WORDS_BIGENDIAN + val.u[0] = wrd1; + val.u[1] = wrd2; +#else val.u[1] = wrd1; - return val.d; + val.u[0] = wrd2; +#endif + *fp = (fptype) val.d; } +STATIC_INLINE void from_double(fptype *fp, uae_u32 *wrd1, uae_u32 *wrd2) +{ + union { + double d; + uae_u32 u[2]; + } val; + + val.d = (double) *fp; +#ifdef WORDS_BIGENDIAN + *wrd1 = val.u[0]; + *wrd2 = val.u[1]; +#else + *wrd1 = val.u[1]; + *wrd2 = val.u[0]; #endif - -#ifndef HAVE_from_double -#define HAVE_from_double -STATIC_INLINE void from_double(double src, uae_u32 * wrd1, uae_u32 * wrd2) +} +#ifdef USE_LONG_DOUBLE +STATIC_INLINE void to_exten(fptype *fp, uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3) { - register uae_u32 *longarray = (uae_u32 *)&src; + union { + long double ld; + uae_u32 u[3]; + } val; - *wrd1 = longarray[1]; // little endian - *wrd2 = longarray[0]; +#if WORDS_BIGENDIAN + val.u[0] = (wrd1 & 0xffff0000) | ((wrd2 & 0xffff0000) >> 16); + val.u[1] = (wrd2 & 0x0000ffff) | ((wrd3 & 0xffff0000) >> 16); + val.u[2] = (wrd3 & 0x0000ffff) << 16; +#else + val.u[0] = wrd3; + val.u[1] = wrd2; + val.u[2] = wrd1 >> 16; +#endif + *fp = val.ld; } +STATIC_INLINE void from_exten(fptype *fp, uae_u32 *wrd1, uae_u32 *wrd2, uae_u32 *wrd3) +{ + union { + long double ld; + uae_u32 u[3]; + } val; + + val.ld = *fp; +#if WORDS_BIGENDIAN + *wrd1 = val.u[0] & 0xffff0000; + *wrd2 = ((val.u[0] & 0x0000ffff) << 16) | ((val.u[1] & 0xffff0000) >> 16); + *wrd3 = ((val.u[1] & 0x0000ffff) << 16) | ((val.u[2] & 0xffff0000) >> 16); +#else + *wrd3 = val.u[0]; + *wrd2 = val.u[1]; + *wrd1 = val.u[2] << 16; #endif - -static double twoto32 = 4294967296.0; -#ifndef HAVE_to_exten -#define HAVE_to_exten -STATIC_INLINE double to_exten(uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3) +} +#else // if !USE_LONG_DOUBLE +static const double twoto32 = 4294967296.0; +STATIC_INLINE void to_exten(fptype *fp, uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3) { double frac; - - if ((wrd1 & 0x7fff0000) == 0 && wrd2 == 0 && wrd3 == 0) - return 0.0; + if ((wrd1 & 0x7fff0000) == 0 && wrd2 == 0 && wrd3 == 0) { + *fp = (wrd1 & 0x80000000) ? -0.0 : +0.0; + return; + } frac = ((double)wrd2 + ((double)wrd3 / twoto32)) / 2147483648.0; if (wrd1 & 0x80000000) - frac = -frac; - return ldexp (frac, ((wrd1 >> 16) & 0x7fff) - 16383); + frac = -frac; + *fp = ldexp (frac, ((wrd1 >> 16) & 0x7fff) - 16383); } -#endif - -#ifndef HAVE_from_exten -#define HAVE_from_exten -STATIC_INLINE void from_exten(double src, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3) +STATIC_INLINE void from_exten(fptype *fp, uae_u32 *wrd1, uae_u32 *wrd2, uae_u32 *wrd3) { int expon; double frac; - - if (src == 0.0) { - *wrd1 = 0; - *wrd2 = 0; - *wrd3 = 0; - return; - } - if (src < 0) { - *wrd1 = 0x80000000; - src = -src; + fptype v; + + v = *fp; + if (v == 0.0) { + *wrd1 = signbit(v) ? 0x80000000 : 0; + *wrd2 = 0; + *wrd3 = 0; + return; + } + if (v < 0) { + *wrd1 = 0x80000000; + v = -v; } else { - *wrd1 = 0; + *wrd1 = 0; } - frac = frexp (src, &expon); + frac = frexp (v, &expon); frac += 0.5 / (twoto32 * twoto32); if (frac >= 1.0) { - frac /= 2.0; - expon++; + frac /= 2.0; + expon++; } *wrd1 |= (((expon + 16383 - 1) & 0x7fff) << 16); *wrd2 = (uae_u32) (frac * twoto32); *wrd3 = (uae_u32) ((frac * twoto32 - *wrd2) * twoto32); } +#endif // !USE_LONG_DOUBLE +STATIC_INLINE void to_exten_fmovem(fptype *fp, uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3) +{ + to_exten(fp, wrd1, wrd2, wrd3); +} +STATIC_INLINE void from_exten_fmovem(fptype *fp, uae_u32 *wrd1, uae_u32 *wrd2, uae_u32 *wrd3) +{ + from_exten(fp, wrd1, wrd2, wrd3); +} + +STATIC_INLINE void to_pack (fptype *fp, uae_u32 *wrd) +{ + char *cp; + char str[100]; + + if (((wrd[0] >> 16) & 0x7fff) == 0x7fff) { + // infinity has extended exponent and all 0 packed fraction + // nans are copies bit by bit + to_exten(fp, wrd[0], wrd[1], wrd[2]); + return; + } + if (!(wrd[0] & 0xf) && !wrd[1] && !wrd[2]) { + // exponent is not cared about, if mantissa is zero + wrd[0] &= 0x80000000; + to_exten(fp, wrd[0], wrd[1], wrd[2]); + return; + } + + cp = str; + if (wrd[0] & 0x80000000) + *cp++ = '-'; + *cp++ = (wrd[0] & 0xf) + '0'; + *cp++ = '.'; + *cp++ = ((wrd[1] >> 28) & 0xf) + '0'; + *cp++ = ((wrd[1] >> 24) & 0xf) + '0'; + *cp++ = ((wrd[1] >> 20) & 0xf) + '0'; + *cp++ = ((wrd[1] >> 16) & 0xf) + '0'; + *cp++ = ((wrd[1] >> 12) & 0xf) + '0'; + *cp++ = ((wrd[1] >> 8) & 0xf) + '0'; + *cp++ = ((wrd[1] >> 4) & 0xf) + '0'; + *cp++ = ((wrd[1] >> 0) & 0xf) + '0'; + *cp++ = ((wrd[2] >> 28) & 0xf) + '0'; + *cp++ = ((wrd[2] >> 24) & 0xf) + '0'; + *cp++ = ((wrd[2] >> 20) & 0xf) + '0'; + *cp++ = ((wrd[2] >> 16) & 0xf) + '0'; + *cp++ = ((wrd[2] >> 12) & 0xf) + '0'; + *cp++ = ((wrd[2] >> 8) & 0xf) + '0'; + *cp++ = ((wrd[2] >> 4) & 0xf) + '0'; + *cp++ = ((wrd[2] >> 0) & 0xf) + '0'; + *cp++ = 'E'; + if (wrd[0] & 0x40000000) + *cp++ = '-'; + *cp++ = ((wrd[0] >> 24) & 0xf) + '0'; + *cp++ = ((wrd[0] >> 20) & 0xf) + '0'; + *cp++ = ((wrd[0] >> 16) & 0xf) + '0'; + *cp = 0; + +#ifdef USE_LONG_DOUBLE + sscanf (str, "%Le", fp); +#else + sscanf (str, "%le", fp); +#endif +} +STATIC_INLINE void from_pack (fptype *fp, uae_u32 *wrd, int kfactor) +{ + int i, j, t; + int exp; + int ndigits; + char *cp, *strp; + char str[100]; + + if (fp_is_nan (fp)) { + // copy bit by bit, handle signaling nan + from_exten(fp, &wrd[0], &wrd[1], &wrd[2]); + return; + } + if (fp_is_infinity (fp)) { + // extended exponent and all 0 packed fraction + from_exten(fp, &wrd[0], &wrd[1], &wrd[2]); + wrd[1] = wrd[2] = 0; + return; + } + + wrd[0] = wrd[1] = wrd[2] = 0; + +#ifdef USE_LONG_DOUBLE + sprintf (str, "%#.17Le", *fp); +#else + sprintf (str, "%#.17e", *fp); +#endif + + // get exponent + cp = str; + while (*cp != 'e') { + if (*cp == 0) + return; + cp++; + } + cp++; + if (*cp == '+') + cp++; + exp = atoi (cp); + + // remove trailing zeros + cp = str; + while (*cp != 'e') + cp++; + cp[0] = 0; + cp--; + while (cp > str && *cp == '0') { + *cp = 0; + cp--; + } + + cp = str; + // get sign + if (*cp == '-') { + cp++; + wrd[0] = 0x80000000; + } else if (*cp == '+') { + cp++; + } + strp = cp; + + if (kfactor <= 0) { + ndigits = abs (exp) + (-kfactor) + 1; + } else { + if (kfactor > 17) { + kfactor = 17; + fpsr_set_exception(0x00002000); // OPERR + } + ndigits = kfactor; + } + + if (ndigits < 0) + ndigits = 0; + if (ndigits > 16) + ndigits = 16; + + // remove decimal point + strp[1] = strp[0]; + strp++; + // add trailing zeros + i = strlen (strp); + cp = strp + i; + while (i < ndigits) { + *cp++ = '0'; + i++; + } + i = ndigits + 1; + while (i < 17) { + strp[i] = 0; + i++; + } + *cp = 0; + i = ndigits - 1; + // need to round? + if (i >= 0 && strp[i + 1] >= '5') { + while (i >= 0) { + strp[i]++; + if (strp[i] <= '9') + break; + if (i == 0) { + strp[i] = '1'; + exp++; + } else { + strp[i] = '0'; + } + i--; + } + } + strp[ndigits] = 0; + + // store first digit of mantissa + cp = strp; + wrd[0] |= *cp++ - '0'; + + // store rest of mantissa + for (j = 1; j < 3; j++) { + for (i = 0; i < 8; i++) { + wrd[j] <<= 4; + if (*cp >= '0' && *cp <= '9') + wrd[j] |= *cp++ - '0'; + } + } + + // exponent + if (exp < 0) { + wrd[0] |= 0x40000000; + exp = -exp; + } + if (exp > 9999) // ?? + exp = 9999; + if (exp > 999) { + int d = exp / 1000; + wrd[0] |= d << 12; + exp -= d * 1000; + fpsr_set_exception(0x00002000); // OPERR + } + i = 100; + t = 0; + while (i >= 1) { + int d = exp / i; + t <<= 4; + t |= d; + exp -= d * i; + i /= 10; + } + wrd[0] |= t << 16; +} + +#ifndef USE_HOST_ROUNDING +#ifdef USE_LONG_DOUBLE +#define fp_round_to_minus_infinity(x) floorl(x) +#define fp_round_to_plus_infinity(x) ceill(x) +#define fp_round_to_zero(x) ((x) >= 0.0 ? floorl(x) : ceill(x)) +#define fp_round_to_nearest(x) roundl(x) +#else // if !USE_LONG_DOUBLE +#define fp_round_to_minus_infinity(x) floor(x) +#define fp_round_to_plus_infinity(x) ceil(x) +#define fp_round_to_zero(x) ((x) >= 0.0 ? floor(x) : ceil(x)) +#define fp_round_to_nearest(x) round(x) +#endif // !USE_LONG_DOUBLE +#endif // USE_HOST_ROUNDING + +STATIC_INLINE uae_s64 to_int(fptype *src, int size) +{ + static fptype fxsizes[6] = + { + -128.0, 127.0, + -32768.0, 32767.0, + -2147483648.0, 2147483647.0 + }; + + if (*src < fxsizes[size * 2 + 0]) + *src = fxsizes[size * 2 + 0]; + if (*src > fxsizes[size * 2 + 1]) + *src = fxsizes[size * 2 + 1]; +#ifdef USE_HOST_ROUNDING +#ifdef USE_LONG_DOUBLE + return lrintl(*src); +#else + return lrint(*src); +#endif +#else + switch (regs.fpcr & FPCR_ROUNDING_MODE) + { + case FPCR_ROUND_ZERO: + return fp_round_to_zero (*src); + case FPCR_ROUND_MINF: + return fp_round_to_minus_infinity (*src); + case FPCR_ROUND_NEAR: + return fp_round_to_nearest (*src); + case FPCR_ROUND_PINF: + return fp_round_to_plus_infinity (*src); + default: + return (int) *src; + } +#endif +} +STATIC_INLINE fptype from_int(uae_s32 src) +{ + return (fptype) src; +} + +/* Functions for returning exception state data */ +/* (almost impossible to emulate using native floats) */ +STATIC_INLINE fptype fp_get_internal_overflow(void) +{ + return 0.0; +} +STATIC_INLINE fptype fp_get_internal_underflow(void) +{ + return 0.0; +} +STATIC_INLINE fptype fp_get_internal(void) +{ + return 0.0; +} +STATIC_INLINE fptype fp_get_internal_round(void) +{ + return 0.0; +} +STATIC_INLINE fptype fp_get_internal_round_all(void) +{ + return 0.0; +} +STATIC_INLINE fptype fp_get_internal_round_exten(void) +{ + return 0.0; +} +STATIC_INLINE uae_u32 fp_get_internal_grs(void) +{ + return 0.0; +} + +/* Function for denormalizing */ +STATIC_INLINE void fp_denormalize(fptype *fp, int esign) +{ + // do nothing +} + +/* Functions for rounding */ + +// round to float with extended precision exponent +STATIC_INLINE void fp_round32(fptype *fp) +{ + int expon; + float mant; +#ifdef USE_LONG_DOUBLE + mant = (float)(frexpl(*fp, &expon) * 2.0); + *fp = ldexpl((fptype)mant, expon - 1); +#else + mant = (float)(frexp(*fp, &expon) * 2.0); + *fp = ldexp((fptype)mant, expon - 1); +#endif +} + +// round to double with extended precision exponent +STATIC_INLINE void fp_round64(fptype *fp) +{ + int expon; + double mant; +#ifdef USE_LONG_DOUBLE + mant = (double)(frexpl(*fp, &expon) * 2.0); + *fp = ldexpl((fptype)mant, expon - 1); +#else + mant = (double)(frexp(*fp, &expon) * 2.0); + *fp = ldexp((fptype)mant, expon - 1); +#endif +} + +// round to float +STATIC_INLINE void fp_round_single(fptype *fp) +{ + *fp = (float) *fp; +} + +// round to double +STATIC_INLINE void fp_round_double(fptype *fp) +{ + *fp = (double) *fp; +} + +// round to selected precision +STATIC_INLINE void fp_round(fptype *fp) +{ + switch(fp_rnd_prec) { + case 32: + *fp = (float) *fp; + break; + case 64: + *fp = (double) *fp; + break; + default: + break; + } +} + + +/* Arithmetic functions */ + +#ifdef USE_LONG_DOUBLE + +STATIC_INLINE void fp_move(fptype *a, fptype *b) +{ + *a = *b; + fp_round(a); +} +STATIC_INLINE void fp_move_single(fptype *a, fptype *b) +{ + *a = *b; + fp_round_single(a); +} +STATIC_INLINE void fp_move_double(fptype *a, fptype *b) +{ + *a = *b; + fp_round_double(a); +} +STATIC_INLINE void fp_int(fptype *a, fptype *b) +{ +#ifdef USE_HOST_ROUNDING + *a = rintl(*b); +#else + switch (regs.fpcr & FPCR_ROUNDING_MODE) + { + case FPCR_ROUND_NEAR: + *a = fp_round_to_nearest(*b); + break; + case FPCR_ROUND_ZERO: + *a = fp_round_to_zero(*b); + break; + case FPCR_ROUND_MINF: + *a = fp_round_to_minus_infinity(*b); + break; + case FPCR_ROUND_PINF: + *a = fp_round_to_plus_infinity(*b); + break; + default: /* never reached */ + break; + } +#endif + fp_round(a); +} +STATIC_INLINE void fp_sinh(fptype *a, fptype *b) +{ + *a = sinhl(*b); + fp_round(a); +} +STATIC_INLINE void fp_intrz(fptype *a, fptype *b) +{ +#ifdef USE_HOST_ROUNDING + *a = truncl(*b); +#else + *a = fp_round_to_zero (*b); +#endif + fp_round(a); +} +STATIC_INLINE void fp_sqrt(fptype *a, fptype *b) +{ + *a = sqrtl(*b); + fp_round(a); +} +STATIC_INLINE void fp_sqrt_single(fptype *a, fptype *b) +{ + *a = sqrtl(*b); + fp_round_single(a); +} +STATIC_INLINE void fp_sqrt_double(fptype *a, fptype *b) +{ + *a = sqrtl(*b); + fp_round_double(a); +} +STATIC_INLINE void fp_lognp1(fptype *a, fptype *b) +{ + *a = log1pl(*b); + fp_round(a); +} +STATIC_INLINE void fp_etoxm1(fptype *a, fptype *b) +{ + *a = expm1l(*b); + fp_round(a); +} +STATIC_INLINE void fp_tanh(fptype *a, fptype *b) +{ + *a = tanhl(*b); + fp_round(a); +} +STATIC_INLINE void fp_atan(fptype *a, fptype *b) +{ + *a = atanl(*b); + fp_round(a); +} +STATIC_INLINE void fp_asin(fptype *a, fptype *b) +{ + *a = asinl(*b); + fp_round(a); +} +STATIC_INLINE void fp_atanh(fptype *a, fptype *b) +{ + *a = atanhl(*b); + fp_round(a); +} +STATIC_INLINE void fp_sin(fptype *a, fptype *b) +{ + *a = sinl(*b); + fp_round(a); +} +STATIC_INLINE void fp_tan(fptype *a, fptype *b) +{ + *a = tanl(*b); + fp_round(a); +} +STATIC_INLINE void fp_etox(fptype *a, fptype *b) +{ + *a = expl(*b); + fp_round(a); +} +STATIC_INLINE void fp_twotox(fptype *a, fptype *b) +{ + *a = powl(2.0, *b); + fp_round(a); +} +STATIC_INLINE void fp_tentox(fptype *a, fptype *b) +{ + *a = powl(10.0, *b); + fp_round(a); +} +STATIC_INLINE void fp_logn(fptype *a, fptype *b) +{ + *a = logl(*b); + fp_round(a); +} +STATIC_INLINE void fp_log10(fptype *a, fptype *b) +{ + *a = log10l(*b); + fp_round(a); +} +STATIC_INLINE void fp_log2(fptype *a, fptype *b) +{ + *a = log2l(*b); + fp_round(a); +} +STATIC_INLINE void fp_abs(fptype *a, fptype *b) +{ + *a = fabsl(*b); + fp_round(a); +} +STATIC_INLINE void fp_abs_single(fptype *a, fptype *b) +{ + *a = fabsl(*b); + fp_round_single(a); +} +STATIC_INLINE void fp_abs_double(fptype *a, fptype *b) +{ + *a = fabsl(*b); + fp_round_double(a); +} +STATIC_INLINE void fp_cosh(fptype *a, fptype *b) +{ + *a = coshl(*b); + fp_round(a); +} +STATIC_INLINE void fp_neg(fptype *a, fptype *b) +{ + *a = -(*b); + fp_round(a); +} +STATIC_INLINE void fp_neg_single(fptype *a, fptype *b) +{ + *a = -(*b); + fp_round_single(a); +} +STATIC_INLINE void fp_neg_double(fptype *a, fptype *b) +{ + *a = -(*b); + fp_round_double(a); +} +STATIC_INLINE void fp_acos(fptype *a, fptype *b) +{ + *a = acosl(*b); + fp_round(a); +} +STATIC_INLINE void fp_cos(fptype *a, fptype *b) +{ + *a = cosl(*b); + fp_round(a); +} +STATIC_INLINE void fp_getexp(fptype *a, fptype *b) +{ + int expon; + frexpl(*b, &expon); + *a = (long double) (expon - 1); + fp_round(a); +} +STATIC_INLINE void fp_getman(fptype *a, fptype *b) +{ + int expon; + *a = frexpl(*b, &expon) * 2.0; + fp_round(a); +} +STATIC_INLINE void fp_div(fptype *a, fptype *b) +{ + *a /= *b; + fp_round(a); +} +STATIC_INLINE void fp_div_single(fptype *a, fptype *b) +{ + *a /= *b; + fp_round_single(a); +} +STATIC_INLINE void fp_div_double(fptype *a, fptype *b) +{ + *a /= *b; + fp_round_double(a); +} +STATIC_INLINE void fp_mod(fptype *a, fptype *b, uae_u64 *q, uae_s8 *s) +{ + fptype quot; +#ifdef USE_HOST_ROUNDING + quot = truncl(*a / *b); +#else + quot = fp_round_to_zero(*a / *b); +#endif + if (quot < 0.0) { + *s = 1; + quot = -quot; + } else { + *s = 0; + } + *q = (uae_u64)quot; + *a = fmodl(*a, *b); + fp_round(a); +} +STATIC_INLINE void fp_add(fptype *a, fptype *b) +{ + *a += *b; + fp_round(a); +} +STATIC_INLINE void fp_add_single(fptype *a, fptype *b) +{ + *a += *b; + fp_round_single(a); +} +STATIC_INLINE void fp_add_double(fptype *a, fptype *b) +{ + *a += *b; + fp_round_double(a); +} +STATIC_INLINE void fp_mul(fptype *a, fptype *b) +{ + *a *= *b; + fp_round(a); +} +STATIC_INLINE void fp_mul_single(fptype *a, fptype *b) +{ + *a *= *b; + fp_round_single(a); +} +STATIC_INLINE void fp_mul_double(fptype *a, fptype *b) +{ + *a *= *b; + fp_round_double(a); +} +STATIC_INLINE void fp_sgldiv(fptype *a, fptype *b) +{ + fptype z; + float mant; + int expon; + z = *a / *b; + + mant = (float)(frexpl(z, &expon) * 2.0); + *a = ldexpl((fptype)mant, expon - 1); +} +STATIC_INLINE void fp_rem(fptype *a, fptype *b, uae_u64 *q, uae_s8 *s) +{ + fptype quot; +#ifdef USE_HOST_ROUNDING + quot = roundl(*a / *b); +#else + quot = fp_round_to_nearest(*a / *b); +#endif + if (quot < 0.0) { + *s = 1; + quot = -quot; + } else { + *s = 0; + } + *q = (uae_u64)quot; + *a = remainderl(*a, *b); + fp_round(a); +} +STATIC_INLINE void fp_scale(fptype *a, fptype *b) +{ + *a = ldexpl(*a, (int) *b); + fp_round(a); +} +STATIC_INLINE void fp_sglmul(fptype *a, fptype *b) +{ + fptype z; + float mant; + int expon; + /* FIXME: truncate mantissa of a and b to single precision */ + z = *a * (*b); + + mant = (float)(frexpl(z, &expon) * 2.0); + *a = ldexpl((fptype)mant, expon - 1); +} +STATIC_INLINE void fp_sub(fptype *a, fptype *b) +{ + *a -= *b; + fp_round(a); +} +STATIC_INLINE void fp_sub_single(fptype *a, fptype *b) +{ + *a -= *b; + fp_round_single(a); +} +STATIC_INLINE void fp_sub_double(fptype *a, fptype *b) +{ + *a -= *b; + fp_round_double(a); +} +STATIC_INLINE void fp_cmp(fptype *a, fptype *b) +{ + *a = (*a - *b); /* FIXME: comparing is different from subtraction */ +} +STATIC_INLINE void fp_tst(fptype *a, fptype *b) +{ + *a = *b; /* FIXME: test b */ +} + +#else // if !USE_LONG_DOUBLE + +STATIC_INLINE void fp_move(fptype *a, fptype *b) +{ + *a = *b; + fp_round(a); +} +STATIC_INLINE void fp_move_single(fptype *a, fptype *b) +{ + *a = *b; + fp_round_single(a); +} +STATIC_INLINE void fp_move_double(fptype *a, fptype *b) +{ + *a = *b; + fp_round_double(a); +} +STATIC_INLINE void fp_int(fptype *a, fptype *b) +{ +#ifdef USE_HOST_ROUNDING + *a = rint(*b); +#else + switch (regs.fpcr & FPCR_ROUNDING_MODE) + { + case FPCR_ROUND_NEAR: + *a = fp_round_to_nearest(*b); + break; + case FPCR_ROUND_ZERO: + *a = fp_round_to_zero(*b); + break; + case FPCR_ROUND_MINF: + *a = fp_round_to_minus_infinity(*b); + break; + case FPCR_ROUND_PINF: + *a = fp_round_to_plus_infinity(*b); + break; + default: /* never reached */ + break; + } +#endif + fp_round(a); +} +STATIC_INLINE void fp_sinh(fptype *a, fptype *b) +{ + *a = sinh(*b); + fp_round(a); +} +STATIC_INLINE void fp_intrz(fptype *a, fptype *b) +{ +#ifdef USE_HOST_ROUNDING + *a = trunc(*b); +#else + *a = fp_round_to_zero (*b); +#endif + fp_round(a); +} +STATIC_INLINE void fp_sqrt(fptype *a, fptype *b) +{ + *a = sqrt(*b); + fp_round(a); +} +STATIC_INLINE void fp_sqrt_single(fptype *a, fptype *b) +{ + *a = sqrt(*b); + fp_round_single(a); +} +STATIC_INLINE void fp_sqrt_double(fptype *a, fptype *b) +{ + *a = sqrt(*b); + fp_round_double(a); +} +STATIC_INLINE void fp_lognp1(fptype *a, fptype *b) +{ + *a = log1p(*b); + fp_round(a); +} +STATIC_INLINE void fp_etoxm1(fptype *a, fptype *b) +{ + *a = expm1(*b); + fp_round(a); +} +STATIC_INLINE void fp_tanh(fptype *a, fptype *b) +{ + *a = tanh(*b); + fp_round(a); +} +STATIC_INLINE void fp_atan(fptype *a, fptype *b) +{ + *a = atan(*b); + fp_round(a); +} +STATIC_INLINE void fp_asin(fptype *a, fptype *b) +{ + *a = asin(*b); + fp_round(a); +} +STATIC_INLINE void fp_atanh(fptype *a, fptype *b) +{ + *a = atanh(*b); + fp_round(a); +} +STATIC_INLINE void fp_sin(fptype *a, fptype *b) +{ + *a = sin(*b); + fp_round(a); +} +STATIC_INLINE void fp_tan(fptype *a, fptype *b) +{ + *a = tan(*b); + fp_round(a); +} +STATIC_INLINE void fp_etox(fptype *a, fptype *b) +{ + *a = exp(*b); + fp_round(a); +} +STATIC_INLINE void fp_twotox(fptype *a, fptype *b) +{ + *a = pow(2.0, *b); + fp_round(a); +} +STATIC_INLINE void fp_tentox(fptype *a, fptype *b) +{ + *a = pow(10.0, *b); + fp_round(a); +} +STATIC_INLINE void fp_logn(fptype *a, fptype *b) +{ + *a = log(*b); + fp_round(a); +} +STATIC_INLINE void fp_log10(fptype *a, fptype *b) +{ + *a = log10(*b); + fp_round(a); +} +STATIC_INLINE void fp_log2(fptype *a, fptype *b) +{ + *a = log2(*b); + fp_round(a); +} +STATIC_INLINE void fp_abs(fptype *a, fptype *b) +{ + *a = fabs(*b); + fp_round(a); +} +STATIC_INLINE void fp_abs_single(fptype *a, fptype *b) +{ + *a = fabs(*b); + fp_round_single(a); +} +STATIC_INLINE void fp_abs_double(fptype *a, fptype *b) +{ + *a = fabs(*b); + fp_round_double(a); +} +STATIC_INLINE void fp_cosh(fptype *a, fptype *b) +{ + *a = cosh(*b); + fp_round(a); +} +STATIC_INLINE void fp_neg(fptype *a, fptype *b) +{ + *a = -(*b); + fp_round(a); +} +STATIC_INLINE void fp_neg_single(fptype *a, fptype *b) +{ + *a = -(*b); + fp_round_single(a); +} +STATIC_INLINE void fp_neg_double(fptype *a, fptype *b) +{ + *a = -(*b); + fp_round_double(a); +} +STATIC_INLINE void fp_acos(fptype *a, fptype *b) +{ + *a = acos(*b); + fp_round(a); +} +STATIC_INLINE void fp_cos(fptype *a, fptype *b) +{ + *a = cos(*b); + fp_round(a); +} +STATIC_INLINE void fp_getexp(fptype *a, fptype *b) +{ + int expon; + frexp(*b, &expon); + *a = (long double) (expon - 1); + fp_round(a); +} +STATIC_INLINE void fp_getman(fptype *a, fptype *b) +{ + int expon; + *a = frexp(*b, &expon) * 2.0; + fp_round(a); +} +STATIC_INLINE void fp_div(fptype *a, fptype *b) +{ + *a /= *b; + fp_round(a); +} +STATIC_INLINE void fp_div_single(fptype *a, fptype *b) +{ + *a /= *b; + fp_round_single(a); +} +STATIC_INLINE void fp_div_double(fptype *a, fptype *b) +{ + *a /= *b; + fp_round_double(a); +} +STATIC_INLINE void fp_mod(fptype *a, fptype *b, uae_u64 *q, uae_s8 *s) +{ + fptype quot; +#ifdef USE_HOST_ROUNDING + quot = trunc(*a / *b); +#else + quot = fp_round_to_zero(*a / *b); +#endif + if (quot < 0.0) { + *s = 1; + quot = -quot; + } else { + *s = 0; + } + *q = (uae_u64)quot; + *a = fmod(*a, *b); + fp_round(a); +} +STATIC_INLINE void fp_add(fptype *a, fptype *b) +{ + *a += *b; + fp_round(a); +} +STATIC_INLINE void fp_add_single(fptype *a, fptype *b) +{ + *a += *b; + fp_round_single(a); +} +STATIC_INLINE void fp_add_double(fptype *a, fptype *b) +{ + *a += *b; + fp_round_double(a); +} +STATIC_INLINE void fp_mul(fptype *a, fptype *b) +{ + *a *= *b; + fp_round(a); +} +STATIC_INLINE void fp_mul_single(fptype *a, fptype *b) +{ + *a *= *b; + fp_round_single(a); +} +STATIC_INLINE void fp_mul_double(fptype *a, fptype *b) +{ + *a *= *b; + fp_round_double(a); +} +STATIC_INLINE void fp_sgldiv(fptype *a, fptype *b) +{ + fptype z; + float mant; + int expon; + z = *a / *b; + + mant = (float)(frexp(z, &expon) * 2.0); + *a = ldexp((fptype)mant, expon - 1); +} +STATIC_INLINE void fp_rem(fptype *a, fptype *b, uae_u64 *q, uae_s8 *s) +{ + fptype quot; +#ifdef USE_HOST_ROUNDING + quot = round(*a / *b); +#else + quot = fp_round_to_nearest(*a / *b); +#endif + if (quot < 0.0) { + *s = 1; + quot = -quot; + } else { + *s = 0; + } + *q = (uae_u64)quot; + *a = remainder(*a, *b); + fp_round(a); +} +STATIC_INLINE void fp_scale(fptype *a, fptype *b) +{ + *a = ldexp(*a, (int) *b); + fp_round(a); +} +STATIC_INLINE void fp_sglmul(fptype *a, fptype *b) +{ + fptype z; + float mant; + int expon; + /* FIXME: truncate mantissa of a and b to single precision */ + z = *a * (*b); + + mant = (float)(frexp(z, &expon) * 2.0); + *a = ldexp((fptype)mant, expon - 1); +} +STATIC_INLINE void fp_sub(fptype *a, fptype *b) +{ + *a -= *b; + fp_round(a); +} +STATIC_INLINE void fp_sub_single(fptype *a, fptype *b) +{ + *a -= *b; + fp_round_single(a); +} +STATIC_INLINE void fp_sub_double(fptype *a, fptype *b) +{ + *a -= *b; + fp_round_double(a); +} +STATIC_INLINE void fp_cmp(fptype *a, fptype *b) +{ + *a = (*a - *b); /* FIXME: comparing is different from subtraction */ +} +STATIC_INLINE void fp_tst(fptype *a, fptype *b) +{ + *a = *b; /* FIXME: test b */ +} + +#endif // !USE_LONG_DOUBLE + #endif