Author: aandrejevic
Date: Sat Jan 3 03:26:31 2015
New Revision: 65945
URL:
http://svn.reactos.org/svn/reactos?rev=65945&view=rev
Log:
[FAST486]
Halfplement floating point division.
Halfplement opcode 0xD9.
Modified:
trunk/reactos/lib/fast486/common.inl
trunk/reactos/lib/fast486/fpu.c
trunk/reactos/lib/fast486/fpu.h
Modified: trunk/reactos/lib/fast486/common.inl
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/fast486/common.inl?rev…
==============================================================================
--- trunk/reactos/lib/fast486/common.inl [iso-8859-1] (original)
+++ trunk/reactos/lib/fast486/common.inl [iso-8859-1] Sat Jan 3 03:26:31 2015
@@ -1528,12 +1528,17 @@
}
else
{
- /* Make it denormalized */
- Data->Mantissa <<= Data->Exponent - 1;
- Data->Exponent = 1;
-
- /* Underflow */
- State->FpuStatus.Ue = TRUE;
+ if (State->FpuControl.Um)
+ {
+ /* Make it denormalized */
+ Data->Mantissa <<= Data->Exponent - 1;
+ Data->Exponent = 1;
+ }
+ else
+ {
+ /* Raise the underflow exception */
+ State->FpuStatus.Ue = TRUE;
+ }
}
}
@@ -1560,7 +1565,7 @@
FPU_ST(0) = *Data;
FPU_SET_TAG(0, Fast486GetValueTag(Data));
}
- else State->FpuStatus.Ie = TRUE;
+ else State->FpuStatus.Sf = TRUE;
}
FORCEINLINE
@@ -1573,7 +1578,7 @@
FPU_SET_TAG(0, FPU_TAG_EMPTY);
State->FpuStatus.Top++;
}
- else State->FpuStatus.Ie = TRUE;
+ else State->FpuStatus.Sf = TRUE;
}
#endif
Modified: trunk/reactos/lib/fast486/fpu.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/fast486/fpu.c?rev=6594…
==============================================================================
--- trunk/reactos/lib/fast486/fpu.c [iso-8859-1] (original)
+++ trunk/reactos/lib/fast486/fpu.c [iso-8859-1] Sat Jan 3 03:26:31 2015
@@ -66,6 +66,77 @@
return LowProduct;
}
+static ULONGLONG
+UnsignedDivMod128(ULONGLONG DividendLow,
+ ULONGLONG DividendHigh,
+ ULONGLONG Divisor,
+ PULONGLONG QuotientLow,
+ PULONGLONG QuotientHigh)
+{
+ ULONGLONG ValueLow = DividendLow;
+ ULONGLONG ValueHigh = DividendHigh;
+ ULONGLONG CurrentLow = 0ULL;
+ ULONGLONG CurrentHigh = Divisor;
+ ULONG Bits;
+
+ ASSERT(Divisor != 0ULL);
+
+ /* Initialize the quotient */
+ *QuotientLow = *QuotientHigh = 0ULL;
+
+ /* Normalize the current divisor */
+ Bits = CountLeadingZeros64(CurrentHigh);
+ CurrentHigh <<= Bits;
+
+ /* Loop while the value is higher than or equal to the original divisor */
+ while ((ValueHigh > 0ULL) || (ValueLow >= Divisor))
+ {
+ /* Shift the quotient left by one bit */
+ *QuotientHigh <<= 1;
+ *QuotientHigh |= *QuotientLow >> 63;
+ *QuotientLow <<= 1;
+
+ /* Check if the value is higher than or equal to the current divisor */
+ if ((ValueHigh > CurrentHigh)
+ || ((ValueHigh == CurrentHigh) && (ValueLow >= CurrentLow)))
+ {
+ BOOLEAN Carry = ValueLow < CurrentLow;
+
+ /* Subtract the current divisor from the value */
+ ValueHigh -= CurrentHigh;
+ ValueLow -= CurrentLow;
+ if (Carry) ValueHigh--;
+
+ /* Set the lowest bit of the quotient */
+ *QuotientLow |= 1;
+ }
+
+ /* Shift the current divisor right by one bit */
+ CurrentLow >>= 1;
+ CurrentLow |= (CurrentHigh & 1) << 63;
+ CurrentHigh >>= 1;
+ }
+
+ /*
+ * Calculate the number of significant bits the current
+ * divisor has more than the original divisor
+ */
+ Bits = CountLeadingZeros64(Divisor) + 64;
+ Bits -= (CurrentHigh > 0ULL) ? CountLeadingZeros64(CurrentHigh) : 64;
+ Bits -= (CurrentLow > 0ULL) ? CountLeadingZeros64(CurrentLow) : 64;
+
+ if (Bits)
+ {
+ /* Shift the quotient left by that amount */
+ *QuotientHigh <<= Bits;
+ *QuotientHigh |= *QuotientLow >> (64 - Bits);
+ *QuotientLow <<= Bits;
+ }
+
+ /* Return the remainder */
+ return ValueLow;
+}
+
static inline VOID FASTCALL
Fast486FpuFromInteger(PFAST486_STATE State,
LONGLONG Value,
@@ -557,8 +628,31 @@
PFAST486_FPU_DATA_REG Result)
{
FAST486_FPU_DATA_REG TempResult;
-
- if (FPU_IS_ZERO(SecondOperand))
+ ULONGLONG QuotientLow, QuotientHigh, Remainder;
+ LONG Exponent;
+
+ if (FPU_IS_INDEFINITE(FirstOperand)
+ || FPU_IS_INDEFINITE(SecondOperand)
+ || (FPU_IS_INFINITY(FirstOperand) && FPU_IS_INFINITY(SecondOperand))
+ || (FPU_IS_ZERO(FirstOperand) && FPU_IS_ZERO(SecondOperand)))
+ {
+ if (State->FpuControl.Im)
+ {
+ /* Return the indefinite NaN */
+ Result->Sign = TRUE;
+ Result->Exponent = FPU_MAX_EXPONENT + 1;
+ Result->Mantissa = FPU_INDEFINITE_MANTISSA;
+ }
+ else
+ {
+ /* Raise the invalid operation exception */
+ State->FpuStatus.Ie = TRUE;
+ }
+
+ return;
+ }
+
+ if (FPU_IS_ZERO(SecondOperand) || FPU_IS_INFINITY(FirstOperand))
{
if (State->FpuControl.Zm)
{
@@ -571,16 +665,75 @@
{
/* Raise the division by zero exception */
State->FpuStatus.Ze = TRUE;
+ }
+
+ return;
+ }
+
+ /* Calculate the sign of the result */
+ TempResult.Sign = FirstOperand->Sign ^ SecondOperand->Sign;
+
+ if (FPU_IS_ZERO(FirstOperand) || FPU_IS_INFINITY(SecondOperand))
+ {
+ /* Return zero */
+ Result->Sign = TempResult.Sign;
+ Result->Mantissa = 0ULL;
+ Result->Exponent = 0;
+ return;
+ }
+
+ /* Calculate the exponent of the result */
+ Exponent = (LONG)FirstOperand->Exponent - (LONG)SecondOperand->Exponent - 64;
+
+ /* Divide the two mantissas */
+ Remainder = UnsignedDivMod128(0ULL,
+ /* Notice the 64 above - this is the high part */
+ FirstOperand->Mantissa,
+ SecondOperand->Mantissa,
+ &QuotientLow,
+ &QuotientHigh);
+ UNREFERENCED_PARAMETER(Remainder); // TODO: Rounding
+
+ TempResult.Mantissa = QuotientLow;
+
+ if (QuotientHigh > 0ULL)
+ {
+ ULONG BitsToShift = 64 - CountLeadingZeros64(QuotientHigh);
+
+ if (!State->FpuControl.Pm)
+ {
+ /* Raise the precision expection */
+ State->FpuStatus.Pe = TRUE;
return;
}
- }
-
- TempResult.Exponent = FirstOperand->Exponent - SecondOperand->Exponent;
- TempResult.Sign = FirstOperand->Sign ^ SecondOperand->Sign;
-
- // TODO: NOT IMPLEMENTED
- UNREFERENCED_PARAMETER(TempResult);
- UNIMPLEMENTED;
+
+ TempResult.Mantissa >>= BitsToShift;
+ TempResult.Mantissa |= QuotientHigh << (64 - BitsToShift);
+ Exponent += BitsToShift;
+
+ // TODO: Rounding
+ }
+
+ if (Exponent < -FPU_REAL10_BIAS)
+ {
+ TempResult.Mantissa >>= -(Exponent + FPU_REAL10_BIAS);
+ Exponent = -FPU_REAL10_BIAS;
+
+ if ((TempResult.Mantissa == 0ULL) && !State->FpuControl.Um)
+ {
+ /* Raise the underflow exception */
+ State->FpuStatus.Ue = TRUE;
+ return;
+ }
+
+ // TODO: Rounding
+ }
+
+ TempResult.Exponent = (USHORT)(Exponent + FPU_REAL10_BIAS);
+
+ /* Normalize the result */
+ Fast486FpuNormalize(State, &TempResult);
+ *Result = TempResult;
}
static inline VOID FASTCALL
@@ -853,10 +1006,86 @@
FPU_CHECK();
#ifndef FAST486_NO_FPU
- // TODO: NOT IMPLEMENTED
- UNIMPLEMENTED;
-#else
- /* Do nothing */
+
+ if (ModRegRm.Memory)
+ {
+ switch (ModRegRm.Register)
+ {
+ /* FLD */
+ case 0:
+ {
+ ULONG Value;
+ FAST486_FPU_DATA_REG MemoryData;
+
+ if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL,
&Value))
+ {
+ /* Exception occurred */
+ return;
+ }
+
+ Fast486FpuFromSingleReal(State, Value, &MemoryData);
+ Fast486FpuPush(State, &MemoryData);
+
+ break;
+ }
+
+ /* FST */
+ case 2:
+ /* FSTP */
+ case 3:
+ {
+ // TODO: NOT IMPLEMENTED
+ UNIMPLEMENTED;
+
+ break;
+ }
+
+ /* FLDENV */
+ case 4:
+ {
+ // TODO: NOT IMPLEMENTED
+ UNIMPLEMENTED;
+
+ break;
+ }
+
+ /* FLDCW */
+ case 5:
+ {
+ Fast486ReadModrmWordOperands(State, &ModRegRm, NULL,
&State->FpuControl.Value);
+ break;
+ }
+
+ /* FSTENV */
+ case 6:
+ {
+ // TODO: NOT IMPLEMENTED
+ UNIMPLEMENTED;
+
+ break;
+ }
+
+ /* FSTCW */
+ case 7:
+ {
+ Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE,
State->FpuControl.Value);
+ break;
+ }
+
+ /* Invalid */
+ default:
+ {
+ Fast486Exception(State, FAST486_EXCEPTION_UD);
+ return;
+ }
+ }
+ }
+ else
+ {
+ // TODO: NOT IMPLEMENTED
+ UNIMPLEMENTED;
+ }
+
#endif
}
Modified: trunk/reactos/lib/fast486/fpu.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/fast486/fpu.h?rev=6594…
==============================================================================
--- trunk/reactos/lib/fast486/fpu.h [iso-8859-1] (original)
+++ trunk/reactos/lib/fast486/fpu.h [iso-8859-1] Sat Jan 3 03:26:31 2015
@@ -59,6 +59,7 @@
#define FPU_IS_INFINITY(x) (FPU_IS_NAN(x) && ((x)->Mantissa ==
FPU_MANTISSA_HIGH_BIT))
#define FPU_IS_POS_INF(x) (FPU_IS_INFINITY(x) && !(x)->Sign)
#define FPU_IS_NEG_INF(x) (FPU_IS_INFINITY(x) && (x)->Sign)
+#define FPU_IS_INDEFINITE(x) (FPU_IS_NAN(x) && !FPU_IS_INFINITY(x))
enum
{