From b96fb17aab25cd1df025db6f5359623d4bd7de80 Mon Sep 17 00:00:00 2001 From: Aleksandar Andrejevic Date: Mon, 18 May 2015 15:27:08 +0000 Subject: [PATCH] [FAST486] Implement FYL2X and FYL2XP1. svn path=/trunk/; revision=67821 --- reactos/lib/fast486/fpu.c | 164 +++++++++++++++++++++++++++++++++++++- 1 file changed, 160 insertions(+), 4 deletions(-) diff --git a/reactos/lib/fast486/fpu.c b/reactos/lib/fast486/fpu.c index 87ee330359f..3f2d2a7ccd0 100644 --- a/reactos/lib/fast486/fpu.c +++ b/reactos/lib/fast486/fpu.c @@ -1019,6 +1019,110 @@ Fast486FpuCalculateTwoPowerMinusOne(PFAST486_STATE State, *Result = TempResult; } +/* + * Calculates using the identities: + * log2(x) = log10(x) / log10(2) + * log10(x)= sum { -1^(n+1) * x^n / n!, n >= 1 } + */ +static inline BOOLEAN FASTCALL +Fast486FpuCalculateLogBase2(PFAST486_STATE State, + PFAST486_FPU_DATA_REG Operand, + PFAST486_FPU_DATA_REG Result) +{ + INT i; + FAST486_FPU_DATA_REG Value = *Operand; + FAST486_FPU_DATA_REG SeriesElement; + FAST486_FPU_DATA_REG TempResult; + FAST486_FPU_DATA_REG TempValue; + LONGLONG UnbiasedExp = (LONGLONG)Operand->Exponent - FPU_REAL10_BIAS; + + if (Operand->Sign) + { + /* Raise the invalid operation exception */ + State->FpuStatus.Ie = TRUE; + + if (State->FpuControl.Im) + { + /* Return the indefinite NaN */ + Result->Sign = TRUE; + Result->Exponent = FPU_MAX_EXPONENT + 1; + Result->Mantissa = FPU_INDEFINITE_MANTISSA; + return TRUE; + } + else + { + Fast486FpuException(State); + return FALSE; + } + } + + /* Get only the mantissa as a floating-pointer number between 1 and 2 */ + Value.Exponent = FPU_REAL10_BIAS; + + /* Check if it's denormalized */ + if (!FPU_IS_NORMALIZED(&Value)) + { + ULONG Bits; + State->FpuStatus.De = TRUE; + + if (!State->FpuControl.Dm) + { + Fast486FpuException(State); + return FALSE; + } + + /* Normalize the number */ + Bits = CountLeadingZeros64(Value.Mantissa); + UnbiasedExp -= Bits; + Value.Mantissa <<= Bits; + } + + /* Subtract one from the value */ + if (!Fast486FpuSubtract(State, &Value, &FpuOne, &Value)) return FALSE; + + /* Calculate the base 10 logarithm */ + SeriesElement = TempResult = Value; + + for (i = 2; i < INVERSE_NUMBERS_COUNT / 2; i++) + { + if (!Fast486FpuMultiply(State, &SeriesElement, &Value, &SeriesElement)) + { + /* An exception occurred */ + return FALSE; + } + + /* Toggle the sign of the series element */ + SeriesElement.Sign = !SeriesElement.Sign; + + /* Divide it by the counter */ + if (!Fast486FpuMultiply(State, &SeriesElement, &FpuInverseNumber[i - 1], &TempValue)) + { + /* An exception occurred */ + return FALSE; + } + + /* And add it to the result */ + if (!Fast486FpuAdd(State, &TempResult, &TempValue, &TempResult)) + { + /* An exception occurred */ + return FALSE; + } + } + + /* Now convert the base 10 logarithm into a base 2 logarithm */ + if (!Fast486FpuDivide(State, &TempResult, &FpuLgTwo, &TempResult)) return FALSE; + + /* + * Add the exponent to the result + * log2(x * 2^y) = log2(x) + log2(2^y) = log2(x) + y + */ + Fast486FpuFromInteger(State, UnbiasedExp, &TempValue); + if (!Fast486FpuAdd(State, &TempValue, &TempResult, &TempResult)) return FALSE; + + *Result = TempResult; + return TRUE; +} + /* * Calculates using the identity: * sin(x) = sum { -1^n * x^(2n + 1) / (2n + 1)!, n >= 0 } @@ -1726,8 +1830,31 @@ FAST486_OPCODE_HANDLER(Fast486FpuOpcodeD9) /* FYL2X */ case 0x31: { - // TODO: NOT IMPLEMENTED - UNIMPLEMENTED; + FAST486_FPU_DATA_REG Logarithm; + + if (FPU_GET_TAG(0) == FPU_TAG_EMPTY || FPU_GET_TAG(1) == FPU_TAG_EMPTY) + { + State->FpuStatus.Ie = TRUE; + + if (!State->FpuControl.Im) Fast486FpuException(State); + break; + } + + if (!Fast486FpuCalculateLogBase2(State, &FPU_ST(0), &Logarithm)) + { + /* Exception occurred */ + break; + } + + if (!Fast486FpuMultiply(State, &Logarithm, &FPU_ST(1), &FPU_ST(1))) + { + /* Exception occurred */ + break; + } + + /* Pop the stack so that the result ends up in ST0 */ + Fast486FpuPop(State); + FPU_UPDATE_TAG(0); break; } @@ -1828,8 +1955,37 @@ FAST486_OPCODE_HANDLER(Fast486FpuOpcodeD9) /* FYL2XP1 */ case 0x39: { - // TODO: NOT IMPLEMENTED - UNIMPLEMENTED; + FAST486_FPU_DATA_REG Value, Logarithm; + + if (FPU_GET_TAG(0) == FPU_TAG_EMPTY || FPU_GET_TAG(1) == FPU_TAG_EMPTY) + { + State->FpuStatus.Ie = TRUE; + + if (!State->FpuControl.Im) Fast486FpuException(State); + break; + } + + if (!Fast486FpuAdd(State, &FPU_ST(0), &FpuOne, &Value)) + { + /* Exception occurred */ + break; + } + + if (!Fast486FpuCalculateLogBase2(State, &Value, &Logarithm)) + { + /* Exception occurred */ + break; + } + + if (!Fast486FpuMultiply(State, &Logarithm, &FPU_ST(1), &FPU_ST(1))) + { + /* Exception occurred */ + break; + } + + /* Pop the stack so that the result ends up in ST0 */ + Fast486FpuPop(State); + FPU_UPDATE_TAG(0); break; }