Author: aandrejevic
Date: Thu Jan 1 22:51:21 2015
New Revision: 65935
URL:
http://svn.reactos.org/svn/reactos?rev=65935&view=rev
Log:
[FAST486]
Fix several serious bugs in Fast486FpuToInteger.
Halfplement opcode 0xDD (everything except FRSTOR and FSAVE).
Cleanup the code a little bit.
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=6593…
==============================================================================
--- trunk/reactos/lib/fast486/fpu.c [iso-8859-1] (original)
+++ trunk/reactos/lib/fast486/fpu.c [iso-8859-1] Thu Jan 1 22:51:21 2015
@@ -66,7 +66,7 @@
return LowProduct;
}
-static VOID
+static inline VOID FASTCALL
Fast486FpuFromInteger(PFAST486_STATE State,
LONGLONG Value,
PFAST486_FPU_DATA_REG Result)
@@ -89,7 +89,7 @@
Result->Exponent = FPU_REAL10_BIAS + 63 - ZeroCount;
}
-static BOOLEAN
+static inline BOOLEAN FASTCALL
Fast486FpuToInteger(PFAST486_STATE State,
PFAST486_FPU_DATA_REG Value,
PLONGLONG Result)
@@ -100,7 +100,7 @@
if (FPU_IS_ZERO(Value))
{
- Result = 0LL;
+ *Result = 0LL;
return TRUE;
}
@@ -127,7 +127,7 @@
/* Check if the highest bit of the remainder is set */
if (Remainder & (1 << (Bits - 1)))
{
- *Result++;
+ (*Result)++;
/* Check if all the other bits are clear */
if (!(Remainder & ((1 << (Bits - 1)) - 1)))
@@ -142,13 +142,13 @@
case FPU_ROUND_DOWN:
{
- if ((Remainder != 0ULL) && Value->Sign) *Result++;
+ if ((Remainder != 0ULL) && Value->Sign) (*Result)++;
break;
}
case FPU_ROUND_UP:
{
- if ((Remainder != 0ULL) && !Value->Sign) *Result++;
+ if ((Remainder != 0ULL) && !Value->Sign) (*Result)++;
break;
}
@@ -162,7 +162,7 @@
return TRUE;
}
-static VOID
+static inline VOID FASTCALL
Fast486FpuFromSingleReal(PFAST486_STATE State,
ULONG Value,
PFAST486_FPU_DATA_REG Result)
@@ -183,7 +183,7 @@
}
}
-static VOID
+static inline VOID FASTCALL
Fast486FpuFromDoubleReal(PFAST486_STATE State,
ULONGLONG Value,
PFAST486_FPU_DATA_REG Result)
@@ -204,7 +204,94 @@
}
}
-static VOID
+static inline BOOLEAN FASTCALL
+Fast486FpuToDoubleReal(PFAST486_STATE State,
+ PFAST486_FPU_DATA_REG Value,
+ PULONGLONG Result)
+{
+ ULONGLONG Remainder;
+ SHORT UnbiasedExp = (SHORT)Value->Exponent - FPU_REAL10_BIAS;
+
+ if (FPU_IS_ZERO(Value))
+ {
+ *Result = 0LL;
+ return TRUE;
+ }
+
+ /* Calculate the mantissa */
+ *Result = (Value->Mantissa >> 11) & ((1ULL << 52) - 1);
+
+ if (FPU_IS_NAN(Value))
+ {
+ *Result |= 0x3FF0000000000000ULL;
+ goto SetSign;
+ }
+
+ /* Check for underflow */
+ if (!FPU_IS_NORMALIZED(Value) || (UnbiasedExp < -1023))
+ {
+ State->FpuStatus.Ue = TRUE;
+ return FALSE;
+ }
+
+ /* Check for overflow */
+ if (UnbiasedExp > 1023)
+ {
+ State->FpuStatus.Oe = TRUE;
+ return FALSE;
+ }
+
+ /* Calculate the remainder */
+ Remainder = Value->Mantissa & ((1 << 11) - 1);
+
+ switch (State->FpuControl.Rc)
+ {
+ case FPU_ROUND_NEAREST:
+ {
+ /* Check if the highest bit of the remainder is set */
+ if (Remainder & (1 << 10))
+ {
+ (*Result)++;
+
+ /* Check if all the other bits are clear */
+ if (!(Remainder & ((1 << 10) - 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 */
+ }
+ }
+
+ /* Store the biased exponent */
+ *Result |= (ULONGLONG)(UnbiasedExp + FPU_REAL8_BIAS) << 52;
+
+SetSign:
+
+ if (Value->Sign) *Result |= 1ULL << 63;
+ return TRUE;
+}
+
+static inline VOID FASTCALL
Fast486FpuAdd(PFAST486_STATE State,
PFAST486_FPU_DATA_REG FirstOperand,
PFAST486_FPU_DATA_REG SecondOperand,
@@ -284,7 +371,7 @@
*Result = TempResult;
}
-static VOID
+static inline VOID FASTCALL
Fast486FpuSubtract(PFAST486_STATE State,
PFAST486_FPU_DATA_REG FirstOperand,
PFAST486_FPU_DATA_REG SecondOperand,
@@ -299,7 +386,7 @@
Fast486FpuAdd(State, Result, FirstOperand, &NegativeSecondOperand);
}
-static VOID
+static inline VOID FASTCALL
Fast486FpuCompare(PFAST486_STATE State,
PFAST486_FPU_DATA_REG FirstOperand,
PFAST486_FPU_DATA_REG SecondOperand)
@@ -352,7 +439,7 @@
}
}
-static VOID
+static inline VOID FASTCALL
Fast486FpuMultiply(PFAST486_STATE State,
PFAST486_FPU_DATA_REG FirstOperand,
PFAST486_FPU_DATA_REG SecondOperand,
@@ -378,7 +465,7 @@
*Result = TempResult;
}
-static VOID
+static inline VOID FASTCALL
Fast486FpuDivide(PFAST486_STATE State,
PFAST486_FPU_DATA_REG FirstOperand,
PFAST486_FPU_DATA_REG SecondOperand,
@@ -399,6 +486,72 @@
// TODO: NOT IMPLEMENTED
UNREFERENCED_PARAMETER(TempResult);
UNIMPLEMENTED;
+}
+
+static inline VOID FASTCALL
+Fast486FpuArithmeticOperation(PFAST486_STATE State,
+ INT Operation,
+ PFAST486_FPU_DATA_REG SourceOperand,
+ PFAST486_FPU_DATA_REG DestOperand)
+{
+ ASSERT(!(Operation & ~7));
+
+ /* Check the operation */
+ switch (Operation)
+ {
+ /* FADD */
+ case 0:
+ {
+ Fast486FpuAdd(State, DestOperand, SourceOperand, DestOperand);
+ break;
+ }
+
+ /* FMUL */
+ case 1:
+ {
+ Fast486FpuMultiply(State, DestOperand, SourceOperand, DestOperand);
+ break;
+ }
+
+ /* FCOM */
+ case 2:
+ /* FCOMP */
+ case 3:
+ {
+ Fast486FpuCompare(State, DestOperand, SourceOperand);
+ if (Operation == 3) Fast486FpuPop(State);
+
+ break;
+ }
+
+ /* FSUB */
+ case 4:
+ {
+ Fast486FpuSubtract(State, DestOperand, SourceOperand, DestOperand);
+ break;
+ }
+
+ /* FSUBR */
+ case 5:
+ {
+ Fast486FpuSubtract(State, SourceOperand, DestOperand, DestOperand);
+ break;
+ }
+
+ /* FDIV */
+ case 6:
+ {
+ Fast486FpuDivide(State, DestOperand, SourceOperand, DestOperand);
+ break;
+ }
+
+ /* FDIVR */
+ case 7:
+ {
+ Fast486FpuDivide(State, SourceOperand, DestOperand, DestOperand);
+ break;
+ }
+ }
}
#endif
@@ -497,62 +650,8 @@
}
}
- /* Check the operation */
- switch (ModRegRm.Register)
- {
- /* FADD */
- case 0:
- {
- Fast486FpuAdd(State, DestOperand, SourceOperand, DestOperand);
- break;
- }
-
- /* FMUL */
- case 1:
- {
- Fast486FpuMultiply(State, DestOperand, SourceOperand, DestOperand);
- break;
- }
-
- /* FCOM */
- case 2:
- /* FCOMP */
- case 3:
- {
- Fast486FpuCompare(State, DestOperand, SourceOperand);
- if (ModRegRm.Register == 3) Fast486FpuPop(State);
-
- break;
- }
-
- /* FSUB */
- case 4:
- {
- Fast486FpuSubtract(State, DestOperand, SourceOperand, DestOperand);
- break;
- }
-
- /* FSUBR */
- case 5:
- {
- Fast486FpuSubtract(State, SourceOperand, DestOperand, DestOperand);
- break;
- }
-
- /* FDIV */
- case 6:
- {
- Fast486FpuDivide(State, DestOperand, SourceOperand, DestOperand);
- break;
- }
-
- /* FDIVR */
- case 7:
- {
- Fast486FpuDivide(State, SourceOperand, DestOperand, DestOperand);
- break;
- }
- }
+ /* Perform the requested operation */
+ Fast486FpuArithmeticOperation(State, ModRegRm.Register, SourceOperand, DestOperand);
#endif
}
@@ -644,62 +743,8 @@
return;
}
- /* Check the operation */
- switch (ModRegRm.Register)
- {
- /* FIADD */
- case 0:
- {
- Fast486FpuAdd(State, DestOperand, SourceOperand, DestOperand);
- break;
- }
-
- /* FIMUL */
- case 1:
- {
- Fast486FpuMultiply(State, DestOperand, SourceOperand, DestOperand);
- break;
- }
-
- /* FICOM */
- case 2:
- /* FICOMP */
- case 3:
- {
- Fast486FpuCompare(State, DestOperand, SourceOperand);
- if (ModRegRm.Register == 3) Fast486FpuPop(State);
-
- break;
- }
-
- /* FISUB */
- case 4:
- {
- Fast486FpuSubtract(State, DestOperand, SourceOperand, DestOperand);
- break;
- }
-
- /* FISUBR */
- case 5:
- {
- Fast486FpuSubtract(State, SourceOperand, DestOperand, DestOperand);
- break;
- }
-
- /* FIDIV */
- case 6:
- {
- Fast486FpuDivide(State, DestOperand, SourceOperand, DestOperand);
- break;
- }
-
- /* FIDIVR */
- case 7:
- {
- Fast486FpuDivide(State, SourceOperand, DestOperand, DestOperand);
- break;
- }
- }
+ /* Perform the requested operation */
+ Fast486FpuArithmeticOperation(State, ModRegRm.Register, SourceOperand, DestOperand);
#endif
}
@@ -815,7 +860,7 @@
{
UCHAR Buffer[10];
- if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY) || (FPU_GET_TAG(0) ==
FPU_TAG_SPECIAL))
+ if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
{
/* Fail */
State->FpuStatus.Ie = TRUE;
@@ -915,10 +960,174 @@
FPU_CHECK();
#ifndef FAST486_NO_FPU
- // TODO: NOT IMPLEMENTED
- UNIMPLEMENTED;
-#else
- /* Do nothing */
+
+ if (ModRegRm.Memory)
+ {
+ switch (ModRegRm.Register)
+ {
+ /* FLD */
+ case 0:
+ {
+ ULONGLONG Value;
+ FAST486_FPU_DATA_REG MemoryData;
+
+ if (!Fast486ReadMemory(State,
+ (State->PrefixFlags & FAST486_PREFIX_SEG)
+ ? State->SegmentOverride : FAST486_REG_DS,
+ ModRegRm.MemoryAddress,
+ FALSE,
+ &Value,
+ sizeof(ULONGLONG)))
+ {
+ /* Exception occurred */
+ return;
+ }
+
+ Fast486FpuFromDoubleReal(State, Value, &MemoryData);
+ Fast486FpuPush(State, &MemoryData);
+
+ break;
+ }
+
+ /* FST */
+ case 2:
+ /* FSTP */
+ case 3:
+ {
+ ULONGLONG Value;
+
+ if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
+ {
+ /* Fail */
+ State->FpuStatus.Ie = TRUE;
+ return;
+ }
+
+ if (!Fast486FpuToDoubleReal(State, &FPU_ST(0), &Value))
+ {
+ /* Exception occurred */
+ return;
+ }
+
+ if (!Fast486WriteMemory(State,
+ (State->PrefixFlags & FAST486_PREFIX_SEG)
+ ? State->SegmentOverride : FAST486_REG_DS,
+ ModRegRm.MemoryAddress,
+ &Value,
+ sizeof(ULONGLONG)))
+ {
+ /* Exception occurred */
+ return;
+ }
+
+ if (ModRegRm.Register == 3) Fast486FpuPop(State);
+ break;
+ }
+
+ /* FRSTOR */
+ case 4:
+ {
+ // TODO: NOT IMPLEMENTED
+ UNIMPLEMENTED;
+
+ break;
+ }
+
+ /* FSAVE */
+ case 6:
+ {
+ // TODO: NOT IMPLEMENTED
+ UNIMPLEMENTED;
+
+ break;
+ }
+
+ /* FSTSW */
+ case 7:
+ {
+ Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE,
State->FpuStatus.Value);
+ break;
+ }
+
+ /* Invalid */
+ default:
+ {
+ Fast486Exception(State, FAST486_EXCEPTION_UD);
+ }
+ }
+ }
+ else
+ {
+ switch (ModRegRm.Register)
+ {
+ /* FFREE */
+ case 0:
+ {
+ FPU_SET_TAG(ModRegRm.SecondRegister, FPU_TAG_EMPTY);
+ break;
+ }
+
+ /* FXCH */
+ case 1:
+ {
+ FAST486_FPU_DATA_REG Temp;
+
+ if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY)
+ || FPU_GET_TAG(ModRegRm.SecondRegister) == FPU_TAG_EMPTY)
+ {
+ State->FpuStatus.Ie = TRUE;
+ break;
+ }
+
+ /* Exchange */
+ Temp = FPU_ST(0);
+ FPU_ST(0) = FPU_ST(ModRegRm.SecondRegister);
+ FPU_ST(ModRegRm.SecondRegister) = Temp;
+
+ FPU_UPDATE_TAG(0);
+ FPU_UPDATE_TAG(ModRegRm.SecondRegister);
+
+ break;
+ }
+
+ /* FST */
+ case 2:
+ /* FSTP */
+ case 3:
+ {
+ FPU_ST(ModRegRm.SecondRegister) = FPU_ST(0);
+ FPU_UPDATE_TAG(ModRegRm.SecondRegister);
+
+ if (ModRegRm.Register == 3) Fast486FpuPop(State);
+ break;
+ }
+
+ /* FUCOM */
+ case 4:
+ /* FUCOMP */
+ case 5:
+ {
+ if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY)
+ || (FPU_GET_TAG(ModRegRm.SecondRegister) == FPU_TAG_EMPTY))
+ {
+ State->FpuStatus.Ie = TRUE;
+ return;
+ }
+
+ Fast486FpuCompare(State, &FPU_ST(0),
&FPU_ST(ModRegRm.SecondRegister));
+ if (ModRegRm.Register == 5) Fast486FpuPop(State);
+
+ break;
+ }
+
+ /* Invalid */
+ default:
+ {
+ Fast486Exception(State, FAST486_EXCEPTION_UD);
+ }
+ }
+ }
+
#endif
}
@@ -991,63 +1200,8 @@
PopStack = TRUE;
}
- /* Check the operation */
- switch (ModRegRm.Register)
- {
- /* FIADD / FADDP */
- case 0:
- {
- Fast486FpuAdd(State, DestOperand, SourceOperand, DestOperand);
- break;
- }
-
- /* FIMUL / FMULP */
- case 1:
- {
- Fast486FpuMultiply(State, DestOperand, SourceOperand, DestOperand);
- break;
- }
-
- /* FICOM / FCOMP */
- case 2:
- /* FICOMP / FCOMPP */
- case 3:
- {
- Fast486FpuCompare(State, DestOperand, SourceOperand);
- if (ModRegRm.Register == 3) Fast486FpuPop(State);
-
- break;
- }
-
- /* FISUB / FSUBRP */
- case 4:
- {
- Fast486FpuSubtract(State, DestOperand, SourceOperand, DestOperand);
- break;
- }
-
- /* FISUBR / FSUBP */
- case 5:
- {
- Fast486FpuSubtract(State, SourceOperand, DestOperand, DestOperand);
- break;
- }
-
- /* FIDIV / FDIVRP */
- case 6:
- {
- Fast486FpuDivide(State, DestOperand, SourceOperand, DestOperand);
- break;
- }
-
- /* FIDIVR / FDIVP */
- case 7:
- {
- Fast486FpuDivide(State, SourceOperand, DestOperand, DestOperand);
- break;
- }
- }
-
+ /* Perform the requested operation */
+ Fast486FpuArithmeticOperation(State, ModRegRm.Register, SourceOperand, DestOperand);
if (PopStack) Fast486FpuPop(State);
#endif
Modified: trunk/reactos/lib/fast486/fpu.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/fast486/fpu.h?rev=6593…
==============================================================================
--- trunk/reactos/lib/fast486/fpu.h [iso-8859-1] (original)
+++ trunk/reactos/lib/fast486/fpu.h [iso-8859-1] Thu Jan 1 22:51:21 2015
@@ -34,11 +34,13 @@
return; \
}
#define FPU_ST(i) State->FpuRegisters[(State->FpuStatus.Top + (i)) %
FAST486_NUM_FPU_REGS]
-#define FPU_GET_TAG(i) ((State->FpuTag >> ((i) * 2)) & 3)
+
+#define FPU_GET_TAG(i) ((State->FpuTag >> ((i) * 2)) & 3)
#define FPU_SET_TAG(i, t) { \
State->FpuTag &= ~((1 << ((i) * 2)) | (1
<< (((i) * 2) + 1))); \
State->FpuTag |= ((t) & 3) << ((i) * 2); \
}
+#define FPU_UPDATE_TAG(i) FPU_SET_TAG((i), Fast486GetValueTag(&FPU_ST(i)))
#define FPU_REAL4_BIAS 0x7F
#define FPU_REAL8_BIAS 0x3FF