/*++ Copyright (c) 1995 Microsoft Corporation Module Name: fpuload.c Abstract: Floating point load functions Author: 04-Oct-1995 BarryBo Revision History: --*/ #include #include #include #include #include #include #include #include "wx86.h" #include "cpuassrt.h" #include "fragp.h" #include "fpufragp.h" #include "fpuarith.h" ASSERTNAME; VOID GetIntelR4( PFPREG Fp, FLOAT *pIntelReal ) /*++ Routine Description: Load an Intel R4 and convert it to a native R4, accounting for the difference in how MIPS represents QNAN/SNAN. NOTE: This is not in fpufrag.c due to a code-generator bug on PPC - irbexpr.c:932 asserts trying to inline this function. Moving it to a different file defeats the inliner. Arguments: Fp - floating-point register to load the R4 into pIntelReal - R4 value to load (in Intel format) Return Value: None. --*/ { DWORD d = GET_LONG(pIntelReal); if ((d & 0x7f800000) == 0x7f800000) { Fp->Tag = TAG_SPECIAL; // Found some sort of NAN if (d == 0xffc00000) { // Indefinite // Create the native indefinite form #if NATIVE_NAN_IS_INTEL_FORMAT Fp->rdw[0] = 0; Fp->rdw[1] = 0xfff80000; #else Fp->rdw[0] = 0xffffffff; Fp->rdw[1] = 0x7ff7ffff; #endif Fp->TagSpecial = TAG_SPECIAL_INDEF; } else if (d == 0x7f800000) { // +infinity Fp->r64 = R8PositiveInfinity; Fp->TagSpecial = TAG_SPECIAL_INFINITY; } else if (d == 0xff800000) { // -infinity Fp->r64 = R8NegativeInfinity; Fp->TagSpecial = TAG_SPECIAL_INFINITY; } else { // SNAN/QNAN DWORD Sign; if (d & 0x00400000) { // // Intel QNAN // Fp->TagSpecial = TAG_SPECIAL_QNAN; } else { // // Intel SNAN // Fp->TagSpecial = TAG_SPECIAL_SNAN; } #if !NATIVE_NAN_IS_INTEL_FORMAT // // Toggle the NAN to native format // d ^= 0x00400000; #endif // // Cast the r4 RISC QNAN to double. Don't trust the CRT to // do the right thing - MIPS converts them both to INDEFINITE. // Sign = d & 0x80000000; d &= 0x007fffff; // grab the mantissa from the r4 (23 bits) Fp->rdw[1] = Sign | 0x7ff00000 | (d >> 3); // store 20 bits of mantissa, plus sign Fp->rdw[0] = d << 25; // store 3 bits of mantissa } } else { // denormal, zero, or number // Coerce it to an R8 Fp->r64 = (DOUBLE)*(FLOAT *)&d; // Compute its tag by looking at the value *after* the conversion, // as the native FPU may have normalized the value if (Fp->r64 == 0.0) { Fp->Tag = TAG_ZERO; } else if ((Fp->rdw[1] & 0x7ff00000) == 0) { // Exponent is 0 - R8 denormal Fp->Tag = TAG_SPECIAL; Fp->TagSpecial = TAG_SPECIAL_DENORM; } else { Fp->Tag = TAG_VALID; #if DBG SetTag(Fp); CPUASSERT(Fp->Tag == TAG_VALID); #endif } } } #if !NATIVE_NAN_IS_INTEL_FORMAT VOID GetIntelR8( PFPREG Fp, DOUBLE *pIntelReal ) /*++ Routine Description: Load an Intel R8 and convert it to a native R8, accounting for the difference in how MIPS represents QNAN/SNAN. Arguments: Fp - floating-point register to load the R8 into pIntelReal - R8 value to load (in Intel format) Return Value: None. --*/ { // // Copy the R8 into the FP register // Fp->r64 = *(UNALIGNED DOUBLE *)pIntelReal; // // Compute its tag // SetTag(Fp); // // If the value is QNAN/SNAN/INDEF, convert it to native format // if (IS_TAG_NAN(Fp)) { if (Fp->rdw[0] == 0 && Fp->rdw[1] == 0xfff80000) { // indefinite - make the R8 into a native indefinite Fp->TagSpecial = TAG_SPECIAL_INDEF; Fp->rdw[0] = 0xffffffff; Fp->rdw[1] = 0x7ff7ffff; } else { if (Fp->rdw[1] & 0x00080000) { // top bit of mantissa is set - QNAN Fp->TagSpecial = TAG_SPECIAL_QNAN; } else { // top bit of mantissa clear - SNAN Fp->TagSpecial = TAG_SPECIAL_SNAN; } Fp->rdw[1] ^= 0x00080000; // invert the top bit of the mantissa } } } #endif //!NATIVE_NAN_IS_INTEL_FORMAT VOID SetTag( PFPREG FpReg ) /*++ Routine Description: Sets the Tag value corresponding to a r64 value in an FP register. Assumes the R8 value is in native format (ie. Intel NANs are already converted to native NANs). Arguments: FpReg - register to set Tag field in. Return Value: None --*/ { DWORD Exponent; /* On average, the value will be zero or a valid real, so those cases * have the fastest code paths. NANs tend to be less frequent and are * slower to calculate. */ Exponent = FpReg->rdw[1] & 0x7ff00000; if (Exponent == 0x7ff00000) { // exponent is all 1's - NAN of some sort FpReg->Tag = TAG_SPECIAL; if (FpReg->rdw[0] == 0 && (FpReg->rdw[1] & 0x7fffffff) == 0x7ff00000) { // Exponent is all 1s, mantissa is all 0s - Infinity FpReg->TagSpecial = TAG_SPECIAL_INFINITY; } else { #if NATIVE_NAN_IS_INTEL_FORMAT if (FpReg->rdw[0] == 0 && FpReg->rdw[1] == 0xfff80000) { // indefinite FpReg->TagSpecial = TAG_SPECIAL_INDEF; } else if (FpReg->rdw[1] & 0x00080000) { // top bit of mantissa is set - QNAN FpReg->TagSpecial = TAG_SPECIAL_QNAN; } else { // Top bit of mantissa clear - but some mantissa bit set - QNAN FpReg->TagSpecial = TAG_SPECIAL_SNAN; } #else //!NATIVE_NAN_IS_INTEL_FORMAT if (FpReg->rdw[0] == 0xffffffff && FpReg->rdw[1] == 0x7ff7ffff) { // indefinite FpReg->TagSpecial = TAG_SPECIAL_INDEF; } else if (FpReg->rdw[1] & 0x00080000) { // top bit of mantissa is set - SNAN FpReg->TagSpecial = TAG_SPECIAL_SNAN; } else { // top bit of mantissa clear - QNAN FpReg->TagSpecial = TAG_SPECIAL_QNAN; } #endif //!NATIVE_NAN_IS_INTEL_FORMAT } } else if (Exponent == 0) { // exponent is 0 - DENORMAL or ZERO if ((FpReg->rdw[1] & 0x1ffff) == 0 && FpReg->rdw[0] == 0) { // mantissa is all zeroes - ZERO FpReg->Tag = TAG_ZERO; } else { FpReg->Tag = TAG_SPECIAL; FpReg->TagSpecial = TAG_SPECIAL_DENORM; } } else { // Exponent is not all 1's and not all 0's - a VALID FpReg->Tag = TAG_VALID; } } FRAG1(FILD16, SHORT) // FILD m16int { PFPREG ST0; FpArithDataPreamble(cpu, pop1); cpu->FpStatusC1 = 0; // assume no error PUSHFLT(ST0); if (ST0->Tag != TAG_EMPTY) { HandleStackFull(cpu, ST0); } else { SHORT s; s = (SHORT)GET_SHORT(pop1); ST0->r64 = (DOUBLE)s; if (s) { ST0->Tag = TAG_VALID; } else { ST0->Tag = TAG_ZERO; } } } FRAG1(FILD32, LONG) // FILD m32int { PFPREG ST0; FpArithDataPreamble(cpu, pop1); cpu->FpStatusC1 = 0; // assume no error PUSHFLT(ST0); if (ST0->Tag != TAG_EMPTY) { HandleStackFull(cpu, ST0); } else { LONG l; l = (LONG)GET_LONG(pop1); ST0->r64 = (DOUBLE)l; if (l) { ST0->Tag = TAG_VALID; } else { ST0->Tag = TAG_ZERO; } } } FRAG1(FILD64, LONGLONG) // FILD m64int { PFPREG ST0; FpArithDataPreamble(cpu, pop1); cpu->FpStatusC1 = 0; // assume no error PUSHFLT(ST0); if (ST0->Tag != TAG_EMPTY) { HandleStackFull(cpu, ST0); } else { LONGLONG ll; ll = *(UNALIGNED LONGLONG *)pop1; ST0->r64 = (DOUBLE)ll; if (ll) { ST0->Tag = TAG_VALID; } else { ST0->Tag = TAG_ZERO; } } } FRAG1(FLD32, FLOAT) // FLD m32real { PFPREG ST0; FpArithDataPreamble(cpu, pop1); cpu->FpStatusC1 = 0; // assume no error PUSHFLT(ST0); if (ST0->Tag != TAG_EMPTY) { HandleStackFull(cpu, ST0); } else { GetIntelR4(ST0, pop1); if (ST0->Tag == TAG_SPECIAL) { if (ST0->TagSpecial == TAG_SPECIAL_DENORM) { if (!(cpu->FpControlMask & FPCONTROL_DM)) { cpu->FpStatusES = 1; // Unmasked exception // // Instruction needs to be aborted due to unmasked // exception. We've already hosed ST0, so "correct" // it by popping the FP stack. Note that // the contents of the register have been lost, which // is a compatibility break with Intel. // POPFLT; } cpu->FpStatusExceptions |= FPCONTROL_DM; } else if (ST0->TagSpecial == TAG_SPECIAL_SNAN) { if (HandleSnan(cpu, ST0)) { // // Instruction needs to be aborted due to unmasked // exception. We've already hosed ST0, so "correct" // it by popping the FP stack. Note that // the contents of the register have been lost, which // is a compatibility break with Intel. // POPFLT; } } } } } FRAG1(FLD64, DOUBLE) // FLD m64real { PFPREG ST0; FpArithDataPreamble(cpu, pop1); cpu->FpStatusC1 = 0; // assume no error PUSHFLT(ST0); if (ST0->Tag != TAG_EMPTY) { HandleStackFull(cpu, ST0); } else { GetIntelR8(ST0, pop1); if (ST0->Tag == TAG_SPECIAL) { if (ST0->TagSpecial == TAG_SPECIAL_DENORM) { if (!(cpu->FpControlMask & FPCONTROL_DM)) { cpu->FpStatusES = 1; // Unmasked exception // // Instruction needs to be aborted due to unmasked // exception. We've already hosed ST0, so "correct" // it by popping the FP stack. Note that // the contents of the register have been lost, which // is a compatibility break with Intel. // POPFLT; } cpu->FpStatusExceptions |= FPCONTROL_DM; } else if (ST0->TagSpecial == TAG_SPECIAL_SNAN) { if (HandleSnan(cpu, ST0)) { // // Instruction needs to be aborted due to unmasked // exception. We've already hosed ST0, so "correct" // it by popping the FP stack. Note that // the contents of the register have been lost, which // is a compatibility break with Intel. // POPFLT; } } } } } FRAG0(FLD1) { PFPREG ST0; FpArithPreamble(cpu); cpu->FpStatusC1 = 0; // assume no error PUSHFLT(ST0); if (ST0->Tag != TAG_EMPTY) { HandleStackFull(cpu, ST0); } else { ST0->r64 = 1.0; ST0->Tag = TAG_VALID; } } FRAG0(FLDL2T) { PFPREG ST0; FpArithPreamble(cpu); cpu->FpStatusC1 = 0; // assume no error PUSHFLT(ST0); if (ST0->Tag != TAG_EMPTY) { HandleStackFull(cpu, ST0); } else { ST0->r64 = 2.3025850929940456840E0 / 6.9314718055994530942E-1; //log2(10) = ln10/ln2 ST0->Tag = TAG_VALID; } } FRAG0(FLDL2E) { PFPREG ST0; FpArithPreamble(cpu); cpu->FpStatusC1 = 0; // assume no error PUSHFLT(ST0); if (ST0->Tag != TAG_EMPTY) { HandleStackFull(cpu, ST0); } else { ST0->r64 = 1.4426950408889634074E0; ST0->Tag = TAG_VALID; } } FRAG0(FLDPI) { PFPREG ST0; FpArithPreamble(cpu); cpu->FpStatusC1 = 0; // assume no error PUSHFLT(ST0); if (ST0->Tag != TAG_EMPTY) { HandleStackFull(cpu, ST0); } else { ST0->r64 = 3.14159265358979323846; ST0->Tag = TAG_VALID; } } FRAG0(FLDLG2) { PFPREG ST0; FpArithPreamble(cpu); cpu->FpStatusC1 = 0; // assume no error PUSHFLT(ST0); if (ST0->Tag != TAG_EMPTY) { HandleStackFull(cpu, ST0); } else { ST0->r64 = 6.9314718055994530942E-1 / 2.3025850929940456840E0; ST0->Tag = TAG_VALID; } } FRAG0(FLDLN2) { PFPREG ST0; FpArithPreamble(cpu); cpu->FpStatusC1 = 0; // assume no error PUSHFLT(ST0); if (ST0->Tag != TAG_EMPTY) { HandleStackFull(cpu, ST0); } else { ST0->r64 = 6.9314718055994530942E-1; ST0->Tag = TAG_VALID; } } FRAG1IMM(FLD_STi, INT) { PFPREG ST0; PFPREG STi; FpArithPreamble(cpu); cpu->FpStatusC1 = 0; // assume no error STi = &cpu->FpStack[ST(op1)]; PUSHFLT(ST0); if (ST0->Tag != TAG_EMPTY) { HandleStackFull(cpu, ST0); } else { ST0->r64 = STi->r64; ST0->Tag = STi->Tag; ST0->TagSpecial = STi->TagSpecial; } } FRAG0(FLDZ) { PFPREG ST0; FpArithPreamble(cpu); cpu->FpStatusC1 = 0; // assume no error PUSHFLT(ST0); if (ST0->Tag != TAG_EMPTY) { HandleStackFull(cpu, ST0); } else { ST0->r64 = 0.0; ST0->Tag = TAG_ZERO; } }