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

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

unix.superglobalmegacorp.com

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