root/drivers/FPU-emu/fpu_trig.c

/* [previous][next][first][last][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. trig_a
  25. trig_b

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

/* [previous][next][first][last][top][bottom][index][help] */