^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*---------------------------------------------------------------------------+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) | fpu_trig.c |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) | Implementation of the FPU "transcendental" functions. |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) | Copyright (C) 1992,1993,1994,1997,1999 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) | Australia. E-mail billm@melbpc.org.au |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) +---------------------------------------------------------------------------*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include "fpu_system.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include "exception.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include "fpu_emu.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include "status_w.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include "control_w.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include "reg_constant.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) static void rem_kernel(unsigned long long st0, unsigned long long *y,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) unsigned long long st1, unsigned long long q, int n);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define BETTER_THAN_486
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define FCOS 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) /* Used only by fptan, fsin, fcos, and fsincos. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) /* This routine produces very accurate results, similar to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) using a value of pi with more than 128 bits precision. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) /* Limited measurements show no results worse than 64 bit precision
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) except for the results for arguments close to 2^63, where the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) precision of the result sometimes degrades to about 63.9 bits */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) static int trig_arg(FPU_REG *st0_ptr, int even)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) FPU_REG tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) u_char tmptag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) unsigned long long q;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) int old_cw = control_word, saved_status = partial_status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) int tag, st0_tag = TAG_Valid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) if (exponent(st0_ptr) >= 63) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) partial_status |= SW_C2; /* Reduction incomplete. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) control_word &= ~CW_RC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) control_word |= RC_CHOP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) setpositive(st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) tag = FPU_u_div(st0_ptr, &CONST_PI2, &tmp, PR_64_BITS | RC_CHOP | 0x3f,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) SIGN_POS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) FPU_round_to_int(&tmp, tag); /* Fortunately, this can't overflow
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) to 2^64 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) q = significand(&tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) if (q) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) rem_kernel(significand(st0_ptr),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) &significand(&tmp),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) significand(&CONST_PI2),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) q, exponent(st0_ptr) - exponent(&CONST_PI2));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) setexponent16(&tmp, exponent(&CONST_PI2));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) st0_tag = FPU_normalize(&tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) FPU_copy_to_reg0(&tmp, st0_tag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) if ((even && !(q & 1)) || (!even && (q & 1))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) st0_tag =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) FPU_sub(REV | LOADED | TAG_Valid, (int)&CONST_PI2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) FULL_PRECISION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) #ifdef BETTER_THAN_486
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) /* So far, the results are exact but based upon a 64 bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) precision approximation to pi/2. The technique used
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) now is equivalent to using an approximation to pi/2 which
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) is accurate to about 128 bits. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) if ((exponent(st0_ptr) <= exponent(&CONST_PI2extra) + 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) || (q > 1)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) /* This code gives the effect of having pi/2 to better than
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) 128 bits precision. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) significand(&tmp) = q + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) setexponent16(&tmp, 63);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) FPU_normalize(&tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) tmptag =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) FPU_u_mul(&CONST_PI2extra, &tmp, &tmp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) FULL_PRECISION, SIGN_POS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) exponent(&CONST_PI2extra) +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) exponent(&tmp));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) setsign(&tmp, getsign(&CONST_PI2extra));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) st0_tag = FPU_add(&tmp, tmptag, 0, FULL_PRECISION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) if (signnegative(st0_ptr)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) /* CONST_PI2extra is negative, so the result of the addition
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) can be negative. This means that the argument is actually
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) in a different quadrant. The correction is always < pi/2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) so it can't overflow into yet another quadrant. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) setpositive(st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) q++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) #endif /* BETTER_THAN_486 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) #ifdef BETTER_THAN_486
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) /* So far, the results are exact but based upon a 64 bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) precision approximation to pi/2. The technique used
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) now is equivalent to using an approximation to pi/2 which
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) is accurate to about 128 bits. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) if (((q > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) && (exponent(st0_ptr) <= exponent(&CONST_PI2extra) + 64))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) || (q > 1)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) /* This code gives the effect of having p/2 to better than
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 128 bits precision. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) significand(&tmp) = q;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) setexponent16(&tmp, 63);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) FPU_normalize(&tmp); /* This must return TAG_Valid */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) tmptag =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) FPU_u_mul(&CONST_PI2extra, &tmp, &tmp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) FULL_PRECISION, SIGN_POS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) exponent(&CONST_PI2extra) +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) exponent(&tmp));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) setsign(&tmp, getsign(&CONST_PI2extra));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) st0_tag = FPU_sub(LOADED | (tmptag & 0x0f), (int)&tmp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) FULL_PRECISION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) if ((exponent(st0_ptr) == exponent(&CONST_PI2)) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) ((st0_ptr->sigh > CONST_PI2.sigh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) || ((st0_ptr->sigh == CONST_PI2.sigh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) && (st0_ptr->sigl > CONST_PI2.sigl)))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) /* CONST_PI2extra is negative, so the result of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) subtraction can be larger than pi/2. This means
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) that the argument is actually in a different quadrant.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) The correction is always < pi/2, so it can't overflow
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) into yet another quadrant. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) st0_tag =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) FPU_sub(REV | LOADED | TAG_Valid,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) (int)&CONST_PI2, FULL_PRECISION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) q++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) #endif /* BETTER_THAN_486 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) FPU_settag0(st0_tag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) control_word = old_cw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) partial_status = saved_status & ~SW_C2; /* Reduction complete. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) return (q & 3) | even;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) /* Convert a long to register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) static void convert_l2reg(long const *arg, int deststnr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) int tag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) long num = *arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) u_char sign;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) FPU_REG *dest = &st(deststnr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) if (num == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) if (num > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) sign = SIGN_POS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) num = -num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) sign = SIGN_NEG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) dest->sigh = num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) dest->sigl = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) setexponent16(dest, 31);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) tag = FPU_normalize(dest);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) FPU_settagi(deststnr, tag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) setsign(dest, sign);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) static void single_arg_error(FPU_REG *st0_ptr, u_char st0_tag)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) if (st0_tag == TAG_Empty)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) FPU_stack_underflow(); /* Puts a QNaN in st(0) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) else if (st0_tag == TW_NaN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) real_1op_NaN(st0_ptr); /* return with a NaN in st(0) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) #ifdef PARANOID
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) EXCEPTION(EX_INTERNAL | 0x0112);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) #endif /* PARANOID */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) static void single_arg_2_error(FPU_REG *st0_ptr, u_char st0_tag)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) int isNaN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) switch (st0_tag) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) case TW_NaN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) isNaN = (exponent(st0_ptr) == EXP_OVER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) && (st0_ptr->sigh & 0x80000000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) if (isNaN && !(st0_ptr->sigh & 0x40000000)) { /* Signaling ? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) EXCEPTION(EX_Invalid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) if (control_word & CW_Invalid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) /* The masked response */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) /* Convert to a QNaN */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) st0_ptr->sigh |= 0x40000000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) push();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) FPU_copy_to_reg0(st0_ptr, TAG_Special);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) } else if (isNaN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) /* A QNaN */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) push();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) FPU_copy_to_reg0(st0_ptr, TAG_Special);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) /* pseudoNaN or other unsupported */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) EXCEPTION(EX_Invalid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) if (control_word & CW_Invalid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) /* The masked response */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) push();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) break; /* return with a NaN in st(0) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) #ifdef PARANOID
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) EXCEPTION(EX_INTERNAL | 0x0112);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) #endif /* PARANOID */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) /*---------------------------------------------------------------------------*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) static void f2xm1(FPU_REG *st0_ptr, u_char tag)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) FPU_REG a;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) clear_C1();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) if (tag == TAG_Valid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) /* For an 80486 FPU, the result is undefined if the arg is >= 1.0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) if (exponent(st0_ptr) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) denormal_arg:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) FPU_to_exp16(st0_ptr, &a);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) /* poly_2xm1(x) requires 0 < st(0) < 1. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) poly_2xm1(getsign(st0_ptr), &a, st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) set_precision_flag_up(); /* 80486 appears to always do this */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) if (tag == TAG_Zero)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) if (tag == TAG_Special)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) tag = FPU_Special(st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) switch (tag) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) case TW_Denormal:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) if (denormal_operand() < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) goto denormal_arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) case TW_Infinity:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) if (signnegative(st0_ptr)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) /* -infinity gives -1 (p16-10) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) FPU_copy_to_reg0(&CONST_1, TAG_Valid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) setnegative(st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) single_arg_error(st0_ptr, tag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) static void fptan(FPU_REG *st0_ptr, u_char st0_tag)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) FPU_REG *st_new_ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) int q;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) u_char arg_sign = getsign(st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) /* Stack underflow has higher priority */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) if (st0_tag == TAG_Empty) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) FPU_stack_underflow(); /* Puts a QNaN in st(0) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) if (control_word & CW_Invalid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) st_new_ptr = &st(-1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) push();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) FPU_stack_underflow(); /* Puts a QNaN in the new st(0) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) if (STACK_OVERFLOW) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) FPU_stack_overflow();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) if (st0_tag == TAG_Valid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) if (exponent(st0_ptr) > -40) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) if ((q = trig_arg(st0_ptr, 0)) == -1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) /* Operand is out of range */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) poly_tan(st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) setsign(st0_ptr, (q & 1) ^ (arg_sign != 0));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) set_precision_flag_up(); /* We do not really know if up or down */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) /* For a small arg, the result == the argument */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) /* Underflow may happen */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) denormal_arg:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) FPU_to_exp16(st0_ptr, st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) st0_tag =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) FPU_round(st0_ptr, 1, 0, FULL_PRECISION, arg_sign);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) FPU_settag0(st0_tag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) push();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) FPU_copy_to_reg0(&CONST_1, TAG_Valid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) if (st0_tag == TAG_Zero) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) push();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) FPU_copy_to_reg0(&CONST_1, TAG_Valid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) setcc(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) if (st0_tag == TAG_Special)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) st0_tag = FPU_Special(st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) if (st0_tag == TW_Denormal) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) if (denormal_operand() < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) goto denormal_arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) if (st0_tag == TW_Infinity) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) /* The 80486 treats infinity as an invalid operand */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) if (arith_invalid(0) >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) st_new_ptr = &st(-1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) push();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) arith_invalid(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) single_arg_2_error(st0_ptr, st0_tag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) static void fxtract(FPU_REG *st0_ptr, u_char st0_tag)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) FPU_REG *st_new_ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) u_char sign;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) register FPU_REG *st1_ptr = st0_ptr; /* anticipate */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) if (STACK_OVERFLOW) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) FPU_stack_overflow();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) clear_C1();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) if (st0_tag == TAG_Valid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) long e;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) push();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) sign = getsign(st1_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) reg_copy(st1_ptr, st_new_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) setexponent16(st_new_ptr, exponent(st_new_ptr));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) denormal_arg:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) e = exponent16(st_new_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) convert_l2reg(&e, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) setexponentpos(st_new_ptr, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) setsign(st_new_ptr, sign);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) FPU_settag0(TAG_Valid); /* Needed if arg was a denormal */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) } else if (st0_tag == TAG_Zero) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) sign = getsign(st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) if (FPU_divide_by_zero(0, SIGN_NEG) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) push();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) setsign(st_new_ptr, sign);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) if (st0_tag == TAG_Special)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) st0_tag = FPU_Special(st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) if (st0_tag == TW_Denormal) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) if (denormal_operand() < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) push();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) sign = getsign(st1_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) FPU_to_exp16(st1_ptr, st_new_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) goto denormal_arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) } else if (st0_tag == TW_Infinity) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) sign = getsign(st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) setpositive(st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) push();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) FPU_copy_to_reg0(&CONST_INF, TAG_Special);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) setsign(st_new_ptr, sign);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) } else if (st0_tag == TW_NaN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) if (real_1op_NaN(st0_ptr) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) push();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) FPU_copy_to_reg0(st0_ptr, TAG_Special);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) } else if (st0_tag == TAG_Empty) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) /* Is this the correct behaviour? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) if (control_word & EX_Invalid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) FPU_stack_underflow();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) push();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) FPU_stack_underflow();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) EXCEPTION(EX_StackUnder);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) #ifdef PARANOID
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) EXCEPTION(EX_INTERNAL | 0x119);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) #endif /* PARANOID */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) static void fdecstp(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) clear_C1();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) top--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) static void fincstp(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) clear_C1();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) top++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) static void fsqrt_(FPU_REG *st0_ptr, u_char st0_tag)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) int expon;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) clear_C1();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) if (st0_tag == TAG_Valid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) u_char tag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) if (signnegative(st0_ptr)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) arith_invalid(0); /* sqrt(negative) is invalid */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) /* make st(0) in [1.0 .. 4.0) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) expon = exponent(st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) denormal_arg:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) setexponent16(st0_ptr, (expon & 1));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) /* Do the computation, the sign of the result will be positive. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) tag = wm_sqrt(st0_ptr, 0, 0, control_word, SIGN_POS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) addexponent(st0_ptr, expon >> 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) FPU_settag0(tag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) if (st0_tag == TAG_Zero)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) if (st0_tag == TAG_Special)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) st0_tag = FPU_Special(st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) if (st0_tag == TW_Infinity) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) if (signnegative(st0_ptr))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) arith_invalid(0); /* sqrt(-Infinity) is invalid */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) } else if (st0_tag == TW_Denormal) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) if (signnegative(st0_ptr)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) arith_invalid(0); /* sqrt(negative) is invalid */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) if (denormal_operand() < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) FPU_to_exp16(st0_ptr, st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) expon = exponent16(st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) goto denormal_arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) single_arg_error(st0_ptr, st0_tag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) static void frndint_(FPU_REG *st0_ptr, u_char st0_tag)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) int flags, tag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) if (st0_tag == TAG_Valid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) u_char sign;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) denormal_arg:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) sign = getsign(st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) if (exponent(st0_ptr) > 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) if (st0_tag == TW_Denormal) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) if (denormal_operand() < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) /* Fortunately, this can't overflow to 2^64 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) if ((flags = FPU_round_to_int(st0_ptr, st0_tag)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) set_precision_flag(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) setexponent16(st0_ptr, 63);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) tag = FPU_normalize(st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) setsign(st0_ptr, sign);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) FPU_settag0(tag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) if (st0_tag == TAG_Zero)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) if (st0_tag == TAG_Special)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) st0_tag = FPU_Special(st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) if (st0_tag == TW_Denormal)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) goto denormal_arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) else if (st0_tag == TW_Infinity)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) single_arg_error(st0_ptr, st0_tag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) static int fsin(FPU_REG *st0_ptr, u_char tag)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) u_char arg_sign = getsign(st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) if (tag == TAG_Valid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) int q;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) if (exponent(st0_ptr) > -40) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) if ((q = trig_arg(st0_ptr, 0)) == -1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) /* Operand is out of range */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) poly_sine(st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) if (q & 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) changesign(st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) setsign(st0_ptr, getsign(st0_ptr) ^ arg_sign);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) /* We do not really know if up or down */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) set_precision_flag_up();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) /* For a small arg, the result == the argument */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) set_precision_flag_up(); /* Must be up. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) if (tag == TAG_Zero) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) setcc(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) if (tag == TAG_Special)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) tag = FPU_Special(st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) if (tag == TW_Denormal) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) if (denormal_operand() < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) /* For a small arg, the result == the argument */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) /* Underflow may happen */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) FPU_to_exp16(st0_ptr, st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) tag = FPU_round(st0_ptr, 1, 0, FULL_PRECISION, arg_sign);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) FPU_settag0(tag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) } else if (tag == TW_Infinity) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) /* The 80486 treats infinity as an invalid operand */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) arith_invalid(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) single_arg_error(st0_ptr, tag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) static int f_cos(FPU_REG *st0_ptr, u_char tag)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) u_char st0_sign;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) st0_sign = getsign(st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) if (tag == TAG_Valid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) int q;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) if (exponent(st0_ptr) > -40) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) if ((exponent(st0_ptr) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) || ((exponent(st0_ptr) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) && (significand(st0_ptr) <=
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) 0xc90fdaa22168c234LL))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) poly_cos(st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) /* We do not really know if up or down */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) set_precision_flag_down();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) } else if ((q = trig_arg(st0_ptr, FCOS)) != -1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) poly_sine(st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) if ((q + 1) & 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) changesign(st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) /* We do not really know if up or down */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) set_precision_flag_down();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) /* Operand is out of range */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) denormal_arg:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) setcc(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) FPU_copy_to_reg0(&CONST_1, TAG_Valid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) #ifdef PECULIAR_486
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) set_precision_flag_down(); /* 80486 appears to do this. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) set_precision_flag_up(); /* Must be up. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) #endif /* PECULIAR_486 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) } else if (tag == TAG_Zero) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) FPU_copy_to_reg0(&CONST_1, TAG_Valid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) setcc(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) if (tag == TAG_Special)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) tag = FPU_Special(st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) if (tag == TW_Denormal) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) if (denormal_operand() < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) goto denormal_arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) } else if (tag == TW_Infinity) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) /* The 80486 treats infinity as an invalid operand */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) arith_invalid(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) single_arg_error(st0_ptr, tag); /* requires st0_ptr == &st(0) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) static void fcos(FPU_REG *st0_ptr, u_char st0_tag)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) f_cos(st0_ptr, st0_tag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) static void fsincos(FPU_REG *st0_ptr, u_char st0_tag)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) FPU_REG *st_new_ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) FPU_REG arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) u_char tag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) /* Stack underflow has higher priority */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) if (st0_tag == TAG_Empty) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) FPU_stack_underflow(); /* Puts a QNaN in st(0) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) if (control_word & CW_Invalid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) st_new_ptr = &st(-1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) push();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) FPU_stack_underflow(); /* Puts a QNaN in the new st(0) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) if (STACK_OVERFLOW) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) FPU_stack_overflow();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) if (st0_tag == TAG_Special)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) tag = FPU_Special(st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) tag = st0_tag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) if (tag == TW_NaN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) single_arg_2_error(st0_ptr, TW_NaN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) } else if (tag == TW_Infinity) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) /* The 80486 treats infinity as an invalid operand */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) if (arith_invalid(0) >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) /* Masked response */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) push();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) arith_invalid(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) reg_copy(st0_ptr, &arg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) if (!fsin(st0_ptr, st0_tag)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) push();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) FPU_copy_to_reg0(&arg, st0_tag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) f_cos(&st(0), st0_tag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) /* An error, so restore st(0) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) FPU_copy_to_reg0(&arg, st0_tag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) /*---------------------------------------------------------------------------*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) /* The following all require two arguments: st(0) and st(1) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) /* A lean, mean kernel for the fprem instructions. This relies upon
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) the division and rounding to an integer in do_fprem giving an
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) exact result. Because of this, rem_kernel() needs to deal only with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) the least significant 64 bits, the more significant bits of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) result must be zero.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) static void rem_kernel(unsigned long long st0, unsigned long long *y,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) unsigned long long st1, unsigned long long q, int n)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) int dummy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) unsigned long long x;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) x = st0 << n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) /* Do the required multiplication and subtraction in the one operation */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) /* lsw x -= lsw st1 * lsw q */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) asm volatile ("mull %4; subl %%eax,%0; sbbl %%edx,%1":"=m"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) (((unsigned *)&x)[0]), "=m"(((unsigned *)&x)[1]),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) "=a"(dummy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) :"2"(((unsigned *)&st1)[0]), "m"(((unsigned *)&q)[0])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) :"%dx");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) /* msw x -= msw st1 * lsw q */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) asm volatile ("mull %3; subl %%eax,%0":"=m" (((unsigned *)&x)[1]),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) "=a"(dummy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) :"1"(((unsigned *)&st1)[1]), "m"(((unsigned *)&q)[0])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) :"%dx");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) /* msw x -= lsw st1 * msw q */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) asm volatile ("mull %3; subl %%eax,%0":"=m" (((unsigned *)&x)[1]),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) "=a"(dummy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) :"1"(((unsigned *)&st1)[0]), "m"(((unsigned *)&q)[1])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) :"%dx");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) *y = x;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) /* Remainder of st(0) / st(1) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) /* This routine produces exact results, i.e. there is never any
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) rounding or truncation, etc of the result. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) static void do_fprem(FPU_REG *st0_ptr, u_char st0_tag, int round)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) FPU_REG *st1_ptr = &st(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) u_char st1_tag = FPU_gettagi(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) if (!((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) FPU_REG tmp, st0, st1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) u_char st0_sign, st1_sign;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) u_char tmptag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) int tag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) int old_cw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) int expdif;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) long long q;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) unsigned short saved_status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) int cc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) fprem_valid:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) /* Convert registers for internal use. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) st0_sign = FPU_to_exp16(st0_ptr, &st0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) st1_sign = FPU_to_exp16(st1_ptr, &st1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) expdif = exponent16(&st0) - exponent16(&st1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) old_cw = control_word;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) cc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) /* We want the status following the denorm tests, but don't want
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) the status changed by the arithmetic operations. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) saved_status = partial_status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) control_word &= ~CW_RC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) control_word |= RC_CHOP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) if (expdif < 64) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) /* This should be the most common case */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) if (expdif > -2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) u_char sign = st0_sign ^ st1_sign;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) tag = FPU_u_div(&st0, &st1, &tmp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) PR_64_BITS | RC_CHOP | 0x3f,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) sign);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) setsign(&tmp, sign);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) if (exponent(&tmp) >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) FPU_round_to_int(&tmp, tag); /* Fortunately, this can't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) overflow to 2^64 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) q = significand(&tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) rem_kernel(significand(&st0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) &significand(&tmp),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) significand(&st1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) q, expdif);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) setexponent16(&tmp, exponent16(&st1));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) reg_copy(&st0, &tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) q = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) if ((round == RC_RND)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) && (tmp.sigh & 0xc0000000)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) /* We may need to subtract st(1) once more,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) to get a result <= 1/2 of st(1). */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) unsigned long long x;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) expdif =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) exponent16(&st1) - exponent16(&tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) if (expdif <= 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) if (expdif == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) x = significand(&st1) -
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) significand(&tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) else /* expdif is 1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) x = (significand(&st1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) << 1) -
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) significand(&tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) if ((x < significand(&tmp)) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) /* or equi-distant (from 0 & st(1)) and q is odd */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) ((x == significand(&tmp))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) && (q & 1))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) st0_sign = !st0_sign;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) significand(&tmp) = x;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) q++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) if (q & 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) cc |= SW_C0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) if (q & 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) cc |= SW_C3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) if (q & 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) cc |= SW_C1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) control_word = old_cw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) setcc(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) /* There is a large exponent difference ( >= 64 ) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) /* To make much sense, the code in this section should
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) be done at high precision. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) int exp_1, N;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) u_char sign;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) /* prevent overflow here */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) /* N is 'a number between 32 and 63' (p26-113) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) reg_copy(&st0, &tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) tmptag = st0_tag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) N = (expdif & 0x0000001f) + 32; /* This choice gives results
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) identical to an AMD 486 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) setexponent16(&tmp, N);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) exp_1 = exponent16(&st1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) setexponent16(&st1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) expdif -= N;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) sign = getsign(&tmp) ^ st1_sign;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) tag =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) FPU_u_div(&tmp, &st1, &tmp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) PR_64_BITS | RC_CHOP | 0x3f, sign);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) setsign(&tmp, sign);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) FPU_round_to_int(&tmp, tag); /* Fortunately, this can't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) overflow to 2^64 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) rem_kernel(significand(&st0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) &significand(&tmp),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) significand(&st1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) significand(&tmp), exponent(&tmp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) setexponent16(&tmp, exp_1 + expdif);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) /* It is possible for the operation to be complete here.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) What does the IEEE standard say? The Intel 80486 manual
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) implies that the operation will never be completed at this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) point, and the behaviour of a real 80486 confirms this.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) if (!(tmp.sigh | tmp.sigl)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) /* The result is zero */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) control_word = old_cw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) partial_status = saved_status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) setsign(&st0, st0_sign);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) #ifdef PECULIAR_486
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) setcc(SW_C2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) setcc(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) #endif /* PECULIAR_486 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) cc = SW_C2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) control_word = old_cw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) partial_status = saved_status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) tag = FPU_normalize_nuo(&tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) reg_copy(&tmp, st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) /* The only condition to be looked for is underflow,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) and it can occur here only if underflow is unmasked. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) if ((exponent16(&tmp) <= EXP_UNDER) && (tag != TAG_Zero)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) && !(control_word & CW_Underflow)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) setcc(cc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) tag = arith_underflow(st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) setsign(st0_ptr, st0_sign);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) FPU_settag0(tag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) } else if ((exponent16(&tmp) > EXP_UNDER) || (tag == TAG_Zero)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) stdexp(st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) setsign(st0_ptr, st0_sign);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) tag =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) FPU_round(st0_ptr, 0, 0, FULL_PRECISION, st0_sign);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) FPU_settag0(tag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) setcc(cc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) if (st0_tag == TAG_Special)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) st0_tag = FPU_Special(st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) if (st1_tag == TAG_Special)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) st1_tag = FPU_Special(st1_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) if (((st0_tag == TAG_Valid) && (st1_tag == TW_Denormal))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) || ((st0_tag == TW_Denormal) && (st1_tag == TAG_Valid))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) || ((st0_tag == TW_Denormal) && (st1_tag == TW_Denormal))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) if (denormal_operand() < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) goto fprem_valid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) } else if ((st0_tag == TAG_Empty) || (st1_tag == TAG_Empty)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) FPU_stack_underflow();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) } else if (st0_tag == TAG_Zero) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) if (st1_tag == TAG_Valid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) setcc(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) } else if (st1_tag == TW_Denormal) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) if (denormal_operand() < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) setcc(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) } else if (st1_tag == TAG_Zero) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) arith_invalid(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) } /* fprem(?,0) always invalid */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) else if (st1_tag == TW_Infinity) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) setcc(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) } else if ((st0_tag == TAG_Valid) || (st0_tag == TW_Denormal)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) if (st1_tag == TAG_Zero) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) arith_invalid(0); /* fprem(Valid,Zero) is invalid */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) } else if (st1_tag != TW_NaN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) if (((st0_tag == TW_Denormal)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) || (st1_tag == TW_Denormal))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) && (denormal_operand() < 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) if (st1_tag == TW_Infinity) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) /* fprem(Valid,Infinity) is o.k. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) setcc(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) } else if (st0_tag == TW_Infinity) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) if (st1_tag != TW_NaN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) arith_invalid(0); /* fprem(Infinity,?) is invalid */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) /* One of the registers must contain a NaN if we got here. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) #ifdef PARANOID
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) if ((st0_tag != TW_NaN) && (st1_tag != TW_NaN))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) EXCEPTION(EX_INTERNAL | 0x118);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) #endif /* PARANOID */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) real_2op_NaN(st1_ptr, st1_tag, 0, st1_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) /* ST(1) <- ST(1) * log ST; pop ST */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) static void fyl2x(FPU_REG *st0_ptr, u_char st0_tag)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) FPU_REG *st1_ptr = &st(1), exponent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) u_char st1_tag = FPU_gettagi(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) u_char sign;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) int e, tag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) clear_C1();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) if ((st0_tag == TAG_Valid) && (st1_tag == TAG_Valid)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) both_valid:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) /* Both regs are Valid or Denormal */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) if (signpositive(st0_ptr)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) if (st0_tag == TW_Denormal)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) FPU_to_exp16(st0_ptr, st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) /* Convert st(0) for internal use. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) setexponent16(st0_ptr, exponent(st0_ptr));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) if ((st0_ptr->sigh == 0x80000000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) && (st0_ptr->sigl == 0)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) /* Special case. The result can be precise. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) u_char esign;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) e = exponent16(st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) if (e >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) exponent.sigh = e;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) esign = SIGN_POS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) exponent.sigh = -e;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) esign = SIGN_NEG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) exponent.sigl = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) setexponent16(&exponent, 31);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) tag = FPU_normalize_nuo(&exponent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) stdexp(&exponent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) setsign(&exponent, esign);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) tag =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) FPU_mul(&exponent, tag, 1, FULL_PRECISION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) if (tag >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) FPU_settagi(1, tag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) /* The usual case */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) sign = getsign(st1_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) if (st1_tag == TW_Denormal)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) FPU_to_exp16(st1_ptr, st1_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) /* Convert st(1) for internal use. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) setexponent16(st1_ptr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) exponent(st1_ptr));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) poly_l2(st0_ptr, st1_ptr, sign);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) /* negative */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) if (arith_invalid(1) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) FPU_pop();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) if (st0_tag == TAG_Special)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) st0_tag = FPU_Special(st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) if (st1_tag == TAG_Special)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) st1_tag = FPU_Special(st1_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) if ((st0_tag == TAG_Empty) || (st1_tag == TAG_Empty)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) FPU_stack_underflow_pop(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) } else if ((st0_tag <= TW_Denormal) && (st1_tag <= TW_Denormal)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) if (st0_tag == TAG_Zero) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) if (st1_tag == TAG_Zero) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) /* Both args zero is invalid */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) if (arith_invalid(1) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) u_char sign;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) sign = getsign(st1_ptr) ^ SIGN_NEG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) if (FPU_divide_by_zero(1, sign) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) setsign(st1_ptr, sign);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) } else if (st1_tag == TAG_Zero) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) /* st(1) contains zero, st(0) valid <> 0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) /* Zero is the valid answer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) sign = getsign(st1_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) if (signnegative(st0_ptr)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) /* log(negative) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) if (arith_invalid(1) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) } else if ((st0_tag == TW_Denormal)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) && (denormal_operand() < 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) if (exponent(st0_ptr) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) sign ^= SIGN_NEG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) FPU_copy_to_reg1(&CONST_Z, TAG_Zero);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) setsign(st1_ptr, sign);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) /* One or both operands are denormals. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) if (denormal_operand() < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) goto both_valid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) } else if ((st0_tag == TW_NaN) || (st1_tag == TW_NaN)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) /* One or both arg must be an infinity */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) else if (st0_tag == TW_Infinity) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) if ((signnegative(st0_ptr)) || (st1_tag == TAG_Zero)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) /* log(-infinity) or 0*log(infinity) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) if (arith_invalid(1) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) u_char sign = getsign(st1_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) if ((st1_tag == TW_Denormal)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) && (denormal_operand() < 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) FPU_copy_to_reg1(&CONST_INF, TAG_Special);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) setsign(st1_ptr, sign);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) /* st(1) must be infinity here */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) else if (((st0_tag == TAG_Valid) || (st0_tag == TW_Denormal))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) && (signpositive(st0_ptr))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) if (exponent(st0_ptr) >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) if ((exponent(st0_ptr) == 0) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156) (st0_ptr->sigh == 0x80000000) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157) (st0_ptr->sigl == 0)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) /* st(0) holds 1.0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) /* infinity*log(1) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) if (arith_invalid(1) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163) /* else st(0) is positive and > 1.0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165) /* st(0) is positive and < 1.0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167) if ((st0_tag == TW_Denormal)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) && (denormal_operand() < 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171) changesign(st1_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) /* st(0) must be zero or negative */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175) if (st0_tag == TAG_Zero) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) /* This should be invalid, but a real 80486 is happy with it. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) #ifndef PECULIAR_486
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) sign = getsign(st1_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) if (FPU_divide_by_zero(1, sign) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182) #endif /* PECULIAR_486 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) changesign(st1_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185) } else if (arith_invalid(1) < 0) /* log(negative) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189) FPU_pop();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192) static void fpatan(FPU_REG *st0_ptr, u_char st0_tag)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194) FPU_REG *st1_ptr = &st(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195) u_char st1_tag = FPU_gettagi(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196) int tag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198) clear_C1();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199) if (!((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200) valid_atan:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202) poly_atan(st0_ptr, st0_tag, st1_ptr, st1_tag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204) FPU_pop();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209) if (st0_tag == TAG_Special)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210) st0_tag = FPU_Special(st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211) if (st1_tag == TAG_Special)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) st1_tag = FPU_Special(st1_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214) if (((st0_tag == TAG_Valid) && (st1_tag == TW_Denormal))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215) || ((st0_tag == TW_Denormal) && (st1_tag == TAG_Valid))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216) || ((st0_tag == TW_Denormal) && (st1_tag == TW_Denormal))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217) if (denormal_operand() < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220) goto valid_atan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221) } else if ((st0_tag == TAG_Empty) || (st1_tag == TAG_Empty)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222) FPU_stack_underflow_pop(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224) } else if ((st0_tag == TW_NaN) || (st1_tag == TW_NaN)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225) if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226) FPU_pop();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228) } else if ((st0_tag == TW_Infinity) || (st1_tag == TW_Infinity)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229) u_char sign = getsign(st1_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230) if (st0_tag == TW_Infinity) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231) if (st1_tag == TW_Infinity) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232) if (signpositive(st0_ptr)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233) FPU_copy_to_reg1(&CONST_PI4, TAG_Valid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235) setpositive(st1_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236) tag =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237) FPU_u_add(&CONST_PI4, &CONST_PI2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238) st1_ptr, FULL_PRECISION,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239) SIGN_POS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240) exponent(&CONST_PI4),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241) exponent(&CONST_PI2));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242) if (tag >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243) FPU_settagi(1, tag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1244) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1245) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1246) if ((st1_tag == TW_Denormal)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1247) && (denormal_operand() < 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1248) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1250) if (signpositive(st0_ptr)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1251) FPU_copy_to_reg1(&CONST_Z, TAG_Zero);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1252) setsign(st1_ptr, sign); /* An 80486 preserves the sign */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1253) FPU_pop();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1254) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1255) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1256) FPU_copy_to_reg1(&CONST_PI, TAG_Valid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1257) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1258) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1259) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1260) /* st(1) is infinity, st(0) not infinity */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1261) if ((st0_tag == TW_Denormal)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1262) && (denormal_operand() < 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1263) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1265) FPU_copy_to_reg1(&CONST_PI2, TAG_Valid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1266) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1267) setsign(st1_ptr, sign);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1268) } else if (st1_tag == TAG_Zero) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1269) /* st(0) must be valid or zero */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1270) u_char sign = getsign(st1_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1272) if ((st0_tag == TW_Denormal) && (denormal_operand() < 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1273) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1275) if (signpositive(st0_ptr)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1276) /* An 80486 preserves the sign */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1277) FPU_pop();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1278) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1279) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1281) FPU_copy_to_reg1(&CONST_PI, TAG_Valid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1282) setsign(st1_ptr, sign);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1283) } else if (st0_tag == TAG_Zero) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1284) /* st(1) must be TAG_Valid here */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1285) u_char sign = getsign(st1_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1287) if ((st1_tag == TW_Denormal) && (denormal_operand() < 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1288) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1290) FPU_copy_to_reg1(&CONST_PI2, TAG_Valid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1291) setsign(st1_ptr, sign);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1292) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1293) #ifdef PARANOID
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1294) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1295) EXCEPTION(EX_INTERNAL | 0x125);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1296) #endif /* PARANOID */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1297)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1298) FPU_pop();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1299) set_precision_flag_up(); /* We do not really know if up or down */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1300) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1301)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1302) static void fprem(FPU_REG *st0_ptr, u_char st0_tag)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1303) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1304) do_fprem(st0_ptr, st0_tag, RC_CHOP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1305) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1307) static void fprem1(FPU_REG *st0_ptr, u_char st0_tag)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1308) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1309) do_fprem(st0_ptr, st0_tag, RC_RND);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1310) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1312) static void fyl2xp1(FPU_REG *st0_ptr, u_char st0_tag)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1313) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1314) u_char sign, sign1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1315) FPU_REG *st1_ptr = &st(1), a, b;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1316) u_char st1_tag = FPU_gettagi(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1318) clear_C1();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1319) if (!((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1320) valid_yl2xp1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1322) sign = getsign(st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1323) sign1 = getsign(st1_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1325) FPU_to_exp16(st0_ptr, &a);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1326) FPU_to_exp16(st1_ptr, &b);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1328) if (poly_l2p1(sign, sign1, &a, &b, st1_ptr))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1329) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1330)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1331) FPU_pop();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1332) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1333) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1334)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1335) if (st0_tag == TAG_Special)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1336) st0_tag = FPU_Special(st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1337) if (st1_tag == TAG_Special)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1338) st1_tag = FPU_Special(st1_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1339)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1340) if (((st0_tag == TAG_Valid) && (st1_tag == TW_Denormal))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1341) || ((st0_tag == TW_Denormal) && (st1_tag == TAG_Valid))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1342) || ((st0_tag == TW_Denormal) && (st1_tag == TW_Denormal))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1343) if (denormal_operand() < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1344) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1346) goto valid_yl2xp1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1347) } else if ((st0_tag == TAG_Empty) | (st1_tag == TAG_Empty)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1348) FPU_stack_underflow_pop(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1349) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1350) } else if (st0_tag == TAG_Zero) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1351) switch (st1_tag) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1352) case TW_Denormal:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1353) if (denormal_operand() < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1354) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1355) fallthrough;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1356) case TAG_Zero:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1357) case TAG_Valid:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1358) setsign(st0_ptr, getsign(st0_ptr) ^ getsign(st1_ptr));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1359) FPU_copy_to_reg1(st0_ptr, st0_tag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1360) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1362) case TW_Infinity:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1363) /* Infinity*log(1) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1364) if (arith_invalid(1) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1365) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1366) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1367)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1368) case TW_NaN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1369) if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1370) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1371) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1373) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1374) #ifdef PARANOID
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1375) EXCEPTION(EX_INTERNAL | 0x116);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1376) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1377) #endif /* PARANOID */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1378) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1379) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1380) } else if ((st0_tag == TAG_Valid) || (st0_tag == TW_Denormal)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1381) switch (st1_tag) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1382) case TAG_Zero:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1383) if (signnegative(st0_ptr)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1384) if (exponent(st0_ptr) >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1385) /* st(0) holds <= -1.0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1386) #ifdef PECULIAR_486 /* Stupid 80486 doesn't worry about log(negative). */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1387) changesign(st1_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1388) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1389) if (arith_invalid(1) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1390) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1391) #endif /* PECULIAR_486 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1392) } else if ((st0_tag == TW_Denormal)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1393) && (denormal_operand() < 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1394) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1395) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1396) changesign(st1_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1397) } else if ((st0_tag == TW_Denormal)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1398) && (denormal_operand() < 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1399) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1400) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1402) case TW_Infinity:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1403) if (signnegative(st0_ptr)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1404) if ((exponent(st0_ptr) >= 0) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1405) !((st0_ptr->sigh == 0x80000000) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1406) (st0_ptr->sigl == 0))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1407) /* st(0) holds < -1.0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1408) #ifdef PECULIAR_486 /* Stupid 80486 doesn't worry about log(negative). */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1409) changesign(st1_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1410) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1411) if (arith_invalid(1) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1412) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1413) #endif /* PECULIAR_486 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1414) } else if ((st0_tag == TW_Denormal)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1415) && (denormal_operand() < 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1416) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1417) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1418) changesign(st1_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1419) } else if ((st0_tag == TW_Denormal)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1420) && (denormal_operand() < 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1421) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1422) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1423)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1424) case TW_NaN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1425) if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1426) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1427) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1428)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1429) } else if (st0_tag == TW_NaN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1430) if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1431) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1432) } else if (st0_tag == TW_Infinity) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1433) if (st1_tag == TW_NaN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1434) if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1435) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1436) } else if (signnegative(st0_ptr)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1437) #ifndef PECULIAR_486
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1438) /* This should have higher priority than denormals, but... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1439) if (arith_invalid(1) < 0) /* log(-infinity) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1440) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1441) #endif /* PECULIAR_486 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1442) if ((st1_tag == TW_Denormal)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1443) && (denormal_operand() < 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1444) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1445) #ifdef PECULIAR_486
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1446) /* Denormal operands actually get higher priority */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1447) if (arith_invalid(1) < 0) /* log(-infinity) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1448) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1449) #endif /* PECULIAR_486 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1450) } else if (st1_tag == TAG_Zero) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1451) /* log(infinity) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1452) if (arith_invalid(1) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1453) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1454) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1455)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1456) /* st(1) must be valid here. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1457)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1458) else if ((st1_tag == TW_Denormal) && (denormal_operand() < 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1459) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1460)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1461) /* The Manual says that log(Infinity) is invalid, but a real
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1462) 80486 sensibly says that it is o.k. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1463) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1464) u_char sign = getsign(st1_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1465) FPU_copy_to_reg1(&CONST_INF, TAG_Special);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1466) setsign(st1_ptr, sign);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1467) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1468) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1469) #ifdef PARANOID
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1470) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1471) EXCEPTION(EX_INTERNAL | 0x117);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1472) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1473) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1474) #endif /* PARANOID */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1475)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1476) FPU_pop();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1477) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1478)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1479) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1480)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1481) static void fscale(FPU_REG *st0_ptr, u_char st0_tag)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1482) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1483) FPU_REG *st1_ptr = &st(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1484) u_char st1_tag = FPU_gettagi(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1485) int old_cw = control_word;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1486) u_char sign = getsign(st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1487)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1488) clear_C1();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1489) if (!((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1490) long scale;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1491) FPU_REG tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1492)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1493) /* Convert register for internal use. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1494) setexponent16(st0_ptr, exponent(st0_ptr));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1495)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1496) valid_scale:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1497)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1498) if (exponent(st1_ptr) > 30) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1499) /* 2^31 is far too large, would require 2^(2^30) or 2^(-2^30) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1500)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1501) if (signpositive(st1_ptr)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1502) EXCEPTION(EX_Overflow);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1503) FPU_copy_to_reg0(&CONST_INF, TAG_Special);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1504) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1505) EXCEPTION(EX_Underflow);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1506) FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1507) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1508) setsign(st0_ptr, sign);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1509) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1510) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1511)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1512) control_word &= ~CW_RC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1513) control_word |= RC_CHOP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1514) reg_copy(st1_ptr, &tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1515) FPU_round_to_int(&tmp, st1_tag); /* This can never overflow here */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1516) control_word = old_cw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1517) scale = signnegative(st1_ptr) ? -tmp.sigl : tmp.sigl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1518) scale += exponent16(st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1519)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1520) setexponent16(st0_ptr, scale);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1522) /* Use FPU_round() to properly detect under/overflow etc */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1523) FPU_round(st0_ptr, 0, 0, control_word, sign);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1525) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1526) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1527)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1528) if (st0_tag == TAG_Special)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1529) st0_tag = FPU_Special(st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1530) if (st1_tag == TAG_Special)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1531) st1_tag = FPU_Special(st1_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1532)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1533) if ((st0_tag == TAG_Valid) || (st0_tag == TW_Denormal)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1534) switch (st1_tag) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1535) case TAG_Valid:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1536) /* st(0) must be a denormal */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1537) if ((st0_tag == TW_Denormal)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1538) && (denormal_operand() < 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1539) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1540)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1541) FPU_to_exp16(st0_ptr, st0_ptr); /* Will not be left on stack */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1542) goto valid_scale;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1543)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1544) case TAG_Zero:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1545) if (st0_tag == TW_Denormal)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1546) denormal_operand();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1547) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1548)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1549) case TW_Denormal:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1550) denormal_operand();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1551) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1552)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1553) case TW_Infinity:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1554) if ((st0_tag == TW_Denormal)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1555) && (denormal_operand() < 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1556) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1557)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1558) if (signpositive(st1_ptr))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1559) FPU_copy_to_reg0(&CONST_INF, TAG_Special);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1560) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1561) FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1562) setsign(st0_ptr, sign);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1563) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1564)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1565) case TW_NaN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1566) real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1567) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1568) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1569) } else if (st0_tag == TAG_Zero) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1570) switch (st1_tag) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1571) case TAG_Valid:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1572) case TAG_Zero:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1573) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1574)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1575) case TW_Denormal:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1576) denormal_operand();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1577) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1578)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1579) case TW_Infinity:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1580) if (signpositive(st1_ptr))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1581) arith_invalid(0); /* Zero scaled by +Infinity */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1582) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1583)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1584) case TW_NaN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1585) real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1586) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1587) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1588) } else if (st0_tag == TW_Infinity) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1589) switch (st1_tag) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1590) case TAG_Valid:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1591) case TAG_Zero:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1592) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1593)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1594) case TW_Denormal:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1595) denormal_operand();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1596) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1597)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1598) case TW_Infinity:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1599) if (signnegative(st1_ptr))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1600) arith_invalid(0); /* Infinity scaled by -Infinity */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1601) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1602)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1603) case TW_NaN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1604) real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1605) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1606) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1607) } else if (st0_tag == TW_NaN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1608) if (st1_tag != TAG_Empty) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1609) real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1610) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1611) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1612) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1613) #ifdef PARANOID
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1614) if (!((st0_tag == TAG_Empty) || (st1_tag == TAG_Empty))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1615) EXCEPTION(EX_INTERNAL | 0x115);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1616) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1617) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1618) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1619)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1620) /* At least one of st(0), st(1) must be empty */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1621) FPU_stack_underflow();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1622)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1623) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1624)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1625) /*---------------------------------------------------------------------------*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1626)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1627) static FUNC_ST0 const trig_table_a[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1628) f2xm1, fyl2x, fptan, fpatan,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1629) fxtract, fprem1, (FUNC_ST0) fdecstp, (FUNC_ST0) fincstp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1630) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1631)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1632) void FPU_triga(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1633) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1634) (trig_table_a[FPU_rm]) (&st(0), FPU_gettag0());
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1635) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1636)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1637) static FUNC_ST0 const trig_table_b[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1638) fprem, fyl2xp1, fsqrt_, fsincos, frndint_, fscale, (FUNC_ST0) fsin, fcos
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1639) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1640)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1641) void FPU_trigb(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1642) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1643) (trig_table_b[FPU_rm]) (&st(0), FPU_gettag0());
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1644) }