root/kernel/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. f2xm1
  5. fptan
  6. fxtract
  7. fdecstp
  8. fincstp
  9. fsqrt_
  10. frndint_
  11. fsin
  12. f_cos
  13. fcos
  14. fsincos
  15. fprem_kernel
  16. fyl2x
  17. fpatan
  18. fprem
  19. fprem1
  20. fyl2xp1
  21. fscale
  22. trig_a
  23. trig_b

   1 /*---------------------------------------------------------------------------+
   2  |  fpu_trig.c                                                               |
   3  |                                                                           |
   4  | Implementation of the FPU "transcendental" functions.                     |
   5  |                                                                           |
   6  | Copyright (C) 1992    W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
   7  |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
   8  |                                                                           |
   9  |                                                                           |
  10  +---------------------------------------------------------------------------*/
  11 
  12 #include "fpu_system.h"
  13 #include "exception.h"
  14 #include "fpu_emu.h"
  15 #include "status_w.h"
  16 #include "control_w.h"
  17 #include "reg_constant.h"       
  18 
  19 
  20 
  21 static int trig_arg(FPU_REG *X)
     /* [previous][next][first][last][top][bottom][index][help] */
  22 {
  23   FPU_REG tmp, quot;
  24   int rv;
  25   long long q;
  26   int old_cw = control_word;
  27 
  28   control_word &= ~CW_RC;
  29   control_word |= RC_CHOP;
  30   
  31   reg_move(X, &quot);
  32   reg_div(&quot, &CONST_PI2, &quot);
  33 
  34   reg_move(&quot, &tmp);
  35   round_to_int(&tmp);
  36   if ( tmp.sigh & 0x80000000 )
  37     return -1;              /* |Arg| is >= 2^63 */
  38   tmp.exp = EXP_BIAS + 63;
  39   q = *(long long *)&(tmp.sigl);
  40   normalize(&tmp);
  41 
  42   reg_sub(&quot, &tmp, X);
  43   rv = q & 7;
  44   
  45   control_word = old_cw;
  46   return rv;;
  47 }
  48 
  49 
  50 /* Convert a long to register */
  51 void convert_l2reg(long *arg, FPU_REG *dest)
     /* [previous][next][first][last][top][bottom][index][help] */
  52 {
  53   long num = *arg;
  54   
  55   if (num == 0)
  56     { reg_move(&CONST_Z, dest); return; }
  57 
  58   if (num > 0)
  59     dest->sign = SIGN_POS;
  60   else
  61     { num = -num; dest->sign = SIGN_NEG; }
  62   
  63   dest->sigh = num;
  64   dest->sigl = 0;
  65   dest->exp = EXP_BIAS + 31;
  66   dest->tag = TW_Valid;
  67   normalize(dest);
  68 }
  69 
  70 
  71 static void single_arg_error(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  72 {
  73   switch ( FPU_st0_tag )
  74     {
  75     case TW_NaN:
  76       if ( !(FPU_st0_ptr->sigh & 0x40000000) )   /* Signaling ? */
  77         {
  78           EXCEPTION(EX_Invalid);
  79           /* Convert to a QNaN */
  80           FPU_st0_ptr->sigh |= 0x40000000;
  81         }
  82     case TW_Empty:
  83       stack_underflow();
  84 #ifdef PARANOID
  85     default:
  86       EXCEPTION(EX_INTERNAL|0x0112);
  87 #endif PARANOID
  88     }
  89 }
  90 
  91 
  92 /*---------------------------------------------------------------------------*/
  93 
  94 static void f2xm1()
     /* [previous][next][first][last][top][bottom][index][help] */
  95 {
  96   switch ( FPU_st0_tag )
  97     {
  98     case TW_Valid:
  99       {
 100         FPU_REG rv, tmp;
 101         
 102         if ( FPU_st0_ptr->sign == SIGN_POS )
 103           {
 104             /* poly_2xm1(x) requires 0 < x < 1. */
 105             if ( poly_2xm1(FPU_st0_ptr, &rv) )
 106               return;
 107             reg_mul(&rv, FPU_st0_ptr, FPU_st0_ptr);
 108             return;
 109           }
 110         else
 111           {
 112 /* **** Should change poly_2xm1() to at least handle numbers near 0 */
 113             /* poly_2xm1(x) doesn't handle negative numbers. */
 114             /* So we compute (poly_2xm1(x+1)-1)/2, for -1 < x < 0 */
 115             reg_add(FPU_st0_ptr, &CONST_1, &tmp);
 116             poly_2xm1(&tmp, &rv);
 117             reg_mul(&rv, &tmp, &tmp);
 118             reg_sub(&tmp, &CONST_1, FPU_st0_ptr);
 119             FPU_st0_ptr->exp--;
 120           }
 121         if ( FPU_st0_ptr->exp <= EXP_UNDER )
 122           arith_underflow(FPU_st0_ptr);
 123         return;
 124       }
 125     case TW_Zero:
 126       return;
 127     case TW_Infinity:
 128       if ( FPU_st0_ptr->sign == SIGN_NEG )
 129         {
 130           /* -infinity gives -1 (p16-10) */
 131           reg_move(&CONST_1, FPU_st0_ptr);
 132           FPU_st0_ptr->sign = SIGN_NEG;
 133         }
 134       return;
 135     default:
 136       single_arg_error();
 137     }
 138 }
 139 
 140 static void fptan()
     /* [previous][next][first][last][top][bottom][index][help] */
 141 {
 142   FPU_REG *st_new_ptr;
 143   int q;
 144   char arg_sign = FPU_st0_ptr->sign;
 145 
 146   if ( STACK_OVERFLOW )
 147     { stack_overflow(); return; }
 148 
 149   switch ( FPU_st0_tag )
 150     {
 151     case TW_Valid:
 152       FPU_st0_ptr->sign = SIGN_POS;
 153       if ( (q = trig_arg(FPU_st0_ptr)) != -1 )
 154         {
 155           if (q & 1)
 156             reg_sub(&CONST_1, FPU_st0_ptr, FPU_st0_ptr);
 157           
 158           poly_tan(FPU_st0_ptr, FPU_st0_ptr);
 159 
 160           FPU_st0_ptr->sign = (q & 1) ^ arg_sign;
 161           
 162           if ( FPU_st0_ptr->exp <= EXP_UNDER )
 163             arith_underflow(FPU_st0_ptr);
 164           
 165           push();
 166           reg_move(&CONST_1, FPU_st0_ptr);
 167           setcc(0);
 168         }
 169       else
 170         {
 171           /* Operand is out of range */
 172           setcc(SW_C2);
 173           FPU_st0_ptr->sign = arg_sign;         /* restore st(0) */
 174           return;
 175         }
 176       break;
 177     case TW_Infinity:
 178       arith_invalid(FPU_st0_ptr);
 179       setcc(0);
 180       return;
 181     case TW_Zero:
 182       push();
 183       reg_move(&CONST_1, FPU_st0_ptr);
 184       setcc(0);
 185       break;
 186     default:
 187       single_arg_error();
 188       break;
 189     }
 190 }
 191 
 192 
 193 static void fxtract()
     /* [previous][next][first][last][top][bottom][index][help] */
 194 {
 195   FPU_REG *st_new_ptr;
 196   register FPU_REG *st1_ptr = FPU_st0_ptr;  /* anticipate */
 197 
 198   if ( STACK_OVERFLOW )
 199     {  stack_overflow(); return; }
 200 
 201   if ( !(FPU_st0_tag ^ TW_Valid) )
 202     {
 203       long e;
 204           
 205       push();
 206       reg_move(st1_ptr, FPU_st0_ptr);
 207       FPU_st0_ptr->exp = EXP_BIAS;
 208       e = st1_ptr->exp - EXP_BIAS;
 209       convert_l2reg(&e, st1_ptr);
 210       return;
 211     }
 212   else if ( FPU_st0_tag == TW_Zero )
 213     {
 214       char sign = FPU_st0_ptr->sign;
 215       divide_by_zero(SIGN_NEG, FPU_st0_ptr);
 216       push();
 217       reg_move(&CONST_Z, FPU_st0_ptr);
 218       FPU_st0_ptr->sign = sign;
 219       return;
 220     }
 221   else if ( FPU_st0_tag == TW_Infinity )
 222     {
 223       char sign = FPU_st0_ptr->sign;
 224       FPU_st0_ptr->sign = SIGN_POS;
 225       push();
 226       reg_move(&CONST_INF, FPU_st0_ptr);
 227       FPU_st0_ptr->sign = sign;
 228       return;
 229     }
 230   else if ( FPU_st0_tag == TW_NaN )
 231     {
 232       if ( !(FPU_st0_ptr->sigh & 0x40000000) )   /* Signaling ? */
 233         {
 234           EXCEPTION(EX_Invalid);
 235           /* Convert to a QNaN */
 236           FPU_st0_ptr->sigh |= 0x40000000;
 237         }
 238       push();
 239       reg_move(st1_ptr, FPU_st0_ptr);
 240       return;
 241     }
 242   else if ( FPU_st0_tag == TW_Empty )
 243     {
 244       /* Is this the correct behaviour? */
 245       if ( control_word & EX_Invalid )
 246         {
 247           stack_underflow();
 248           push();
 249           stack_underflow();
 250         }
 251       else
 252         EXCEPTION(EX_StackUnder);
 253     }
 254 #ifdef PARANOID
 255   else
 256     EXCEPTION(EX_INTERNAL | 0x119);
 257 #endif PARANOID
 258 }
 259 
 260 
 261 static void fdecstp()
     /* [previous][next][first][last][top][bottom][index][help] */
 262 {
 263   top--;  /* FPU_st0_ptr will be fixed in math_emulate() before the next instr */
 264 }
 265 
 266 static void fincstp()
     /* [previous][next][first][last][top][bottom][index][help] */
 267 {
 268   top++;  /* FPU_st0_ptr will be fixed in math_emulate() before the next instr */
 269 }
 270 
 271 
 272 static void fsqrt_()
     /* [previous][next][first][last][top][bottom][index][help] */
 273 {
 274   if ( !(FPU_st0_tag ^ TW_Valid) )
 275     {
 276       int expon;
 277       
 278       if (FPU_st0_ptr->sign == SIGN_NEG)
 279         {
 280           arith_invalid(FPU_st0_ptr);
 281           return;
 282         }
 283 
 284       expon = FPU_st0_ptr->exp - EXP_BIAS;
 285       FPU_st0_ptr->exp = EXP_BIAS + (expon & 1);  /* make st(0) in  [1.0 .. 4.0) */
 286       
 287       wm_sqrt(FPU_st0_ptr);     /* Do the computation */
 288       
 289       FPU_st0_ptr->exp += expon >> 1;
 290       FPU_st0_ptr->tag = TW_Valid;
 291       FPU_st0_ptr->sign = SIGN_POS;
 292     }
 293   else if ( FPU_st0_tag == TW_Zero )
 294     return;
 295   else if ( FPU_st0_tag == TW_Infinity )
 296     {
 297       if ( FPU_st0_ptr->sign == SIGN_NEG )
 298         arith_invalid(FPU_st0_ptr);
 299       return;
 300     }
 301   else
 302     single_arg_error();
 303 }
 304 
 305 
 306 static void frndint_()
     /* [previous][next][first][last][top][bottom][index][help] */
 307 {
 308   if ( !(FPU_st0_tag ^ TW_Valid) )
 309     {
 310       if (FPU_st0_ptr->exp > EXP_BIAS+63)
 311         return;
 312 
 313       round_to_int(FPU_st0_ptr);  /* Fortunately, this can't overflow to 2^64 */
 314       FPU_st0_ptr->exp = EXP_BIAS + 63;
 315       normalize(FPU_st0_ptr);
 316       return;
 317     }
 318   else if ( (FPU_st0_tag == TW_Zero) || (FPU_st0_tag == TW_Infinity) )
 319     return;
 320   else
 321     single_arg_error();
 322 }
 323 
 324 
 325 static void fsin()
     /* [previous][next][first][last][top][bottom][index][help] */
 326 {
 327   if ( FPU_st0_tag == TW_Valid )
 328     {
 329       int q;
 330       char arg_sign = FPU_st0_ptr->sign;
 331       FPU_st0_ptr->sign = SIGN_POS;
 332       if ( (q = trig_arg(FPU_st0_ptr)) != -1 )
 333         {
 334           FPU_REG rv;
 335           
 336           if (q & 1)
 337             reg_sub(&CONST_1, FPU_st0_ptr, FPU_st0_ptr);
 338           
 339           poly_sine(FPU_st0_ptr, &rv);
 340           
 341           setcc(0);
 342           if (q & 2)
 343             rv.sign ^= SIGN_POS ^ SIGN_NEG;
 344           rv.sign ^= arg_sign;
 345           reg_move(&rv, FPU_st0_ptr);
 346 
 347           if ( FPU_st0_ptr->exp <= EXP_UNDER )
 348             arith_underflow(FPU_st0_ptr);
 349 
 350           return;
 351         }
 352       else
 353         {
 354           /* Operand is out of range */
 355           setcc(SW_C2);
 356           FPU_st0_ptr->sign = arg_sign;         /* restore st(0) */
 357           EXCEPTION(EX_Invalid);
 358           return;
 359         }
 360     }
 361   else if ( FPU_st0_tag == TW_Zero )
 362     {
 363       setcc(0);
 364       return;
 365     }
 366   else if ( FPU_st0_tag == TW_Infinity )
 367     {
 368       arith_invalid(FPU_st0_ptr);
 369       setcc(0);
 370       return;
 371     }
 372   else
 373     single_arg_error();
 374 }
 375 
 376 
 377 static int f_cos(FPU_REG *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 378 {
 379   if ( arg->tag == TW_Valid )
 380     {
 381       int q;
 382       char arg_sign = arg->sign;
 383       arg->sign = SIGN_POS;
 384       if ( (q = trig_arg(arg)) != -1 )
 385         {
 386           FPU_REG rv;
 387           
 388           if ( !(q & 1) )
 389             reg_sub(&CONST_1, arg, arg);
 390           
 391           poly_sine(arg, &rv);
 392           
 393           setcc(0);
 394           if ((q+1) & 2)
 395             rv.sign ^= SIGN_POS ^ SIGN_NEG;
 396           reg_move(&rv, arg);
 397           
 398           return 0;
 399         }
 400       else
 401         {
 402           /* Operand is out of range */
 403           setcc(SW_C2);
 404           arg->sign = arg_sign;         /* restore st(0) */
 405           EXCEPTION(EX_Invalid);
 406           return 1;
 407         }
 408     }
 409   else if ( arg->tag == TW_Zero )
 410     {
 411       reg_move(&CONST_1, arg);
 412       setcc(0);
 413       return 0;
 414     }
 415   else if ( FPU_st0_tag == TW_Infinity )
 416     {
 417       arith_invalid(FPU_st0_ptr);
 418       setcc(0);
 419       return 1;
 420     }
 421   else
 422     {
 423       single_arg_error();  /* requires arg == &st(0) */
 424       return 1;
 425     }
 426 }
 427 
 428 
 429 static void fcos()
     /* [previous][next][first][last][top][bottom][index][help] */
 430 {
 431   f_cos(FPU_st0_ptr);
 432 }
 433 
 434 
 435 static void fsincos()
     /* [previous][next][first][last][top][bottom][index][help] */
 436 {
 437   FPU_REG *st_new_ptr;
 438   FPU_REG arg;
 439           
 440   if ( STACK_OVERFLOW )
 441     { stack_overflow(); return; }
 442 
 443   reg_move(FPU_st0_ptr,&arg);
 444   if ( !f_cos(&arg) )
 445     {
 446       fsin();
 447       push();
 448       reg_move(&arg,FPU_st0_ptr);
 449     }
 450 
 451 }
 452 
 453 
 454 /*---------------------------------------------------------------------------*/
 455 /* The following all require two arguments: st(0) and st(1) */
 456 
 457 /* remainder of st(0) / st(1) */
 458 /* Assumes that st(0) and st(1) are both TW_Valid */
 459 static void fprem_kernel(int round)
     /* [previous][next][first][last][top][bottom][index][help] */
 460 {
 461   FPU_REG *st1_ptr = &st(1);
 462   char st1_tag = st1_ptr->tag;
 463 
 464   if ( !((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
 465     {
 466       FPU_REG tmp;
 467       int old_cw = control_word;
 468       int expdif = FPU_st0_ptr->exp - (st1_ptr)->exp;
 469       
 470       control_word &= ~CW_RC;
 471       control_word |= round;
 472       
 473       if (expdif < 64)
 474         {
 475           /* This should be the most common case */
 476           long long q;
 477           int c = 0;
 478           reg_div(FPU_st0_ptr, st1_ptr, &tmp);
 479           
 480           round_to_int(&tmp);  /* Fortunately, this can't overflow to 2^64 */
 481           tmp.exp = EXP_BIAS + 63;
 482           q = *(long long *)&(tmp.sigl);
 483           normalize(&tmp);
 484           
 485           reg_mul(st1_ptr, &tmp, &tmp);
 486           reg_sub(FPU_st0_ptr, &tmp, FPU_st0_ptr);
 487           
 488           if (q&4) c |= SW_C3;
 489           if (q&2) c |= SW_C1;
 490           if (q&1) c |= SW_C0;
 491           
 492           setcc(c);
 493         }
 494       else
 495         {
 496           /* There is a large exponent difference ( >= 64 ) */
 497           int N_exp;
 498           
 499           reg_div(FPU_st0_ptr, st1_ptr, &tmp);
 500           /* N is 'a number between 32 and 63' (p26-113) */
 501           N_exp = (tmp.exp & 31) + 32;
 502           tmp.exp = EXP_BIAS + N_exp;
 503           
 504           round_to_int(&tmp);  /* Fortunately, this can't overflow to 2^64 */
 505           tmp.exp = EXP_BIAS + 63;
 506           normalize(&tmp);
 507           
 508           tmp.exp = EXP_BIAS + expdif - N_exp;
 509           
 510           reg_mul(st1_ptr, &tmp, &tmp);
 511           reg_sub(FPU_st0_ptr, &tmp, FPU_st0_ptr);
 512           
 513           setcc(SW_C2);
 514         }
 515       control_word = old_cw;
 516 
 517       if ( FPU_st0_ptr->exp <= EXP_UNDER )
 518         arith_underflow(FPU_st0_ptr);
 519       return;
 520     }
 521   else if ( (FPU_st0_tag == TW_Empty) | (st1_tag == TW_Empty) )
 522     { stack_underflow(); return; }
 523   else if ( FPU_st0_tag == TW_Zero )
 524     {
 525       if ( (st1_tag == TW_Valid) || (st1_tag == TW_Infinity) )
 526         { setcc(0); return; }
 527       if ( st1_tag == TW_Zero )
 528         { arith_invalid(FPU_st0_ptr); return; }
 529     }
 530 
 531   if ( (FPU_st0_tag == TW_NaN) | (st1_tag == TW_NaN) )
 532     { real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr); return; }
 533   else if ( FPU_st0_tag == TW_Infinity )
 534     { arith_invalid(FPU_st0_ptr); return; }
 535 #ifdef PARANOID
 536   else
 537     EXCEPTION(EX_INTERNAL | 0x118);
 538 #endif PARANOID
 539 
 540 }
 541 
 542 
 543 /* ST(1) <- ST(1) * log ST;  pop ST */
 544 static void fyl2x()
     /* [previous][next][first][last][top][bottom][index][help] */
 545 {
 546   FPU_REG *st1_ptr = &st(1);
 547   char st1_tag = st1_ptr->tag;
 548 
 549   if ( !((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
 550     {
 551       if ( FPU_st0_ptr->sign == SIGN_POS )
 552         {
 553           poly_l2(FPU_st0_ptr, FPU_st0_ptr);
 554           
 555           reg_mul(FPU_st0_ptr, st1_ptr, st1_ptr);
 556           pop(); FPU_st0_ptr = &st(0);
 557           if ( FPU_st0_ptr->exp <= EXP_UNDER )
 558             arith_underflow(FPU_st0_ptr);
 559           else if ( FPU_st0_ptr->exp >= EXP_OVER )
 560             arith_overflow(FPU_st0_ptr);
 561         }
 562       else
 563         {
 564           /* negative   */
 565           pop(); FPU_st0_ptr = &st(0);
 566           arith_invalid(FPU_st0_ptr);
 567         }
 568       return;
 569     }
 570 
 571   if ( (FPU_st0_tag == TW_Empty) || (st1_tag == TW_Empty) )
 572     { stack_underflow(); return; }
 573 
 574   if ( (FPU_st0_tag == TW_NaN) || (st1_tag == TW_NaN) )
 575     {
 576       real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr);
 577       pop();
 578       return;
 579     }
 580 
 581   if ( (FPU_st0_tag <= TW_Zero) && (st1_tag <= TW_Zero) )
 582     {
 583       /* one of the args is zero, the other valid, or both zero */
 584       if ( FPU_st0_tag == TW_Zero )
 585         {
 586           pop(); FPU_st0_ptr = &st(0);
 587           if ( FPU_st0_ptr->tag == TW_Zero )
 588             arith_invalid(FPU_st0_ptr);
 589           else
 590             divide_by_zero(st1_ptr->sign ^ SIGN_NEG, FPU_st0_ptr);
 591           return;
 592         }
 593       if ( st1_ptr->sign == SIGN_POS )
 594         {
 595           /* Zero is the valid answer */
 596           char sign = FPU_st0_ptr->sign;
 597           if ( FPU_st0_ptr->exp < EXP_BIAS ) sign ^= SIGN_NEG;
 598           pop(); FPU_st0_ptr = &st(0);
 599           reg_move(&CONST_Z, FPU_st0_ptr);
 600           FPU_st0_ptr->sign = sign;
 601           return;
 602         }
 603       pop(); FPU_st0_ptr = &st(0);
 604       arith_invalid(FPU_st0_ptr);
 605       return;
 606     }
 607 
 608   /* One or both arg must be an infinity */
 609   if ( FPU_st0_tag == TW_Infinity )
 610     {
 611       if ( (FPU_st0_ptr->sign == SIGN_NEG) || (st1_tag == TW_Zero) )
 612         { pop(); FPU_st0_ptr = &st(0); arith_invalid(FPU_st0_ptr); return; }
 613       else
 614         {
 615           char sign = st1_ptr->sign;
 616           pop(); FPU_st0_ptr = &st(0);
 617           reg_move(&CONST_INF, FPU_st0_ptr);
 618           FPU_st0_ptr->sign = sign;
 619           return;
 620         }
 621     }
 622 
 623   /* st(1) must be infinity here */
 624   if ( (FPU_st0_tag == TW_Valid) && (FPU_st0_ptr->sign == SIGN_POS) )
 625     {
 626       if ( FPU_st0_ptr->exp >= EXP_BIAS )
 627         {
 628           if ( (FPU_st0_ptr->exp == EXP_BIAS) &&
 629               (FPU_st0_ptr->sigh == 0x80000000) &&
 630               (FPU_st0_ptr->sigl == 0) )
 631             {
 632               pop(); FPU_st0_ptr = &st(0);
 633               arith_invalid(FPU_st0_ptr);
 634               return;
 635             }
 636           pop();
 637           return;
 638         }
 639       else
 640         {
 641           pop(); FPU_st0_ptr = &st(0);
 642           FPU_st0_ptr->sign ^= SIGN_NEG;
 643           return;
 644         }
 645     }
 646   /* st(0) must be zero or negative */
 647   pop(); FPU_st0_ptr = &st(0);
 648   arith_invalid(FPU_st0_ptr);
 649   return;
 650 }
 651 
 652 
 653 static void fpatan()
     /* [previous][next][first][last][top][bottom][index][help] */
 654 {
 655   FPU_REG *st1_ptr = &st(1);
 656   char st1_tag = st1_ptr->tag;
 657 
 658   if ( !((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
 659     {
 660       FPU_REG sum;
 661       int quadrant = st1_ptr->sign | ((FPU_st0_ptr->sign)<<1);
 662       st1_ptr->sign = FPU_st0_ptr->sign = SIGN_POS;
 663       if (compare(st1_ptr) == COMP_A_LT_B)
 664         {
 665           quadrant |= 4;
 666           reg_div(FPU_st0_ptr, st1_ptr, &sum);
 667         }
 668       else
 669         reg_div(st1_ptr, FPU_st0_ptr, &sum);
 670       
 671       poly_atan(&sum);
 672       
 673       if (quadrant & 4)
 674         {
 675           reg_sub(&CONST_PI2, &sum, &sum);
 676         }
 677       if (quadrant & 2)
 678         {
 679           reg_sub(&CONST_PI, &sum, &sum);
 680         }
 681       if (quadrant & 1)
 682         sum.sign ^= SIGN_POS^SIGN_NEG;
 683       
 684       reg_move(&sum, st1_ptr);
 685       pop(); FPU_st0_ptr = &st(0);
 686       if ( FPU_st0_ptr->exp <= EXP_UNDER )
 687         arith_underflow(FPU_st0_ptr);
 688       return;
 689     }
 690 
 691   if ( (FPU_st0_tag == TW_Empty) || (st1_tag == TW_Empty) )
 692     { stack_underflow(); return; }
 693 
 694   if ( (FPU_st0_tag == TW_NaN) || (st1_tag == TW_NaN) )
 695     {
 696       real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr);
 697       pop();
 698       return;
 699     }
 700 
 701   if ( (FPU_st0_tag == TW_Infinity) || (st1_tag == TW_Infinity) )
 702     {
 703       char sign = st1_ptr->sign;
 704       if ( FPU_st0_tag == TW_Infinity )
 705         {
 706           if ( st1_tag == TW_Infinity )
 707             {
 708               if ( FPU_st0_ptr->sign == SIGN_POS )
 709                 { reg_move(&CONST_PI4, st1_ptr); }
 710               else
 711                 reg_add(&CONST_PI4, &CONST_PI2, st1_ptr);
 712             }
 713           else
 714             {
 715               if ( FPU_st0_ptr->sign == SIGN_POS )
 716                 { reg_move(&CONST_Z, st1_ptr); }
 717               else
 718                 reg_move(&CONST_PI, st1_ptr);
 719             }
 720         }
 721       else
 722         {
 723           reg_move(&CONST_PI2, st1_ptr);
 724         }
 725       st1_ptr->sign = sign;
 726       pop();
 727       return;
 728     }
 729 
 730  if ( st1_tag == TW_Zero )
 731     {
 732       char sign = st1_ptr->sign;
 733       /* st(0) must be valid or zero */
 734       if ( FPU_st0_ptr->sign == SIGN_POS )
 735         { reg_move(&CONST_Z, st1_ptr); }
 736       else
 737         reg_move(&CONST_PI, st1_ptr);
 738       st1_tag = sign;
 739       pop();
 740       return;
 741     }
 742   else if ( FPU_st0_tag == TW_Zero )
 743     {
 744       char sign = st1_ptr->sign;
 745       /* st(1) must be TW_Valid here */
 746       reg_move(&CONST_PI2, st1_ptr);
 747       st1_tag = sign;
 748       pop();
 749       return;
 750     }
 751 #ifdef PARANOID
 752   EXCEPTION(EX_INTERNAL | 0x220);
 753 #endif PARANOID
 754 }
 755 
 756 
 757 static void fprem()
     /* [previous][next][first][last][top][bottom][index][help] */
 758 {
 759   fprem_kernel(RC_CHOP);
 760 }
 761 
 762 
 763 static void fprem1()
     /* [previous][next][first][last][top][bottom][index][help] */
 764 {
 765   fprem_kernel(RC_RND);
 766 }
 767 
 768 
 769 static void fyl2xp1()
     /* [previous][next][first][last][top][bottom][index][help] */
 770 {
 771   FPU_REG *st1_ptr = &st(1);
 772   char st1_tag = st1_ptr->tag;
 773 
 774   if ( !((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
 775     {
 776       if ( poly_l2p1(FPU_st0_ptr, FPU_st0_ptr) )
 777         {
 778           arith_invalid(st1_ptr); pop(); return;
 779         }
 780       
 781       reg_mul(FPU_st0_ptr, st1_ptr, st1_ptr);
 782       pop();
 783       return;
 784     }
 785   else if ( (FPU_st0_tag == TW_Empty) | (st1_tag == TW_Empty) )
 786     stack_underflow();
 787   else if ( FPU_st0_tag == TW_Zero )
 788     {
 789       if ( st1_tag <= TW_Zero )
 790         {
 791           st1_ptr->sign ^= FPU_st0_ptr->sign;
 792           reg_move(FPU_st0_ptr, st1_ptr);
 793         }
 794       else if ( st1_tag == TW_Infinity )
 795         {
 796           arith_invalid(st1_ptr);
 797         }
 798       else if ( st1_tag == TW_NaN )
 799         {
 800           if ( !(st1_ptr->sigh & 0x40000000) )
 801             EXCEPTION(EX_Invalid);            /* signaling NaN */
 802           st1_ptr->sigh |= 0x40000000;     /* QNaN */
 803         }
 804 #ifdef PARANOID
 805       else
 806         {
 807           EXCEPTION(EX_INTERNAL | 0x116);
 808         }
 809 #endif PARANOID
 810       pop();
 811       return;
 812     }
 813   else if ( FPU_st0_tag == TW_NaN )
 814     {
 815       real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr);
 816       pop();
 817       return;
 818     }
 819   else if ( FPU_st0_tag == TW_Infinity )
 820     {
 821       if ( st1_tag == TW_NaN )
 822         real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr);
 823       else
 824         arith_invalid(st1_ptr);
 825       pop();
 826       return;
 827     }
 828 #ifdef PARANOID
 829   else
 830     EXCEPTION(EX_INTERNAL | 0x117);
 831 #endif PARANOID
 832 }
 833 
 834 
 835 static void fscale()
     /* [previous][next][first][last][top][bottom][index][help] */
 836 {
 837   FPU_REG *st1_ptr = &st(1);
 838   char st1_tag = st1_ptr->tag;
 839 
 840   if ( !((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
 841     {
 842       long scale;
 843       FPU_REG tmp;
 844 
 845       /* 2^31 is far too large, 2^-31 is far too small */
 846       if ( st1_ptr->exp > EXP_BIAS + 30 )
 847         {
 848           char sign;
 849           EXCEPTION(EX_Overflow);
 850           sign = FPU_st0_ptr->sign;
 851           reg_move(&CONST_INF, FPU_st0_ptr);
 852           FPU_st0_ptr->sign = sign;
 853           return;
 854         }
 855       else if ( st1_ptr->exp < EXP_BIAS - 30 )
 856         {
 857           EXCEPTION(EX_Underflow);
 858           reg_move(&CONST_Z, FPU_st0_ptr);
 859           return;
 860         }
 861 
 862       reg_move(st1_ptr, &tmp);
 863       round_to_int(&tmp);               /* This can never overflow here */
 864       scale = st1_ptr->sign ? -tmp.sigl : tmp.sigl;
 865       scale += FPU_st0_ptr->exp;
 866       FPU_st0_ptr->exp = scale;
 867 
 868       if ( scale <= EXP_UNDER )
 869         arith_underflow(FPU_st0_ptr);
 870       else if ( scale >= EXP_OVER )
 871         arith_overflow(FPU_st0_ptr);
 872 
 873       return;
 874     }
 875   else if ( FPU_st0_tag == TW_Valid )
 876     {
 877       if ( st1_tag == TW_Zero )
 878         { return; }
 879       if ( st1_tag == TW_Infinity )
 880         {
 881           char sign = st1_ptr->sign;
 882           if ( sign == SIGN_POS )
 883             { reg_move(&CONST_INF, FPU_st0_ptr); }
 884           else
 885               reg_move(&CONST_Z, FPU_st0_ptr);
 886           FPU_st0_ptr->sign = sign;
 887           return;
 888         }
 889       if ( st1_tag == TW_NaN )
 890         { real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr); return; }
 891     }
 892   else if ( FPU_st0_tag == TW_Zero )
 893     {
 894       if ( st1_tag <= TW_Zero ) { return; }
 895       else if ( st1_tag == TW_Infinity )
 896         {
 897           if ( st1_ptr->sign == SIGN_NEG )
 898             return;
 899           else
 900             { arith_invalid(FPU_st0_ptr); return; }
 901         }
 902       else if ( st1_tag == TW_NaN )
 903         { real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr); return; }
 904     }
 905   else if ( FPU_st0_tag == TW_Infinity )
 906     {
 907       if ( ((st1_tag == TW_Infinity) && (st1_ptr->sign == SIGN_POS))
 908           || (st1_tag <= TW_Zero) )
 909         return;
 910       else if ( st1_tag == TW_Infinity )
 911         { arith_invalid(FPU_st0_ptr); return; }
 912       else if ( st1_tag == TW_NaN )
 913         { real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr); return; }
 914     }
 915   else if ( FPU_st0_tag == TW_NaN )
 916     {
 917       if ( st1_tag != TW_Empty )
 918         { real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr); return; }
 919     }
 920 
 921 #ifdef PARANOID
 922   if ( !((FPU_st0_tag == TW_Empty) || (st1_tag == TW_Empty)) )
 923     {
 924       EXCEPTION(EX_INTERNAL | 0x115);
 925       return;
 926     }
 927 #endif
 928 
 929   /* At least one of st(0), st(1) must be empty */
 930   stack_underflow();
 931 
 932 }
 933 
 934 
 935 /*---------------------------------------------------------------------------*/
 936 
 937 static FUNC trig_table_a[] = {
 938   f2xm1, fyl2x, fptan, fpatan, fxtract, fprem1, fdecstp, fincstp
 939 };
 940 
 941 void trig_a()
     /* [previous][next][first][last][top][bottom][index][help] */
 942 {
 943   (trig_table_a[FPU_rm])();
 944 }
 945 
 946 
 947 static FUNC trig_table_b[] =
 948   {
 949     fprem, fyl2xp1, fsqrt_, fsincos, frndint_, fscale, fsin, fcos
 950   };
 951 
 952 void trig_b()
     /* [previous][next][first][last][top][bottom][index][help] */
 953 {
 954   (trig_table_b[FPU_rm])();
 955 }

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