root/kernel/FPU-emu/reg_ld_str.c

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

DEFINITIONS

This source file includes following definitions.
  1. reg_load_extended
  2. reg_load_double
  3. reg_load_single
  4. reg_load_int64
  5. reg_load_int32
  6. reg_load_int16
  7. reg_load_bcd
  8. reg_store_extended
  9. reg_store_double
  10. reg_store_single
  11. reg_store_int64
  12. reg_store_int32
  13. reg_store_int16
  14. reg_store_bcd
  15. round_to_int
  16. fldenv
  17. frstor
  18. tag_word
  19. fstenv
  20. fsave

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

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