Author: aandrejevic Date: Thu Jan 1 04:25:09 2015 New Revision: 65927
URL: http://svn.reactos.org/svn/reactos?rev=65927&view=rev Log: [FAST486] Finish implementing FPU opcode 0xDB (FILD, FIST, FISTP, FLD, FSTP).
Modified: trunk/reactos/lib/fast486/fpu.c trunk/reactos/lib/fast486/fpu.h
Modified: trunk/reactos/lib/fast486/fpu.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/fast486/fpu.c?rev=65927... ============================================================================== --- trunk/reactos/lib/fast486/fpu.c [iso-8859-1] (original) +++ trunk/reactos/lib/fast486/fpu.c [iso-8859-1] Thu Jan 1 04:25:09 2015 @@ -67,9 +67,105 @@ }
static VOID -Fast486FpuGetSingleReal(PFAST486_STATE State, - ULONG Value, - PFAST486_FPU_DATA_REG Result) +Fast486FpuFromInteger(PFAST486_STATE State, + LONGLONG Value, + PFAST486_FPU_DATA_REG Result) +{ + ULONG ZeroCount; + + Result->Sign = Result->Exponent = Result->Mantissa = 0; + if (Value == 0LL) return; + + if (Value < 0LL) + { + Result->Sign = 1; + Value = -Value; + } + + Result->Mantissa = (ULONGLONG)Value; + ZeroCount = CountLeadingZeros64(Result->Mantissa); + + Result->Mantissa <<= ZeroCount; + Result->Exponent = FPU_REAL10_BIAS + 63 - ZeroCount; +} + +static BOOLEAN +Fast486FpuToInteger(PFAST486_STATE State, + PFAST486_FPU_DATA_REG Value, + PLONGLONG Result) +{ + ULONG Bits; + ULONGLONG Remainder; + SHORT UnbiasedExp = (SHORT)Value->Exponent - FPU_REAL10_BIAS; + + if (FPU_IS_ZERO(Value)) + { + Result = 0LL; + return TRUE; + } + + if (FPU_IS_NAN(Value) || !FPU_IS_NORMALIZED(Value) + || (UnbiasedExp < 0) || (UnbiasedExp > 63)) + { + State->FpuStatus.Ie = TRUE; + return FALSE; + } + + Bits = 63 - UnbiasedExp; + + /* Calculate the result and the remainder */ + *Result = (LONGLONG)(Value->Mantissa >> Bits); + Remainder = Value->Mantissa & ((1 << Bits) - 1); + + /* The result must be positive here */ + ASSERT(*Result >= 0LL); + + switch (State->FpuControl.Rc) + { + case FPU_ROUND_NEAREST: + { + /* Check if the highest bit of the remainder is set */ + if (Remainder & (1 << (Bits - 1))) + { + *Result++; + + /* Check if all the other bits are clear */ + if (!(Remainder & ((1 << (Bits - 1)) - 1))) + { + /* Round to even */ + *Result &= ~1; + } + } + + break; + } + + case FPU_ROUND_DOWN: + { + if ((Remainder != 0ULL) && Value->Sign) *Result++; + break; + } + + case FPU_ROUND_UP: + { + if ((Remainder != 0ULL) && !Value->Sign) *Result++; + break; + } + + default: + { + /* Leave it truncated */ + } + } + + if (Value->Sign) *Result = -*Result; + return TRUE; +} + +static VOID +Fast486FpuFromSingleReal(PFAST486_STATE State, + ULONG Value, + PFAST486_FPU_DATA_REG Result) { /* Extract the sign, exponent and mantissa */ Result->Sign = (UCHAR)(Value >> 31); @@ -88,9 +184,9 @@ }
static VOID -Fast486FpuGetDoubleReal(PFAST486_STATE State, - ULONGLONG Value, - PFAST486_FPU_DATA_REG Result) +Fast486FpuFromDoubleReal(PFAST486_STATE State, + ULONGLONG Value, + PFAST486_FPU_DATA_REG Result) { /* Extract the sign, exponent and mantissa */ Result->Sign = (UCHAR)(Value >> 63); @@ -347,7 +443,7 @@ return; }
- Fast486FpuGetDoubleReal(State, Value, &MemoryData); + Fast486FpuFromDoubleReal(State, Value, &MemoryData); } else { @@ -359,7 +455,7 @@ return; }
- Fast486FpuGetSingleReal(State, Value, &MemoryData); + Fast486FpuFromSingleReal(State, Value, &MemoryData); }
SourceOperand = &MemoryData; @@ -509,8 +605,130 @@
if (ModRegRm.Memory) { - // TODO: NOT IMPLEMENTED - UNIMPLEMENTED; + switch (ModRegRm.Register) + { + /* FILD */ + case 0: + { + LONG Value; + FAST486_FPU_DATA_REG Temp; + + if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, (PULONG)&Value)) + { + /* Exception occurred */ + return; + } + + Fast486FpuFromInteger(State, (LONGLONG)Value, &Temp); + Fast486FpuPush(State, &Temp); + + break; + } + + /* FIST */ + case 2: + /* FISTP */ + case 3: + { + LONGLONG Temp; + + if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY) || (FPU_GET_TAG(0) == FPU_TAG_SPECIAL)) + { + /* Fail */ + State->FpuStatus.Ie = TRUE; + return; + } + + if (!Fast486FpuToInteger(State, &FPU_ST(0), &Temp)) + { + /* Exception occurred */ + return; + } + + /* Check if it can fit in a signed 32-bit integer */ + if ((((ULONGLONG)Temp >> 31) + 1ULL) > 1ULL) + { + State->FpuStatus.Ie = TRUE; + return; + } + + if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, (ULONG)((LONG)Temp))) + { + /* Exception occurred */ + return; + } + + if (ModRegRm.Register == 3) + { + /* Pop the FPU stack too */ + Fast486FpuPop(State); + } + + break; + } + + /* FLD */ + case 5: + { + FAST486_FPU_DATA_REG Value; + UCHAR Buffer[10]; + + if (!Fast486ReadMemory(State, + (State->PrefixFlags & FAST486_PREFIX_SEG) + ? State->SegmentOverride : FAST486_REG_DS, + ModRegRm.MemoryAddress, + FALSE, + Buffer, + sizeof(Buffer))) + { + /* Exception occurred */ + return; + } + + Value.Mantissa = *((PULONGLONG)Buffer); + Value.Exponent = *((PUSHORT)&Buffer[8]) & (FPU_MAX_EXPONENT + 1); + Value.Sign = *((PUCHAR)&Buffer[9]) >> 7; + + Fast486FpuPush(State, &Value); + break; + } + + /* FSTP */ + case 7: + { + UCHAR Buffer[10]; + + if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY) || (FPU_GET_TAG(0) == FPU_TAG_SPECIAL)) + { + /* Fail */ + State->FpuStatus.Ie = TRUE; + return; + } + + *((PULONGLONG)Buffer) = FPU_ST(0).Mantissa; + *((PUSHORT)&Buffer[sizeof(ULONGLONG)]) = FPU_ST(0).Exponent | (FPU_ST(0).Sign ? 0x8000 : 0); + + if (!Fast486WriteMemory(State, + (State->PrefixFlags & FAST486_PREFIX_SEG) + ? State->SegmentOverride : FAST486_REG_DS, + ModRegRm.MemoryAddress, + Buffer, + sizeof(Buffer))) + { + /* Exception occurred */ + return; + } + + Fast486FpuPop(State); + break; + } + + /* Invalid */ + default: + { + Fast486Exception(State, FAST486_EXCEPTION_UD); + } + } } else {
Modified: trunk/reactos/lib/fast486/fpu.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/fast486/fpu.h?rev=65927... ============================================================================== --- trunk/reactos/lib/fast486/fpu.h [iso-8859-1] (original) +++ trunk/reactos/lib/fast486/fpu.h [iso-8859-1] Thu Jan 1 04:25:09 2015 @@ -68,6 +68,14 @@ FPU_TAG_EMPTY = 3 };
+enum +{ + FPU_ROUND_NEAREST = 0, + FPU_ROUND_DOWN = 1, + FPU_ROUND_UP = 2, + FPU_ROUND_TRUNCATE = 3 +}; + FAST486_OPCODE_HANDLER(Fast486FpuOpcodeD8DC); FAST486_OPCODE_HANDLER(Fast486FpuOpcodeD9); FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDA);