root/arch/x86/math-emu/fpu_trig.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. trig_arg
  2. convert_l2reg
  3. single_arg_error
  4. single_arg_2_error
  5. f2xm1
  6. fptan
  7. fxtract
  8. fdecstp
  9. fincstp
  10. fsqrt_
  11. frndint_
  12. fsin
  13. f_cos
  14. fcos
  15. fsincos
  16. rem_kernel
  17. do_fprem
  18. fyl2x
  19. fpatan
  20. fprem
  21. fprem1
  22. fyl2xp1
  23. fscale
  24. FPU_triga
  25. FPU_trigb

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

/* [<][>][^][v][top][bottom][index][help] */