From 6957c469983fe32c9725eb3787020b6cedd36b75 Mon Sep 17 00:00:00 2001 From: arbee Date: Mon, 27 May 2024 20:40:42 -0400 Subject: cpu/m68000: Updated 680x0 FPU to Softfloat 3 from 2. (MT5411 and MT8793). [R. Belmont] - Update to Softloat 3 from 2 - FREM and FMOD now generate the quotient bits in FPSR, required by Apple's SANE to do sin/cos/tan properly. - FMOVE of a float to a Dx integer register generates the exception status bits, fixing square roots in SANE - Rewrote how FMOVEM instructions are decoded and executed, fixing issues including skipping too few or too many opcode bytes and causing serious weird behavior. - FPU instructions all now have more realistic cycle timings for a 68881. - All FPU instructions now generate exception bits in FPSR. 3rdparty/softfloat3: Updates [R. Belmont] - Softfloat3 was always being built for a big-endian host, causing incorrect math on LE x64 and AArch64 machines. - Fixed up Softfloat3 to build properly as part of MAME and up-ported the Bochs extensions. In latest Bochs, they were only partially up-ported and Softfloat3 had been hacked up to be more like 2; here they're fixed to work with stock Softfloat3. --- 3rdparty/softfloat3/bochs_ext/extF80_scale.c | 156 ++++ 3rdparty/softfloat3/bochs_ext/f2xm1.c | 186 +++++ 3rdparty/softfloat3/bochs_ext/fpatan.c | 326 ++++++++ 3rdparty/softfloat3/bochs_ext/fprem.c | 255 ++++++ 3rdparty/softfloat3/bochs_ext/fpu_constant.h | 80 ++ 3rdparty/softfloat3/bochs_ext/fsincos.c | 457 +++++++++++ 3rdparty/softfloat3/bochs_ext/fyl2x.c | 409 +++++++++ 3rdparty/softfloat3/bochs_ext/poly.c | 91 +++ 3rdparty/softfloat3/bochs_ext/softfloat-extra.h | 68 ++ 3rdparty/softfloat3/bochs_ext/softfloat-helpers.h | 159 ++++ .../softfloat3/bochs_ext/softfloat-specialize.h | 223 +++++ 3rdparty/softfloat3/bochs_ext/softfloat3_ext.h | 17 + 3rdparty/softfloat3/build/MAME/platform.h | 10 +- 3rdparty/softfloat3/source/include/softfloat.h | 46 +- .../softfloat3/source/include/softfloat_types.h | 7 + scripts/src/3rdparty.lua | 13 + src/devices/cpu/m68000/m68kfpu.cpp | 909 ++++++++++++--------- src/devices/cpu/m68000/m68kmusashi.h | 54 +- 18 files changed, 3040 insertions(+), 426 deletions(-) create mode 100644 3rdparty/softfloat3/bochs_ext/extF80_scale.c create mode 100644 3rdparty/softfloat3/bochs_ext/f2xm1.c create mode 100644 3rdparty/softfloat3/bochs_ext/fpatan.c create mode 100644 3rdparty/softfloat3/bochs_ext/fprem.c create mode 100644 3rdparty/softfloat3/bochs_ext/fpu_constant.h create mode 100644 3rdparty/softfloat3/bochs_ext/fsincos.c create mode 100644 3rdparty/softfloat3/bochs_ext/fyl2x.c create mode 100644 3rdparty/softfloat3/bochs_ext/poly.c create mode 100644 3rdparty/softfloat3/bochs_ext/softfloat-extra.h create mode 100644 3rdparty/softfloat3/bochs_ext/softfloat-helpers.h create mode 100644 3rdparty/softfloat3/bochs_ext/softfloat-specialize.h create mode 100644 3rdparty/softfloat3/bochs_ext/softfloat3_ext.h diff --git a/3rdparty/softfloat3/bochs_ext/extF80_scale.c b/3rdparty/softfloat3/bochs_ext/extF80_scale.c new file mode 100644 index 00000000000..6a25764f128 --- /dev/null +++ b/3rdparty/softfloat3/bochs_ext/extF80_scale.c @@ -0,0 +1,156 @@ +/*============================================================================ + +This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic +Package, Release 3e, by John R. Hauser. + +Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of +California. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions, and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions, and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the University nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=============================================================================*/ + +#include +#include + +#include "../source/include/softfloat.h" +#include "../source/include/internals.h" +#include "../source/8086/specialize.h" + +#include "fpu_constant.h" +#include "softfloat-helpers.h" +#include "softfloat-extra.h" +#include "softfloat-specialize.h" + +/*---------------------------------------------------------------------------- +| Scales extended double-precision floating-point value in operand `a' by +| value `b'. The function truncates the value in the second operand 'b' to +| an integral value and adds that value to the exponent of the operand 'a'. +| The operation performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +extFloat80_t extFloat80_scale(extFloat80_t a, extFloat80_t b) +{ + uint16_t uiA64; + uint64_t uiA0; + bool signA; + int32_t expA; + uint64_t sigA; + uint16_t uiB64; + uint64_t uiB0; + bool signB; + int32_t expB; + uint64_t sigB; + struct exp32_sig64 normExpSig; + + // handle unsupported extended double-precision floating encodings + if (extF80_isUnsupported(a) || extF80_isUnsupported(b)) { +invalid: + softfloat_exceptionFlags |= softfloat_flag_invalid; + return packToExtF80(defaultNaNExtF80UI64, defaultNaNExtF80UI0); + } + + /*------------------------------------------------------------------------ + *------------------------------------------------------------------------*/ + uiA64 = a.signExp; + uiA0 = a.signif; + signA = signExtF80UI64(uiA64); + expA = expExtF80UI64(uiA64); + sigA = uiA0; + uiB64 = b.signExp; + uiB0 = b.signif; + signB = signExtF80UI64(uiB64); + expB = expExtF80UI64(uiB64); + sigB = uiB0; + /*------------------------------------------------------------------------ + *------------------------------------------------------------------------*/ + + if (expA == 0x7FFF) { + if ((sigA<<1) || ((expB == 0x7FFF) && (sigB<<1))) { + const uint128 nan = softfloat_propagateNaNExtF80UI(uiA64, uiA0, uiB64, uiB0); + extFloat80_t rv; + rv.signExp = nan.v64; + rv.signif = nan.v0; + return rv; + } + if ((expB == 0x7FFF) && signB) goto invalid; + if (sigB && !expB) + softfloat_exceptionFlags |= softfloat_flag_invalid; // actally denormal + + return a; + } + if (expB == 0x7FFF) { + if (sigB<<1) { + const uint128 nan = softfloat_propagateNaNExtF80UI(uiA64, uiA0, uiB64, uiB0); + extFloat80_t rv; + rv.signExp = nan.v64; + rv.signif = nan.v0; + return rv; + } + if ((expA | sigA) == 0) { + if (! signB) goto invalid; + return a; + } + if (sigA && !expA) + softfloat_exceptionFlags |= softfloat_flag_invalid; // actually denormal + + if (signB) return packToExtF80(signA, 0, 0); + return packToExtF80(signA, 0x7FFF, uint64_t(0x8000000000000000)); + } + if (! expA) { + if (sigB && !expB) + softfloat_exceptionFlags |= softfloat_flag_invalid; // actually denormal + if (! sigA) return a; + softfloat_exceptionFlags |= softfloat_flag_invalid; // actually denormal + normExpSig = softfloat_normSubnormalExtF80Sig(sigA); + expA = normExpSig.exp + 1; + sigA = normExpSig.sig; + if (expB < 0x3FFF) + return softfloat_normRoundPackToExtF80(signA, expA, sigA, 0, 80); + } + if (!expB) { + if (!sigB) return a; + softfloat_exceptionFlags |= softfloat_flag_invalid; // actually denormal + normExpSig = softfloat_normSubnormalExtF80Sig(sigB); + expB = normExpSig.exp + 1; + sigB = normExpSig.sig; + } + + if (expB > 0x400E) { + /* generate appropriate overflow/underflow */ + return softfloat_roundPackToExtF80(signA, signB ? -0x3FFF : 0x7FFF, sigA, 0, 80); + } + + if (expB < 0x3FFF) return a; + + int shiftCount = 0x403E - expB; + sigB >>= shiftCount; + int32_t scale = (int32_t) sigB; + if (signB) scale = -scale; /* -32768..32767 */ + + return softfloat_roundPackToExtF80(signA, expA + scale, sigA, 0, 80); +} diff --git a/3rdparty/softfloat3/bochs_ext/f2xm1.c b/3rdparty/softfloat3/bochs_ext/f2xm1.c new file mode 100644 index 00000000000..a8201937660 --- /dev/null +++ b/3rdparty/softfloat3/bochs_ext/f2xm1.c @@ -0,0 +1,186 @@ +/*============================================================================ +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 FLOAT128 + +#include "../source/include/softfloat.h" +#include "../source/include/internals.h" +#include "softfloat-extra.h" +#include "softfloat-helpers.h" +#include "softfloat-specialize.h" + +static const extFloat80_t floatx80_negone = packFloatx80(1, 0x3fff, uint64_t(0x8000000000000000)); +static const extFloat80_t floatx80_neghalf = packFloatx80(1, 0x3ffe, uint64_t(0x8000000000000000)); +static const float128_t float128_ln2 = + packFloat128(uint64_t(0x3ffe62e42fefa39e), uint64_t(0xf35793c7673007e6)); + +#ifdef BETTER_THAN_PENTIUM + +#define LN2_SIG_HI uint64_t(0xb17217f7d1cf79ab) +#define LN2_SIG_LO uint64_t(0xc9e3b39800000000) /* 96 bit precision */ + +#else + +#define LN2_SIG_HI uint64_t(0xb17217f7d1cf79ab) +#define LN2_SIG_LO uint64_t(0xc000000000000000) /* 67-bit precision */ + +#endif + +#define EXP_ARR_SIZE 15 + +static float128_t exp_arr[EXP_ARR_SIZE] = +{ + PACK_FLOAT_128(0x3fff000000000000, 0x0000000000000000), /* 1 */ + PACK_FLOAT_128(0x3ffe000000000000, 0x0000000000000000), /* 2 */ + PACK_FLOAT_128(0x3ffc555555555555, 0x5555555555555555), /* 3 */ + PACK_FLOAT_128(0x3ffa555555555555, 0x5555555555555555), /* 4 */ + PACK_FLOAT_128(0x3ff8111111111111, 0x1111111111111111), /* 5 */ + PACK_FLOAT_128(0x3ff56c16c16c16c1, 0x6c16c16c16c16c17), /* 6 */ + PACK_FLOAT_128(0x3ff2a01a01a01a01, 0xa01a01a01a01a01a), /* 7 */ + PACK_FLOAT_128(0x3fefa01a01a01a01, 0xa01a01a01a01a01a), /* 8 */ + PACK_FLOAT_128(0x3fec71de3a556c73, 0x38faac1c88e50017), /* 9 */ + PACK_FLOAT_128(0x3fe927e4fb7789f5, 0xc72ef016d3ea6679), /* 10 */ + PACK_FLOAT_128(0x3fe5ae64567f544e, 0x38fe747e4b837dc7), /* 11 */ + PACK_FLOAT_128(0x3fe21eed8eff8d89, 0x7b544da987acfe85), /* 12 */ + PACK_FLOAT_128(0x3fde6124613a86d0, 0x97ca38331d23af68), /* 13 */ + PACK_FLOAT_128(0x3fda93974a8c07c9, 0xd20badf145dfa3e5), /* 14 */ + PACK_FLOAT_128(0x3fd6ae7f3e733b81, 0xf11d8656b0ee8cb0) /* 15 */ +}; + +extern float128_t EvalPoly(float128_t x, const float128_t *arr, int n); + +/* required -1 < x < 1 */ +static float128_t poly_exp(float128_t x) +{ +/* + // 2 3 4 5 6 7 8 9 + // x x x x x x x x x + // e - 1 ~ x + --- + --- + --- + --- + --- + --- + --- + --- + ... + // 2! 3! 4! 5! 6! 7! 8! 9! + // + // 2 3 4 5 6 7 8 + // x x x x x x x x + // = x [ 1 + --- + --- + --- + --- + --- + --- + --- + --- + ... ] + // 2! 3! 4! 5! 6! 7! 8! 9! + // + // 8 8 + // -- 2k -- 2k+1 + // p(x) = > C * x q(x) = > C * x + // -- 2k -- 2k+1 + // k=0 k=0 + // + // x + // e - 1 ~ x * [ p(x) + x * q(x) ] + // +*/ + float128_t t = EvalPoly(x, (const float128_t*) exp_arr, EXP_ARR_SIZE); + return f128_mul(t, x); +} + +// ================================================= +// x +// FX2M1 Compute 2 - 1 +// ================================================= + +// +// Uses the following identities: +// +// 1. ---------------------------------------------------------- +// x x*ln(2) +// 2 = e +// +// 2. ---------------------------------------------------------- +// 2 3 4 5 n +// x x x x x x x +// e = 1 + --- + --- + --- + --- + --- + ... + --- + ... +// 1! 2! 3! 4! 5! n! +// +extFloat80_t extFloat80_2xm1(extFloat80_t a) +{ + uint64_t zSig0, zSig1, zSig2; + struct exp32_sig64 normExpSig; + + // handle unsupported extended double-precision floating encodings + if (extF80_isUnsupported(a)) { + softfloat_exceptionFlags |= softfloat_flag_invalid; + return floatx80_default_nan; + } + + uint64_t aSig = extF80_fraction(a); + int32_t aExp = extF80_exp(a); + int aSign = extF80_sign(a); + + if (aExp == 0x7FFF) { + if (aSig << 1) { + const uint128 nan = softfloat_propagateNaNExtF80UI(a.signExp, aSig, 0, 0); + extFloat80_t rv; + rv.signExp = nan.v64; + rv.signif = nan.v0; + return rv; + } + + return (aSign) ? floatx80_negone : a; + } + + if (! aExp) { + if (! aSig) return a; + softfloat_exceptionFlags |= softfloat_flag_inexact; // denormal also + normExpSig = softfloat_normSubnormalExtF80Sig(aSig); + aExp = normExpSig.exp + 1; + aSig = normExpSig.sig; + + tiny_argument: + mul128By64To192(LN2_SIG_HI, LN2_SIG_LO, aSig, &zSig0, &zSig1, &zSig2); + if (0 < (int64_t) zSig0) { + shortShift128Left(zSig0, zSig1, 1, &zSig0, &zSig1); + --aExp; + } + return softfloat_roundPackToExtF80(aSign, aExp, zSig0, zSig1, 80); + } + + softfloat_exceptionFlags |= softfloat_flag_inexact; + + if (aExp < 0x3FFF) + { + if (aExp < FLOATX80_EXP_BIAS-68) + goto tiny_argument; + + /* ******************************** */ + /* using float128 for approximation */ + /* ******************************** */ + + float128_t x = extF80_to_f128(a); + x = f128_mul(x, float128_ln2); + x = poly_exp(x); + return f128_to_extF80(x); + } + else + { + if (a.signExp == 0xBFFF && ! (aSig<<1)) + return floatx80_neghalf; + + return a; + } +} diff --git a/3rdparty/softfloat3/bochs_ext/fpatan.c b/3rdparty/softfloat3/bochs_ext/fpatan.c new file mode 100644 index 00000000000..88bced6bbd3 --- /dev/null +++ b/3rdparty/softfloat3/bochs_ext/fpatan.c @@ -0,0 +1,326 @@ +/*============================================================================ +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 FLOAT128 + +#include "../source/include/softfloat.h" +#include "../source/include/internals.h" +#include "../source/8086/specialize.h" + +#include "fpu_constant.h" +#include "softfloat-helpers.h" +#include "softfloat-extra.h" +#include "softfloat-specialize.h" + +#define FPATAN_ARR_SIZE 11 + +static const extFloat80_t floatx80_one = packFloatx80(0, 0x3fff, uint64_t(0x8000000000000000)); + +static const float128_t float128_one = + packFloat128(uint64_t(0x3fff000000000000), uint64_t(0x0000000000000000)); +static const float128_t float128_sqrt3 = + packFloat128(uint64_t(0x3fffbb67ae8584ca), uint64_t(0xa73b25742d7078b8)); +static const extFloat80_t floatx80_pi = + packFloatx80(0, 0x4000, uint64_t(0xc90fdaa22168c235)); + +static const float128_t float128_pi2 = + packFloat128(uint64_t(0x3fff921fb54442d1), uint64_t(0x8469898CC5170416)); +static const float128_t float128_pi4 = + packFloat128(uint64_t(0x3ffe921fb54442d1), uint64_t(0x8469898CC5170416)); +static const float128_t float128_pi6 = + packFloat128(uint64_t(0x3ffe0c152382d736), uint64_t(0x58465BB32E0F580F)); + +static float128_t atan_arr[FPATAN_ARR_SIZE] = +{ + PACK_FLOAT_128(0x3fff000000000000, 0x0000000000000000), /* 1 */ + PACK_FLOAT_128(0xbffd555555555555, 0x5555555555555555), /* 3 */ + PACK_FLOAT_128(0x3ffc999999999999, 0x999999999999999a), /* 5 */ + PACK_FLOAT_128(0xbffc249249249249, 0x2492492492492492), /* 7 */ + PACK_FLOAT_128(0x3ffbc71c71c71c71, 0xc71c71c71c71c71c), /* 9 */ + PACK_FLOAT_128(0xbffb745d1745d174, 0x5d1745d1745d1746), /* 11 */ + PACK_FLOAT_128(0x3ffb3b13b13b13b1, 0x3b13b13b13b13b14), /* 13 */ + PACK_FLOAT_128(0xbffb111111111111, 0x1111111111111111), /* 15 */ + PACK_FLOAT_128(0x3ffae1e1e1e1e1e1, 0xe1e1e1e1e1e1e1e2), /* 17 */ + PACK_FLOAT_128(0xbffaaf286bca1af2, 0x86bca1af286bca1b), /* 19 */ + PACK_FLOAT_128(0x3ffa861861861861, 0x8618618618618618) /* 21 */ +}; + +extern float128_t OddPoly(float128_t x, const float128_t *arr, int n); + +/* |x| < 1/4 */ +static float128_t poly_atan(float128_t x1) +{ +/* + // 3 5 7 9 11 13 15 17 + // x x x x x x x x + // atan(x) ~ x - --- + --- - --- + --- - ---- + ---- - ---- + ---- + // 3 5 7 9 11 13 15 17 + // + // 2 4 6 8 10 12 14 16 + // x x x x x x x x + // = x * [ 1 - --- + --- - --- + --- - ---- + ---- - ---- + ---- ] + // 3 5 7 9 11 13 15 17 + // + // 5 5 + // -- 4k -- 4k+2 + // p(x) = > C * x q(x) = > C * x + // -- 2k -- 2k+1 + // k=0 k=0 + // + // 2 + // atan(x) ~ x * [ p(x) + x * q(x) ] + // +*/ + return OddPoly(x1, (const float128_t*) atan_arr, FPATAN_ARR_SIZE); +} + +// ================================================= +// FPATAN Compute arctan(y/x) +// ================================================= + +// +// Uses the following identities: +// +// 1. ---------------------------------------------------------- +// +// atan(-x) = -atan(x) +// +// 2. ---------------------------------------------------------- +// +// x + y +// atan(x) + atan(y) = atan -------, xy < 1 +// 1-xy +// +// x + y +// atan(x) + atan(y) = atan ------- + PI, x > 0, xy > 1 +// 1-xy +// +// x + y +// atan(x) + atan(y) = atan ------- - PI, x < 0, xy > 1 +// 1-xy +// +// 3. ---------------------------------------------------------- +// +// atan(x) = atan(INF) + atan(- 1/x) +// +// x-1 +// atan(x) = PI/4 + atan( ----- ) +// x+1 +// +// x * sqrt(3) - 1 +// atan(x) = PI/6 + atan( ----------------- ) +// x + sqrt(3) +// +// 4. ---------------------------------------------------------- +// 3 5 7 9 2n+1 +// x x x x n x +// atan(x) = x - --- + --- - --- + --- - ... + (-1) ------ + ... +// 3 5 7 9 2n+1 +// + +extFloat80_t extFloat80_atan(extFloat80_t a, extFloat80_t b) +{ + // handle unsupported extended double-precision floating encodings + if (extF80_isUnsupported(a) || extF80_isUnsupported(b)) { + softfloat_exceptionFlags |= softfloat_flag_invalid; + return floatx80_default_nan; + } + + uint64_t aSig = extF80_fraction(a); + int32_t aExp = extF80_exp(a); + int aSign = extF80_sign(a); + uint64_t bSig = extF80_fraction(b); + int32_t bExp = extF80_exp(b); + int bSign = extF80_sign(b); + + int zSign = aSign ^ bSign; + + if (bExp == 0x7FFF) + { + extFloat80_t rv; + if (bSig<<1) { + const uint128 nan = softfloat_propagateNaNExtF80UI(a.signExp, aSig, b.signExp, bSig); + rv.signExp = nan.v64; + rv.signif = nan.v0; + return rv; + } + if (aExp == 0x7FFF) { + if (aSig<<1) { + const uint128 nan = softfloat_propagateNaNExtF80UI(a.signExp, aSig, b.signExp, bSig); + rv.signExp = nan.v64; + rv.signif = nan.v0; + return rv; + } + if (aSign) /* return 3PI/4 */ + return softfloat_roundPackToExtF80(bSign, FLOATX80_3PI4_EXP, FLOAT_3PI4_HI, FLOAT_3PI4_LO, 80); + else /* return PI/4 */ + return softfloat_roundPackToExtF80(bSign, FLOATX80_PI4_EXP, FLOAT_PI_HI, FLOAT_PI_LO, 80); + } + + if (aSig && ! aExp) + softfloat_exceptionFlags |= softfloat_flag_invalid; // denormal actually + + /* return PI/2 */ + return softfloat_roundPackToExtF80(bSign, FLOATX80_PI2_EXP, FLOAT_PI_HI, FLOAT_PI_LO, 80); + } + if (aExp == 0x7FFF) + { + if (aSig<<1) { + extFloat80_t rv; + const uint128 nan = softfloat_propagateNaNExtF80UI(a.signExp, aSig, b.signExp, bSig); + rv.signExp = nan.v64; + rv.signif = nan.v0; + return rv; + } + if (bSig && ! bExp) + softfloat_exceptionFlags |= softfloat_flag_invalid; // denormal actually + +return_PI_or_ZERO: + + if (aSign) /* return PI */ + return softfloat_roundPackToExtF80(bSign, FLOATX80_PI_EXP, FLOAT_PI_HI, FLOAT_PI_LO, 80); + else /* return 0 */ + return packToExtF80(bSign, 0, 0); + } + if (! bExp) + { + if (! bSig) { + if (aSig && ! aExp) + softfloat_exceptionFlags |= softfloat_flag_invalid; // denormal actually + + goto return_PI_or_ZERO; + } + + softfloat_exceptionFlags |= softfloat_flag_invalid; // denormal actually + struct exp32_sig64 normExpSig = softfloat_normSubnormalExtF80Sig(bSig); + bExp = normExpSig.exp + 1; + bSig = normExpSig.sig; + } + if (! aExp) + { + if (! aSig) /* return PI/2 */ + return softfloat_roundPackToExtF80(bSign, FLOATX80_PI2_EXP, FLOAT_PI_HI, FLOAT_PI_LO, 80); + + softfloat_exceptionFlags |= softfloat_flag_invalid; // denormal actually + struct exp32_sig64 normExpSig = softfloat_normSubnormalExtF80Sig(aSig); + aExp = normExpSig.exp + 1; + aSig = normExpSig.sig; + } + + softfloat_exceptionFlags |= softfloat_flag_inexact; + + /* |a| = |b| ==> return PI/4 */ + if (aSig == bSig && aExp == bExp) { + if (aSign) + return softfloat_roundPackToExtF80(bSign, FLOATX80_3PI4_EXP, FLOAT_3PI4_HI, FLOAT_3PI4_LO, 80); + else + return softfloat_roundPackToExtF80(bSign, FLOATX80_PI4_EXP, FLOAT_PI_HI, FLOAT_PI_LO, 80); + } + + /* ******************************** */ + /* using float128 for approximation */ + /* ******************************** */ + + float128_t a128 = softfloat_normRoundPackToF128(0, aExp-0x10, aSig, 0); + float128_t b128 = softfloat_normRoundPackToF128(0, bExp-0x10, bSig, 0); + float128_t x; + int swap = 0, add_pi6 = 0, add_pi4 = 0; + + if (aExp > bExp || (aExp == bExp && aSig > bSig)) + { + x = f128_div(b128, a128); + } + else { + x = f128_div(a128, b128); + swap = 1; + } + + int32_t xExp = expF128UI64(x.v[1]); + + if (xExp <= FLOATX80_EXP_BIAS-40) + goto approximation_completed; + + if (x.v[1] >= uint64_t(0x3ffe800000000000)) // 3/4 < x < 1 + { + /* + arctan(x) = arctan((x-1)/(x+1)) + pi/4 + */ + float128_t t1 = f128_sub(x, float128_one); + float128_t t2 = f128_add(x, float128_one); + x = f128_div(t1, t2); + add_pi4 = 1; + } + else + { + /* argument correction */ + if (xExp >= 0x3FFD) // 1/4 < x < 3/4 + { + /* + arctan(x) = arctan((x*sqrt(3)-1)/(x+sqrt(3))) + pi/6 + */ + float128_t t1 = f128_mul(x, float128_sqrt3); + float128_t t2 = f128_add(x, float128_sqrt3); + x = f128_sub(t1, float128_one); + x = f128_div(x, t2); + add_pi6 = 1; + } + } + + x = poly_atan(x); + if (add_pi6) x = f128_add(x, float128_pi6); + if (add_pi4) x = f128_add(x, float128_pi4); + +approximation_completed: + if (swap) x = f128_sub(float128_pi2, x); + extFloat80_t result = f128_to_extF80(x); + if (zSign) floatx80_chs(result); + int rSign = extF80_sign(result); + if (!bSign && rSign) + return extF80_add(result, floatx80_pi); + if (bSign && !rSign) + return extF80_sub(result, floatx80_pi); + return result; +} + +extFloat80_t packToExtF80(uint16_t signExp, uint64_t sig) +{ + extFloat80_t z; + z.signExp = signExp; + z.signif = sig; + return z; +} + +extFloat80_t packToExtF80(bool sign, uint16_t exp, uint64_t sig) +{ + extFloat80_t z; + z.signExp = packToExtF80UI64(sign, exp); + z.signif = sig; + return z; +} + +extFloat80_t extFloat80_68katan(extFloat80_t a) +{ + return extFloat80_atan(a, floatx80_one); +} 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 + +#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); +} diff --git a/3rdparty/softfloat3/bochs_ext/fpu_constant.h b/3rdparty/softfloat3/bochs_ext/fpu_constant.h new file mode 100644 index 00000000000..827dbdec514 --- /dev/null +++ b/3rdparty/softfloat3/bochs_ext/fpu_constant.h @@ -0,0 +1,80 @@ +/*============================================================================ +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. +=============================================================================*/ + +#ifndef _FPU_CONSTANTS_H_ +#define _FPU_CONSTANTS_H_ + +// Pentium CPU uses only 68-bit precision M_PI approximation +// #define BETTER_THAN_PENTIUM + +/*============================================================================ + * Written for Bochs (x86 achitecture simulator) by + * Stanislav Shwartsman [sshwarts at sourceforge net] + * ==========================================================================*/ + +////////////////////////////// +// PI, PI/2, PI/4 constants +////////////////////////////// + +#define FLOATX80_PI_EXP (0x4000) + +// 128-bit PI fraction +#ifdef BETTER_THAN_PENTIUM +#define FLOAT_PI_HI (uint64_t(0xc90fdaa22168c234)) +#define FLOAT_PI_LO (uint64_t(0xc4c6628b80dc1cd1)) +#else +#define FLOAT_PI_HI (uint64_t(0xc90fdaa22168c234)) +#define FLOAT_PI_LO (uint64_t(0xC000000000000000)) +#endif + +#define FLOATX80_PI2_EXP (0x3FFF) +#define FLOATX80_PI4_EXP (0x3FFE) + +////////////////////////////// +// 3PI/4 constant +////////////////////////////// + +#define FLOATX80_3PI4_EXP (0x4000) + +// 128-bit 3PI/4 fraction +#ifdef BETTER_THAN_PENTIUM +#define FLOAT_3PI4_HI (uint64_t(0x96cbe3f9990e91a7)) +#define FLOAT_3PI4_LO (uint64_t(0x9394c9e8a0a5159c)) +#else +#define FLOAT_3PI4_HI (uint64_t(0x96cbe3f9990e91a7)) +#define FLOAT_3PI4_LO (uint64_t(0x9000000000000000)) +#endif + +////////////////////////////// +// 1/LN2 constant +////////////////////////////// + +#define FLOAT_LN2INV_EXP (0x3FFF) + +// 128-bit 1/LN2 fraction +#ifdef BETTER_THAN_PENTIUM +#define FLOAT_LN2INV_HI (uint64_t(0xb8aa3b295c17f0bb)) +#define FLOAT_LN2INV_LO (uint64_t(0xbe87fed0691d3e89)) +#else +#define FLOAT_LN2INV_HI (uint64_t(0xb8aa3b295c17f0bb)) +#define FLOAT_LN2INV_LO (uint64_t(0xC000000000000000)) +#endif + +#endif diff --git a/3rdparty/softfloat3/bochs_ext/fsincos.c b/3rdparty/softfloat3/bochs_ext/fsincos.c new file mode 100644 index 00000000000..303d66cc5b8 --- /dev/null +++ b/3rdparty/softfloat3/bochs_ext/fsincos.c @@ -0,0 +1,457 @@ +/*============================================================================ +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 FLOAT128 + +#define USE_estimateDiv128To64 +#define FLOAT128 + +#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" + +static const extFloat80_t floatx80_one = packFloatx80(0, 0x3fff, uint64_t(0x8000000000000000)); + +/* reduce trigonometric function argument using 128-bit precision + M_PI approximation */ +static uint64_t argument_reduction_kernel(uint64_t aSig0, int Exp, uint64_t *zSig0, uint64_t *zSig1) +{ + uint64_t term0, term1, term2; + uint64_t aSig1 = 0; + + shortShift128Left(aSig1, aSig0, Exp, &aSig1, &aSig0); + uint64_t q = estimateDiv128To64(aSig1, aSig0, FLOAT_PI_HI); + mul128By64To192(FLOAT_PI_HI, FLOAT_PI_LO, q, &term0, &term1, &term2); + sub128(aSig1, aSig0, term0, term1, zSig1, zSig0); + while ((int64_t)(*zSig1) < 0) { + --q; + add192(*zSig1, *zSig0, term2, 0, FLOAT_PI_HI, FLOAT_PI_LO, zSig1, zSig0, &term2); + } + *zSig1 = term2; + return q; +} + +static int reduce_trig_arg(int expDiff, int &zSign, uint64_t &aSig0, uint64_t &aSig1) +{ + uint64_t term0, term1, q = 0; + + if (expDiff < 0) { + shortShift128Right(aSig0, 0, 1, &aSig0, &aSig1); + expDiff = 0; + } + if (expDiff > 0) { + q = argument_reduction_kernel(aSig0, expDiff, &aSig0, &aSig1); + } + else { + if (FLOAT_PI_HI <= aSig0) { + aSig0 -= FLOAT_PI_HI; + q = 1; + } + } + + shortShift128Right(FLOAT_PI_HI, FLOAT_PI_LO, 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) { + zSign = !zSign; + ++q; + } + if (lt) sub128(FLOAT_PI_HI, FLOAT_PI_LO, aSig0, aSig1, &aSig0, &aSig1); + } + + return (int)(q & 3); +} + +#define SIN_ARR_SIZE 11 +#define COS_ARR_SIZE 11 + +static float128_t sin_arr[SIN_ARR_SIZE] = +{ + PACK_FLOAT_128(0x3fff000000000000, 0x0000000000000000), /* 1 */ + PACK_FLOAT_128(0xbffc555555555555, 0x5555555555555555), /* 3 */ + PACK_FLOAT_128(0x3ff8111111111111, 0x1111111111111111), /* 5 */ + PACK_FLOAT_128(0xbff2a01a01a01a01, 0xa01a01a01a01a01a), /* 7 */ + PACK_FLOAT_128(0x3fec71de3a556c73, 0x38faac1c88e50017), /* 9 */ + PACK_FLOAT_128(0xbfe5ae64567f544e, 0x38fe747e4b837dc7), /* 11 */ + PACK_FLOAT_128(0x3fde6124613a86d0, 0x97ca38331d23af68), /* 13 */ + PACK_FLOAT_128(0xbfd6ae7f3e733b81, 0xf11d8656b0ee8cb0), /* 15 */ + PACK_FLOAT_128(0x3fce952c77030ad4, 0xa6b2605197771b00), /* 17 */ + PACK_FLOAT_128(0xbfc62f49b4681415, 0x724ca1ec3b7b9675), /* 19 */ + PACK_FLOAT_128(0x3fbd71b8ef6dcf57, 0x18bef146fcee6e45) /* 21 */ +}; + +static float128_t cos_arr[COS_ARR_SIZE] = +{ + PACK_FLOAT_128(0x3fff000000000000, 0x0000000000000000), /* 0 */ + PACK_FLOAT_128(0xbffe000000000000, 0x0000000000000000), /* 2 */ + PACK_FLOAT_128(0x3ffa555555555555, 0x5555555555555555), /* 4 */ + PACK_FLOAT_128(0xbff56c16c16c16c1, 0x6c16c16c16c16c17), /* 6 */ + PACK_FLOAT_128(0x3fefa01a01a01a01, 0xa01a01a01a01a01a), /* 8 */ + PACK_FLOAT_128(0xbfe927e4fb7789f5, 0xc72ef016d3ea6679), /* 10 */ + PACK_FLOAT_128(0x3fe21eed8eff8d89, 0x7b544da987acfe85), /* 12 */ + PACK_FLOAT_128(0xbfda93974a8c07c9, 0xd20badf145dfa3e5), /* 14 */ + PACK_FLOAT_128(0x3fd2ae7f3e733b81, 0xf11d8656b0ee8cb0), /* 16 */ + PACK_FLOAT_128(0xbfca6827863b97d9, 0x77bb004886a2c2ab), /* 18 */ + PACK_FLOAT_128(0x3fc1e542ba402022, 0x507a9cad2bf8f0bb) /* 20 */ +}; + +extern float128_t OddPoly (float128_t x, const float128_t *arr, int n); + +/* 0 <= x <= pi/4 */ +inline float128_t poly_sin(float128_t x) +{ + // 3 5 7 9 11 13 15 + // x x x x x x x + // sin (x) ~ x - --- + --- - --- + --- - ---- + ---- - ---- = + // 3! 5! 7! 9! 11! 13! 15! + // + // 2 4 6 8 10 12 14 + // x x x x x x x + // = x * [ 1 - --- + --- - --- + --- - ---- + ---- - ---- ] = + // 3! 5! 7! 9! 11! 13! 15! + // + // 3 3 + // -- 4k -- 4k+2 + // p(x) = > C * x > 0 q(x) = > C * x < 0 + // -- 2k -- 2k+1 + // k=0 k=0 + // + // 2 + // sin(x) ~ x * [ p(x) + x * q(x) ] + // + + return OddPoly(x, (const float128_t*) sin_arr, SIN_ARR_SIZE); +} + +extern float128_t EvenPoly(float128_t x, const float128_t *arr, int n); + +/* 0 <= x <= pi/4 */ +inline float128_t poly_cos(float128_t x) +{ + // 2 4 6 8 10 12 14 + // x x x x x x x + // cos (x) ~ 1 - --- + --- - --- + --- - ---- + ---- - ---- + // 2! 4! 6! 8! 10! 12! 14! + // + // 3 3 + // -- 4k -- 4k+2 + // p(x) = > C * x > 0 q(x) = > C * x < 0 + // -- 2k -- 2k+1 + // k=0 k=0 + // + // 2 + // cos(x) ~ [ p(x) + x * q(x) ] + // + + return EvenPoly(x, (const float128_t*) cos_arr, COS_ARR_SIZE); +} + +inline void sincos_invalid(extFloat80_t *sin_a, extFloat80_t *cos_a, extFloat80_t a) +{ + if (sin_a) *sin_a = a; + if (cos_a) *cos_a = a; +} + +inline void sincos_tiny_argument(extFloat80_t *sin_a, extFloat80_t *cos_a, extFloat80_t a) +{ + if (sin_a) *sin_a = a; + if (cos_a) *cos_a = floatx80_one; +} + +static extFloat80_t sincos_approximation(int neg, float128_t r, uint64_t quotient) +{ + if (quotient & 0x1) { + r = poly_cos(r); + neg = 0; + } else { + r = poly_sin(r); + } + + extFloat80_t result = f128_to_extF80(r); + if (quotient & 0x2) + neg = ! neg; + + if (neg) + floatx80_chs(result); + + return result; +} + +// ================================================= +// FSINCOS Compute sin(x) and cos(x) +// ================================================= + +// +// Uses the following identities: +// ---------------------------------------------------------- +// +// sin(-x) = -sin(x) +// cos(-x) = cos(x) +// +// sin(x+y) = sin(x)*cos(y)+cos(x)*sin(y) +// cos(x+y) = sin(x)*sin(y)+cos(x)*cos(y) +// +// sin(x+ pi/2) = cos(x) +// sin(x+ pi) = -sin(x) +// sin(x+3pi/2) = -cos(x) +// sin(x+2pi) = sin(x) +// + +int extFloat80_sincos(extFloat80_t a, extFloat80_t *sin_a, extFloat80_t *cos_a) +{ + uint64_t aSig0, aSig1 = 0; + int32_t aExp, zExp, expDiff; + int aSign, zSign; + int q = 0; + + // handle unsupported extended double-precision floating encodings + if (extF80_isUnsupported(a)) { + goto invalid; + } + + aSig0 = extF80_fraction(a); + aExp = extF80_exp(a); + aSign = extF80_sign(a); + + /* invalid argument */ + if (aExp == 0x7FFF) { + if (aSig0 << 1) { + const uint128 nan = softfloat_propagateNaNExtF80UI(a.signExp, aSig0, 0, 0); + extFloat80_t rv; + rv.signExp = nan.v64; + rv.signif = nan.v0; + sincos_invalid(sin_a, cos_a, rv); + return 0; + } + + invalid: + softfloat_exceptionFlags |= softfloat_flag_invalid; + sincos_invalid(sin_a, cos_a, floatx80_default_nan); + return 0; + } + + if (! aExp) { + if (! aSig0) { + sincos_tiny_argument(sin_a, cos_a, a); + return 0; + } + + softfloat_exceptionFlags |= softfloat_flag_invalid; // actually denormal + + /* handle pseudo denormals */ + if (! (aSig0 & uint64_t(0x8000000000000000))) + { + softfloat_exceptionFlags |= softfloat_flag_inexact; + if (sin_a) + softfloat_exceptionFlags |= softfloat_flag_underflow; + sincos_tiny_argument(sin_a, cos_a, a); + return 0; + } + + struct exp32_sig64 normExpSig = softfloat_normSubnormalExtF80Sig(aSig0); + aExp = normExpSig.exp + 1; + aSig0 = normExpSig.sig; + } + + zSign = aSign; + zExp = FLOATX80_EXP_BIAS; + expDiff = aExp - zExp; + + /* argument is out-of-range */ + if (expDiff >= 63) + return -1; + + softfloat_exceptionFlags |= softfloat_flag_inexact; + + if (expDiff < -1) { // doesn't require reduction + if (expDiff <= -68) { + a = packFloatx80(aSign, aExp, aSig0); + sincos_tiny_argument(sin_a, cos_a, a); + return 0; + } + zExp = aExp; + } + else { + q = reduce_trig_arg(expDiff, zSign, aSig0, aSig1); + } + + /* **************************** */ + /* argument reduction completed */ + /* **************************** */ + + /* using float128 for approximation */ + float128_t r = softfloat_normRoundPackToF128(0, zExp-0x10, aSig0, aSig1); + + if (aSign) q = -q; + if (sin_a) *sin_a = sincos_approximation(zSign, r, q); + if (cos_a) *cos_a = sincos_approximation(zSign, r, q+1); + + return 0; +} + +int extFloat80_sin(extFloat80_t &a) +{ + return extFloat80_sincos(a, &a, 0); +} + +int extFloat80_cos(extFloat80_t &a) +{ + return extFloat80_sincos(a, 0, &a); +} + +// ================================================= +// FPTAN Compute tan(x) +// ================================================= + +// +// Uses the following identities: +// +// 1. ---------------------------------------------------------- +// +// sin(-x) = -sin(x) +// cos(-x) = cos(x) +// +// sin(x+y) = sin(x)*cos(y)+cos(x)*sin(y) +// cos(x+y) = sin(x)*sin(y)+cos(x)*cos(y) +// +// sin(x+ pi/2) = cos(x) +// sin(x+ pi) = -sin(x) +// sin(x+3pi/2) = -cos(x) +// sin(x+2pi) = sin(x) +// +// 2. ---------------------------------------------------------- +// +// sin(x) +// tan(x) = ------ +// cos(x) +// + +int extFloat80_tan(extFloat80_t &a) +{ + uint64_t aSig0, aSig1 = 0; + int32_t aExp, zExp, expDiff; + int aSign, zSign; + int q = 0; + + // handle unsupported extended double-precision floating encodings + if (extF80_isUnsupported(a)) { + goto invalid; + } + + aSig0 = extF80_fraction(a); + aExp = extF80_exp(a); + aSign = extF80_sign(a); + + /* invalid argument */ + if (aExp == 0x7FFF) { + if (aSig0 << 1) + { + const uint128 nan = softfloat_propagateNaNExtF80UI(a.signExp, aSig0, 0, 0); + a.signExp = nan.v64; + a.signif = nan.v0; + return 0; + } + + invalid: + softfloat_exceptionFlags |= softfloat_flag_invalid; + a = floatx80_default_nan; + return 0; + } + + if (! aExp) { + if (! aSig0) return 0; + softfloat_exceptionFlags |= softfloat_flag_invalid; // actually denormal + /* handle pseudo denormals */ + if (! (aSig0 & uint64_t(0x8000000000000000))) + { + softfloat_exceptionFlags |= softfloat_flag_inexact | softfloat_flag_underflow; + return 0; + } + + struct exp32_sig64 normExpSig = softfloat_normSubnormalExtF80Sig(aSig0); + aExp = normExpSig.exp + 1; + aSig0 = normExpSig.sig; + } + + zSign = aSign; + zExp = FLOATX80_EXP_BIAS; + expDiff = aExp - zExp; + + /* argument is out-of-range */ + if (expDiff >= 63) + return -1; + + softfloat_exceptionFlags |= softfloat_flag_inexact; + + if (expDiff < -1) { // doesn't require reduction + if (expDiff <= -68) { + a = packFloatx80(aSign, aExp, aSig0); + return 0; + } + zExp = aExp; + } + else { + q = reduce_trig_arg(expDiff, zSign, aSig0, aSig1); + } + + /* **************************** */ + /* argument reduction completed */ + /* **************************** */ + + /* using float128 for approximation */ + float128_t r = softfloat_normRoundPackToF128(0, zExp-0x10, aSig0, aSig1); + + float128_t sin_r = poly_sin(r); + float128_t cos_r = poly_cos(r); + + if (q & 0x1) { + r = f128_div(cos_r, sin_r); + zSign = ! zSign; + } else { + r = f128_div(sin_r, cos_r); + } + + a = f128_to_extF80(r); + if (zSign) + floatx80_chs(a); + + return 0; +} + +extFloat80_t &floatx80_chs(extFloat80_t ®) +{ + reg.signExp ^= 0x8000; + return reg; +} diff --git a/3rdparty/softfloat3/bochs_ext/fyl2x.c b/3rdparty/softfloat3/bochs_ext/fyl2x.c new file mode 100644 index 00000000000..5b9f21bbf11 --- /dev/null +++ b/3rdparty/softfloat3/bochs_ext/fyl2x.c @@ -0,0 +1,409 @@ +/*============================================================================ +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 FLOAT128 + +#include "../build/MAME/platform.h" +#include "../source/include/internals.h" +#include "../source/include/softfloat.h" + +#include "fpu_constant.h" +#include "softfloat-extra.h" +#include "softfloat-helpers.h" +#include "softfloat-specialize.h" + +static const extFloat80_t floatx80_one = packFloatx80(0, 0x3fff, uint64_t(0x8000000000000000)); +static const extFloat80_t floatx80_ln_2 = packFloatx80(0, 0x3ffe, 0xb17217f7d1cf79acU); +static const extFloat80_t floatx80_log10_2 = packFloatx80(0, 0x3ffd, 0x9a209a84fbcff798U); + +static const float128_t float128_one = + packFloat128(uint64_t(0x3fff000000000000), uint64_t(0x0000000000000000)); +static const float128_t float128_two = + packFloat128(uint64_t(0x4000000000000000), uint64_t(0x0000000000000000)); + +static const float128_t float128_ln2inv2 = + packFloat128(uint64_t(0x400071547652b82f), uint64_t(0xe1777d0ffda0d23a)); + +#define SQRT2_HALF_SIG uint64_t(0xb504f333f9de6484) + +extern float128_t OddPoly(float128_t x, const float128_t *arr, int n); + +#define L2_ARR_SIZE 9 + +static float128_t ln_arr[L2_ARR_SIZE] = +{ + PACK_FLOAT_128(0x3fff000000000000, 0x0000000000000000), /* 1 */ + PACK_FLOAT_128(0x3ffd555555555555, 0x5555555555555555), /* 3 */ + PACK_FLOAT_128(0x3ffc999999999999, 0x999999999999999a), /* 5 */ + PACK_FLOAT_128(0x3ffc249249249249, 0x2492492492492492), /* 7 */ + PACK_FLOAT_128(0x3ffbc71c71c71c71, 0xc71c71c71c71c71c), /* 9 */ + PACK_FLOAT_128(0x3ffb745d1745d174, 0x5d1745d1745d1746), /* 11 */ + PACK_FLOAT_128(0x3ffb3b13b13b13b1, 0x3b13b13b13b13b14), /* 13 */ + PACK_FLOAT_128(0x3ffb111111111111, 0x1111111111111111), /* 15 */ + PACK_FLOAT_128(0x3ffae1e1e1e1e1e1, 0xe1e1e1e1e1e1e1e2) /* 17 */ +}; + +static float128_t poly_ln(float128_t x1) +{ +/* + // + // 3 5 7 9 11 13 15 + // 1+u u u u u u u u + // 1/2 ln --- ~ u + --- + --- + --- + --- + ---- + ---- + ---- = + // 1-u 3 5 7 9 11 13 15 + // + // 2 4 6 8 10 12 14 + // u u u u u u u + // = u * [ 1 + --- + --- + --- + --- + ---- + ---- + ---- ] = + // 3 5 7 9 11 13 15 + // + // 3 3 + // -- 4k -- 4k+2 + // p(u) = > C * u q(u) = > C * u + // -- 2k -- 2k+1 + // k=0 k=0 + // + // 1+u 2 + // 1/2 ln --- ~ u * [ p(u) + u * q(u) ] + // 1-u + // +*/ + return OddPoly(x1, (const float128_t*) ln_arr, L2_ARR_SIZE); +} + +/* required sqrt(2)/2 < x < sqrt(2) */ +static float128_t poly_l2(float128_t x) +{ + /* using float128 for approximation */ + float128_t x_p1 = f128_add(x, float128_one); + float128_t x_m1 = f128_sub(x, float128_one); + x = f128_div(x_m1, x_p1); + x = poly_ln(x); + x = f128_mul(x, float128_ln2inv2); + return x; +} + +static float128_t poly_l2p1(float128_t x) +{ + /* using float128 for approximation */ + float128_t x_plus2 = f128_add(x, float128_two); + x = f128_div(x, x_plus2); + x = poly_ln(x); + x = f128_mul(x, float128_ln2inv2); + return x; +} + +// ================================================= +// FYL2X Compute y * log (x) +// 2 +// ================================================= + +// +// Uses the following identities: +// +// 1. ---------------------------------------------------------- +// ln(x) +// log (x) = -------, ln (x*y) = ln(x) + ln(y) +// 2 ln(2) +// +// 2. ---------------------------------------------------------- +// 1+u x-1 +// ln (x) = ln -----, when u = ----- +// 1-u x+1 +// +// 3. ---------------------------------------------------------- +// 3 5 7 2n+1 +// 1+u u u u u +// ln ----- = 2 [ u + --- + --- + --- + ... + ------ + ... ] +// 1-u 3 5 7 2n+1 +// + +extFloat80_t extFloat80_fyl2x(extFloat80_t a, extFloat80_t b) +{ + // handle unsupported extended double-precision floating encodings + if (extF80_isUnsupported(a) || extF80_isUnsupported(b)) { +invalid: + softfloat_exceptionFlags |= softfloat_flag_invalid; + return floatx80_default_nan; + } + + uint64_t aSig = extF80_fraction(a); + int32_t aExp = extF80_exp(a); + int aSign = extF80_sign(a); + uint64_t bSig = extF80_fraction(b); + int32_t bExp = extF80_exp(b); + int bSign = extF80_sign(b); + + int zSign = bSign ^ 1; + + if (aExp == 0x7FFF) { + if ((aSig<<1) || ((bExp == 0x7FFF) && (bSig<<1))) { + const uint128 nan = softfloat_propagateNaNExtF80UI(a.signExp, aSig, b.signExp, bSig); + extFloat80_t rv; + rv.signExp = nan.v64; + rv.signif = nan.v0; + return rv; + } + if (aSign) goto invalid; + else { + if (! bExp) { + if (! bSig) goto invalid; + softfloat_exceptionFlags |= softfloat_flag_invalid; // actually denormal + } + return packFloatx80(bSign, 0x7FFF, uint64_t(0x8000000000000000)); + } + } + if (bExp == 0x7FFF) { + if (bSig << 1) { + const uint128 nan = softfloat_propagateNaNExtF80UI(a.signExp, aSig, b.signExp, bSig); + extFloat80_t rv; + rv.signExp = nan.v64; + rv.signif = nan.v0; + return rv; + } + if (aSign && (uint64_t)(aExp | aSig)) goto invalid; + if (aSig && ! aExp) + softfloat_exceptionFlags |= softfloat_flag_invalid; // actually denormal + if (aExp < 0x3FFF) + { + return packFloatx80(zSign, 0x7FFF, uint64_t(0x8000000000000000)); + } + if (aExp == 0x3FFF && ! (aSig<<1)) goto invalid; + return packFloatx80(bSign, 0x7FFF, uint64_t(0x8000000000000000)); + } + if (! aExp) { + if (! aSig) { + if ((bExp | bSig) == 0) goto invalid; + softfloat_exceptionFlags |= softfloat_flag_invalid; // divide by zero + return packFloatx80(zSign, 0x7FFF, uint64_t(0x8000000000000000)); + } + if (aSign) goto invalid; + softfloat_exceptionFlags |= softfloat_flag_invalid; // actually denormal + struct exp32_sig64 normExpSig = softfloat_normSubnormalExtF80Sig(aSig); + aExp = normExpSig.exp + 1; + aSig = normExpSig.sig; + } + if (aSign) goto invalid; + if (! bExp) { + if (! bSig) { + if (aExp < 0x3FFF) return packFloatx80(zSign, 0, 0); + return packFloatx80(bSign, 0, 0); + } + softfloat_exceptionFlags |= softfloat_flag_invalid; // actually denormal + struct exp32_sig64 normExpSig = softfloat_normSubnormalExtF80Sig(bSig); + bExp = normExpSig.exp + 1; + bSig = normExpSig.sig; + } + if (aExp == 0x3FFF && ! (aSig<<1)) + return packFloatx80(bSign, 0, 0); + + softfloat_exceptionFlags |= softfloat_flag_inexact; + + int ExpDiff = aExp - 0x3FFF; + aExp = 0; + if (aSig >= SQRT2_HALF_SIG) { + ExpDiff++; + aExp--; + } + + /* ******************************** */ + /* using float128 for approximation */ + /* ******************************** */ + + float128_t b128 = softfloat_normRoundPackToF128(bSign, bExp-0x10, bSig, 0); + + uint64_t zSig0, zSig1; + shortShift128Right(aSig<<1, 0, 16, &zSig0, &zSig1); + float128_t x = packFloat128(0, aExp+0x3FFF, zSig0, zSig1); + x = poly_l2(x); + x = f128_add(x, i32_to_f128(ExpDiff)); + x = f128_mul(x, b128); + return f128_to_extF80(x); +} + +// ================================================= +// FYL2XP1 Compute y * log (x + 1) +// 2 +// ================================================= + +// +// Uses the following identities: +// +// 1. ---------------------------------------------------------- +// ln(x) +// log (x) = ------- +// 2 ln(2) +// +// 2. ---------------------------------------------------------- +// 1+u x +// ln (x+1) = ln -----, when u = ----- +// 1-u x+2 +// +// 3. ---------------------------------------------------------- +// 3 5 7 2n+1 +// 1+u u u u u +// ln ----- = 2 [ u + --- + --- + --- + ... + ------ + ... ] +// 1-u 3 5 7 2n+1 +// + +extFloat80_t extFloat80_fyl2xp1(extFloat80_t a, extFloat80_t b) +{ + int32_t aExp, bExp; + uint64_t aSig, bSig, zSig0, zSig1, zSig2; + int aSign, bSign; + + // handle unsupported extended double-precision floating encodings + if (extF80_isUnsupported(a) || extF80_isUnsupported(b)) { +invalid: + softfloat_exceptionFlags |= softfloat_flag_invalid; + return floatx80_default_nan; + } + + + aSig = extF80_fraction(a); + aExp = extF80_exp(a); + aSign = extF80_sign(a); + bSig = extF80_fraction(b); + bExp = extF80_exp(b); + bSign = extF80_sign(b); + int zSign = aSign ^ bSign; + + if (aExp == 0x7FFF) { + if ((aSig<<1) != 0 || ((bExp == 0x7FFF) && (bSig<<1) != 0)) { + const uint128 nan = softfloat_propagateNaNExtF80UI(a.signExp, aSig, b.signExp, bSig); + extFloat80_t rv; + rv.signExp = nan.v64; + rv.signif = nan.v0; + return rv; + } + if (aSign) goto invalid; + else { + if (! bExp) { + if (! bSig) goto invalid; + softfloat_exceptionFlags |= softfloat_flag_invalid; // actually denormal + } + return packFloatx80(bSign, 0x7FFF, uint64_t(0x8000000000000000)); + } + } + if (bExp == 0x7FFF) + { + if (bSig << 1) { + const uint128 nan = softfloat_propagateNaNExtF80UI(a.signExp, aSig, b.signExp, bSig); + extFloat80_t rv; + rv.signExp = nan.v64; + rv.signif = nan.v0; + return rv; + } + if (! aExp) { + if (! aSig) goto invalid; + softfloat_exceptionFlags |= softfloat_flag_invalid; // actually denormal + } + + return packFloatx80(zSign, 0x7FFF, uint64_t(0x8000000000000000)); + } + if (! aExp) { + if (! aSig) { + if (bSig && ! bExp) + softfloat_exceptionFlags |= softfloat_flag_invalid; // actually denormal + + return packFloatx80(zSign, 0, 0); + } + softfloat_exceptionFlags |= softfloat_flag_invalid; // actually denormal + struct exp32_sig64 normExpSig = softfloat_normSubnormalExtF80Sig(aSig); + aExp = normExpSig.exp + 1; + aSig = normExpSig.sig; + } + if (! bExp) { + if (! bSig) return packFloatx80(zSign, 0, 0); + softfloat_exceptionFlags |= softfloat_flag_invalid; // actually denormal + struct exp32_sig64 normExpSig = softfloat_normSubnormalExtF80Sig(bSig); + bExp = normExpSig.exp + 1; + bSig = normExpSig.sig; + } + + softfloat_exceptionFlags |= softfloat_flag_inexact; + + if (aSign && aExp >= 0x3FFF) + return a; + + if (aExp >= 0x3FFC) // big argument + { + return extFloat80_fyl2x(extF80_add(a, floatx80_one), b); + } + + // handle tiny argument + if (aExp < FLOATX80_EXP_BIAS-70) + { + // first order approximation, return (a*b)/ln(2) + int32_t zExp = aExp + FLOAT_LN2INV_EXP - 0x3FFE; + + mul128By64To192(FLOAT_LN2INV_HI, FLOAT_LN2INV_LO, aSig, &zSig0, &zSig1, &zSig2); + if (0 < (int64_t) zSig0) { + shortShift128Left(zSig0, zSig1, 1, &zSig0, &zSig1); + --zExp; + } + + zExp = zExp + bExp - 0x3FFE; + mul128By64To192(zSig0, zSig1, bSig, &zSig0, &zSig1, &zSig2); + if (0 < (int64_t) zSig0) { + shortShift128Left(zSig0, zSig1, 1, &zSig0, &zSig1); + --zExp; + } + + return softfloat_roundPackToExtF80(aSign ^ bSign, zExp, zSig0, zSig1, 80); + } + + /* ******************************** */ + /* using float128 for approximation */ + /* ******************************** */ + + float128_t b128 = softfloat_normRoundPackToF128(bSign, bExp-0x10, bSig, 0); + + shortShift128Right(aSig<<1, 0, 16, &zSig0, &zSig1); + float128_t x = packFloat128(aSign, aExp, zSig0, zSig1); + x = poly_l2p1(x); + x = f128_mul(x, b128); + return f128_to_extF80(x); +} + +extFloat80_t extFloat80_lognp1(extFloat80_t a) +{ + return extFloat80_fyl2x(a, floatx80_ln_2); +} + +extFloat80_t extFloat80_logn(extFloat80_t a) +{ + return extFloat80_fyl2x(a, floatx80_ln_2); +} + +extFloat80_t extFloat80_log2(extFloat80_t a) +{ + return extFloat80_fyl2x(a, floatx80_one); +} + +extFloat80_t extFloat80_log10(extFloat80_t a) +{ + return extFloat80_fyl2x(a, floatx80_log10_2); +} diff --git a/3rdparty/softfloat3/bochs_ext/poly.c b/3rdparty/softfloat3/bochs_ext/poly.c new file mode 100644 index 00000000000..3498e29ec4d --- /dev/null +++ b/3rdparty/softfloat3/bochs_ext/poly.c @@ -0,0 +1,91 @@ +/*============================================================================ +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] + * ==========================================================================*/ + +#include + +#include "../source/include/softfloat.h" + +// 2 3 4 n +// f(x) ~ C + (C * x) + (C * x) + (C * x) + (C * x) + ... + (C * x) +// 0 1 2 3 4 n +// +// -- 2k -- 2k+1 +// p(x) = > C * x q(x) = > C * x +// -- 2k -- 2k+1 +// +// f(x) ~ [ p(x) + x * q(x) ] +// + +float128_t EvalPoly(float128_t x, const float128_t *arr, int n) +{ + float128_t r = arr[--n]; + + do { + r = f128_mulAdd(r, x, arr[--n]); +// r = f128_mul(r, x); +// r = f128_add(r, arr[--n]); + + } while (n > 0); + + return r; +} + +// 2 4 6 8 2n +// f(x) ~ C + (C * x) + (C * x) + (C * x) + (C * x) + ... + (C * x) +// 0 1 2 3 4 n +// +// -- 4k -- 4k+2 +// p(x) = > C * x q(x) = > C * x +// -- 2k -- 2k+1 +// +// 2 +// f(x) ~ [ p(x) + x * q(x) ] +// + +float128_t EvenPoly(float128_t x, const float128_t *arr, int n) +{ + return EvalPoly(f128_mul(x, x), arr, n); +} + +// 3 5 7 9 2n+1 +// f(x) ~ (C * x) + (C * x) + (C * x) + (C * x) + (C * x) + ... + (C * x) +// 0 1 2 3 4 n +// 2 4 6 8 2n +// = x * [ C + (C * x) + (C * x) + (C * x) + (C * x) + ... + (C * x) +// 0 1 2 3 4 n +// +// -- 4k -- 4k+2 +// p(x) = > C * x q(x) = > C * x +// -- 2k -- 2k+1 +// +// 2 +// f(x) ~ x * [ p(x) + x * q(x) ] +// + +float128_t OddPoly(float128_t x, const float128_t *arr, int n) +{ + return f128_mul(x, EvenPoly(x, arr, n)); +} + diff --git a/3rdparty/softfloat3/bochs_ext/softfloat-extra.h b/3rdparty/softfloat3/bochs_ext/softfloat-extra.h new file mode 100644 index 00000000000..087656e5a58 --- /dev/null +++ b/3rdparty/softfloat3/bochs_ext/softfloat-extra.h @@ -0,0 +1,68 @@ +/*============================================================================ + +This C header file is part of the SoftFloat IEEE Floating-Point Arithmetic +Package, Release 3e, by John R. Hauser. + +Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the +University of California. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions, and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions, and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the University nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=============================================================================*/ + +#ifndef softfloat_extra_h +#define softfloat_extra_h 1 + +#include "../source/include/internals.h" + +// ======= floatx80 ======= // + +inline bool extF80_isUnsupported(extFloat80_t a) +{ + return ((a.signExp & 0x7FFF) && !(a.signif & uint64_t(0x8000000000000000))); +} + +inline bool extF80_sign(extFloat80_t a) +{ + return signExtF80UI64(a.signExp); +} + +inline int16_t extF80_exp(extFloat80_t a) +{ + return expExtF80UI64(a.signExp); +} + +inline uint64_t extF80_fraction(extFloat80_t a) +{ + return a.signif; +} + +extFloat80_t &floatx80_chs(extFloat80_t ®); + +extFloat80_t packToExtF80(uint16_t signExp, uint64_t sig); +extFloat80_t packToExtF80(bool sign, uint16_t exp, uint64_t sig); + +#endif diff --git a/3rdparty/softfloat3/bochs_ext/softfloat-helpers.h b/3rdparty/softfloat3/bochs_ext/softfloat-helpers.h new file mode 100644 index 00000000000..b8833a126e6 --- /dev/null +++ b/3rdparty/softfloat3/bochs_ext/softfloat-helpers.h @@ -0,0 +1,159 @@ +/*============================================================================ +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. +=============================================================================*/ + +/*============================================================================ + * Adapted for Bochs (x86 achitecture simulator) by + * Stanislav Shwartsman [sshwarts at sourceforge net] + * ==========================================================================*/ + +#ifndef _SOFTFLOAT_HELPERS_H_ +#define _SOFTFLOAT_HELPERS_H_ + +#include +#include + +#include "../source/include/primitives.h" +#include "../source/include/primitiveTypes.h" + +/*---------------------------------------------------------------------------- +| Multiplies the 128-bit value formed by concatenating `a0' and `a1' by +| `b' to obtain a 192-bit product. The product is broken into three 64-bit +| pieces which are stored at the locations pointed to by `z0Ptr', `z1Ptr', and +| `z2Ptr'. +*----------------------------------------------------------------------------*/ + +inline void mul128By64To192(uint64_t a64, uint64_t a0, uint64_t b, uint64_t *z0Ptr, uint64_t *z1Ptr, uint64_t *z2Ptr) +{ + uint64_t zPtr[4]; + + softfloat_mul128To256M(a64, a0, 0, b, (uint64_t*) zPtr); + + assert(zPtr[indexWord(4, 3)] == 0); + + *z0Ptr = zPtr[indexWord(4, 2)]; + *z1Ptr = zPtr[indexWord(4, 1)]; + *z2Ptr = zPtr[indexWord(4, 0)]; +} + +/*---------------------------------------------------------------------------- +| Shifts the 128-bit value formed by concatenating `a0' and `a1' left by the +| number of bits given in `count'. Any bits shifted off are lost. The value +| of `count' must be less than 64. The result is broken into two 64-bit +| pieces which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'. +*----------------------------------------------------------------------------*/ + +inline void shortShift128Left(uint64_t a0, uint64_t a1, int count, uint64_t *z0Ptr, uint64_t *z1Ptr) +{ + *z1Ptr = a1<>((-count) & 63)); +} + +/*---------------------------------------------------------------------------- +| Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the +| number of bits given in `count'. Any bits shifted off are lost. The value +| of `count' must be less than 64. The result is broken into two 64-bit pieces +| which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'. +*----------------------------------------------------------------------------*/ + +inline void shortShift128Right(uint64_t a0, uint64_t a1, int count, uint64_t *z0Ptr, uint64_t *z1Ptr) +{ + uint64_t z0 = a0, z1 = a1; + int negCount = (-count) & 63; + + if (count != 0) { + z1 = (a0<>count); + z0 = a0>>count; + } + *z1Ptr = z1; + *z0Ptr = z0; +} + +/*---------------------------------------------------------------------------- +| Returns an approximation to the 64-bit integer quotient obtained by dividing +| `b' into the 128-bit value formed by concatenating `a0' and `a1'. The +| divisor `b' must be at least 2^63. If q is the exact quotient truncated +| toward zero, the approximation returned lies between q and q + 2 inclusive. +| If the exact quotient q is larger than 64 bits, the maximum positive 64-bit +| unsigned integer is returned. +*----------------------------------------------------------------------------*/ + +#ifdef USE_estimateDiv128To64 +static uint64_t estimateDiv128To64(uint64_t a0, uint64_t a1, uint64_t b) +{ + uint128 term, rem; + uint64_t b0, b1; + uint64_t z; + if (b <= a0) return uint64_t(0xFFFFFFFFFFFFFFFF); + b0 = b>>32; + z = (b0<<32 <= a0) ? uint64_t(0xFFFFFFFF00000000) : (a0 / b0)<<32; + term = softfloat_mul64To128(b, z); + rem = softfloat_sub128(a0, a1, term.v64, term.v0); + while (((int64_t) rem.v64) < 0) { + z -= UINT64_C(0x100000000); + b1 = b<<32; + rem = softfloat_add128(rem.v64, rem.v0, b0, b1); + } + rem.v64 = (rem.v64<<32) | (rem.v0>>32); + z |= (b0<<32 <= rem.v64) ? 0xFFFFFFFF : rem.v64 / b0; + return z; +} +#endif + +/*---------------------------------------------------------------------------- +| Adds the 192-bit value formed by concatenating `a0', `a1', and `a2' to the +| 192-bit value formed by concatenating `b0', `b1', and `b2'. Addition is +| modulo 2^192, so any carry out is lost. The result is broken into three +| 64-bit pieces which are stored at the locations pointed to by `z0Ptr', +| `z1Ptr', and `z2Ptr'. +*----------------------------------------------------------------------------*/ + +inline void add192(uint64_t a0, uint64_t a1, uint64_t a2, uint64_t b0, uint64_t b1, uint64_t b2, uint64_t *z0Ptr, uint64_t *z1Ptr, uint64_t *z2Ptr) +{ + uint64_t z0, z1, z2; + unsigned carry0, carry1; + + z2 = a2 + b2; + carry1 = (z2 < a2); + z1 = a1 + b1; + carry0 = (z1 < a1); + z0 = a0 + b0; + z1 += carry1; + z0 += (z1 < carry1); + z0 += carry0; + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; +} + +/*---------------------------------------------------------------------------- +| Subtracts the 128-bit value formed by concatenating `b0' and `b1' from the +| 128-bit value formed by concatenating `a0' and `a1'. Subtraction is modulo +| 2^128, so any borrow out (carry out) is lost. The result is broken into two +| 64-bit pieces which are stored at the locations pointed to by `z0Ptr' and +| `z1Ptr'. +*----------------------------------------------------------------------------*/ + +inline void sub128(uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1, uint64_t *z0Ptr, uint64_t *z1Ptr) +{ + *z1Ptr = a1 - b1; + *z0Ptr = a0 - b0 - (a1 < b1); +} + +#endif diff --git a/3rdparty/softfloat3/bochs_ext/softfloat-specialize.h b/3rdparty/softfloat3/bochs_ext/softfloat-specialize.h new file mode 100644 index 00000000000..f4c5bd2b2cd --- /dev/null +++ b/3rdparty/softfloat3/bochs_ext/softfloat-specialize.h @@ -0,0 +1,223 @@ +/*============================================================================ +This C source fragment is part of the SoftFloat IEC/IEEE Floating-point +Arithmetic Package, Release 2b. + +Written by John R. Hauser. This work was made possible in part by the +International Computer Science Institute, located at Suite 600, 1947 Center +Street, Berkeley, California 94704. Funding was partially provided by the +National Science Foundation under grant MIP-9311980. The original version +of this code was written as part of a project to build a fixed-point vector +processor in collaboration with the University of California at Berkeley, +overseen by Profs. Nelson Morgan and John Wawrzynek. More information +is available through the Web page `http://www.cs.berkeley.edu/~jhauser/ +arithmetic/SoftFloat.html'. + +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. +=============================================================================*/ + +#ifndef _SOFTFLOAT_SPECIALIZE_H_ +#define _SOFTFLOAT_SPECIALIZE_H_ + +#include "../source/include/softfloat_types.h" +#include "../source/8086/specialize.h" + +/*============================================================================ + * Adapted for Bochs (x86 achitecture simulator) by + * Stanislav Shwartsman [sshwarts at sourceforge net] + * ==========================================================================*/ + +const int16_t int16_indefinite = (int16_t) 0x8000; +const int32_t int32_indefinite = (int32_t) 0x80000000; +const int64_t int64_indefinite = (int64_t) uint64_t(0x8000000000000000); + +const uint16_t uint16_indefinite = 0xffff; +const uint32_t uint32_indefinite = 0xffffffff; +const uint64_t uint64_indefinite = uint64_t(0xffffffffffffffff); + +/*---------------------------------------------------------------------------- +| Commonly used half-precision floating point constants +*----------------------------------------------------------------------------*/ +const uint16_t float16_negative_inf = 0xfc00; +const uint16_t float16_positive_inf = 0x7c00; +const uint16_t float16_negative_zero = 0x8000; +const uint16_t float16_positive_zero = 0x0000; + +/*---------------------------------------------------------------------------- +| The pattern for a default generated half-precision NaN. +*----------------------------------------------------------------------------*/ +const uint16_t float16_default_nan = 0xFE00; + +#define FLOAT16_EXP_BIAS 0xF + +/*---------------------------------------------------------------------------- +| Packs the sign `zSign', exponent `zExp', and significand `zSig' into a +| single-precision floating-point value, returning the result. After being +| shifted into the proper positions, the three fields are simply added +| together to form the result. This means that any integer portion of `zSig' +| will be added into the exponent. Since a properly normalized significand +| will have an integer portion equal to 1, the `zExp' input should be 1 less +| than the desired result exponent whenever `zSig' is a complete, normalized +| significand. +*----------------------------------------------------------------------------*/ + +inline uint16_t packFloat16(int zSign, int zExp, uint16_t zSig) +{ + return (((uint16_t) zSign)<<15) + (((uint16_t) zExp)<<10) + zSig; +} + +/*---------------------------------------------------------------------------- +| Commonly used single-precision floating point constants +*----------------------------------------------------------------------------*/ +const uint32_t float32_negative_inf = 0xff800000; +const uint32_t float32_positive_inf = 0x7f800000; +const uint32_t float32_negative_zero = 0x80000000; +const uint32_t float32_positive_zero = 0x00000000; +const uint32_t float32_negative_one = 0xbf800000; +const uint32_t float32_positive_one = 0x3f800000; +const uint32_t float32_max_float = 0x7f7fffff; +const uint32_t float32_min_float = 0xff7fffff; + +/*---------------------------------------------------------------------------- +| The pattern for a default generated single-precision NaN. +*----------------------------------------------------------------------------*/ +const uint32_t float32_default_nan = 0xffc00000; + +#define FLOAT32_EXP_BIAS 0x7F + +/*---------------------------------------------------------------------------- +| Packs the sign `zSign', exponent `zExp', and significand `zSig' into a +| single-precision floating-point value, returning the result. After being +| shifted into the proper positions, the three fields are simply added +| together to form the result. This means that any integer portion of `zSig' +| will be added into the exponent. Since a properly normalized significand +| will have an integer portion equal to 1, the `zExp' input should be 1 less +| than the desired result exponent whenever `zSig' is a complete, normalized +| significand. +*----------------------------------------------------------------------------*/ + +inline uint32_t packFloat32(int zSign, int16_t zExp, uint32_t zSig) +{ + return (((uint32_t) zSign)<<31) + (((uint32_t) zExp)<<23) + zSig; +} + +/*---------------------------------------------------------------------------- +| Commonly used single-precision floating point constants +*----------------------------------------------------------------------------*/ +const uint64_t float64_negative_inf = uint64_t(0xfff0000000000000); +const uint64_t float64_positive_inf = uint64_t(0x7ff0000000000000); +const uint64_t float64_negative_zero = uint64_t(0x8000000000000000); +const uint64_t float64_positive_zero = uint64_t(0x0000000000000000); +const uint64_t float64_negative_one = uint64_t(0xbff0000000000000); +const uint64_t float64_positive_one = uint64_t(0x3ff0000000000000); +const uint64_t float64_max_float = uint64_t(0x7fefffffffffffff); +const uint64_t float64_min_float = uint64_t(0xffefffffffffffff); + +/*---------------------------------------------------------------------------- +| The pattern for a default generated double-precision NaN. +*----------------------------------------------------------------------------*/ +const uint64_t float64_default_nan = uint64_t(0xFFF8000000000000); + +#define FLOAT64_EXP_BIAS 0x3FF + +/*---------------------------------------------------------------------------- +| Packs the sign `zSign', exponent `zExp', and significand `zSig' into a +| double-precision floating-point value, returning the result. After being +| shifted into the proper positions, the three fields are simply added +| together to form the result. This means that any integer portion of `zSig' +| will be added into the exponent. Since a properly normalized significand +| will have an integer portion equal to 1, the `zExp' input should be 1 less +| than the desired result exponent whenever `zSig' is a complete, normalized +| significand. +*----------------------------------------------------------------------------*/ + +inline uint64_t packFloat64(int zSign, int16_t zExp, uint64_t zSig) +{ + return (((uint64_t) zSign)<<63) + (((uint64_t) zExp)<<52) + zSig; +} + +/*---------------------------------------------------------------------------- +| The pattern for a default generated extended double-precision NaN. The +| `high' and `low' values hold the most- and least-significant bits, +| respectively. +*----------------------------------------------------------------------------*/ +#define floatx80_default_nan_exp 0xFFFF +#define floatx80_default_nan_fraction uint64_t(0xC000000000000000) + +#define FLOATX80_EXP_BIAS 0x3FFF + +/*---------------------------------------------------------------------------- +| Packs the sign `zSign', exponent `zExp', and significand `zSig' into an +| extended double-precision floating-point value, returning the result. +*----------------------------------------------------------------------------*/ + +inline extFloat80_t packFloatx80(int zSign, int32_t zExp, uint64_t zSig) +{ + extFloat80_t z; + z.signif = zSig; + z.signExp = (zSign << 15) + zExp; + return z; +} + +/*---------------------------------------------------------------------------- +| The pattern for a default generated extended double-precision NaN. +*----------------------------------------------------------------------------*/ +static const extFloat80_t floatx80_default_nan = + packFloatx80(0, floatx80_default_nan_exp, floatx80_default_nan_fraction); + +#ifdef FLOAT128 + +/*---------------------------------------------------------------------------- +| Packs the sign `zSign', the exponent `zExp', and the significand formed +| by the concatenation of `zSig0' and `zSig1' into a quadruple-precision +| floating-point value, returning the result. After being shifted into the +| proper positions, the three fields `zSign', `zExp', and `zSig0' are simply +| added together to form the most significant 32 bits of the result. This +| means that any integer portion of `zSig0' will be added into the exponent. +| Since a properly normalized significand will have an integer portion equal +| to 1, the `zExp' input should be 1 less than the desired result exponent +| whenever `zSig0' and `zSig1' concatenated form a complete, normalized +| significand. +*----------------------------------------------------------------------------*/ + +inline float128_t packFloat128(int zSign, int32_t zExp, uint64_t zSig0, uint64_t zSig1) +{ + float128_t z; + z.v[0] = zSig1; + z.v[1] = (((uint64_t) zSign)<<63) + (((uint64_t) zExp)<<48) + zSig0; + return z; +} + +/*---------------------------------------------------------------------------- +| Packs two 64-bit precision integers into into the quadruple-precision +| floating-point value, returning the result. +*----------------------------------------------------------------------------*/ + +inline float128_t packFloat128(uint64_t zHi, uint64_t zLo) +{ + float128_t z; + z.v[0] = zLo; + z.v[1] = zHi; + return z; +} + +#ifdef _MSC_VER +#define PACK_FLOAT_128(hi,lo) { lo, hi } +#else +#define PACK_FLOAT_128(hi,lo) packFloat128(uint64_t(hi),uint64_t(lo)) +#endif + +#endif /* FLOAT128 */ + +#endif diff --git a/3rdparty/softfloat3/bochs_ext/softfloat3_ext.h b/3rdparty/softfloat3/bochs_ext/softfloat3_ext.h new file mode 100644 index 00000000000..b6f560bb45a --- /dev/null +++ b/3rdparty/softfloat3/bochs_ext/softfloat3_ext.h @@ -0,0 +1,17 @@ +int extFloat80_ieee754_remainder(extFloat80_t a, extFloat80_t b, extFloat80_t &r, uint64_t &q); +int extFloat80_remainder(extFloat80_t a, extFloat80_t b, extFloat80_t &r, uint64_t &q); +int extFloat80_sincos(extFloat80_t a, extFloat80_t *sin_a, extFloat80_t *cos_a); +int extFloat80_sin(extFloat80_t &a); +int extFloat80_cos(extFloat80_t &a); +int extFloat80_tan(extFloat80_t &a); +extFloat80_t extFloat80_atan(extFloat80_t a, extFloat80_t b); +extFloat80_t extFloat80_68katan(extFloat80_t a); +extFloat80_t extFloat80_getman(extFloat80_t a); +extFloat80_t extFloat80_fyl2x(extFloat80_t a, extFloat80_t b); +extFloat80_t extFloat80_fyl2xp1(extFloat80_t a, extFloat80_t b); +extFloat80_t extFloat80_2xm1(extFloat80_t a); +extFloat80_t extFloat80_lognp1(extFloat80_t a); +extFloat80_t extFloat80_logn(extFloat80_t a); +extFloat80_t extFloat80_log2(extFloat80_t a); +extFloat80_t extFloat80_log10(extFloat80_t a); +extFloat80_t extFloat80_scale(extFloat80_t a, extFloat80_t b); diff --git a/3rdparty/softfloat3/build/MAME/platform.h b/3rdparty/softfloat3/build/MAME/platform.h index 5dfa704955c..6fd29db58fd 100644 --- a/3rdparty/softfloat3/build/MAME/platform.h +++ b/3rdparty/softfloat3/build/MAME/platform.h @@ -33,7 +33,7 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ - +# /*---------------------------------------------------------------------------- Softfloat 3 MAME modifications *----------------------------------------------------------------------------*/ @@ -45,11 +45,7 @@ Softfloat 3 MAME modifications /*---------------------------------------------------------------------------- *----------------------------------------------------------------------------*/ -#ifdef __GNUC_STDC_INLINE__ -#define INLINE inline -#else -#define INLINE extern inline -#endif +#define INLINE static inline /*---------------------------------------------------------------------------- *----------------------------------------------------------------------------*/ @@ -78,4 +74,4 @@ Softfloat 3 MAME modifications #endif // defined(_MSC_VER) -#include "opts-GCC.h" +#include "../../source/include/opts-GCC.h" diff --git a/3rdparty/softfloat3/source/include/softfloat.h b/3rdparty/softfloat3/source/include/softfloat.h index 9ed17c1b90d..863796d3b4b 100644 --- a/3rdparty/softfloat3/source/include/softfloat.h +++ b/3rdparty/softfloat3/source/include/softfloat.h @@ -46,6 +46,22 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef softfloat_h #define softfloat_h 1 +// copy config #defines from 3rdparty.lua to match the build configuration +#ifndef SOFTFLOAT_FAST_INT64 +#define SOFTFLOAT_FAST_INT64 +#define SOFTFLOAT_FAST_DIV32TO16 +#define SOFTFLOAT_FAST_DIV64TO32 +#define SOFTFLOAT_ROUND_ODD +#endif + +#ifndef INLINE_LEVEL +#define INLINE_LEVEL (5) +#endif + +#ifndef INLINE +#define INLINE static inline +#endif + #include #include #include "softfloat_types.h" @@ -59,8 +75,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *----------------------------------------------------------------------------*/ extern THREAD_LOCAL uint_fast8_t softfloat_detectTininess; enum { - softfloat_tininess_beforeRounding = 0, - softfloat_tininess_afterRounding = 1 + softfloat_tininess_beforeRounding = 0, + softfloat_tininess_afterRounding = 1 }; /*---------------------------------------------------------------------------- @@ -69,12 +85,12 @@ enum { *----------------------------------------------------------------------------*/ extern THREAD_LOCAL uint_fast8_t softfloat_roundingMode; enum { - softfloat_round_near_even = 0, - softfloat_round_minMag = 1, - softfloat_round_min = 2, - softfloat_round_max = 3, - softfloat_round_near_maxMag = 4, - softfloat_round_odd = 6 + softfloat_round_near_even = 0, + softfloat_round_minMag = 1, + softfloat_round_min = 2, + softfloat_round_max = 3, + softfloat_round_near_maxMag = 4, + softfloat_round_odd = 6 }; /*---------------------------------------------------------------------------- @@ -82,11 +98,11 @@ enum { *----------------------------------------------------------------------------*/ extern THREAD_LOCAL uint_fast8_t softfloat_exceptionFlags; enum { - softfloat_flag_inexact = 1, - softfloat_flag_underflow = 2, - softfloat_flag_overflow = 4, - softfloat_flag_infinite = 8, - softfloat_flag_invalid = 16 + softfloat_flag_inexact = 1, + softfloat_flag_underflow = 2, + softfloat_flag_overflow = 4, + softfloat_flag_infinite = 8, + softfloat_flag_invalid = 16 }; /*---------------------------------------------------------------------------- @@ -290,7 +306,7 @@ float64_t extF80M_to_f64( const extFloat80_t * ); void extF80M_to_f128M( const extFloat80_t *, float128_t * ); void extF80M_roundToInt( - const extFloat80_t *, uint_fast8_t, bool, extFloat80_t * ); + const extFloat80_t *, uint_fast8_t, bool, extFloat80_t * ); void extF80M_add( const extFloat80_t *, const extFloat80_t *, extFloat80_t * ); void extF80M_sub( const extFloat80_t *, const extFloat80_t *, extFloat80_t * ); void extF80M_mul( const extFloat80_t *, const extFloat80_t *, extFloat80_t * ); @@ -355,7 +371,7 @@ void f128M_sub( const float128_t *, const float128_t *, float128_t * ); void f128M_mul( const float128_t *, const float128_t *, float128_t * ); void f128M_mulAdd( - const float128_t *, const float128_t *, const float128_t *, float128_t * + const float128_t *, const float128_t *, const float128_t *, float128_t * ); void f128M_div( const float128_t *, const float128_t *, float128_t * ); void f128M_rem( const float128_t *, const float128_t *, float128_t * ); diff --git a/3rdparty/softfloat3/source/include/softfloat_types.h b/3rdparty/softfloat3/source/include/softfloat_types.h index b92d24625eb..3657ac0483d 100644 --- a/3rdparty/softfloat3/source/include/softfloat_types.h +++ b/3rdparty/softfloat3/source/include/softfloat_types.h @@ -39,6 +39,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include +// MAME: when #included from actual MAME code, we need the endianness to match what the build system set +#ifdef LSB_FIRST +#ifndef LITTLEENDIAN +#define LITTLEENDIAN +#endif +#endif + /*---------------------------------------------------------------------------- | Types used to pass 16-bit, 32-bit, 64-bit, and 128-bit floating-point | arguments and results to/from functions. These types must be exactly diff --git a/scripts/src/3rdparty.lua b/scripts/src/3rdparty.lua index 7fd1213f9de..9a86eed9fc8 100755 --- a/scripts/src/3rdparty.lua +++ b/scripts/src/3rdparty.lua @@ -285,6 +285,7 @@ project "softfloat3" MAME_DIR .. "3rdparty/softfloat3/source", MAME_DIR .. "3rdparty/softfloat3/source/include", MAME_DIR .. "3rdparty/softfloat3/source/8086", + MAME_DIR .. "3rdparty/softfloat3/bochs_ext" } configuration { "gmake or ninja" } @@ -313,6 +314,11 @@ end "SOFTFLOAT_FAST_INT64" } +if _OPTIONS["BIGENDIAN"]~="1" then + defines { + "LITTLEENDIAN=1" + } +end files { MAME_DIR .. "3rdparty/softfloat3/source/s_eq128.c", MAME_DIR .. "3rdparty/softfloat3/source/s_le128.c", @@ -615,6 +621,13 @@ end MAME_DIR .. "3rdparty/softfloat3/source/f128M_eq_signaling.c", MAME_DIR .. "3rdparty/softfloat3/source/f128M_le_quiet.c", MAME_DIR .. "3rdparty/softfloat3/source/f128M_lt_quiet.c", + MAME_DIR .. "3rdparty/softfloat3/bochs_ext/f2xm1.c", + MAME_DIR .. "3rdparty/softfloat3/bochs_ext/fpatan.c", + MAME_DIR .. "3rdparty/softfloat3/bochs_ext/fprem.c", + MAME_DIR .. "3rdparty/softfloat3/bochs_ext/fsincos.c", + MAME_DIR .. "3rdparty/softfloat3/bochs_ext/fyl2x.c", + MAME_DIR .. "3rdparty/softfloat3/bochs_ext/poly.c", + MAME_DIR .. "3rdparty/softfloat3/bochs_ext/extF80_scale.c", } diff --git a/src/devices/cpu/m68000/m68kfpu.cpp b/src/devices/cpu/m68000/m68kfpu.cpp index e8acf965db6..b04496effcb 100644 --- a/src/devices/cpu/m68000/m68kfpu.cpp +++ b/src/devices/cpu/m68000/m68kfpu.cpp @@ -1,22 +1,51 @@ // license:BSD-3-Clause -// copyright-holders:Karl Stenerud +// copyright-holders:Karl Stenerud, R. Belmont + +/* + SoftFloat 3E version, May/June 2024 + - Exception flags now set for all opcodes + - FREM/FMOD now generate the quotient bits in FPSR, required for SANE to do trigonometry + - FMOVE of a float to an integer register generates the proper INEXACT exception, required + for SANE to calculate square roots. +*/ + +#include #include "emu.h" #include "m68kmusashi.h" +#define LOG_FPSR (1U << 1) +#define LOG_INSTRUCTIONS (1U << 2) +#define LOG_INSTRUCTIONS_VERBOSE (1U << 3) +#define LOG_LOADSTORE (1U << 4) + +#define VERBOSE (LOG_GENERAL | LOG_INSTRUCTIONS | LOG_INSTRUCTIONS_VERBOSE | LOG_LOADSTORE) + +#define LOG_OUTPUT_FUNC osd_printf_info +#include "logmacro.h" + static constexpr int FPCC_N = 0x08000000; static constexpr int FPCC_Z = 0x04000000; static constexpr int FPCC_I = 0x02000000; static constexpr int FPCC_NAN = 0x01000000; -static constexpr int FPES_OE = 0x00002000; -static constexpr int FPAE_IOP = 0x00000080; +static constexpr u32 FPES_INEXDEC = 0x00000100; +static constexpr u32 FPES_INEXACT = 0x00000200; +static constexpr u32 FPES_DIVZERO = 0x00000400; +static constexpr u32 FPES_OVERFLOW = 0x00000800; +static constexpr u32 FPES_UNDERFLOW = 0x00001000; +static constexpr u32 FPES_OPERR = 0x00002000; +static constexpr u32 FPES_SNAN = 0x00004000; + +static constexpr u32 FPAE_INEXACT = 0x00000008; +static constexpr u32 FPAE_DIVZERO = 0x00000010; +static constexpr u32 FPAE_OVERFLOW = 0x00000020; +static constexpr u32 FPAE_UNDERFLOW = 0x00000040; +static constexpr u32 FPAE_OPERR = 0x00000010; -#ifdef UNUSED_DEFINITION -static constexpr u64 DOUBLE_INFINITY = 0x7ff0000000000000U; -static constexpr u64 DOUBLE_EXPONENT = 0x7ff0000000000000U; -static constexpr u64 DOUBLE_MANTISSA = 0x000fffffffffffffU; -#endif +static constexpr u32 EXC_ENB_INEXACT = 0x00000001; +static constexpr u32 EXC_ENB_UNDFLOW = 0x00000002; +static constexpr u32 EXC_ENB_OVRFLOW = 0x00000004; // masks for packed dwords, positive k-factor const u32 m68000_musashi_device::pkmask2[18] = @@ -34,34 +63,34 @@ const u32 m68000_musashi_device::pkmask3[18] = 0xfffff000, 0xffffff00, 0xfffffff0, 0xffffffff, }; -inline floatx80 m68000_musashi_device::load_extended_float80(u32 ea) +inline extFloat80_t m68000_musashi_device::load_extended_float80(u32 ea) { u32 d1,d2; u16 d3; - floatx80 fp; + extFloat80_t fp; d3 = m68ki_read_16(ea); d1 = m68ki_read_32(ea+4); d2 = m68ki_read_32(ea+8); - fp.high = d3; - fp.low = ((u64)d1<<32) | (d2 & 0xffffffff); + fp.signExp = d3; + fp.signif = ((u64)d1<<32) | (d2 & 0xffffffff); return fp; } -inline void m68000_musashi_device::store_extended_float80(u32 ea, floatx80 fpr) +inline void m68000_musashi_device::store_extended_float80(u32 ea, extFloat80_t fpr) { - m68ki_write_16(ea+0, fpr.high); + m68ki_write_16(ea+0, fpr.signExp); m68ki_write_16(ea+2, 0); - m68ki_write_32(ea+4, (fpr.low>>32)&0xffffffff); - m68ki_write_32(ea+8, fpr.low&0xffffffff); + m68ki_write_32(ea+4, (fpr.signif>>32)&0xffffffff); + m68ki_write_32(ea+8, fpr.signif&0xffffffff); } -inline floatx80 m68000_musashi_device::load_pack_float80(u32 ea) +inline extFloat80_t m68000_musashi_device::load_pack_float80(u32 ea) { u32 dw1, dw2, dw3; - floatx80 result; + extFloat80_t result; double tmp; char str[128], *ch; @@ -109,7 +138,7 @@ inline floatx80 m68000_musashi_device::load_pack_float80(u32 ea) return result; } -inline void m68000_musashi_device::store_pack_float80(u32 ea, int k, floatx80 fpr) +inline void m68000_musashi_device::store_pack_float80(u32 ea, int k, extFloat80_t fpr) { u32 dw1, dw2, dw3; char str[128], *ch; @@ -118,7 +147,7 @@ inline void m68000_musashi_device::store_pack_float80(u32 ea, int k, floatx80 fp dw1 = dw2 = dw3 = 0; ch = &str[0]; - snprintf(str, 128, "%.16e", fx80_to_double(fpr)); + snprintf(str, sizeof(str), "%.16e", fx80_to_double(fpr)); if (*ch == '-') { @@ -241,87 +270,65 @@ inline void m68000_musashi_device::store_pack_float80(u32 ea, int k, floatx80 fp m68ki_write_32(ea+8, dw3); } -inline floatx80 propagateFloatx80NaNOneArg(floatx80 a) +void m68000_musashi_device::set_condition_codes(extFloat80_t reg) { - if (floatx80_is_signaling_nan(a)) - float_raise(float_flag_invalid); - - a.low |= 0xC000000000000000U; - - return a; -} - -static void normalizeFloatx80Subnormal(uint64_t aSig, int32_t *zExpPtr, uint64_t *zSigPtr) -{ - int shiftCount = countLeadingZeros64(aSig); - *zSigPtr = aSig << shiftCount; - *zExpPtr = 1 - shiftCount; -} + m_fpsr &= ~(FPCC_N|FPCC_Z|FPCC_I|FPCC_NAN); -inline floatx80 getman(floatx80 src) -{ - const flag sign = (src.high >> 15); - int32_t exp = (src.high & 0x7fff); - uint64_t signific = src.low; + // sign flag + if (reg.signExp & 0x8000) + { + m_fpsr |= FPCC_N; + } - if (exp == 0x7fff) + // zero flag + if (((reg.signExp & 0x7fff) == 0) && ((reg.signif<<1) == 0)) { - if ((uint64_t)(signific << 1)) - { - return propagateFloatx80NaNOneArg(src); - } - else - { - return packFloatx80(0, 0xffff, 0xffffffffffffffffU); - } + m_fpsr |= FPCC_Z; } - if (exp == 0) + // infinity flag + if (((reg.signExp & 0x7fff) == 0x7fff) && ((reg.signif<<1) == 0)) { - if (signific == 0) - { - return packFloatx80(sign, 0, 0); - } - normalizeFloatx80Subnormal(signific, &exp, &signific); + m_fpsr |= FPCC_I; } - return packFloatx80(sign, 0x3fff, signific); + // NaN flag + if (extF80_isSignalingNaN(reg)) + { + m_fpsr |= FPCC_NAN; + } } -inline void m68000_musashi_device::SET_CONDITION_CODES(floatx80 reg) +void m68000_musashi_device::clear_exception_flags() { -// u64 *regi; - -// regi = (u64 *)® - - m_fpsr &= ~(FPCC_N|FPCC_Z|FPCC_I|FPCC_NAN); + softfloat_exceptionFlags = 0; + m_fpsr &= ~(FPES_SNAN | FPES_OPERR | FPES_OVERFLOW | FPES_UNDERFLOW | FPES_DIVZERO | FPAE_DIVZERO | FPAE_INEXACT | FPAE_OPERR | FPAE_OVERFLOW | FPAE_UNDERFLOW | FPES_INEXDEC); +} - // sign flag - if (reg.high & 0x8000) +void m68000_musashi_device::sync_exception_flags(extFloat80_t op1, extFloat80_t op2, u32 enables) +{ + if (extF80_isSignalingNaN(op1) || extF80_isSignalingNaN(op2)) { - m_fpsr |= FPCC_N; + m_fpsr |= FPES_SNAN; } - // zero flag - if (((reg.high & 0x7fff) == 0) && ((reg.low<<1) == 0)) + if ((enables & EXC_ENB_INEXACT) && (softfloat_exceptionFlags & softfloat_flag_inexact)) { - m_fpsr |= FPCC_Z; + m_fpsr |= FPES_INEXACT | FPAE_INEXACT; } - // infinity flag - if (((reg.high & 0x7fff) == 0x7fff) && ((reg.low<<1) == 0)) + if ((enables & EXC_ENB_UNDFLOW) && (softfloat_exceptionFlags & softfloat_flag_underflow)) { - m_fpsr |= FPCC_I; + m_fpsr |= FPES_UNDERFLOW | FPAE_UNDERFLOW; } - // NaN flag - if (floatx80_is_nan(reg)) + if ((enables & EXC_ENB_OVRFLOW) && (softfloat_exceptionFlags & softfloat_flag_overflow)) { - m_fpsr |= FPCC_NAN; + m_fpsr |= FPES_OVERFLOW | FPAE_OVERFLOW; } } -inline int m68000_musashi_device::TEST_CONDITION(int condition) +int m68000_musashi_device::test_condition(int condition) { int n = (m_fpsr & FPCC_N) != 0; int z = (m_fpsr & FPCC_Z) != 0; @@ -383,6 +390,25 @@ inline int m68000_musashi_device::TEST_CONDITION(int condition) return r; } +s32 m68000_musashi_device::convert_to_int(extFloat80_t source, s32 lowerLimit, s32 upperLimit) +{ + clear_exception_flags(); + s32 result = extF80_to_i32(source, softfloat_roundingMode, true); + sync_exception_flags(source, source, EXC_ENB_INEXACT); + if (result < lowerLimit) + { + result = lowerLimit; + m_fpsr |= FPES_INEXACT | FPAE_INEXACT; + } + else if (result > upperLimit) + { + result = upperLimit; + m_fpsr |= FPES_INEXACT | FPAE_INEXACT; + } + + return result; +} + u8 m68000_musashi_device::READ_EA_8(int ea) { int mode = (ea >> 3) & 0x7; @@ -392,11 +418,7 @@ u8 m68000_musashi_device::READ_EA_8(int ea) { case 0: // Dn { - return REG_D()[reg]; - } - case 1: // An - { - return REG_A()[reg]; + return REG_D()[reg] & 0xff; } case 2: // (An) { @@ -472,11 +494,7 @@ u16 m68000_musashi_device::READ_EA_16(int ea) { case 0: // Dn { - return (u16)(REG_D()[reg]); - } - case 1: // An - { - return (u16)REG_A()[reg]; + return (u16)(REG_D()[reg] & 0xffff); } case 2: // (An) { @@ -555,10 +573,6 @@ u32 m68000_musashi_device::READ_EA_32(int ea) { return REG_D()[reg]; } - case 1: // An - { - return REG_A()[reg]; - } case 2: // (An) { u32 ea = REG_A()[reg]; @@ -709,9 +723,9 @@ u64 m68000_musashi_device::READ_EA_64(int ea) return 0; } -floatx80 m68000_musashi_device::READ_EA_FPE(int mode, int reg, uint32 di_mode_ea) +extFloat80_t m68000_musashi_device::READ_EA_FPE(int mode, int reg, uint32_t di_mode_ea) { - floatx80 fpr; + extFloat80_t fpr; switch (mode) { @@ -792,9 +806,9 @@ floatx80 m68000_musashi_device::READ_EA_FPE(int mode, int reg, uint32 di_mode_ea return fpr; } -floatx80 m68000_musashi_device::READ_EA_PACK(int ea) +extFloat80_t m68000_musashi_device::READ_EA_PACK(int ea) { - floatx80 fpr; + extFloat80_t fpr; int mode = (ea >> 3) & 0x7; int reg = (ea & 0x7); @@ -815,13 +829,6 @@ floatx80 m68000_musashi_device::READ_EA_PACK(int ea) break; } - case 5: // (d16,An) - { - u32 ea = REG_A()[reg] + MAKE_INT_16(m68ki_read_imm_16()); - fpr = load_pack_float80(ea); - break; - } - case 7: // extended modes { switch (reg) @@ -855,7 +862,8 @@ void m68000_musashi_device::WRITE_EA_8(int ea, u8 data) { case 0: // Dn { - REG_D()[reg] = data; + REG_D()[reg] &= 0xffffff00; + REG_D()[reg] |= data; break; } case 2: // (An) @@ -923,7 +931,8 @@ void m68000_musashi_device::WRITE_EA_16(int ea, u16 data) { case 0: // Dn { - REG_D()[reg] = data; + REG_D()[reg] &= 0xffff0000; + REG_D()[reg] |= data; break; } case 2: // (An) @@ -1134,7 +1143,7 @@ void m68000_musashi_device::WRITE_EA_64(int ea, u64 data) } } -void m68000_musashi_device::WRITE_EA_FPE(int mode, int reg, floatx80 fpr, uint32 di_mode_ea) +void m68000_musashi_device::WRITE_EA_FPE(int mode, int reg, extFloat80_t fpr, uint32_t di_mode_ea) { switch (mode) { @@ -1172,13 +1181,6 @@ void m68000_musashi_device::WRITE_EA_FPE(int mode, int reg, floatx80 fpr, uint32 break; } - case 6: // (An) + (Xn) + d8 - { - u32 ea = EA_AY_IX_32(); - store_extended_float80(ea, fpr); - break; - } - case 7: { switch (reg) @@ -1190,7 +1192,7 @@ void m68000_musashi_device::WRITE_EA_FPE(int mode, int reg, floatx80 fpr, uint32 } } -void m68000_musashi_device::WRITE_EA_PACK(int ea, int k, floatx80 fpr) +void m68000_musashi_device::WRITE_EA_PACK(int ea, int k, extFloat80_t fpr) { int mode = (ea >> 3) & 0x7; int reg = (ea & 0x7); @@ -1236,12 +1238,12 @@ void m68000_musashi_device::WRITE_EA_PACK(int ea, int k, floatx80 fpr) void m68000_musashi_device::fpgen_rm_reg(u16 w2) { - const int ea = m_ir & 0x3f; - const int rm = (w2 >> 14) & 0x1; - const int src = (w2 >> 10) & 0x7; - const int dst = (w2 >> 7) & 0x7; - const int opmode = w2 & 0x7f; - floatx80 source; + int ea = m_ir & 0x3f; + int rm = (w2 >> 14) & 0x1; + int src = (w2 >> 10) & 0x7; + int dst = (w2 >> 7) & 0x7; + int opmode = w2 & 0x7f; + extFloat80_t source; // fmovecr #$f, fp0 f200 5c0f @@ -1252,20 +1254,21 @@ void m68000_musashi_device::fpgen_rm_reg(u16 w2) case 0: // Long-Word Integer { s32 d = READ_EA_32(ea); - source = int32_to_floatx80(d); + source = i32_to_extF80(d); break; } case 1: // Single-precision Real { u32 d = READ_EA_32(ea); - source = float32_to_floatx80(d); + float32_t *pF = (float32_t *)&d; + source = f32_to_extF80(*pF); break; } case 2: // Extended-precision Real { int imode = (ea >> 3) & 0x7; int reg = (ea & 0x7); - uint32 di_mode_ea = imode == 5 ? (REG_A()[reg] + MAKE_INT_16(m68ki_read_imm_16())) : 0; + uint32_t di_mode_ea = imode == 5 ? (REG_A()[reg] + MAKE_INT_16(m68ki_read_imm_16())) : 0; source = READ_EA_FPE(imode, reg, di_mode_ea); break; } @@ -1277,20 +1280,20 @@ void m68000_musashi_device::fpgen_rm_reg(u16 w2) case 4: // Word Integer { s16 d = READ_EA_16(ea); - source = int32_to_floatx80((s32)d); + source = i32_to_extF80((s32)d); break; } case 5: // Double-precision Real { u64 d = READ_EA_64(ea); - - source = float64_to_floatx80(d); + float64_t *pF = (float64_t *)&d; + source = f64_to_extF80(*pF); break; } case 6: // Byte Integer { s8 d = READ_EA_8(ea); - source = int32_to_floatx80((s32)d); + source = i32_to_extF80((s32)d); break; } case 7: // FMOVECR load from constant ROM @@ -1298,107 +1301,107 @@ void m68000_musashi_device::fpgen_rm_reg(u16 w2) switch (w2 & 0x7f) { case 0x0: // Pi - source.high = 0x4000; - source.low = 0xc90fdaa22168c235U; + source.signExp = 0x4000; + source.signif = 0xc90fdaa22168c235U; break; case 0xb: // log10(2) - source.high = 0x3ffd; - source.low = 0x9a209a84fbcff798U; + source.signExp = 0x3ffd; + source.signif = 0x9a209a84fbcff798U; break; case 0xc: // e - source.high = 0x4000; - source.low = 0xadf85458a2bb4a9bU; + source.signExp = 0x4000; + source.signif = 0xadf85458a2bb4a9bU; break; case 0xd: // log2(e) - source.high = 0x3fff; - source.low = 0xb8aa3b295c17f0bcU; + source.signExp = 0x3fff; + source.signif = 0xb8aa3b295c17f0bcU; break; case 0xe: // log10(e) - source.high = 0x3ffd; - source.low = 0xde5bd8a937287195U; + source.signExp = 0x3ffd; + source.signif = 0xde5bd8a937287195U; break; case 0xf: // 0.0 - source = int32_to_floatx80((s32)0); + source = i32_to_extF80((s32)0); break; case 0x30: // ln(2) - source.high = 0x3ffe; - source.low = 0xb17217f7d1cf79acU; + source.signExp = 0x3ffe; + source.signif = 0xb17217f7d1cf79acU; break; case 0x31: // ln(10) - source.high = 0x4000; - source.low = 0x935d8dddaaa8ac17U; + source.signExp = 0x4000; + source.signif = 0x935d8dddaaa8ac17U; break; case 0x32: // 1 (or 100? manuals are unclear, but 1 would make more sense) - source = int32_to_floatx80((s32)1); + source = i32_to_extF80((s32)1); break; case 0x33: // 10^1 - source = int32_to_floatx80((s32)10); + source = i32_to_extF80((s32)10); break; case 0x34: // 10^2 - source = int32_to_floatx80((s32)10*10); + source = i32_to_extF80((s32)10 * 10); break; case 0x35: // 10^4 - source = int32_to_floatx80((s32)1000*10); + source = i32_to_extF80((s32)1000 * 10); break; case 0x36: // 1.0e8 - source = int32_to_floatx80((s32)10000000*10); + source = i32_to_extF80((s32)10000000 * 10); break; case 0x37: // 1.0e16 - can't get the right precision from s32 so go "direct" with constants from h/w - source.high = 0x4034; - source.low = 0x8e1bc9bf04000000U; + source.signExp = 0x4034; + source.signif = 0x8e1bc9bf04000000U; break; case 0x38: // 1.0e32 - source.high = 0x4069; - source.low = 0x9dc5ada82b70b59eU; + source.signExp = 0x4069; + source.signif = 0x9dc5ada82b70b59eU; break; case 0x39: // 1.0e64 - source.high = 0x40d3; - source.low = 0xc2781f49ffcfa6d5U; + source.signExp = 0x40d3; + source.signif = 0xc2781f49ffcfa6d5U; break; case 0x3a: // 1.0e128 - source.high = 0x41a8; - source.low = 0x93ba47c980e98ce0U; + source.signExp = 0x41a8; + source.signif = 0x93ba47c980e98ce0U; break; case 0x3b: // 1.0e256 - source.high = 0x4351; - source.low = 0xaa7eebfb9df9de8eU; + source.signExp = 0x4351; + source.signif = 0xaa7eebfb9df9de8eU; break; case 0x3c: // 1.0e512 - source.high = 0x46a3; - source.low = 0xe319a0aea60e91c7U; + source.signExp = 0x46a3; + source.signif = 0xe319a0aea60e91c7U; break; case 0x3d: // 1.0e1024 - source.high = 0x4d48; - source.low = 0xc976758681750c17U; + source.signExp = 0x4d48; + source.signif = 0xc976758681750c17U; break; case 0x3e: // 1.0e2048 - source.high = 0x5a92; - source.low = 0x9e8b3b5dc53d5de5U; + source.signExp = 0x5a92; + source.signif = 0x9e8b3b5dc53d5de5U; break; case 0x3f: // 1.0e4096 - source.high = 0x7525; - source.low = 0xc46052028a20979bU; + source.signExp = 0x7525; + source.signif = 0xc46052028a20979bU; break; default: @@ -1408,251 +1411,331 @@ void m68000_musashi_device::fpgen_rm_reg(u16 w2) // handle it right here, the usual opmode bits aren't valid in the FMOVECR case m_fpr[dst] = source; - SET_CONDITION_CODES(m_fpr[dst]); + set_condition_codes(m_fpr[dst]); m_icount -= 4; return; } default: fatalerror("fmove_rm_reg: invalid source specifier %x at %08X\n", src, m_pc-4); } + + LOGMASKED(LOG_LOADSTORE, "Load source type %d = %f\n", src, fx80_to_double(source)); } else { source = m_fpr[src]; + LOGMASKED(LOG_LOADSTORE, "Load source from FPR %d = %f\n", src, fx80_to_double(source)); } - + LOGMASKED(LOG_INSTRUCTIONS, "FPU: opmode %02x (PC=%08x)\n", opmode, m_pc); + const extFloat80_t dstCopy = m_fpr[dst]; + if (opmode != 0) + { + clear_exception_flags(); + } switch (opmode) { case 0x00: // FMOVE { m_fpr[dst] = source; - SET_CONDITION_CODES(m_fpr[dst]); - m_icount -= 4; + set_condition_codes(m_fpr[dst]); + m_icount -= 56; break; } case 0x01: // FINT { - s32 temp; - temp = floatx80_to_int32(source); - m_fpr[dst] = int32_to_floatx80(temp); - SET_CONDITION_CODES(m_fpr[dst]); + s32 temp = convert_to_int(source, INT32_MIN, INT32_MAX); + m_fpr[dst] = i32_to_extF80(temp); + set_condition_codes(m_fpr[dst]); + sync_exception_flags(source, source, EXC_ENB_INEXACT); + m_icount -= 78; break; } case 0x03: // FINTRZ { - s32 temp; - temp = floatx80_to_int32_round_to_zero(source); - m_fpr[dst] = int32_to_floatx80(temp); - SET_CONDITION_CODES(m_fpr[dst]); + s32 temp = extF80_to_i32_r_minMag(source, true); + m_fpr[dst] = i32_to_extF80(temp); + set_condition_codes(m_fpr[dst]); + sync_exception_flags(source, source, 0); + m_icount -= 78; break; } case 0x04: // FSQRT { - m_fpr[dst] = floatx80_sqrt(source); - SET_CONDITION_CODES(m_fpr[dst]); + m_fpr[dst] = extF80_sqrt(source); + set_condition_codes(m_fpr[dst]); + sync_exception_flags(source, source, EXC_ENB_INEXACT); m_icount -= 109; break; } case 0x06: // FLOGNP1 { - m_fpr[dst] = floatx80_flognp1(source); - SET_CONDITION_CODES(m_fpr[dst]); - m_icount -= 594; // for MC68881 + m_fpr[dst] = extFloat80_lognp1(source); + set_condition_codes(m_fpr[dst]); + sync_exception_flags(source, source, EXC_ENB_INEXACT | EXC_ENB_UNDFLOW); + m_icount -= 594; break; } - case 0x0a: // FATAN + case 0x0a: // FATAN { - m_fpr[dst] = floatx80_fatan (source); - SET_CONDITION_CODES(m_fpr[dst]); - m_icount -= 426; // for MC68881 + m_fpr[dst] = source; + m_fpr[dst] = extFloat80_68katan(m_fpr[dst]); + set_condition_codes(m_fpr[dst]); + sync_exception_flags(source, source, EXC_ENB_INEXACT | EXC_ENB_UNDFLOW); + m_icount -= 426; break; } case 0x0e: // FSIN { m_fpr[dst] = source; - floatx80_fsin(m_fpr[dst]); - SET_CONDITION_CODES(m_fpr[dst]); - m_icount -= 75; + extFloat80_sin(m_fpr[dst]); + set_condition_codes(m_fpr[dst]); + sync_exception_flags(source, source, EXC_ENB_INEXACT | EXC_ENB_UNDFLOW); + m_icount -= 414; break; } case 0x0f: // FTAN { m_fpr[dst] = source; - floatx80_ftan(m_fpr[dst]); - SET_CONDITION_CODES(m_fpr[dst]); - m_icount -= 75; + extFloat80_tan(m_fpr[dst]); + set_condition_codes(m_fpr[dst]); + sync_exception_flags(source, source, EXC_ENB_INEXACT | EXC_ENB_OVRFLOW | EXC_ENB_UNDFLOW); + m_icount -= 496; break; } case 0x14: // FLOGN { - m_fpr[dst] = floatx80_flogn (source); - SET_CONDITION_CODES(m_fpr[dst]); - m_icount -= 548; // for MC68881 + m_fpr[dst] = extFloat80_logn(source); + set_condition_codes(m_fpr[dst]); + sync_exception_flags(source, source, EXC_ENB_INEXACT); + m_icount -= 548; break; } case 0x15: // FLOG10 { - m_fpr[dst] = floatx80_flog10 (source); - SET_CONDITION_CODES(m_fpr[dst]); - m_icount -= 604; // for MC68881 + m_fpr[dst] = extFloat80_log10 (source); + set_condition_codes(m_fpr[dst]); + sync_exception_flags(source, source, EXC_ENB_INEXACT); + m_icount -= 604; break; } case 0x16: // FLOG2 { - m_fpr[dst] = floatx80_flog2 (source); - SET_CONDITION_CODES(m_fpr[dst]); - m_icount -= 604; // for MC68881 + m_fpr[dst] = extFloat80_log2 (source); + set_condition_codes(m_fpr[dst]); + sync_exception_flags(source, source, EXC_ENB_INEXACT); + m_icount -= 604; break; } case 0x18: // FABS { m_fpr[dst] = source; - m_fpr[dst].high &= 0x7fff; - SET_CONDITION_CODES(m_fpr[dst]); - m_icount -= 3; + m_fpr[dst].signExp &= 0x7fff; + set_condition_codes(m_fpr[dst]); + m_icount -= 58; break; } case 0x1a: // FNEG { m_fpr[dst] = source; - m_fpr[dst].high ^= 0x8000; - SET_CONDITION_CODES(m_fpr[dst]); - m_icount -= 3; + m_fpr[dst].signExp ^= 0x8000; + set_condition_codes(m_fpr[dst]); + m_icount -= 58; break; } case 0x1d: // FCOS { m_fpr[dst] = source; - floatx80_fcos(m_fpr[dst]); - SET_CONDITION_CODES(m_fpr[dst]); - m_icount -= 75; + extFloat80_cos(m_fpr[dst]); + set_condition_codes(m_fpr[dst]); + sync_exception_flags(source, source, EXC_ENB_INEXACT); + m_icount -= 414; break; } case 0x1e: // FGETEXP { s16 temp2; - temp2 = source.high; // get the exponent + temp2 = source.signExp; // get the exponent temp2 -= 0x3fff; // take off the bias m_fpr[dst] = double_to_fx80((double)temp2); - SET_CONDITION_CODES(m_fpr[dst]); - m_icount -= 6; + LOGMASKED(LOG_INSTRUCTIONS_VERBOSE, "FGETEXP: %f\n", fx80_to_double(m_fpr[dst])); + set_condition_codes(m_fpr[dst]); + sync_exception_flags(source, source, 0); // only NaNs can raise an exception here + m_icount -= 68; break; } case 0x1f: // FGETMAN { - m_fpr[dst] = getman(source); - SET_CONDITION_CODES(m_fpr[dst]); - m_icount -= 31; + m_fpr[dst] = extFloat80_getman(source); + LOGMASKED(LOG_INSTRUCTIONS_VERBOSE, "FGETMAN: %f\n", fx80_to_double(m_fpr[dst])); + set_condition_codes(m_fpr[dst]); + sync_exception_flags(source, source, 0); // only NaNs can raise an exception here + m_icount -= 54; break; } case 0x60: // FSDIVS + { + float32_t sngSrc, sngDst; + sngSrc = extF80_to_f32(source); + sngDst = extF80_to_f32(m_fpr[dst]); + if (f32_eq(sngSrc, i32_to_f32(0))) + { + m_fpsr |= FPES_DIVZERO | FPAE_DIVZERO; + } + sngDst = f32_div(sngDst, sngSrc); + m_fpr[dst] = f32_to_extF80(sngDst); + set_condition_codes(m_fpr[dst]); + sync_exception_flags(source, dstCopy, EXC_ENB_OVRFLOW | EXC_ENB_UNDFLOW); + m_icount -= 124; + break; + } + case 0x64: // FDDIV + { + float64_t sngSrc, sngDst; + sngSrc = extF80_to_f64(source); + sngDst = extF80_to_f64(m_fpr[dst]); + if (f64_eq(sngSrc, i32_to_f64(0))) + { + m_fpsr |= FPES_DIVZERO | FPAE_DIVZERO; + } + sngDst = f64_div(sngDst, sngSrc); + m_fpr[dst] = f64_to_extF80(sngDst); + set_condition_codes(m_fpr[dst]); + sync_exception_flags(source, dstCopy, EXC_ENB_OVRFLOW | EXC_ENB_UNDFLOW); + m_icount -= 130; + break; + } case 0x20: // FDIV { - m_fpr[dst] = floatx80_div(m_fpr[dst], source); - SET_CONDITION_CODES(m_fpr[dst]); - m_icount -= 43; + if (extF80_eq(source, i32_to_extF80(0))) + { + m_fpsr |= FPES_DIVZERO | FPAE_DIVZERO; + } + m_fpr[dst] = extF80_div(m_fpr[dst], source); + set_condition_codes(m_fpr[dst]); + sync_exception_flags(source, dstCopy, EXC_ENB_OVRFLOW|EXC_ENB_UNDFLOW); + m_icount -= 128; break; } case 0x21: // FMOD { - s8 const mode = float_rounding_mode; - float_rounding_mode = float_round_to_zero; - m_fpr[dst] = floatx80_rem(m_fpr[dst], source); - SET_CONDITION_CODES(m_fpr[dst]); - float_rounding_mode = mode; - m_icount -= 43; // guess + s8 const mode = softfloat_roundingMode; + uint64_t quotient; + softfloat_roundingMode = softfloat_round_minMag; + extFloat80_remainder(m_fpr[dst], source, m_fpr[dst], quotient); + set_condition_codes(m_fpr[dst]); + softfloat_roundingMode = mode; + m_fpsr &= 0xff00ffff; + m_fpsr |= (quotient & 0x7f) << 16; + if (m_fpr[dst].signExp & 0x8000) + { + m_fpsr |= 0x00800000; + } + m_icount -= 95; break; } case 0x22: // FADD { - m_fpr[dst] = floatx80_add(m_fpr[dst], source); - SET_CONDITION_CODES(m_fpr[dst]); - m_icount -= 9; + m_fpr[dst] = extF80_add(m_fpr[dst], source); + set_condition_codes(m_fpr[dst]); + sync_exception_flags(source, dstCopy, EXC_ENB_OVRFLOW|EXC_ENB_UNDFLOW); + LOGMASKED(LOG_INSTRUCTIONS_VERBOSE, "FADD: %f + %f = %f\n", fx80_to_double(dstCopy), fx80_to_double(source), fx80_to_double(m_fpr[dst])); + m_icount -= 76; break; } case 0x63: // FSMULS (JFF) case 0x23: // FMUL { - m_fpr[dst] = floatx80_mul(m_fpr[dst], source); - SET_CONDITION_CODES(m_fpr[dst]); - m_icount -= 11; + m_fpr[dst] = extF80_mul(m_fpr[dst], source); + set_condition_codes(m_fpr[dst]); + sync_exception_flags(source, dstCopy, EXC_ENB_UNDFLOW); + LOGMASKED(LOG_INSTRUCTIONS_VERBOSE, "FMUL: %f * %f = %f\n", fx80_to_double(dstCopy), fx80_to_double(source), fx80_to_double(m_fpr[dst])); + m_icount -= 96; break; } case 0x24: // FSGLDIV { - float32 a = floatx80_to_float32( m_fpr[dst] ); - float32 b = floatx80_to_float32( source ); - m_fpr[dst] = float32_to_floatx80( float32_div(a, b) ); - m_icount -= 43; // // ? (value is from FDIV) + float32_t a = extF80_to_f32( m_fpr[dst] ); + float32_t b = extF80_to_f32( source ); + m_fpr[dst] = f32_to_extF80( f32_div(a, b) ); + set_condition_codes(m_fpr[dst]); + sync_exception_flags(source, dstCopy, EXC_ENB_INEXACT | EXC_ENB_OVRFLOW | EXC_ENB_UNDFLOW); + m_icount -= 94; break; } case 0x25: // FREM { - s8 const mode = float_rounding_mode; - float_rounding_mode = float_round_nearest_even; - m_fpr[dst] = floatx80_rem(m_fpr[dst], source); - SET_CONDITION_CODES(m_fpr[dst]); - float_rounding_mode = mode; - m_icount -= 43; // guess + s8 const mode = softfloat_roundingMode; + uint64_t quotient; + softfloat_roundingMode = softfloat_round_near_even; + extFloat80_ieee754_remainder(m_fpr[dst], source, m_fpr[dst], quotient); + set_condition_codes(m_fpr[dst]); + sync_exception_flags(dstCopy, source, EXC_ENB_UNDFLOW); + softfloat_roundingMode = mode; + m_fpsr &= 0xff00ffff; + m_fpsr |= (quotient & 0x7f) << 16; + if (m_fpr[dst].signExp & 0x8000) + { + m_fpsr |= 0x00800000; + } + m_icount -= 125; break; } case 0x26: // FSCALE { - m_fpr[dst] = floatx80_scale(m_fpr[dst], source); - SET_CONDITION_CODES(m_fpr[dst]); - m_icount -= 46; // (better?) guess + m_fpr[dst] = extFloat80_scale(m_fpr[dst], source); + set_condition_codes(m_fpr[dst]); + sync_exception_flags(source, dstCopy, EXC_ENB_OVRFLOW | EXC_ENB_UNDFLOW); + m_icount -= 66; break; } case 0x27: // FSGLMUL { - float32 a = floatx80_to_float32( m_fpr[dst] ); - float32 b = floatx80_to_float32( source ); - m_fpr[dst] = float32_to_floatx80( float32_mul(a, b) ); - SET_CONDITION_CODES(m_fpr[dst]); - m_icount -= 11; // ? (value is from FMUL) + float32_t a = extF80_to_f32( m_fpr[dst] ); + float32_t b = extF80_to_f32( source ); + m_fpr[dst] = f32_to_extF80( f32_mul(a, b) ); + set_condition_codes(m_fpr[dst]); + sync_exception_flags(source, dstCopy, EXC_ENB_INEXACT | EXC_ENB_OVRFLOW | EXC_ENB_UNDFLOW); + m_icount -= 94; break; } - case 0x28: // FSUB + case 0x28: case 0x29: case 0x2a: case 0x2b: + case 0x2c: case 0x2d: case 0x2e: case 0x2f: // FSUB { - m_fpr[dst] = floatx80_sub(m_fpr[dst], source); - SET_CONDITION_CODES(m_fpr[dst]); - m_icount -= 9; + m_fpr[dst] = extF80_sub(m_fpr[dst], source); + set_condition_codes(m_fpr[dst]); + sync_exception_flags(source, dstCopy, EXC_ENB_INEXACT | EXC_ENB_OVRFLOW | EXC_ENB_UNDFLOW); + LOGMASKED(LOG_INSTRUCTIONS_VERBOSE, "FSUB: %f - %f = %f\n", fx80_to_double(dstCopy), fx80_to_double(source), fx80_to_double(m_fpr[dst])); + m_icount -= 76; break; } - case 0x30: // FSINCOS - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - case 0x36: - case 0x37: - { - m_fpr[dst] = source; - floatx80_fsin(m_fpr[dst]); - SET_CONDITION_CODES(m_fpr[dst]); // condition codes are set for the sine result - m_fpr[(w2 & 0x7)] = source; - floatx80_fcos(m_fpr[(w2 & 0x7)]); - m_icount -= 451; + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: + case 0x36: case 0x37: // FSINCOS + { + extFloat80_sincos(source, &m_fpr[dst], &m_fpr[w2 & 7]); + set_condition_codes(m_fpr[dst]); // CCs are set on the sin result + sync_exception_flags(source, dstCopy, EXC_ENB_INEXACT | EXC_ENB_UNDFLOW); + m_icount -= 474; break; } - case 0x38: // FCMP + + case 0x38: case 0x39: case 0x3c: case 0x3d: // FCMP { - floatx80 res; - res = floatx80_sub(m_fpr[dst], source); - SET_CONDITION_CODES(res); - m_icount -= 7; + const extFloat80_t res = extF80_sub(m_fpr[dst], source); + set_condition_codes(res); + sync_exception_flags(source, dstCopy, 0); + + LOGMASKED(LOG_INSTRUCTIONS_VERBOSE, "FCMP: %f - %f = %f\n", fx80_to_double(dstCopy), fx80_to_double(source), fx80_to_double(res)); + m_icount -= 58; break; } - case 0x3a: // FTST + case 0x3a: case 0x3b: case 0x3e: case 0x3f: // FTST { - floatx80 res; - res = source; - SET_CONDITION_CODES(res); - m_icount -= 7; + set_condition_codes(source); + sync_exception_flags(source, dstCopy, 0); + m_icount -= 56; break; } @@ -1671,13 +1754,15 @@ void m68000_musashi_device::fmove_reg_mem(u16 w2) { case 0: // Long-Word Integer { - s32 d = (s32)floatx80_to_int32(m_fpr[src]); + s32 d = convert_to_int(m_fpr[src], INT32_MIN, INT32_MAX); WRITE_EA_32(ea, d); break; } case 1: // Single-precision Real { - u32 d = floatx80_to_float32(m_fpr[src]); + u32 d; + float32_t *pF = (float32_t *)&d; + *pF = extF80_to_f32(m_fpr[src]); WRITE_EA_32(ea, d); break; } @@ -1685,7 +1770,7 @@ void m68000_musashi_device::fmove_reg_mem(u16 w2) { int mode = (ea >> 3) & 0x7; int reg = (ea & 0x7); - uint32 di_mode_ea = mode == 5 ? (REG_A()[reg] + MAKE_INT_16(m68ki_read_imm_16())) : 0; + uint32_t di_mode_ea = mode == 5 ? (REG_A()[reg] + MAKE_INT_16(m68ki_read_imm_16())) : 0; WRITE_EA_FPE(mode, reg, m_fpr[src], di_mode_ea); break; @@ -1699,31 +1784,25 @@ void m68000_musashi_device::fmove_reg_mem(u16 w2) } case 4: // Word Integer { - s32 value = floatx80_to_int32(m_fpr[src]); - if (value > 0x7fff || value < -0x8000 ) - { - m_fpsr |= FPES_OE | FPAE_IOP; - } - WRITE_EA_16(ea, (s16)value); + LOGMASKED(LOG_INSTRUCTIONS_VERBOSE, "FMOVE: %f to reg %d\n", fx80_to_double(m_fpr[src]), dst); + s16 value = (s16)convert_to_int(m_fpr[src], INT16_MIN, INT16_MAX); + WRITE_EA_16(ea, value); break; } case 5: // Double-precision Real { u64 d; - - d = floatx80_to_float64(m_fpr[src]); - + float64_t *pF = (float64_t *)&d; + clear_exception_flags(); + *pF = extF80_to_f64(m_fpr[src]); + sync_exception_flags(m_fpr[src], m_fpr[src], 0); WRITE_EA_64(ea, d); break; } case 6: // Byte Integer { - s32 value = floatx80_to_int32(m_fpr[src]); - if (value > 127 || value < -128) - { - m_fpsr |= FPES_OE | FPAE_IOP; - } - WRITE_EA_8(ea, (s8) value); + s8 value = (s8)convert_to_int(m_fpr[src], INT8_MIN, INT8_MAX); + WRITE_EA_8(ea, value); break; } case 7: // Packed-decimal Real with Dynamic K-factor @@ -1741,36 +1820,87 @@ void m68000_musashi_device::fmove_fpcr(u16 w2) int ea = m_ir & 0x3f; int dir = (w2 >> 13) & 0x1; int regsel = (w2 >> 10) & 0x7; + int reg = ea & 7; int mode = (ea >> 3) & 0x7; - if ((mode == 5) || (mode == 6)) - { - u32 address = 0xffffffff; // force a bus error if this doesn't get assigned + LOGMASKED(LOG_FPSR, "FMOVE FP*R: EA %x dir %x reg %d mode %d regsel %x\n", ea, dir, reg, mode, regsel); - if (mode == 5) + u32 address = 0; + switch (mode) + { + case 0: // Dn + #if 0 + if (dir) { - address = EA_AY_DI_32(); + if (regsel & 4) WRITE_EA_32(ea, m_fpcr); + if (regsel & 2) WRITE_EA_32(ea, m_fpsr); + if (regsel & 1) WRITE_EA_32(ea, m_fpiar); } - else if (mode == 6) + else { - address = EA_AY_IX_32(); + if (regsel & 4) m_fpcr = READ_EA_32(ea); + if (regsel & 2) m_fpsr = READ_EA_32(ea); + if (regsel & 1) m_fpiar = READ_EA_32(ea); } + #endif + break; - if (dir) // From system control reg to - { - if (regsel & 4) { m68ki_write_32(address, m_fpcr); address += 4; } - if (regsel & 2) { m68ki_write_32(address, m_fpsr); address += 4; } - if (regsel & 1) { m68ki_write_32(address, m_fpiar); address += 4; } - } - else // From to system control reg + case 2: // (An) + address = REG_A()[reg]; + break; + + case 3: // (An)+ + case 4: // -(An) + break; + + case 5: // (d16, An) + address = EA_AY_DI_32(); + break; + + case 6: // (An) + (Xn) + d8 + address = EA_AY_IX_32(); + break; + + case 7: + { + switch (reg) { - if (regsel & 4) { m_fpcr = m68ki_read_32(address); address += 4; } - if (regsel & 2) { m_fpsr = m68ki_read_32(address); address += 4; } - if (regsel & 1) { m_fpiar = m68ki_read_32(address); address += 4; } + case 0: // (xxx).W + address = OPER_I_16(); + break; + + case 1: // (xxx).L + { + u32 d1 = OPER_I_16(); + u32 d2 = OPER_I_16(); + address = (d1 << 16) | d2; + } + break; + case 2: // (d16, PC) + address = EA_PCDI_32(); + break; + + case 3: // (PC) + (Xn) + d8 + address = EA_PCIX_32(); + break; + + default: + fatalerror("M68kFPU: fmove_fpcr: unhandled mode %d, reg %d at %08X\n", mode, reg, m_pc); + break; } } - else + break; + + default: + fatalerror("M68kFPU: fmove_fpcr: unhandled mode %d, reg %d at %08X\n", mode, reg, m_pc); + break; + } + + switch (mode) { + case 0: // Dn + case 3: // (An)+ + case 4: // -(An) if (dir) // From system control reg to { if (regsel & 4) WRITE_EA_32(ea, m_fpcr); @@ -1778,15 +1908,51 @@ void m68000_musashi_device::fmove_fpcr(u16 w2) if (regsel & 1) WRITE_EA_32(ea, m_fpiar); } else // From to system control reg + { + if (regsel & 4) m_fpcr = READ_EA_32(ea); + if (regsel & 2) m_fpsr = READ_EA_32(ea); + if (regsel & 1) m_fpiar = READ_EA_32(ea); + } + break; + + default: + if (dir) // From system control reg to { if (regsel & 4) { - m_fpcr = READ_EA_32(ea); - // should update softfloat rounding mode here + m68ki_write_32(address, m_fpcr); + address += 4; + } + if (regsel & 2) + { + m68ki_write_32(address, m_fpsr); + address += 4; + } + if (regsel & 1) + { + m68ki_write_32(address, m_fpiar); + address += 4; } - if (regsel & 2) m_fpsr = READ_EA_32(ea); - if (regsel & 1) m_fpiar = READ_EA_32(ea); } + else // From to system control reg + { + if (regsel & 4) + { + m_fpcr = m68ki_read_32(address); + address += 4; + } + if (regsel & 2) + { + m_fpsr = m68ki_read_32(address); + address += 4; + } + if (regsel & 1) + { + m_fpiar = m68ki_read_32(address); + address += 4; + } + } + break; } // FIXME: (2011-12-18 ost) @@ -1800,44 +1966,42 @@ void m68000_musashi_device::fmove_fpcr(u16 w2) int rnd = (m_fpcr >> 4) & 3; int prec = (m_fpcr >> 6) & 3; -// logerror("m68k_fpsp:fmove_fpcr fpcr=%04x prec=%d rnd=%d\n", m_fpcr, prec, rnd); + // logerror("fmove_fpcr: fpcr=%04x prec=%d rnd=%d\n", m_fpcr, prec, rnd); -#ifdef FLOATX80 switch (prec) { case 0: // Extend (X) - floatx80_rounding_precision = 80; + extF80_roundingPrecision = 80; break; case 1: // Single (S) - floatx80_rounding_precision = 32; + extF80_roundingPrecision = 32; break; case 2: // Double (D) - floatx80_rounding_precision = 64; + extF80_roundingPrecision = 64; break; case 3: // Undefined - floatx80_rounding_precision = 80; + extF80_roundingPrecision = 80; break; } -#endif switch (rnd) { case 0: // To Nearest (RN) - float_rounding_mode = float_round_nearest_even; + softfloat_roundingMode = softfloat_round_near_even; break; case 1: // To Zero (RZ) - float_rounding_mode = float_round_to_zero; + softfloat_roundingMode = softfloat_round_minMag; break; case 2: // To Minus Infinitiy (RM) - float_rounding_mode = float_round_down; + softfloat_roundingMode = softfloat_round_min; break; case 3: // To Plus Infinitiy (RP) - float_rounding_mode = float_round_up; + softfloat_roundingMode = softfloat_round_max; break; } } - m_icount -= 10; + m_icount -= 30; } void m68000_musashi_device::fmovem(u16 w2) @@ -1848,6 +2012,17 @@ void m68000_musashi_device::fmovem(u16 w2) int mode = (w2 >> 11) & 0x3; int reglist = w2 & 0xff; + u32 mem_addr = 0; + switch (ea >> 3) + { + case 5: // (d16, An) + mem_addr= EA_AY_DI_32(); + break; + case 6: // (An) + (Xn) + d8 + mem_addr= EA_AY_IX_32(); + break; + } + if (dir) // From FP regs to mem { switch (mode) @@ -1865,29 +2040,21 @@ void m68000_musashi_device::fmovem(u16 w2) int imode = (ea >> 3) & 0x7; int reg = (ea & 0x7); int di_mode = imode == 5; - uint32 di_mode_ea = di_mode ? (REG_A()[reg] + MAKE_INT_16(m68ki_read_imm_16())) : 0; + uint32_t di_mode_ea = di_mode ? (REG_A()[reg] + MAKE_INT_16(m68ki_read_imm_16())) : 0; - if (reglist) + for (i=0; i < 8; i++) { - for (i=0; i < 8; i++) + if (reglist & (1 << i)) { - if (reglist & (1 << i)) + WRITE_EA_FPE(imode, reg, m_fpr[i], di_mode_ea); + if (di_mode) { - WRITE_EA_FPE(imode, reg, m_fpr[i], di_mode_ea); - if (di_mode) - { - di_mode_ea += 12; - } - - m_icount -= 2; + di_mode_ea += 12; } + + m_icount -= 2; } } - else if (imode == 6) - // advance PC if the register list is empty - EA_AY_IX_32(); - else if (imode == 7) - fatalerror("m68881: fmovem addressing mode %d unimplemented at 0x%08x\n", imode, m_pc - 4); break; } @@ -1899,30 +2066,23 @@ void m68000_musashi_device::fmovem(u16 w2) { int imode = (ea >> 3) & 0x7; int reg = (ea & 0x7); - int di_mode = (imode == 5); - uint32 di_mode_ea = di_mode ? (REG_A()[reg] + MAKE_INT_16(m68ki_read_imm_16())) : 0; + int di_mode = imode == 5; - if (reglist) + uint32_t di_mode_ea = di_mode ? (REG_A()[reg] + MAKE_INT_16(m68ki_read_imm_16())) : 0; + + for (i=0; i < 8; i++) { - for (i=0; i < 8; i++) + if (reglist & (1 << i)) { - if (reglist & (1 << i)) + WRITE_EA_FPE(imode, reg, m_fpr[7 - i], di_mode_ea); + if (di_mode) { - WRITE_EA_FPE(imode, reg, m_fpr[7 - i], di_mode_ea); - if (di_mode) - { - di_mode_ea += 12; - } - - m_icount -= 2; + di_mode_ea += 12; } + + m_icount -= 2; } } - else if (imode == 6) - // advance PC if the register list is empty - EA_AY_IX_32(); - else if (imode == 7) - fatalerror("m68881: fmovem addressing mode %d unimplemented at 0x%08x\n", imode, m_pc - 4); break; } @@ -1941,17 +2101,23 @@ void m68000_musashi_device::fmovem(u16 w2) { int imode = (ea >> 3) & 0x7; int reg = (ea & 0x7); - int di_mode = (imode == 5); - uint32 di_mode_ea = di_mode ? (REG_A()[reg] + MAKE_INT_16(m68ki_read_imm_16())) : 0; + int di_mode = imode == 5; + uint32_t di_mode_ea = di_mode ? (REG_A()[reg] + MAKE_INT_16(m68ki_read_imm_16())) : 0; for (i=0; i < 8; i++) { if (reglist & (1 << i)) { - m_fpr[7 - i] = READ_EA_FPE(imode, reg, di_mode_ea); - if (di_mode) + switch (ea >> 3) { - di_mode_ea += 12; + case 5: // (d16, An) + case 6: // (An) + (Xn) + d8 + m_fpr[7-i] = load_extended_float80(mem_addr); + mem_addr += 12; + break; + default: + m_fpr[7 - i] = READ_EA_FPE(imode, reg, di_mode_ea); + break; } m_icount -= 2; } @@ -1968,7 +2134,7 @@ void m68000_musashi_device::fscc() { const int mode = (m_ir & 0x38) >> 3; const int condition = OPER_I_16() & 0x3f; - const int v = (TEST_CONDITION(condition) ? 0xff : 0x00); + const int v = (test_condition(condition) ? 0xff : 0x00); switch (mode) { @@ -1995,7 +2161,7 @@ void m68000_musashi_device::fbcc16() offset = (s16)(OPER_I_16()); // TODO: condition and jump!!! - if (TEST_CONDITION(condition)) + if (test_condition(condition)) { m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ m68ki_branch_16(offset-2); @@ -2012,7 +2178,7 @@ void m68000_musashi_device::fbcc32() offset = OPER_I_32(); // TODO: condition and jump!!! - if (TEST_CONDITION(condition)) + if (test_condition(condition)) { m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ m68ki_branch_32(offset-4); @@ -2021,7 +2187,6 @@ void m68000_musashi_device::fbcc32() m_icount -= 7; } - void m68000_musashi_device::m68040_fpu_op0() { m_fpu_just_reset = 0; @@ -2144,8 +2309,8 @@ void m68000_musashi_device::do_frestore_null() m_fpiar = 0; for (i = 0; i < 8; i++) { - m_fpr[i].high = 0x7fff; - m_fpr[i].low = 0xffffffffffffffffU; + m_fpr[i].signExp = 0x7fff; + m_fpr[i].signif = 0xffffffffffffffffU; } // Mac IIci at 408458e6 wants an FSAVE of a just-restored nullptr frame to also be nullptr @@ -2333,7 +2498,7 @@ void m68000_musashi_device::m68881_ftrap() u16 w2 = OPER_I_16(); // now check the condition - if (TEST_CONDITION(w2 & 0x3f)) + if (test_condition(w2 & 0x3f)) { // trap here m68ki_exception_trap(EXCEPTION_TRAPV); diff --git a/src/devices/cpu/m68000/m68kmusashi.h b/src/devices/cpu/m68000/m68kmusashi.h index aa89ea40d80..53670da8b33 100644 --- a/src/devices/cpu/m68000/m68kmusashi.h +++ b/src/devices/cpu/m68000/m68kmusashi.h @@ -7,15 +7,8 @@ #include "m68kcommon.h" -// SoftFloat 2 lacks an include guard -#ifndef softfloat2_h -#define softfloat2_h 1 -#include "softfloat/milieu.h" -#include "softfloat/softfloat.h" -#endif - -extern flag floatx80_is_nan(floatx80 a); - +#include "softfloat3/source/include/softfloat.h" +#include "softfloat3/bochs_ext/softfloat3_ext.h" /* MMU constants */ constexpr int MMU_ATC_ENTRIES = (22); // 68851 has 64, 030 has 22 @@ -152,7 +145,7 @@ protected: u32 m_cacr; /* Cache Control Register (m68020, unemulated) */ u32 m_caar; /* Cache Address Register (m68020, unemulated) */ u32 m_ir; /* Instruction Register */ - floatx80 m_fpr[8]; /* FPU Data Register (m68030/040) */ + extFloat80_t m_fpr[8]; /* FPU Data Register (m68030/040) */ u32 m_fpiar; /* FPU Instruction Address Register (m68040) */ u32 m_fpsr; /* FPU Status Register (m68040) */ u32 m_fpcr; /* FPU Control Register (m68040) */ @@ -329,48 +322,45 @@ protected: #include "m68kops.h" #include "m68kmmu.h" - static double fx80_to_double(floatx80 fx) + static double fx80_to_double(extFloat80_t fx) { - u64 d; - double *foo; - - foo = (double *)&d; - - d = floatx80_to_float64(fx); + const float64_t d = extF80_to_f64(fx); + const double *foo = (double *)&d; return *foo; } - static floatx80 double_to_fx80(double in) + static extFloat80_t double_to_fx80(double in) { - u64 *d; - - d = (u64 *)∈ + float64_t *d = (float64_t *)∈ - return float64_to_floatx80(*d); + return f64_to_extF80(*d); } // defined in m68kfpu.cpp static const u32 pkmask2[18]; static const u32 pkmask3[18]; - inline floatx80 load_extended_float80(u32 ea); - inline void store_extended_float80(u32 ea, floatx80 fpr); - inline floatx80 load_pack_float80(u32 ea); - inline void store_pack_float80(u32 ea, int k, floatx80 fpr); - inline void SET_CONDITION_CODES(floatx80 reg); - inline int TEST_CONDITION(int condition); + inline extFloat80_t load_extended_float80(u32 ea); + inline void store_extended_float80(u32 ea, extFloat80_t fpr); + inline extFloat80_t load_pack_float80(u32 ea); + inline void store_pack_float80(u32 ea, int k, extFloat80_t fpr); + void set_condition_codes(extFloat80_t reg); + int test_condition(int condition); + void clear_exception_flags(); + void sync_exception_flags(extFloat80_t op1, extFloat80_t op2, u32 enables); + s32 convert_to_int(extFloat80_t source, s32 lowerLimit, s32 upperLimit); u8 READ_EA_8(int ea); u16 READ_EA_16(int ea); u32 READ_EA_32(int ea); u64 READ_EA_64(int ea); - floatx80 READ_EA_FPE(int mode, int reg, uint32 di_mode_ea); - floatx80 READ_EA_PACK(int ea); + extFloat80_t READ_EA_FPE(int mode, int reg, uint32_t di_mode_ea); + extFloat80_t READ_EA_PACK(int ea); void WRITE_EA_8(int ea, u8 data); void WRITE_EA_16(int ea, u16 data); void WRITE_EA_32(int ea, u32 data); void WRITE_EA_64(int ea, u64 data); - void WRITE_EA_FPE(int mode, int reg, floatx80 fpr, uint32 di_mode_ea); - void WRITE_EA_PACK(int ea, int k, floatx80 fpr); + void WRITE_EA_FPE(int mode, int reg, extFloat80_t fpr, uint32_t di_mode_ea); + void WRITE_EA_PACK(int ea, int k, extFloat80_t fpr); void fpgen_rm_reg(u16 w2); void fmove_reg_mem(u16 w2); void fmove_fpcr(u16 w2); -- cgit v1.2.3