Annotation of coherent/b/kernel/emulator/fpu_trig.c, revision 1.1.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.