|
|
1.1 ! root 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 [email protected] | ! 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) ! 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, "); ! 32: reg_div(", &CONST_PI2, "); ! 33: ! 34: reg_move(", &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(", &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) ! 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) ! 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() ! 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() ! 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() ! 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() ! 262: { ! 263: top--; /* FPU_st0_ptr will be fixed in math_emulate() before the next instr */ ! 264: } ! 265: ! 266: static void fincstp() ! 267: { ! 268: top++; /* FPU_st0_ptr will be fixed in math_emulate() before the next instr */ ! 269: } ! 270: ! 271: ! 272: static void fsqrt_() ! 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_() ! 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() ! 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) ! 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() ! 430: { ! 431: f_cos(FPU_st0_ptr); ! 432: } ! 433: ! 434: ! 435: static void fsincos() ! 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) ! 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() ! 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() ! 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 (emCompare(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() ! 758: { ! 759: fprem_kernel(RC_CHOP); ! 760: } ! 761: ! 762: ! 763: static void fprem1() ! 764: { ! 765: fprem_kernel(RC_RND); ! 766: } ! 767: ! 768: ! 769: static void fyl2xp1() ! 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() ! 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() ! 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() ! 953: { ! 954: (trig_table_b[FPU_rm])(); ! 955: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.