Annotation of coherent/b/kernel/emulator/reg_ld_str.c, revision 1.1

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: /*===========================================================================*/

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.