long_double __mulxf3(long_double A, long_double B) { #if __SIZEOF_LONG_DOUBLE__ == 12 return floatx80_mul(A, B); #else return float128_mul(A, B); #endif }
static void fpgen_rm_reg(m68000_base_device *m68k, UINT16 w2) { int ea = m68k->ir & 0x3f; int rm = (w2 >> 14) & 0x1; int src = (w2 >> 10) & 0x7; int dst = (w2 >> 7) & 0x7; int opmode = w2 & 0x7f; floatx80 source; // fmovecr #$f, fp0 f200 5c0f if (rm) { switch (src) { case 0: // Long-Word Integer { INT32 d = READ_EA_32(m68k, ea); source = int32_to_floatx80(d); break; } case 1: // Single-precision Real { UINT32 d = READ_EA_32(m68k, ea); source = float32_to_floatx80(d); break; } case 2: // Extended-precision Real { source = READ_EA_FPE(m68k, ea); break; } case 3: // Packed-decimal Real { source = READ_EA_PACK(m68k, ea); break; } case 4: // Word Integer { INT16 d = READ_EA_16(m68k, ea); source = int32_to_floatx80((INT32)d); break; } case 5: // Double-precision Real { UINT64 d = READ_EA_64(m68k, ea); source = float64_to_floatx80(d); break; } case 6: // Byte Integer { INT8 d = READ_EA_8(m68k, ea); source = int32_to_floatx80((INT32)d); break; } case 7: // FMOVECR load from constant ROM { switch (w2 & 0x7f) { case 0x0: // Pi source.high = 0x4000; source.low = U64(0xc90fdaa22168c235); break; case 0xb: // log10(2) source.high = 0x3ffd; source.low = U64(0x9a209a84fbcff798); break; case 0xc: // e source.high = 0x4000; source.low = U64(0xadf85458a2bb4a9b); break; case 0xd: // log2(e) source.high = 0x3fff; source.low = U64(0xb8aa3b295c17f0bc); break; case 0xe: // log10(e) source.high = 0x3ffd; source.low = U64(0xde5bd8a937287195); break; case 0xf: // 0.0 source = int32_to_floatx80((INT32)0); break; case 0x30: // ln(2) source.high = 0x3ffe; source.low = U64(0xb17217f7d1cf79ac); break; case 0x31: // ln(10) source.high = 0x4000; source.low = U64(0x935d8dddaaa8ac17); break; case 0x32: // 1 (or 100? manuals are unclear, but 1 would make more sense) source = int32_to_floatx80((INT32)1); break; case 0x33: // 10^1 source = int32_to_floatx80((INT32)10); break; case 0x34: // 10^2 source = int32_to_floatx80((INT32)10*10); break; case 0x35: // 10^4 source = int32_to_floatx80((INT32)1000*10); break; case 0x36: // 1.0e8 source = int32_to_floatx80((INT32)10000000*10); break; case 0x37: // 1.0e16 - can't get the right precision from INT32 so go "direct" with constants from h/w source.high = 0x4034; source.low = U64(0x8e1bc9bf04000000); break; case 0x38: // 1.0e32 source.high = 0x4069; source.low = U64(0x9dc5ada82b70b59e); break; case 0x39: // 1.0e64 source.high = 0x40d3; source.low = U64(0xc2781f49ffcfa6d5); break; case 0x3a: // 1.0e128 source.high = 0x41a8; source.low = U64(0x93ba47c980e98ce0); break; case 0x3b: // 1.0e256 source.high = 0x4351; source.low = U64(0xaa7eebfb9df9de8e); break; case 0x3c: // 1.0e512 source.high = 0x46a3; source.low = U64(0xe319a0aea60e91c7); break; case 0x3d: // 1.0e1024 source.high = 0x4d48; source.low = U64(0xc976758681750c17); break; case 0x3e: // 1.0e2048 source.high = 0x5a92; source.low = U64(0x9e8b3b5dc53d5de5); break; case 0x3f: // 1.0e4096 source.high = 0x7525; source.low = U64(0xc46052028a20979b); break; default: fatalerror("fmove_rm_reg: unknown constant ROM offset %x at %08x\n", w2&0x7f, REG_PC(m68k)-4); break; } // handle it right here, the usual opmode bits aren't valid in the FMOVECR case REG_FP(m68k)[dst] = source; m68k->remaining_cycles -= 4; return; } default: fatalerror("fmove_rm_reg: invalid source specifier %x at %08X\n", src, REG_PC(m68k)-4); } } else { source = REG_FP(m68k)[src]; } switch (opmode) { case 0x00: // FMOVE { REG_FP(m68k)[dst] = source; SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 4; break; } case 0x01: // FINT { INT32 temp; temp = floatx80_to_int32(source); REG_FP(m68k)[dst] = int32_to_floatx80(temp); break; } case 0x03: // FINTRZ { INT32 temp; temp = floatx80_to_int32_round_to_zero(source); REG_FP(m68k)[dst] = int32_to_floatx80(temp); break; } case 0x04: // FSQRT { REG_FP(m68k)[dst] = floatx80_sqrt(source); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 109; break; } case 0x06: // FLOGNP1 { REG_FP(m68k)[dst] = floatx80_flognp1 (source); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 594; // for MC68881 break; } case 0x0e: // FSIN { REG_FP(m68k)[dst] = source; floatx80_fsin(REG_FP(m68k)[dst]); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 75; break; } case 0x0f: // FTAN { REG_FP(m68k)[dst] = source; floatx80_ftan(REG_FP(m68k)[dst]); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 75; break; } case 0x14: // FLOGN { REG_FP(m68k)[dst] = floatx80_flogn (source); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 548; // for MC68881 break; } case 0x15: // FLOG10 { REG_FP(m68k)[dst] = floatx80_flog10 (source); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 604; // for MC68881 break; } case 0x16: // FLOG2 { REG_FP(m68k)[dst] = floatx80_flog2 (source); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 604; // for MC68881 break; } case 0x18: // FABS { REG_FP(m68k)[dst] = source; REG_FP(m68k)[dst].high &= 0x7fff; SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 3; break; } case 0x1a: // FNEG { REG_FP(m68k)[dst] = source; REG_FP(m68k)[dst].high ^= 0x8000; SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 3; break; } case 0x1d: // FCOS { REG_FP(m68k)[dst] = source; floatx80_fcos(REG_FP(m68k)[dst]); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 75; break; } case 0x1e: // FGETEXP { INT16 temp2; temp2 = source.high; // get the exponent temp2 -= 0x3fff; // take off the bias REG_FP(m68k)[dst] = double_to_fx80((double)temp2); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 6; break; } case 0x20: // FDIV { REG_FP(m68k)[dst] = floatx80_div(REG_FP(m68k)[dst], source); m68k->remaining_cycles -= 43; break; } case 0x22: // FADD { REG_FP(m68k)[dst] = floatx80_add(REG_FP(m68k)[dst], source); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 9; break; } case 0x23: // FMUL { REG_FP(m68k)[dst] = floatx80_mul(REG_FP(m68k)[dst], source); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 11; break; } case 0x24: // FSGLDIV { float32 a = floatx80_to_float32( REG_FP(m68k)[dst] ); float32 b = floatx80_to_float32( source ); REG_FP(m68k)[dst] = float32_to_floatx80( float32_div(a, b) ); m68k->remaining_cycles -= 43; // // ? (value is from FDIV) break; } case 0x25: // FREM { REG_FP(m68k)[dst] = floatx80_rem(REG_FP(m68k)[dst], source); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 43; // guess break; } case 0x27: // FSGLMUL { float32 a = floatx80_to_float32( REG_FP(m68k)[dst] ); float32 b = floatx80_to_float32( source ); REG_FP(m68k)[dst] = float32_to_floatx80( float32_mul(a, b) ); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 11; // ? (value is from FMUL) break; } case 0x28: // FSUB { REG_FP(m68k)[dst] = floatx80_sub(REG_FP(m68k)[dst], source); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 9; break; } case 0x38: // FCMP { floatx80 res; res = floatx80_sub(REG_FP(m68k)[dst], source); SET_CONDITION_CODES(m68k, res); m68k->remaining_cycles -= 7; break; } case 0x3a: // FTST { floatx80 res; res = source; SET_CONDITION_CODES(m68k, res); m68k->remaining_cycles -= 7; break; } default: fatalerror("fpgen_rm_reg: unimplemented opmode %02X at %08X\n", opmode, REG_PPC(m68k)); } }
unsigned int ExtendedCPDO(const unsigned int opcode) { FPA11 *fpa11 = GET_FPA11(); floatx80 rFm, rFn; unsigned int Fd, Fm, Fn, nRc = 1; //printk("ExtendedCPDO(0x%08x)\n",opcode); Fm = getFm(opcode); if (CONSTANT_FM(opcode)) { rFm = getExtendedConstant(Fm); } else { switch (fpa11->fType[Fm]) { case typeSingle: rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle, &fpa11->fp_status); break; case typeDouble: rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble, &fpa11->fp_status); break; case typeExtended: rFm = fpa11->fpreg[Fm].fExtended; break; default: return 0; } } if (!MONADIC_INSTRUCTION(opcode)) { Fn = getFn(opcode); switch (fpa11->fType[Fn]) { case typeSingle: rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status); break; case typeDouble: rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status); break; case typeExtended: rFn = fpa11->fpreg[Fn].fExtended; break; default: return 0; } } Fd = getFd(opcode); switch (opcode & MASK_ARITHMETIC_OPCODE) { /* dyadic opcodes */ case ADF_CODE: fpa11->fpreg[Fd].fExtended = floatx80_add(rFn,rFm, &fpa11->fp_status); break; case MUF_CODE: case FML_CODE: fpa11->fpreg[Fd].fExtended = floatx80_mul(rFn,rFm, &fpa11->fp_status); break; case SUF_CODE: fpa11->fpreg[Fd].fExtended = floatx80_sub(rFn,rFm, &fpa11->fp_status); break; case RSF_CODE: fpa11->fpreg[Fd].fExtended = floatx80_sub(rFm,rFn, &fpa11->fp_status); break; case DVF_CODE: case FDV_CODE: fpa11->fpreg[Fd].fExtended = floatx80_div(rFn,rFm, &fpa11->fp_status); break; case RDF_CODE: case FRD_CODE: fpa11->fpreg[Fd].fExtended = floatx80_div(rFm,rFn, &fpa11->fp_status); break; #if 0 case POW_CODE: fpa11->fpreg[Fd].fExtended = floatx80_pow(rFn,rFm); break; case RPW_CODE: fpa11->fpreg[Fd].fExtended = floatx80_pow(rFm,rFn); break; #endif case RMF_CODE: fpa11->fpreg[Fd].fExtended = floatx80_rem(rFn,rFm, &fpa11->fp_status); break; #if 0 case POL_CODE: fpa11->fpreg[Fd].fExtended = floatx80_pol(rFn,rFm); break; #endif /* monadic opcodes */ case MVF_CODE: fpa11->fpreg[Fd].fExtended = rFm; break; case MNF_CODE: rFm.high ^= 0x8000; fpa11->fpreg[Fd].fExtended = rFm; break; case ABS_CODE: rFm.high &= 0x7fff; fpa11->fpreg[Fd].fExtended = rFm; break; case RND_CODE: case URD_CODE: fpa11->fpreg[Fd].fExtended = floatx80_round_to_int(rFm, &fpa11->fp_status); break; case SQT_CODE: fpa11->fpreg[Fd].fExtended = floatx80_sqrt(rFm, &fpa11->fp_status); break; #if 0 case LOG_CODE: fpa11->fpreg[Fd].fExtended = floatx80_log(rFm); break; case LGN_CODE: fpa11->fpreg[Fd].fExtended = floatx80_ln(rFm); break; case EXP_CODE: fpa11->fpreg[Fd].fExtended = floatx80_exp(rFm); break; case SIN_CODE: fpa11->fpreg[Fd].fExtended = floatx80_sin(rFm); break; case COS_CODE: fpa11->fpreg[Fd].fExtended = floatx80_cos(rFm); break; case TAN_CODE: fpa11->fpreg[Fd].fExtended = floatx80_tan(rFm); break; case ASN_CODE: fpa11->fpreg[Fd].fExtended = floatx80_arcsin(rFm); break; case ACS_CODE: fpa11->fpreg[Fd].fExtended = floatx80_arccos(rFm); break; case ATN_CODE: fpa11->fpreg[Fd].fExtended = floatx80_arctan(rFm); break; #endif case NRM_CODE: break; default: { nRc = 0; } } if (0 != nRc) fpa11->fType[Fd] = typeExtended; return nRc; }
floatx80 floatx80_pow(floatx80 rFn,floatx80 rFm) { return floatx80_exp(floatx80_mul(rFm,floatx80_ln(rFn))); }
static void fpgen_rm_reg(m68ki_cpu_core *m68k, UINT16 w2) { int ea = m68k->ir & 0x3f; int rm = (w2 >> 14) & 0x1; int src = (w2 >> 10) & 0x7; int dst = (w2 >> 7) & 0x7; int opmode = w2 & 0x7f; floatx80 source; // fmovecr #$f, fp0 f200 5c0f if (rm) { switch (src) { case 0: // Long-Word Integer { INT32 d = READ_EA_32(m68k, ea); source = int32_to_floatx80(d); break; } case 1: // Single-precision Real { UINT32 d = READ_EA_32(m68k, ea); source = float32_to_floatx80(d); break; } case 2: // Extended-precision Real { source = READ_EA_FPE(m68k, ea); break; } case 3: // Packed-decimal Real { source = READ_EA_PACK(m68k, ea); break; } case 4: // Word Integer { INT16 d = READ_EA_16(m68k, ea); source = int32_to_floatx80((INT32)d); break; } case 5: // Double-precision Real { UINT64 d = READ_EA_64(m68k, ea); source = float64_to_floatx80(d); break; } case 6: // Byte Integer { INT8 d = READ_EA_8(m68k, ea); source = int32_to_floatx80((INT32)d); break; } case 7: // FMOVECR load from constant ROM { switch (w2 & 0x7f) { case 0x0: // Pi source.high = 0x4000; source.low = U64(0xc90fdaa22168c235); break; case 0xb: // log10(2) source.high = 0x3ffd; source.low = U64(0x9a209a84fbcff798); break; case 0xc: // e source.high = 0x4000; source.low = U64(0xadf85458a2bb4a9b); break; case 0xd: // log2(e) source.high = 0x3fff; source.low = U64(0xb8aa3b295c17f0bc); break; case 0xe: // log10(e) source.high = 0x3ffd; source.low = U64(0xde5bd8a937287195); break; case 0xf: // 0.0 source = int32_to_floatx80((INT32)0); break; case 0x30: // ln(2) source.high = 0x3ffe; source.low = U64(0xb17217f7d1cf79ac); break; case 0x31: // ln(10) source.high = 0x4000; source.low = U64(0x935d8dddaaa8ac17); break; case 0x32: // 1 (or 100? manuals are unclear, but 1 would make more sense) source = int32_to_floatx80((INT32)1); break; case 0x33: // 10^1 source = int32_to_floatx80((INT32)10); break; case 0x34: // 10^2 source = int32_to_floatx80((INT32)10*10); break; default: fatalerror("fmove_rm_reg: unknown constant ROM offset %x at %08x\n", w2&0x7f, REG_PC(m68k)-4); break; } // handle it right here, the usual opmode bits aren't valid in the FMOVECR case REG_FP(m68k)[dst] = source; m68k->remaining_cycles -= 4; return; } default: fatalerror("fmove_rm_reg: invalid source specifier %x at %08X\n", src, REG_PC(m68k)-4); } } else { source = REG_FP(m68k)[src]; } switch (opmode) { case 0x00: // FMOVE { REG_FP(m68k)[dst] = source; SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 4; break; } case 0x01: // FINT { INT32 temp; temp = floatx80_to_int32(source); REG_FP(m68k)[dst] = int32_to_floatx80(temp); break; } case 0x03: // FINTRZ { INT32 temp; temp = floatx80_to_int32_round_to_zero(source); REG_FP(m68k)[dst] = int32_to_floatx80(temp); break; } case 0x04: // FSQRT { REG_FP(m68k)[dst] = floatx80_sqrt(source); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 109; break; } case 0x0e: // FSIN { REG_FP(m68k)[dst] = source; floatx80_fsin(REG_FP(m68k)[dst]); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 75; break; } case 0x0f: // FTAN { REG_FP(m68k)[dst] = source; floatx80_ftan(REG_FP(m68k)[dst]); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 75; break; } case 0x18: // FABS { REG_FP(m68k)[dst] = source; REG_FP(m68k)[dst].high &= 0x7fff; SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 3; break; } case 0x1a: // FNEG { REG_FP(m68k)[dst] = source; REG_FP(m68k)[dst].high ^= 0x8000; SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 3; break; } case 0x1d: // FCOS { REG_FP(m68k)[dst] = source; floatx80_fcos(REG_FP(m68k)[dst]); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 75; break; } case 0x1e: // FGETEXP { INT16 temp2; temp2 = source.high; // get the exponent temp2 -= 0x3fff; // take off the bias REG_FP(m68k)[dst] = double_to_fx80((double)temp2); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 6; } case 0x20: // FDIV { REG_FP(m68k)[dst] = floatx80_div(REG_FP(m68k)[dst], source); m68k->remaining_cycles -= 43; break; } case 0x22: // FADD { REG_FP(m68k)[dst] = floatx80_add(REG_FP(m68k)[dst], source); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 9; break; } case 0x23: // FMUL { REG_FP(m68k)[dst] = floatx80_mul(REG_FP(m68k)[dst], source); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 11; break; } case 0x24: // FSGLDIV { REG_FP(m68k)[dst] = floatx80_div(REG_FP(m68k)[dst], source); m68k->remaining_cycles -= 43; // // ? (value is from FDIV) break; } case 0x25: // FREM { REG_FP(m68k)[dst] = floatx80_rem(REG_FP(m68k)[dst], source); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 43; // guess break; } case 0x27: // FSGLMUL { REG_FP(m68k)[dst] = floatx80_mul(REG_FP(m68k)[dst], source); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 11; // ? (value is from FMUL) break; } case 0x28: // FSUB { REG_FP(m68k)[dst] = floatx80_sub(REG_FP(m68k)[dst], source); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 9; break; } case 0x38: // FCMP { floatx80 res; res = floatx80_sub(REG_FP(m68k)[dst], source); SET_CONDITION_CODES(m68k, res); m68k->remaining_cycles -= 7; break; } case 0x3a: // FTST { floatx80 res; res = source; SET_CONDITION_CODES(m68k, res); m68k->remaining_cycles -= 7; break; } default: fatalerror("fpgen_rm_reg: unimplemented opmode %02X at %08X\n", opmode, REG_PPC(m68k)); } }
floatx80 fyl2xp1(floatx80 a, floatx80 b) { INT32 aExp, bExp; UINT64 aSig, bSig, zSig0, zSig1, zSig2; int aSign, bSign; aSig = extractFloatx80Frac(a); aExp = extractFloatx80Exp(a); aSign = extractFloatx80Sign(a); bSig = extractFloatx80Frac(b); bExp = extractFloatx80Exp(b); bSign = extractFloatx80Sign(b); int zSign = aSign ^ bSign; if (aExp == 0x7FFF) { if ((UINT64) (aSig<<1) || ((bExp == 0x7FFF) && (UINT64) (bSig<<1))) { return propagateFloatx80NaN(a, b); } if (aSign) { invalid: float_raise(float_flag_invalid); return floatx80_default_nan; } else { if (bExp == 0) { if (bSig == 0) goto invalid; float_raise(float_flag_denormal); } return packFloatx80(bSign, 0x7FFF, U64(0x8000000000000000)); } } if (bExp == 0x7FFF) { if ((UINT64) (bSig<<1)) return propagateFloatx80NaN(a, b); if (aExp == 0) { if (aSig == 0) goto invalid; float_raise(float_flag_denormal); } return packFloatx80(zSign, 0x7FFF, U64(0x8000000000000000)); } if (aExp == 0) { if (aSig == 0) { if (bSig && (bExp == 0)) float_raise(float_flag_denormal); return packFloatx80(zSign, 0, 0); } float_raise(float_flag_denormal); normalizeFloatx80Subnormal(aSig, &aExp, &aSig); } if (bExp == 0) { if (bSig == 0) return packFloatx80(zSign, 0, 0); float_raise(float_flag_denormal); normalizeFloatx80Subnormal(bSig, &bExp, &bSig); } float_raise(float_flag_inexact); if (aSign && aExp >= 0x3FFF) return a; if (aExp >= 0x3FFC) // big argument { return fyl2x(floatx80_add(a, floatx80_one), b); } // handle tiny argument if (aExp < EXP_BIAS-70) { // first order approximation, return (a*b)/ln(2) INT32 zExp = aExp + FLOAT_LN2INV_EXP - 0x3FFE; mul128By64To192(FLOAT_LN2INV_HI, FLOAT_LN2INV_LO, aSig, &zSig0, &zSig1, &zSig2); if (0 < (INT64) zSig0) { shortShift128Left(zSig0, zSig1, 1, &zSig0, &zSig1); --zExp; } zExp = zExp + bExp - 0x3FFE; mul128By64To192(zSig0, zSig1, bSig, &zSig0, &zSig1, &zSig2); if (0 < (INT64) zSig0) { shortShift128Left(zSig0, zSig1, 1, &zSig0, &zSig1); --zExp; } return roundAndPackFloatx80(80, aSign ^ bSign, zExp, zSig0, zSig1); } /* ******************************** */ /* using float128 for approximation */ /* ******************************** */ shift128Right(aSig<<1, 0, 16, &zSig0, &zSig1); float128 x = packFloat128(aSign, aExp, zSig0, zSig1); x = poly_l2p1(x); return floatx80_mul(b, float128_to_floatx80(x)); }
static floatx80 fyl2x(floatx80 a, floatx80 b) { UINT64 aSig = extractFloatx80Frac(a); INT32 aExp = extractFloatx80Exp(a); int aSign = extractFloatx80Sign(a); UINT64 bSig = extractFloatx80Frac(b); INT32 bExp = extractFloatx80Exp(b); int bSign = extractFloatx80Sign(b); int zSign = bSign ^ 1; if (aExp == 0x7FFF) { if ((UINT64) (aSig<<1) || ((bExp == 0x7FFF) && (UINT64) (bSig<<1))) { return propagateFloatx80NaN(a, b); } if (aSign) { invalid: float_raise(float_flag_invalid); return floatx80_default_nan; } else { if (bExp == 0) { if (bSig == 0) goto invalid; float_raise(float_flag_denormal); } return packFloatx80(bSign, 0x7FFF, U64(0x8000000000000000)); } } if (bExp == 0x7FFF) { if ((UINT64) (bSig<<1)) return propagateFloatx80NaN(a, b); if (aSign && (UINT64)(aExp | aSig)) goto invalid; if (aSig && (aExp == 0)) float_raise(float_flag_denormal); if (aExp < 0x3FFF) { return packFloatx80(zSign, 0x7FFF, U64(0x8000000000000000)); } if (aExp == 0x3FFF && ((UINT64) (aSig<<1) == 0)) goto invalid; return packFloatx80(bSign, 0x7FFF, U64(0x8000000000000000)); } if (aExp == 0) { if (aSig == 0) { if ((bExp | bSig) == 0) goto invalid; float_raise(float_flag_divbyzero); return packFloatx80(zSign, 0x7FFF, U64(0x8000000000000000)); } if (aSign) goto invalid; float_raise(float_flag_denormal); normalizeFloatx80Subnormal(aSig, &aExp, &aSig); } if (aSign) goto invalid; if (bExp == 0) { if (bSig == 0) { if (aExp < 0x3FFF) return packFloatx80(zSign, 0, 0); return packFloatx80(bSign, 0, 0); } float_raise(float_flag_denormal); normalizeFloatx80Subnormal(bSig, &bExp, &bSig); } if (aExp == 0x3FFF && ((UINT64) (aSig<<1) == 0)) return packFloatx80(bSign, 0, 0); float_raise(float_flag_inexact); int ExpDiff = aExp - 0x3FFF; aExp = 0; if (aSig >= SQRT2_HALF_SIG) { ExpDiff++; aExp--; } /* ******************************** */ /* using float128 for approximation */ /* ******************************** */ UINT64 zSig0, zSig1; shift128Right(aSig<<1, 0, 16, &zSig0, &zSig1); float128 x = packFloat128(0, aExp+0x3FFF, zSig0, zSig1); x = poly_l2(x); x = float128_add(x, int64_to_float128((INT64) ExpDiff)); return floatx80_mul(b, float128_to_floatx80(x)); }