mirror of
https://github.com/reactos/reactos.git
synced 2024-12-31 19:42:51 +00:00
[FAST486]
Halfplement floating point division. Halfplement opcode 0xD9. svn path=/trunk/; revision=65945
This commit is contained in:
parent
af8ae44bc4
commit
d8f89bc80c
3 changed files with 253 additions and 18 deletions
|
@ -1528,12 +1528,17 @@ Fast486FpuNormalize(PFAST486_STATE State,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Make it denormalized */
|
if (State->FpuControl.Um)
|
||||||
Data->Mantissa <<= Data->Exponent - 1;
|
{
|
||||||
Data->Exponent = 1;
|
/* Make it denormalized */
|
||||||
|
Data->Mantissa <<= Data->Exponent - 1;
|
||||||
/* Underflow */
|
Data->Exponent = 1;
|
||||||
State->FpuStatus.Ue = TRUE;
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Raise the underflow exception */
|
||||||
|
State->FpuStatus.Ue = TRUE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1560,7 +1565,7 @@ Fast486FpuPush(PFAST486_STATE State,
|
||||||
FPU_ST(0) = *Data;
|
FPU_ST(0) = *Data;
|
||||||
FPU_SET_TAG(0, Fast486GetValueTag(Data));
|
FPU_SET_TAG(0, Fast486GetValueTag(Data));
|
||||||
}
|
}
|
||||||
else State->FpuStatus.Ie = TRUE;
|
else State->FpuStatus.Sf = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
FORCEINLINE
|
FORCEINLINE
|
||||||
|
@ -1573,7 +1578,7 @@ Fast486FpuPop(PFAST486_STATE State)
|
||||||
FPU_SET_TAG(0, FPU_TAG_EMPTY);
|
FPU_SET_TAG(0, FPU_TAG_EMPTY);
|
||||||
State->FpuStatus.Top++;
|
State->FpuStatus.Top++;
|
||||||
}
|
}
|
||||||
else State->FpuStatus.Ie = TRUE;
|
else State->FpuStatus.Sf = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -66,6 +66,77 @@ UnsignedMult128(ULONGLONG Multiplicand,
|
||||||
return LowProduct;
|
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
|
static inline VOID FASTCALL
|
||||||
Fast486FpuFromInteger(PFAST486_STATE State,
|
Fast486FpuFromInteger(PFAST486_STATE State,
|
||||||
LONGLONG Value,
|
LONGLONG Value,
|
||||||
|
@ -557,8 +628,31 @@ Fast486FpuDivide(PFAST486_STATE State,
|
||||||
PFAST486_FPU_DATA_REG Result)
|
PFAST486_FPU_DATA_REG Result)
|
||||||
{
|
{
|
||||||
FAST486_FPU_DATA_REG TempResult;
|
FAST486_FPU_DATA_REG TempResult;
|
||||||
|
ULONGLONG QuotientLow, QuotientHigh, Remainder;
|
||||||
|
LONG Exponent;
|
||||||
|
|
||||||
if (FPU_IS_ZERO(SecondOperand))
|
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)
|
if (State->FpuControl.Zm)
|
||||||
{
|
{
|
||||||
|
@ -571,16 +665,75 @@ Fast486FpuDivide(PFAST486_STATE State,
|
||||||
{
|
{
|
||||||
/* Raise the division by zero exception */
|
/* Raise the division by zero exception */
|
||||||
State->FpuStatus.Ze = TRUE;
|
State->FpuStatus.Ze = TRUE;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TempResult.Exponent = FirstOperand->Exponent - SecondOperand->Exponent;
|
/* Calculate the sign of the result */
|
||||||
TempResult.Sign = FirstOperand->Sign ^ SecondOperand->Sign;
|
TempResult.Sign = FirstOperand->Sign ^ SecondOperand->Sign;
|
||||||
|
|
||||||
// TODO: NOT IMPLEMENTED
|
if (FPU_IS_ZERO(FirstOperand) || FPU_IS_INFINITY(SecondOperand))
|
||||||
UNREFERENCED_PARAMETER(TempResult);
|
{
|
||||||
UNIMPLEMENTED;
|
/* 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.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
|
static inline VOID FASTCALL
|
||||||
|
@ -853,10 +1006,86 @@ FAST486_OPCODE_HANDLER(Fast486FpuOpcodeD9)
|
||||||
FPU_CHECK();
|
FPU_CHECK();
|
||||||
|
|
||||||
#ifndef FAST486_NO_FPU
|
#ifndef FAST486_NO_FPU
|
||||||
// TODO: NOT IMPLEMENTED
|
|
||||||
UNIMPLEMENTED;
|
if (ModRegRm.Memory)
|
||||||
#else
|
{
|
||||||
/* Do nothing */
|
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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,7 @@
|
||||||
#define FPU_IS_INFINITY(x) (FPU_IS_NAN(x) && ((x)->Mantissa == FPU_MANTISSA_HIGH_BIT))
|
#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_POS_INF(x) (FPU_IS_INFINITY(x) && !(x)->Sign)
|
||||||
#define FPU_IS_NEG_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
|
enum
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue