|
|
1.1 ! root 1: /*---------------------------------------------------------------------------+ ! 2: | reg_ld_str.c | ! 3: | | ! 4: | All of the functions which transfer data between user memory and FPU_REGs.| ! 5: | | ! 6: | Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | ! 7: | Australia. E-mail [email protected] | ! 8: | | ! 9: | | ! 10: +---------------------------------------------------------------------------*/ ! 11: ! 12: /*---------------------------------------------------------------------------+ ! 13: | Note: | ! 14: | The file contains code which accesses user memory. | ! 15: | Emulator static data may change when user memory is accessed, due to | ! 16: | other processes using the emulator while swapping is in progress. | ! 17: +---------------------------------------------------------------------------*/ ! 18: ! 19: #include <asm/segment.h> ! 20: ! 21: #include "fpu_system.h" ! 22: #include "exception.h" ! 23: #include "reg_constant.h" ! 24: #include "fpu_emu.h" ! 25: #include "control_w.h" ! 26: #include "status_w.h" ! 27: ! 28: #define EXTENDED_Emax 0x3fff /* largest valid exponent */ ! 29: #define EXTENDED_Ebias 0x3fff ! 30: #define EXTENDED_Emin (-0x3ffe) /* smallest valid exponent */ ! 31: ! 32: #define DOUBLE_Emax 1023 /* largest valid exponent */ ! 33: #define DOUBLE_Ebias 1023 ! 34: #define DOUBLE_Emin (-1022) /* smallest valid exponent */ ! 35: ! 36: #define SINGLE_Emax 127 /* largest valid exponent */ ! 37: #define SINGLE_Ebias 127 ! 38: #define SINGLE_Emin (-126) /* smallest valid exponent */ ! 39: ! 40: ! 41: FPU_REG FPU_loaded_data; ! 42: ! 43: ! 44: /* Get a long double from user memory */ ! 45: void reg_load_extended(void) ! 46: { ! 47: long double *s = (long double *)FPU_data_address; ! 48: unsigned long sigl, sigh, exp; ! 49: ! 50: RE_ENTRANT_CHECK_OFF ! 51: /* Use temporary variables here because FPU_loaded data is ! 52: static and hence re-entrancy problems can arise */ ! 53: sigl = get_fs_long((unsigned long *) s); ! 54: sigh = get_fs_long(1 + (unsigned long *) s); ! 55: exp = get_fs_word(4 + (unsigned short *) s); ! 56: RE_ENTRANT_CHECK_ON ! 57: ! 58: FPU_loaded_data.sigl = sigl; ! 59: FPU_loaded_data.sigh = sigh; ! 60: FPU_loaded_data.exp = exp; ! 61: ! 62: if (FPU_loaded_data.exp & 0x8000) ! 63: FPU_loaded_data.sign = SIGN_NEG; ! 64: else ! 65: FPU_loaded_data.sign = SIGN_POS; ! 66: if ( (FPU_loaded_data.exp &= 0x7fff) == 0 ) ! 67: { ! 68: if ( !(FPU_loaded_data.sigl | FPU_loaded_data.sigh) ) ! 69: { ! 70: FPU_loaded_data.tag = TW_Zero; ! 71: return; ! 72: } ! 73: /* The number is de-normal */ ! 74: /* The default behaviour will take care of this */ ! 75: } ! 76: else if ( FPU_loaded_data.exp == 0x7fff ) ! 77: { ! 78: FPU_loaded_data.exp = EXTENDED_Emax; ! 79: if ( (FPU_loaded_data.sigh == 0x80000000) ! 80: && (FPU_loaded_data.sigl == 0) ) ! 81: { ! 82: FPU_loaded_data.tag = TW_Infinity; ! 83: return; ! 84: } ! 85: if ( !(FPU_loaded_data.sigh & 0x80000000) ) ! 86: { ! 87: /* Unsupported data type */ ! 88: EXCEPTION(EX_Invalid); ! 89: FPU_loaded_data.tag = TW_NaN; ! 90: return; ! 91: } ! 92: FPU_loaded_data.tag = TW_NaN; ! 93: return; ! 94: } ! 95: FPU_loaded_data.exp = (FPU_loaded_data.exp & 0x7fff) - EXTENDED_Ebias ! 96: + EXP_BIAS; ! 97: FPU_loaded_data.tag = TW_Valid; ! 98: ! 99: normalize(&FPU_loaded_data); ! 100: } ! 101: ! 102: ! 103: /* Get a double from user memory */ ! 104: void reg_load_double(void) ! 105: { ! 106: double *dfloat = (double *)FPU_data_address; ! 107: int exp; ! 108: unsigned m64, l64; ! 109: ! 110: RE_ENTRANT_CHECK_OFF ! 111: m64 = get_fs_long(1 + (unsigned long *) dfloat); ! 112: l64 = get_fs_long((unsigned long *) dfloat); ! 113: RE_ENTRANT_CHECK_ON ! 114: ! 115: if (m64 & 0x80000000) ! 116: FPU_loaded_data.sign = SIGN_NEG; ! 117: else ! 118: FPU_loaded_data.sign = SIGN_POS; ! 119: exp = ((m64 & 0x7ff00000) >> 20) - DOUBLE_Ebias; ! 120: m64 &= 0xfffff; ! 121: if (exp > DOUBLE_Emax) ! 122: { ! 123: /* Infinity or NaN */ ! 124: if ((m64 == 0) && (l64 == 0)) ! 125: { ! 126: /* +- infinity */ ! 127: FPU_loaded_data.exp = EXTENDED_Emax; ! 128: FPU_loaded_data.tag = TW_Infinity; ! 129: return; ! 130: } ! 131: else ! 132: { ! 133: /* Must be a signaling or quiet NaN */ ! 134: FPU_loaded_data.exp = EXTENDED_Emax; ! 135: FPU_loaded_data.tag = TW_NaN; ! 136: FPU_loaded_data.sigh = (m64 << 11) | 0x80000000; ! 137: FPU_loaded_data.sigh |= l64 >> 21; ! 138: FPU_loaded_data.sigl = l64 << 11; ! 139: return; ! 140: } ! 141: } ! 142: else if ( exp < DOUBLE_Emin ) ! 143: { ! 144: /* Zero or de-normal */ ! 145: if ((m64 == 0) && (l64 == 0)) ! 146: { ! 147: /* Zero */ ! 148: int c = FPU_loaded_data.sign; ! 149: reg_move(&CONST_Z, &FPU_loaded_data); ! 150: FPU_loaded_data.sign = c; ! 151: return; ! 152: } ! 153: else ! 154: { ! 155: /* De-normal */ ! 156: FPU_loaded_data.exp = DOUBLE_Emin + EXP_BIAS; ! 157: FPU_loaded_data.tag = TW_Valid; ! 158: FPU_loaded_data.sigh = m64 << 11; ! 159: FPU_loaded_data.sigh |= l64 >> 21; ! 160: FPU_loaded_data.sigl = l64 << 11; ! 161: normalize(&FPU_loaded_data); ! 162: return; ! 163: } ! 164: } ! 165: else ! 166: { ! 167: FPU_loaded_data.exp = exp + EXP_BIAS; ! 168: FPU_loaded_data.tag = TW_Valid; ! 169: FPU_loaded_data.sigh = (m64 << 11) | 0x80000000; ! 170: FPU_loaded_data.sigh |= l64 >> 21; ! 171: FPU_loaded_data.sigl = l64 << 11; ! 172: ! 173: return; ! 174: } ! 175: } ! 176: ! 177: ! 178: /* Get a float from user memory */ ! 179: void reg_load_single(void) ! 180: { ! 181: float *single = (float *)FPU_data_address; ! 182: unsigned m32; ! 183: int exp; ! 184: ! 185: RE_ENTRANT_CHECK_OFF ! 186: m32 = get_fs_long((unsigned long *) single); ! 187: RE_ENTRANT_CHECK_ON ! 188: ! 189: if (m32 & 0x80000000) ! 190: FPU_loaded_data.sign = SIGN_NEG; ! 191: else ! 192: FPU_loaded_data.sign = SIGN_POS; ! 193: if (!(m32 & 0x7fffffff)) ! 194: { ! 195: /* Zero */ ! 196: int c = FPU_loaded_data.sign; ! 197: reg_move(&CONST_Z, &FPU_loaded_data); ! 198: FPU_loaded_data.sign = c; ! 199: return; ! 200: } ! 201: exp = ((m32 & 0x7f800000) >> 23) - SINGLE_Ebias; ! 202: m32 = (m32 & 0x7fffff) << 8; ! 203: if ( exp < SINGLE_Emin ) ! 204: { ! 205: /* De-normals */ ! 206: FPU_loaded_data.exp = SINGLE_Emin + EXP_BIAS; ! 207: FPU_loaded_data.tag = TW_Valid; ! 208: FPU_loaded_data.sigh = m32; ! 209: FPU_loaded_data.sigl = 0; ! 210: normalize(&FPU_loaded_data); ! 211: return; ! 212: } ! 213: else if ( exp > SINGLE_Emax ) ! 214: { ! 215: /* Infinity or NaN */ ! 216: if ( m32 == 0 ) ! 217: { ! 218: /* +- infinity */ ! 219: FPU_loaded_data.exp = EXTENDED_Emax; ! 220: FPU_loaded_data.tag = TW_Infinity; ! 221: return; ! 222: } ! 223: else ! 224: { ! 225: /* Must be a signaling or quiet NaN */ ! 226: FPU_loaded_data.exp = EXTENDED_Emax; ! 227: FPU_loaded_data.tag = TW_NaN; ! 228: FPU_loaded_data.sigh = m32 | 0x80000000; ! 229: FPU_loaded_data.sigl = 0; ! 230: return; ! 231: } ! 232: } ! 233: else ! 234: { ! 235: FPU_loaded_data.exp = exp + EXP_BIAS; ! 236: FPU_loaded_data.sigh = m32 | 0x80000000; ! 237: FPU_loaded_data.sigl = 0; ! 238: FPU_loaded_data.tag = TW_Valid; ! 239: } ! 240: } ! 241: ! 242: ! 243: /* Get a long long from user memory */ ! 244: void reg_load_int64(void) ! 245: { ! 246: long long *_s = (long long *)FPU_data_address; ! 247: int e; ! 248: long long s; ! 249: ! 250: RE_ENTRANT_CHECK_OFF ! 251: ((unsigned long *)&s)[0] = get_fs_long((unsigned long *) _s); ! 252: ((unsigned long *)&s)[1] = get_fs_long(1 + (unsigned long *) _s); ! 253: RE_ENTRANT_CHECK_ON ! 254: ! 255: if (s == 0) ! 256: { reg_move(&CONST_Z, &FPU_loaded_data); return; } ! 257: ! 258: if (s > 0) ! 259: FPU_loaded_data.sign = SIGN_POS; ! 260: else ! 261: { ! 262: s = -s; ! 263: FPU_loaded_data.sign = SIGN_NEG; ! 264: } ! 265: ! 266: e = EXP_BIAS + 63; ! 267: *((long long *)&FPU_loaded_data.sigl) = s; ! 268: FPU_loaded_data.exp = e; ! 269: FPU_loaded_data.tag = TW_Valid; ! 270: normalize(&FPU_loaded_data); ! 271: } ! 272: ! 273: ! 274: /* Get a long from user memory */ ! 275: void reg_load_int32(void) ! 276: { ! 277: long *_s = (long *)FPU_data_address; ! 278: long s; ! 279: int e; ! 280: ! 281: RE_ENTRANT_CHECK_OFF ! 282: s = (long)get_fs_long((unsigned long *) _s); ! 283: RE_ENTRANT_CHECK_ON ! 284: ! 285: if (s == 0) ! 286: { reg_move(&CONST_Z, &FPU_loaded_data); return; } ! 287: ! 288: if (s > 0) ! 289: FPU_loaded_data.sign = SIGN_POS; ! 290: else ! 291: { ! 292: s = -s; ! 293: FPU_loaded_data.sign = SIGN_NEG; ! 294: } ! 295: ! 296: e = EXP_BIAS + 31; ! 297: FPU_loaded_data.sigh = s; ! 298: FPU_loaded_data.sigl = 0; ! 299: FPU_loaded_data.exp = e; ! 300: FPU_loaded_data.tag = TW_Valid; ! 301: normalize(&FPU_loaded_data); ! 302: } ! 303: ! 304: ! 305: /* Get a short from user memory */ ! 306: void reg_load_int16(void) ! 307: { ! 308: short *_s = (short *)FPU_data_address; ! 309: long s; ! 310: int e; ! 311: ! 312: RE_ENTRANT_CHECK_OFF ! 313: s = (int)get_fs_word((unsigned short *) _s); ! 314: RE_ENTRANT_CHECK_ON ! 315: ! 316: if (s == 0) ! 317: { reg_move(&CONST_Z, &FPU_loaded_data); return; } ! 318: ! 319: if (s > 0) ! 320: FPU_loaded_data.sign = SIGN_POS; ! 321: else ! 322: { ! 323: s = -s; ! 324: FPU_loaded_data.sign = SIGN_NEG; ! 325: } ! 326: ! 327: e = EXP_BIAS + 31; ! 328: FPU_loaded_data.sigh = s; ! 329: FPU_loaded_data.sigl = 0; ! 330: FPU_loaded_data.exp = e; ! 331: FPU_loaded_data.tag = TW_Valid; ! 332: normalize(&FPU_loaded_data); ! 333: } ! 334: ! 335: ! 336: /* Get a packed bcd array from user memory */ ! 337: void reg_load_bcd(void) ! 338: { ! 339: char *s = (char *)FPU_data_address; ! 340: int pos; ! 341: unsigned char bcd; ! 342: long long l=0; ! 343: ! 344: for ( pos = 8; pos >= 0; pos--) ! 345: { ! 346: l *= 10; ! 347: RE_ENTRANT_CHECK_OFF ! 348: bcd = (unsigned char)get_fs_byte((unsigned char *) s+pos); ! 349: RE_ENTRANT_CHECK_ON ! 350: l += bcd >> 4; ! 351: l *= 10; ! 352: l += bcd & 0x0f; ! 353: } ! 354: ! 355: /* Finish all access to user memory before putting stuff into ! 356: the static FPU_loaded_data */ ! 357: RE_ENTRANT_CHECK_OFF ! 358: FPU_loaded_data.sign = ! 359: ((unsigned char)get_fs_byte((unsigned char *) s+9)) & 0x80 ? ! 360: SIGN_NEG : SIGN_POS; ! 361: RE_ENTRANT_CHECK_ON ! 362: ! 363: if (l == 0) ! 364: { ! 365: char sign = FPU_loaded_data.sign; ! 366: reg_move(&CONST_Z, &FPU_loaded_data); ! 367: FPU_loaded_data.sign = sign; ! 368: } ! 369: else ! 370: { ! 371: *((long long *)&FPU_loaded_data.sigl) = l; ! 372: FPU_loaded_data.exp = EXP_BIAS + 63; ! 373: FPU_loaded_data.tag = TW_Valid; ! 374: normalize(&FPU_loaded_data); ! 375: } ! 376: } ! 377: ! 378: /*===========================================================================*/ ! 379: ! 380: /* Put a long double into user memory */ ! 381: int reg_store_extended(void) ! 382: { ! 383: long double *d = (long double *)FPU_data_address; ! 384: long e = FPU_st0_ptr->exp - EXP_BIAS + EXTENDED_Ebias; ! 385: unsigned short sign = FPU_st0_ptr->sign*0x8000; ! 386: unsigned long ls, ms; ! 387: ! 388: ! 389: if ( FPU_st0_tag == TW_Valid ) ! 390: { ! 391: if ( e >= 0x7fff ) ! 392: { ! 393: EXCEPTION(EX_Overflow); /* Overflow */ ! 394: /* This is a special case: see sec 16.2.5.1 of the 80486 book */ ! 395: if ( control_word & EX_Overflow ) ! 396: { ! 397: /* Overflow to infinity */ ! 398: ls = 0; ! 399: ms = 0x80000000; ! 400: e = 0x7fff; ! 401: } ! 402: else ! 403: return 0; ! 404: } ! 405: else if ( e <= 0 ) ! 406: { ! 407: if ( e == 0 ) ! 408: { ! 409: EXCEPTION(EX_Denormal); /* Pseudo de-normal */ ! 410: ls = FPU_st0_ptr->sigl; ! 411: ms = FPU_st0_ptr->sigh; ! 412: } ! 413: else if ( e > -64 ) ! 414: { ! 415: /* Make a de-normal */ ! 416: FPU_REG tmp; ! 417: EXCEPTION(EX_Denormal); /* De-normal */ ! 418: reg_move(FPU_st0_ptr, &tmp); ! 419: tmp.exp += -EXTENDED_Emin + 64; /* largest exp to be 63 */ ! 420: round_to_int(&tmp); ! 421: e = 0; ! 422: ls = tmp.sigl; ! 423: ms = tmp.sigh; ! 424: } ! 425: else ! 426: { ! 427: EXCEPTION(EX_Underflow); /* Underflow */ ! 428: /* This is a special case: see sec 16.2.5.1 of the 80486 book */ ! 429: if ( control_word & EX_Underflow ) ! 430: { ! 431: /* Underflow to zero */ ! 432: ls = 0; ! 433: ms = 0; ! 434: e = 0; ! 435: } ! 436: else ! 437: return 0; ! 438: } ! 439: } ! 440: else ! 441: { ! 442: ls = FPU_st0_ptr->sigl; ! 443: ms = FPU_st0_ptr->sigh; ! 444: } ! 445: } ! 446: else if ( FPU_st0_tag == TW_Zero ) ! 447: { ! 448: ls = ms = 0; ! 449: e = 0; ! 450: } ! 451: else if ( FPU_st0_tag == TW_Infinity ) ! 452: { ! 453: ls = 0; ! 454: ms = 0x80000000; ! 455: e = 0x7fff; ! 456: } ! 457: else if ( FPU_st0_tag == TW_NaN ) ! 458: { ! 459: ls = FPU_st0_ptr->sigl; ! 460: ms = FPU_st0_ptr->sigh; ! 461: e = 0x7fff; ! 462: } ! 463: else if ( FPU_st0_tag == TW_Empty ) ! 464: { ! 465: /* Empty register (stack underflow) */ ! 466: EXCEPTION(EX_StackUnder); ! 467: if ( control_word & EX_Invalid ) ! 468: { ! 469: /* The masked response */ ! 470: /* Put out the QNaN indefinite */ ! 471: ls = 0; ! 472: ms = 0xc0000000; ! 473: e = 0xffff; ! 474: } ! 475: else ! 476: return 0; ! 477: } ! 478: else ! 479: { ! 480: /* We don't use TW_Denormal yet ... perhaps never! */ ! 481: EXCEPTION(EX_Invalid); ! 482: /* Store a NaN */ ! 483: e = 0x7fff; ! 484: ls = 1; ! 485: ms = 0x80000000; ! 486: } ! 487: RE_ENTRANT_CHECK_OFF ! 488: #ifdef COHERENT ! 489: if (verify_area(d,10)) { ! 490: put_fs_long(ls, (unsigned long *) d); ! 491: put_fs_long(ms, 1 + (unsigned long *) d); ! 492: put_fs_word((unsigned short)e | sign, 4 + (short *) d); ! 493: } ! 494: #else ! 495: verify_area(d,10); ! 496: put_fs_long(ls, (unsigned long *) d); ! 497: put_fs_long(ms, 1 + (unsigned long *) d); ! 498: put_fs_word((unsigned short)e | sign, 4 + (short *) d); ! 499: #endif ! 500: RE_ENTRANT_CHECK_ON ! 501: ! 502: return 1; ! 503: ! 504: } ! 505: ! 506: /* Put a double into user memory */ ! 507: int reg_store_double(void) ! 508: { ! 509: double *dfloat = (double *)FPU_data_address; ! 510: unsigned long l[2]; ! 511: ! 512: ! 513: if (FPU_st0_tag == TW_Valid) ! 514: { ! 515: /* Rounding can get a little messy.. */ ! 516: int exp = FPU_st0_ptr->exp - EXP_BIAS; ! 517: int increment = ((FPU_st0_ptr->sigl & 0x7ff) > 0x400) | /* nearest */ ! 518: ((FPU_st0_ptr->sigl & 0xc00) == 0xc00); /* odd -> even */ ! 519: if ( increment ) ! 520: { ! 521: if ( FPU_st0_ptr->sigl >= 0xfffff800 ) ! 522: { ! 523: /* the sigl part overflows */ ! 524: if ( FPU_st0_ptr->sigh == 0xffffffff ) ! 525: { ! 526: /* The sigh part overflows */ ! 527: l[0] = l[1] = 0; ! 528: exp++; /* no need to check here for overflow */ ! 529: } ! 530: else ! 531: { ! 532: /* No overflow of sigh will happen, can safely increment */ ! 533: l[0] = (FPU_st0_ptr->sigh+1) << 21; ! 534: l[1] = (((FPU_st0_ptr->sigh+1) >> 11) & 0xfffff); ! 535: } ! 536: } ! 537: else ! 538: { ! 539: /* We only need to increment sigl */ ! 540: l[0] = ((FPU_st0_ptr->sigl+0x800) >> 11) | (FPU_st0_ptr->sigh << 21); ! 541: l[1] = ((FPU_st0_ptr->sigh >> 11) & 0xfffff); ! 542: } ! 543: } ! 544: else ! 545: { ! 546: /* No increment required */ ! 547: l[0] = (FPU_st0_ptr->sigl >> 11) | (FPU_st0_ptr->sigh << 21); ! 548: l[1] = ((FPU_st0_ptr->sigh >> 11) & 0xfffff); ! 549: } ! 550: ! 551: if ( exp > DOUBLE_Emax ) ! 552: { ! 553: EXCEPTION(EX_Overflow); ! 554: /* This is a special case: see sec 16.2.5.1 of the 80486 book */ ! 555: if ( control_word & EX_Overflow ) ! 556: { ! 557: /* Overflow to infinity */ ! 558: l[0] = 0x00000000; /* Set to */ ! 559: l[1] = 0x7ff00000; /* + INF */ ! 560: } ! 561: else ! 562: return 0; ! 563: } ! 564: else if ( exp < DOUBLE_Emin ) ! 565: { ! 566: if ( exp > DOUBLE_Emin-53 ) ! 567: { ! 568: /* Make a de-normal */ ! 569: FPU_REG tmp; ! 570: EXCEPTION(EX_Denormal); ! 571: reg_move(FPU_st0_ptr, &tmp); ! 572: tmp.exp += -DOUBLE_Emin + 52; /* largest exp to be 51 */ ! 573: round_to_int(&tmp); ! 574: l[0] = tmp.sigl; ! 575: l[1] = tmp.sigh; ! 576: } ! 577: else ! 578: { ! 579: EXCEPTION(EX_Underflow); ! 580: /* This is a special case: see sec 16.2.5.1 of the 80486 book */ ! 581: if ( control_word & EX_Underflow ) ! 582: { ! 583: /* Underflow to zero */ ! 584: l[0] = l[1] = 0; ! 585: } ! 586: else ! 587: return 0; ! 588: } ! 589: } ! 590: else ! 591: { ! 592: /* Add the exponent */ ! 593: l[1] |= (((exp+DOUBLE_Ebias) & 0x7ff) << 20); ! 594: } ! 595: } ! 596: else if (FPU_st0_tag == TW_Zero) ! 597: { ! 598: /* Number is zero */ ! 599: l[0] = l[1] = 0; ! 600: } ! 601: else if (FPU_st0_tag == TW_Infinity) ! 602: { ! 603: l[0] = 0; ! 604: l[1] = 0x7ff00000; ! 605: } ! 606: else if (FPU_st0_tag == TW_NaN) ! 607: { ! 608: /* See if we can get a valid NaN from the FPU_REG */ ! 609: l[0] = (FPU_st0_ptr->sigl >> 11) | (FPU_st0_ptr->sigh << 21); ! 610: l[1] = ((FPU_st0_ptr->sigh >> 11) & 0xfffff); ! 611: if ( !(l[0] | l[1]) ) ! 612: { ! 613: /* This case does not seem to be handled by the 80486 specs */ ! 614: EXCEPTION(EX_Invalid); ! 615: /* Make the quiet NaN "real indefinite" */ ! 616: goto put_indefinite; ! 617: } ! 618: l[1] |= 0x7ff00000; ! 619: } ! 620: else if ( FPU_st0_tag == TW_Empty ) ! 621: { ! 622: /* Empty register (stack underflow) */ ! 623: EXCEPTION(EX_StackUnder); ! 624: if ( control_word & EX_Invalid ) ! 625: { ! 626: /* The masked response */ ! 627: /* Put out the QNaN indefinite */ ! 628: put_indefinite: ! 629: RE_ENTRANT_CHECK_OFF ! 630: #ifdef COHERENT ! 631: if (verify_area((void *)dfloat,8)) { ! 632: put_fs_long(0, (unsigned long *) dfloat); ! 633: put_fs_long(0xfff80000, 1 + (unsigned long *) dfloat); ! 634: } ! 635: #else ! 636: verify_area((void *)dfloat,8); ! 637: put_fs_long(0, (unsigned long *) dfloat); ! 638: put_fs_long(0xfff80000, 1 + (unsigned long *) dfloat); ! 639: #endif ! 640: RE_ENTRANT_CHECK_ON ! 641: return 1; ! 642: } ! 643: else ! 644: return 0; ! 645: } ! 646: else if (FPU_st0_tag == TW_Denormal) ! 647: { ! 648: /* Extended real -> double real will always underflow */ ! 649: l[0] = l[1] = 0; ! 650: EXCEPTION(EX_Underflow); ! 651: } ! 652: if (FPU_st0_ptr->sign) ! 653: l[1] |= 0x80000000; ! 654: ! 655: RE_ENTRANT_CHECK_OFF ! 656: #ifdef COHERENT ! 657: if (verify_area((void *)dfloat,8)) { ! 658: put_fs_long(l[0], (unsigned long *)dfloat); ! 659: put_fs_long(l[1], 1 + (unsigned long *)dfloat); ! 660: } ! 661: #else ! 662: verify_area((void *)dfloat,8); ! 663: put_fs_long(l[0], (unsigned long *)dfloat); ! 664: put_fs_long(l[1], 1 + (unsigned long *)dfloat); ! 665: #endif ! 666: RE_ENTRANT_CHECK_ON ! 667: ! 668: return 1; ! 669: ! 670: } ! 671: ! 672: ! 673: /* Put a float into user memory */ ! 674: int reg_store_single(void) ! 675: { ! 676: float *single = (float *)FPU_data_address; ! 677: long templ; ! 678: int exp = FPU_st0_ptr->exp - EXP_BIAS; ! 679: unsigned long sigh = FPU_st0_ptr->sigh; ! 680: ! 681: ! 682: if (FPU_st0_tag == TW_Valid) ! 683: { ! 684: if ( ((sigh & 0xff) > 0x80) /* more than half */ ! 685: || ((sigh & 0x180) == 0x180) ) /* round to even */ ! 686: { ! 687: /* Round up */ ! 688: if ( sigh >= 0xffffff00 ) ! 689: { ! 690: /* sigh would overflow */ ! 691: exp++; ! 692: sigh = 0x80000000; ! 693: } ! 694: else ! 695: { ! 696: sigh += 0x100; ! 697: } ! 698: } ! 699: templ = (sigh >> 8) & 0x007fffff; ! 700: if ( exp > SINGLE_Emax ) ! 701: { ! 702: EXCEPTION(EX_Overflow); ! 703: /* This is a special case: see sec 16.2.5.1 of the 80486 book */ ! 704: if ( control_word & EX_Overflow ) ! 705: { ! 706: /* Overflow to infinity */ ! 707: templ = 0x7f800000; ! 708: } ! 709: else ! 710: return 0; ! 711: } ! 712: else if ( exp < SINGLE_Emin ) ! 713: { ! 714: if ( exp > SINGLE_Emin-24 ) ! 715: { ! 716: /* Make a de-normal */ ! 717: FPU_REG tmp; ! 718: EXCEPTION(EX_Denormal); ! 719: reg_move(FPU_st0_ptr, &tmp); ! 720: tmp.exp += -SINGLE_Emin + 23; /* largest exp to be 22 */ ! 721: round_to_int(&tmp); ! 722: templ = tmp.sigl; ! 723: } ! 724: else ! 725: { ! 726: EXCEPTION(EX_Underflow); ! 727: /* This is a special case: see sec 16.2.5.1 of the 80486 book */ ! 728: if ( control_word & EX_Underflow ) ! 729: { ! 730: /* Underflow to zero */ ! 731: templ = 0; ! 732: } ! 733: else ! 734: return 0; ! 735: } ! 736: } ! 737: else ! 738: templ |= ((exp+SINGLE_Ebias) & 0xff) << 23; ! 739: } ! 740: else if (FPU_st0_tag == TW_Zero) ! 741: { ! 742: templ = 0; ! 743: } ! 744: else if (FPU_st0_tag == TW_Infinity) ! 745: { ! 746: templ = 0x7f800000; ! 747: } ! 748: else if (FPU_st0_tag == TW_NaN) ! 749: { ! 750: /* See if we can get a valid NaN from the FPU_REG */ ! 751: templ = FPU_st0_ptr->sigh >> 8; ! 752: if ( !(templ & 0x3fffff) ) ! 753: { ! 754: /* This case does not seem to be handled by the 80486 specs */ ! 755: EXCEPTION(EX_Invalid); ! 756: /* Make the quiet NaN "real indefinite" */ ! 757: goto put_indefinite; ! 758: } ! 759: templ |= 0x7f800000; ! 760: } ! 761: else if ( FPU_st0_tag == TW_Empty ) ! 762: { ! 763: /* Empty register (stack underflow) */ ! 764: EXCEPTION(EX_StackUnder); ! 765: if ( control_word & EX_Invalid ) ! 766: { ! 767: /* The masked response */ ! 768: /* Put out the QNaN indefinite */ ! 769: put_indefinite: ! 770: RE_ENTRANT_CHECK_OFF ! 771: #ifdef COHERENT ! 772: if (verify_area((void *)single,4)) ! 773: put_fs_long(0xffc00000, (unsigned long *) single); ! 774: #else ! 775: verify_area((void *)single,4); ! 776: put_fs_long(0xffc00000, (unsigned long *) single); ! 777: #endif ! 778: RE_ENTRANT_CHECK_ON ! 779: return 1; ! 780: } ! 781: else ! 782: return 0; ! 783: } ! 784: else if (FPU_st0_tag == TW_Denormal) ! 785: { ! 786: /* Extended real -> real will always underflow */ ! 787: templ = 0; ! 788: EXCEPTION(EX_Underflow); ! 789: } ! 790: #ifdef PARANOID ! 791: else ! 792: { ! 793: EXCEPTION(EX_INTERNAL|0x106); ! 794: return 0; ! 795: } ! 796: #endif ! 797: if (FPU_st0_ptr->sign) ! 798: templ |= 0x80000000; ! 799: ! 800: RE_ENTRANT_CHECK_OFF ! 801: #ifdef COHERENT ! 802: if (verify_area((void *)single,4)) ! 803: put_fs_long(templ,(unsigned long *) single); ! 804: #else ! 805: verify_area((void *)single,4); ! 806: put_fs_long(templ,(unsigned long *) single); ! 807: #endif ! 808: RE_ENTRANT_CHECK_ON ! 809: ! 810: return 1; ! 811: } ! 812: ! 813: ! 814: /* Put a long long into user memory */ ! 815: int reg_store_int64(void) ! 816: { ! 817: long long *d = (long long *)FPU_data_address; ! 818: FPU_REG t; ! 819: long long tll; ! 820: ! 821: if ( FPU_st0_tag == TW_Empty ) ! 822: { ! 823: /* Empty register (stack underflow) */ ! 824: EXCEPTION(EX_StackUnder); ! 825: if ( control_word & EX_Invalid ) ! 826: { ! 827: /* The masked response */ ! 828: /* Put out the QNaN indefinite */ ! 829: goto put_indefinite; ! 830: } ! 831: else ! 832: return 0; ! 833: } ! 834: ! 835: reg_move(FPU_st0_ptr, &t); ! 836: round_to_int(&t); ! 837: ((long *)&tll)[0] = t.sigl; ! 838: ((long *)&tll)[1] = t.sigh; ! 839: if ( (t.sigh & 0x80000000) && ! 840: !((t.sigh == 0x80000000) && (t.sigl == 0) && (t.sign == SIGN_NEG)) ) ! 841: { ! 842: EXCEPTION(EX_Invalid); ! 843: /* This is a special case: see sec 16.2.5.1 of the 80486 book */ ! 844: if ( control_word & EX_Invalid ) ! 845: { ! 846: /* Produce "indefinite" */ ! 847: put_indefinite: ! 848: ((long *)&tll)[1] = 0x80000000; ! 849: ((long *)&tll)[0] = 0; ! 850: } ! 851: else ! 852: return 0; ! 853: } ! 854: else if ( t.sign ) ! 855: tll = - tll; ! 856: ! 857: RE_ENTRANT_CHECK_OFF ! 858: #ifdef COHERENT ! 859: if (verify_area((void *)d,8)) { ! 860: put_fs_long(((long *)&tll)[0],(unsigned long *) d); ! 861: put_fs_long(((long *)&tll)[1],1 + (unsigned long *) d); ! 862: } ! 863: #else ! 864: verify_area((void *)d,8); ! 865: put_fs_long(((long *)&tll)[0],(unsigned long *) d); ! 866: put_fs_long(((long *)&tll)[1],1 + (unsigned long *) d); ! 867: #endif ! 868: RE_ENTRANT_CHECK_ON ! 869: ! 870: return 1; ! 871: } ! 872: ! 873: ! 874: /* Put a long into user memory */ ! 875: int reg_store_int32(void) ! 876: { ! 877: long *d = (long *)FPU_data_address; ! 878: FPU_REG t; ! 879: ! 880: if ( FPU_st0_tag == TW_Empty ) ! 881: { ! 882: /* Empty register (stack underflow) */ ! 883: EXCEPTION(EX_StackUnder); ! 884: if ( control_word & EX_Invalid ) ! 885: { ! 886: /* The masked response */ ! 887: /* Put out the QNaN indefinite */ ! 888: RE_ENTRANT_CHECK_OFF ! 889: #ifdef COHERENT ! 890: if (verify_area(d,4)) ! 891: put_fs_long(0x80000000, (unsigned long *) d); ! 892: #else ! 893: verify_area(d,4); ! 894: put_fs_long(0x80000000, (unsigned long *) d); ! 895: #endif ! 896: RE_ENTRANT_CHECK_ON ! 897: return 1; ! 898: } ! 899: else ! 900: return 0; ! 901: } ! 902: ! 903: reg_move(FPU_st0_ptr, &t); ! 904: round_to_int(&t); ! 905: if (t.sigh || ! 906: ((t.sigl & 0x80000000) && ! 907: !((t.sigl == 0x80000000) && (t.sign == SIGN_NEG))) ) ! 908: { ! 909: EXCEPTION(EX_Invalid); ! 910: /* This is a special case: see sec 16.2.5.1 of the 80486 book */ ! 911: if ( control_word & EX_Invalid ) ! 912: { ! 913: /* Produce "indefinite" */ ! 914: t.sigl = 0x80000000; ! 915: } ! 916: else ! 917: return 0; ! 918: } ! 919: else if ( t.sign ) ! 920: t.sigl = -(long)t.sigl; ! 921: ! 922: RE_ENTRANT_CHECK_OFF ! 923: #ifdef COHERENT ! 924: if (verify_area(d,4)) ! 925: put_fs_long(t.sigl, (unsigned long *) d); ! 926: #else ! 927: verify_area(d,4); ! 928: put_fs_long(t.sigl, (unsigned long *) d); ! 929: #endif ! 930: RE_ENTRANT_CHECK_ON ! 931: ! 932: return 1; ! 933: } ! 934: ! 935: ! 936: /* Put a short into user memory */ ! 937: int reg_store_int16(void) ! 938: { ! 939: short *d = (short *)FPU_data_address; ! 940: FPU_REG t; ! 941: short ts; ! 942: ! 943: if ( FPU_st0_tag == TW_Empty ) ! 944: { ! 945: /* Empty register (stack underflow) */ ! 946: EXCEPTION(EX_StackUnder); ! 947: if ( control_word & EX_Invalid ) ! 948: { ! 949: /* The masked response */ ! 950: /* Put out the QNaN indefinite */ ! 951: RE_ENTRANT_CHECK_OFF ! 952: #ifdef COHERENT ! 953: if (verify_area(d,2)) ! 954: put_fs_word(0x8000, (unsigned short *) d); ! 955: #else ! 956: verify_area(d,2); ! 957: put_fs_word(0x8000, (unsigned short *) d); ! 958: #endif ! 959: RE_ENTRANT_CHECK_ON ! 960: return 1; ! 961: } ! 962: else ! 963: return 0; ! 964: } ! 965: ! 966: reg_move(FPU_st0_ptr, &t); ! 967: round_to_int(&t); ! 968: if (t.sigh || ! 969: ((t.sigl & 0xffff8000) && ! 970: !((t.sigl == 0x8000) && (t.sign == SIGN_NEG))) ) ! 971: { ! 972: EXCEPTION(EX_Invalid); ! 973: /* This is a special case: see sec 16.2.5.1 of the 80486 book */ ! 974: if ( control_word & EX_Invalid ) ! 975: { ! 976: /* Produce "indefinite" */ ! 977: ts = 0x8000; ! 978: } ! 979: else ! 980: return 0; ! 981: } ! 982: else if ( t.sign ) ! 983: t.sigl = -t.sigl; ! 984: ! 985: RE_ENTRANT_CHECK_OFF ! 986: #ifdef COHERENT ! 987: if (verify_area(d,2)) ! 988: put_fs_word((short)t.sigl,(short *) d); ! 989: #else ! 990: verify_area(d,2); ! 991: put_fs_word((short)t.sigl,(short *) d); ! 992: #endif ! 993: RE_ENTRANT_CHECK_ON ! 994: ! 995: return 1; ! 996: } ! 997: ! 998: ! 999: /* Put a packed bcd array into user memory */ ! 1000: int reg_store_bcd(void) ! 1001: { ! 1002: char *d = (char *)FPU_data_address; ! 1003: FPU_REG t; ! 1004: long long ll; ! 1005: unsigned char b; ! 1006: int i; ! 1007: unsigned char sign = (FPU_st0_ptr->sign == SIGN_NEG) ? 0x80 : 0; ! 1008: ! 1009: if ( FPU_st0_tag == TW_Empty ) ! 1010: { ! 1011: /* Empty register (stack underflow) */ ! 1012: EXCEPTION(EX_StackUnder); ! 1013: if ( control_word & EX_Invalid ) ! 1014: { ! 1015: /* The masked response */ ! 1016: /* Put out the QNaN indefinite */ ! 1017: goto put_indefinite; ! 1018: } ! 1019: else ! 1020: return 0; ! 1021: } ! 1022: ! 1023: reg_move(FPU_st0_ptr, &t); ! 1024: round_to_int(&t); ! 1025: ll = *(long long *)(&t.sigl); ! 1026: ! 1027: /* Check for overflow, by comparing with 999999999999999999 decimal. */ ! 1028: if ( (t.sigh > 0x0de0b6b3) || ! 1029: ((t.sigh == 0x0de0b6b3) && (t.sigl > 0xa763ffff)) ) ! 1030: { ! 1031: EXCEPTION(EX_Invalid); ! 1032: /* This is a special case: see sec 16.2.5.1 of the 80486 book */ ! 1033: if ( control_word & EX_Invalid ) ! 1034: { ! 1035: put_indefinite: ! 1036: /* Produce "indefinite" */ ! 1037: RE_ENTRANT_CHECK_OFF ! 1038: #ifdef COHERENT ! 1039: if (verify_area(d,10)) { ! 1040: put_fs_byte(0xff,(unsigned char *) d+7); ! 1041: put_fs_byte(0xff,(unsigned char *) d+8); ! 1042: put_fs_byte(0xff,(unsigned char *) d+9); ! 1043: } ! 1044: #else ! 1045: verify_area(d,10); ! 1046: put_fs_byte(0xff,(unsigned char *) d+7); ! 1047: put_fs_byte(0xff,(unsigned char *) d+8); ! 1048: put_fs_byte(0xff,(unsigned char *) d+9); ! 1049: #endif ! 1050: RE_ENTRANT_CHECK_ON ! 1051: return 1; ! 1052: } ! 1053: else ! 1054: return 0; ! 1055: } ! 1056: #ifdef COHERENT ! 1057: if (!verify_area(d,10)) ! 1058: return 1; ! 1059: #else ! 1060: verify_area(d,10); ! 1061: #endif ! 1062: for ( i = 0; i < 9; i++) ! 1063: { ! 1064: b = div_small(&ll, 10); ! 1065: b |= (div_small(&ll, 10)) << 4; ! 1066: RE_ENTRANT_CHECK_OFF ! 1067: put_fs_byte(b,(unsigned char *) d+i); ! 1068: RE_ENTRANT_CHECK_ON ! 1069: } ! 1070: RE_ENTRANT_CHECK_OFF ! 1071: put_fs_byte(sign,(unsigned char *) d+9); ! 1072: RE_ENTRANT_CHECK_ON ! 1073: ! 1074: return 1; ! 1075: } ! 1076: ! 1077: /*===========================================================================*/ ! 1078: ! 1079: /* r gets mangled such that sig is int, sign: ! 1080: it is NOT normalized*/ ! 1081: /* Overflow is signalled by a non-zero return value (in eax). ! 1082: In the case of overflow, the returned significand always has the ! 1083: the largest possible value */ ! 1084: /* The value returned in eax is never actually needed :-) */ ! 1085: int round_to_int(FPU_REG *r) ! 1086: { ! 1087: char very_big; ! 1088: unsigned eax; ! 1089: ! 1090: if (r->tag == TW_Zero) ! 1091: { ! 1092: /* Make sure that zero is returned */ ! 1093: *(long long *)&r->sigl = 0; ! 1094: return 0; /* o.k. */ ! 1095: } ! 1096: ! 1097: if (r->exp > EXP_BIAS + 63) ! 1098: { ! 1099: r->sigl = r->sigh = ~0; /* The largest representable number */ ! 1100: return 1; /* overflow */ ! 1101: } ! 1102: ! 1103: eax = shrxs(&r->sigl, EXP_BIAS + 63 - r->exp); ! 1104: very_big = !(~(r->sigh) | ~(r->sigl)); /* test for 0xfff...fff */ ! 1105: #define half_or_more (eax & 0x80000000) ! 1106: #define frac_part (eax) ! 1107: #define more_than_half ((eax & 0x80000001) == 0x80000001) ! 1108: switch (control_word & CW_RC) ! 1109: { ! 1110: case RC_RND: ! 1111: if ( more_than_half /* nearest */ ! 1112: || (half_or_more && (r->sigl & 1)) ) /* odd -> even */ ! 1113: { ! 1114: if ( very_big ) return 1; /* overflow */ ! 1115: (*(long long *)(&r->sigl)) ++; ! 1116: } ! 1117: break; ! 1118: case RC_DOWN: ! 1119: if (frac_part && r->sign) ! 1120: { ! 1121: if ( very_big ) return 1; /* overflow */ ! 1122: (*(long long *)(&r->sigl)) ++; ! 1123: } ! 1124: break; ! 1125: case RC_UP: ! 1126: if (frac_part && !r->sign) ! 1127: { ! 1128: if ( very_big ) return 1; /* overflow */ ! 1129: (*(long long *)(&r->sigl)) ++; ! 1130: } ! 1131: break; ! 1132: case RC_CHOP: ! 1133: break; ! 1134: } ! 1135: ! 1136: return 0; /* o.k. */ ! 1137: } ! 1138: ! 1139: /*===========================================================================*/ ! 1140: ! 1141: char *fldenv(void) ! 1142: { ! 1143: char *s = (char *)FPU_data_address; ! 1144: unsigned short tag_word = 0; ! 1145: unsigned char tag; ! 1146: int i; ! 1147: ! 1148: RE_ENTRANT_CHECK_OFF ! 1149: control_word = get_fs_word((unsigned short *) s); ! 1150: status_word = get_fs_word((unsigned short *) (s+4)); ! 1151: top = (status_word & SW_TOP) >> SW_TOPS; ! 1152: if (top) /* "top" is 0 or negative */ ! 1153: top |= ~7; ! 1154: tag_word = get_fs_word((unsigned short *) (s+8)); ! 1155: ip_offset = get_fs_long((unsigned long *) (s+0x0c)); ! 1156: cs_selector = get_fs_long((unsigned long *) (s+0x10)); ! 1157: data_operand_offset = get_fs_long((unsigned long *) (s+0x14)); ! 1158: operand_selector = get_fs_long((unsigned long *) (s+0x18)); ! 1159: RE_ENTRANT_CHECK_ON ! 1160: ! 1161: for ( i = 0; i < 8; i++ ) ! 1162: { ! 1163: tag = tag_word & 3; ! 1164: tag_word >>= 2; ! 1165: ! 1166: switch ( tag ) ! 1167: { ! 1168: case 0: ! 1169: fpregs[i].tag = TW_Valid; ! 1170: break; ! 1171: case 1: ! 1172: fpregs[i].tag = TW_Zero; ! 1173: break; ! 1174: case 2: ! 1175: fpregs[i].tag = TW_NaN; ! 1176: break; ! 1177: case 3: ! 1178: fpregs[i].tag = TW_Empty; ! 1179: break; ! 1180: } ! 1181: } ! 1182: ! 1183: FPU_data_address = (void *)data_operand_offset; /* We want no net effect */ ! 1184: FPU_entry_eip = ip_offset; /* We want no net effect */ ! 1185: ! 1186: return s + 0x1c; ! 1187: } ! 1188: ! 1189: ! 1190: void frstor(void) ! 1191: { ! 1192: int reg_index, stack_index; ! 1193: unsigned char tag; ! 1194: char *s = fldenv(); ! 1195: ! 1196: for ( stack_index = 0; stack_index < 8; stack_index++ ) ! 1197: { ! 1198: reg_index = (top + stack_index) & 7; ! 1199: ! 1200: /* load each register */ ! 1201: FPU_data_address = s + (stack_index * 10); ! 1202: reg_load_extended(); ! 1203: tag = fpregs[reg_index].tag; ! 1204: reg_move(&FPU_loaded_data, &fpregs[reg_index]); ! 1205: ! 1206: if ( tag == TW_NaN ) ! 1207: { ! 1208: unsigned char t = fpregs[reg_index].tag; ! 1209: if ( (t == TW_Valid) || (t == TW_Zero) ) ! 1210: fpregs[reg_index].tag = TW_NaN; ! 1211: } ! 1212: else ! 1213: fpregs[reg_index].tag = tag; ! 1214: } ! 1215: ! 1216: FPU_data_address = (void *)data_operand_offset; /* We want no net effect */ ! 1217: } ! 1218: ! 1219: ! 1220: char *fstenv(void) ! 1221: { ! 1222: char *d = (char *)FPU_data_address; ! 1223: unsigned short tag_word = 0; ! 1224: unsigned char tag; ! 1225: int i; ! 1226: ! 1227: #ifdef COHERENT ! 1228: if (!verify_area(d,28)) ! 1229: return d + 0x1c; ! 1230: #else ! 1231: verify_area(d,28); ! 1232: #endif ! 1233: for ( i = 7; i >= 0; i-- ) ! 1234: { ! 1235: switch ( tag = fpregs[i].tag ) ! 1236: { ! 1237: case TW_Denormal: ! 1238: case TW_Infinity: ! 1239: case TW_NaN: ! 1240: tag = 2; ! 1241: break; ! 1242: case TW_Empty: ! 1243: tag = 3; ! 1244: break; ! 1245: /* TW_Valid and TW_Zero already have the correct value */ ! 1246: } ! 1247: tag_word <<= 2; ! 1248: tag_word |= tag; ! 1249: } ! 1250: ! 1251: #ifndef COHERENT ! 1252: /* This is not what should be done ... but saves overheads. */ ! 1253: *(unsigned short *)&cs_selector = FPU_CS; ! 1254: *(unsigned short *)&operand_selector = FPU_DS; ! 1255: #endif ! 1256: ! 1257: RE_ENTRANT_CHECK_OFF ! 1258: put_fs_word(control_word, (unsigned short *) d); ! 1259: status_word &= ~SW_TOP; ! 1260: status_word |= (top & 7) << SW_TOPS; ! 1261: put_fs_word(status_word, (unsigned short *) (d+4)); ! 1262: put_fs_word(tag_word, (unsigned short *) (d+8)); ! 1263: put_fs_long(ip_offset, (unsigned long *) (d+0x0c)); ! 1264: put_fs_long(cs_selector, (unsigned long *) (d+0x10)); ! 1265: put_fs_long(data_operand_offset, (unsigned long *) (d+0x14)); ! 1266: put_fs_long(operand_selector, (unsigned long *) (d+0x18)); ! 1267: RE_ENTRANT_CHECK_ON ! 1268: ! 1269: return d + 0x1c; ! 1270: } ! 1271: ! 1272: /* Put a long double into user memory for fsave */ ! 1273: static void reg_store_ext(long double *d, FPU_REG *rg) ! 1274: { ! 1275: long e = rg->exp - EXP_BIAS + EXTENDED_Ebias; ! 1276: unsigned short sign = rg->sign*0x8000; ! 1277: unsigned long ls, ms; ! 1278: ! 1279: switch (rg->tag) { ! 1280: case TW_Valid: ! 1281: if ( e >= 0x7fff ) ! 1282: { ! 1283: /* Overflow to infinity */ ! 1284: e = 0x7fff; ! 1285: ls = 0; ! 1286: ms = 0x80000000; ! 1287: } ! 1288: else if ( e <= 0 ) ! 1289: { ! 1290: if ( e == 0 ) ! 1291: { ! 1292: ls = rg->sigl; ! 1293: ms = rg->sigh; ! 1294: } ! 1295: else if ( e > -64 ) ! 1296: { ! 1297: /* Make a de-normal */ ! 1298: FPU_REG tmp; ! 1299: ! 1300: reg_move(rg, &tmp); ! 1301: tmp.exp += -EXTENDED_Emin + 64; /* largest exp to be 63 */ ! 1302: round_to_int(&tmp); ! 1303: ! 1304: e = 0; ! 1305: ls = tmp.sigl; ! 1306: ms = tmp.sigh; ! 1307: } ! 1308: else ! 1309: { ! 1310: /* Underflow to zero */ ! 1311: e = 0; ! 1312: ls = 0; ! 1313: ms = 0; ! 1314: } ! 1315: } ! 1316: else ! 1317: { ! 1318: ls = rg->sigl; ! 1319: ms = rg->sigh; ! 1320: } ! 1321: break; ! 1322: case TW_Zero: ! 1323: e = 0; ! 1324: ls = ms = 0; ! 1325: break; ! 1326: case TW_Infinity: ! 1327: e = 0x7fff; ! 1328: ls = 0; ! 1329: ms = 0x80000000; ! 1330: break; ! 1331: case TW_NaN: ! 1332: e = 0x7fff; ! 1333: ls = rg->sigl; ! 1334: ms = rg->sigh; ! 1335: break; ! 1336: case TW_Empty: ! 1337: /* Empty register (stack underflow) */ ! 1338: /* Put out the QNaN indefinite */ ! 1339: e = 0xffff; ! 1340: ls = 0; ! 1341: ms = 0xc0000000; ! 1342: break; ! 1343: default: ! 1344: /* Store a NaN */ ! 1345: e = 0x7fff; ! 1346: ls = 1; ! 1347: ms = 0x80000000; ! 1348: } ! 1349: RE_ENTRANT_CHECK_OFF ! 1350: put_fs_long(ls, (unsigned long *) d); ! 1351: put_fs_long(ms, 1 + (unsigned long *) d); ! 1352: put_fs_word((unsigned short)e | sign, (short *)(2 + (unsigned long *)d)); ! 1353: RE_ENTRANT_CHECK_ON ! 1354: } ! 1355: ! 1356: void fsave(void) ! 1357: { ! 1358: char *d; ! 1359: int reg_index, stack_index; ! 1360: ! 1361: d = fstenv(); ! 1362: ! 1363: #ifdef COHERENT ! 1364: if (!verify_area(d,80)) ! 1365: return; ! 1366: #else ! 1367: verify_area(d,80); ! 1368: #endif ! 1369: for ( stack_index = 0; stack_index < 8; stack_index++ ) { ! 1370: reg_index = (top + stack_index) & 7; ! 1371: reg_store_ext((long double *)(d + (stack_index * 10)), ! 1372: fpregs + reg_index); ! 1373: } ! 1374: } ! 1375: ! 1376: /*===========================================================================*/
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.