diff options
Diffstat (limited to '3rdparty/softfloat3/bochs_ext/fprem.c')
-rw-r--r-- | 3rdparty/softfloat3/bochs_ext/fprem.c | 255 |
1 files changed, 255 insertions, 0 deletions
diff --git a/3rdparty/softfloat3/bochs_ext/fprem.c b/3rdparty/softfloat3/bochs_ext/fprem.c new file mode 100644 index 00000000000..16f6cccbc49 --- /dev/null +++ b/3rdparty/softfloat3/bochs_ext/fprem.c @@ -0,0 +1,255 @@ +/*============================================================================ +This source file is an extension to the SoftFloat IEC/IEEE Floating-point +Arithmetic Package, Release 2b, written for Bochs (x86 achitecture simulator) +floating point emulation. + +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has +been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES +RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS +AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES, +COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE +EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE +INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR +OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE. + +Derivative works are acceptable, even for commercial purposes, so long as +(1) the source code for the derivative work includes prominent notice that +the work is derivative, and (2) the source code includes prominent notice with +these four paragraphs for those parts of this code that are retained. +=============================================================================*/ + +/*============================================================================ + * Written for Bochs (x86 achitecture simulator) by + * Stanislav Shwartsman [sshwarts at sourceforge net] + * ==========================================================================*/ + +#define USE_estimateDiv128To64 +#define FLOAT128 + +#include <stdint.h> + +#include "../build/MAME/platform.h" +#include "../source/include/internals.h" +#include "../source/include/softfloat.h" + +#include "../source/8086/specialize.h" + +#include "fpu_constant.h" +#include "softfloat-extra.h" +#include "softfloat-helpers.h" +#include "softfloat-specialize.h" + +/* executes single exponent reduction cycle */ +static uint64_t remainder_kernel(uint64_t aSig0, uint64_t bSig, int expDiff, uint64_t *zSig0, uint64_t *zSig1) +{ + uint128 term, z; + uint64_t aSig1 = 0; + shortShift128Left(aSig1, aSig0, expDiff, &aSig1, &aSig0); + uint64_t q = estimateDiv128To64(aSig1, aSig0, bSig); + term = softfloat_mul64To128(bSig, q); + z = softfloat_sub128(aSig1, aSig0, term.v64, term.v0); + while ((int64_t) z.v64 < 0) { + --q; + z = softfloat_add128(z.v64, z.v0, 0, bSig); + } + *zSig0 = z.v0; + *zSig1 = z.v64; + return q; +} + +static int do_fprem(extFloat80_t a, extFloat80_t b, extFloat80_t &r, uint64_t &q, int rounding_mode) +{ + int32_t aExp, bExp, zExp, expDiff; + uint64_t aSig0, aSig1 = 0, bSig; + int aSign; + struct exp32_sig64 normExpSig; + uint128 term; + + q = 0; + + // handle unsupported extended double-precision floating encodings + if (extF80_isUnsupported(a) || extF80_isUnsupported(b)) { + softfloat_exceptionFlags |= softfloat_flag_invalid; + r = floatx80_default_nan; + return -1; + } + + aSig0 = extF80_fraction(a); + aExp = extF80_exp(a); + aSign = extF80_sign(a); + bSig = extF80_fraction(b); + bExp = extF80_exp(b); + + if (aExp == 0x7FFF) { + if ((aSig0<<1) || ((bExp == 0x7FFF) && (bSig<<1))) { + const uint128 nan = softfloat_propagateNaNExtF80UI(a.signExp, a.signif, b.signExp, b.signif); + r.signExp = nan.v64; + r.signif = nan.v0; + return -1; + } + softfloat_exceptionFlags |= softfloat_flag_invalid; + r = floatx80_default_nan; + return -1; + } + if (bExp == 0x7FFF) { + if (bSig << 1) { + const uint128 nan = softfloat_propagateNaNExtF80UI(a.signExp, a.signif, b.signExp, b.signif); + r.signExp = nan.v64; + r.signif = nan.v0; + return -1; + } + if (! aExp && aSig0) { + softfloat_exceptionFlags |= softfloat_flag_invalid; // actually denormal + normExpSig = softfloat_normSubnormalExtF80Sig(aSig0); + aExp = normExpSig.exp + 1; + aSig0 = normExpSig.sig; + r = (a.signif & uint64_t(0x8000000000000000)) ? packToExtF80(aSign, aExp, aSig0) : a; + return 0; + } + r = a; + return 0; + + } + if (! bExp) { + if (! bSig) { + softfloat_exceptionFlags |= softfloat_flag_invalid; + r = floatx80_default_nan; + return -1; + } + softfloat_exceptionFlags |= softfloat_flag_invalid; // actually denormal + normExpSig = softfloat_normSubnormalExtF80Sig(bSig); + bExp = normExpSig.exp + 1; + bSig = normExpSig.sig; + } + if (! aExp) { + if (! aSig0) { + r = a; + return 0; + } + softfloat_exceptionFlags |= softfloat_flag_invalid; // actually denormal + normExpSig = softfloat_normSubnormalExtF80Sig(aSig0); + aExp = normExpSig.exp + 1; + aSig0 = normExpSig.sig; + } + + expDiff = aExp - bExp; + int overflow = 0; + + if (expDiff >= 64) { + int n = (expDiff & 0x1f) | 0x20; + remainder_kernel(aSig0, bSig, n, &aSig0, &aSig1); + zExp = aExp - n; + overflow = 1; + } + else { + zExp = bExp; + + if (expDiff < 0) { + if (expDiff < -1) { + r = (a.signif & uint64_t(0x8000000000000000)) ? packToExtF80(aSign, aExp, aSig0) : a; + return 0; + } + shortShift128Right(aSig0, 0, 1, &aSig0, &aSig1); + expDiff = 0; + } + + if (expDiff > 0) { + q = remainder_kernel(aSig0, bSig, expDiff, &aSig0, &aSig1); + } + else { + if (bSig <= aSig0) { + aSig0 -= bSig; + q = 1; + } + } + + if (rounding_mode == softfloat_round_near_even) { + uint64_t term0, term1; + shortShift128Right(bSig, 0, 1, &term0, &term1); + + if (! softfloat_lt128(aSig0, aSig1, term0, term1)) { + int lt = softfloat_lt128(term0, term1, aSig0, aSig1); + int eq = softfloat_eq128(aSig0, aSig1, term0, term1); + + if ((eq && (q & 1)) || lt) { + aSign = !aSign; + ++q; + } + if (lt) { + term = softfloat_sub128(bSig, 0, aSig0, aSig1); + aSig0 = term.v64; + aSig1 = term.v0; + } + } + } + } + + r = softfloat_normRoundPackToExtF80(aSign, zExp, aSig0, aSig1, 80); + return overflow; +} + +/*---------------------------------------------------------------------------- +| Returns the remainder of the extended double-precision floating-point value +| `a' with respect to the corresponding value `b'. The operation is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int extFloat80_ieee754_remainder(extFloat80_t a, extFloat80_t b, extFloat80_t &r, uint64_t &q) +{ + return do_fprem(a, b, r, q, softfloat_round_near_even); +} + +/*---------------------------------------------------------------------------- +| Returns the remainder of the extended double-precision floating-point value +| `a' with respect to the corresponding value `b'. Unlike previous function +| the function does not compute the remainder specified in the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. This function operates +| differently from the previous function in the way that it rounds the +| quotient of 'a' divided by 'b' to an integer. +*----------------------------------------------------------------------------*/ + +int extFloat80_remainder(extFloat80_t a, extFloat80_t b, extFloat80_t &r, uint64_t &q) +{ + return do_fprem(a, b, r, q, softfloat_round_minMag); +} + +static extFloat80_t propagateFloatx80NaNOneArg(extFloat80_t a) +{ + a.signif |= uint64_t(0x4000000000000000); + return a; +} + +extFloat80_t extFloat80_getman(extFloat80_t a) +{ + const int aSign = (a.signExp >> 15); + int32_t aExp = a.signExp & 0x7fff; + uint64_t aFrac = a.signif; + + if (aExp == 0x7fff) + { + if ((uint64_t)(aFrac << 1)) + { + return propagateFloatx80NaNOneArg(a); + } + + softfloat_raiseFlags(softfloat_flag_invalid); + return floatx80_default_nan; + } + + if (!aExp) + { + if (!aSign) + { + return packFloatx80(aSign, 0, 0); + } + else + { + // normalize the subnormal value + const int leadingZeroes = softfloat_countLeadingZeros64(aFrac); + aFrac = aFrac << leadingZeroes; + aExp = -leadingZeroes; + } + } + + return packFloatx80(aSign, 0x3fff, aFrac); +} |