4449 lines
136 KiB
C
4449 lines
136 KiB
C
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
Copyright (c) 1993 Digital Equipment Corporation
|
|
|
|
Module Name:
|
|
|
|
floatem.c
|
|
|
|
Abstract:
|
|
|
|
This module implements a software emulation of the IEEE single and
|
|
double floating operations. It is required on Alpha processors since
|
|
the hardware does not fully support all of the operations required
|
|
by the IEEE standard. In particular, infinities and NaNs are not
|
|
handled by the hardware, but rather cause an exception. On receipt
|
|
of the exception, a software emulation of the floating operation
|
|
is performed to determine the real result of the operation and if
|
|
an exception will actually be raised.
|
|
|
|
This code is also used to perform all floating operations on EV4
|
|
processors when plus or minus infinity rounding is used.
|
|
|
|
Since floating exceptions are rather rare events, this routine is
|
|
written in C. Should a higher performance implementation be required,
|
|
then the algorithms contained herein, can be used to guide a higher
|
|
performance assembly language implementation.
|
|
|
|
N.B. This routine does not emulate floating loads, floating stores,
|
|
control to/from floating, or move to/from floating instructions.
|
|
These instructions never require emulation.
|
|
|
|
Floating point operations are carried out by unpacking the operands,
|
|
normalizing denormalized numbers, checking for NaNs, interpreting
|
|
infinities, and computing results.
|
|
|
|
Floating operands are converted to a format that has a value with the
|
|
appropriate number of leading zeros, an overflow bit, the mantissa, a
|
|
guard bit, a round bit, and a set of sticky bits. The unpacked mantissa
|
|
includes the hidden bit.
|
|
|
|
The overflow bit is needed for addition and is also used for multiply.
|
|
The mantissa is 24-bits for single operations and 53-bits for double
|
|
operations. The guard bit and round bit are used to hold precise values
|
|
for normalization and rounding.
|
|
|
|
If the result of an operation is normalized, then the guard bit becomes
|
|
the round bit and the round bit is accumulated with the sticky bits. If
|
|
the result of an operation needs to be shifted left one bit for purposes
|
|
of normalization, then the guard bit becomes part of the mantissa and the
|
|
round bit is used for rounding.
|
|
|
|
The round bit plus the sticky bits are used to determine how rounding is
|
|
performed.
|
|
|
|
Author:
|
|
|
|
David N. Cutler (davec) 16-Jun-1991
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Revision History:
|
|
|
|
Thomas Van Baak (tvb) 12-Sep-1992
|
|
|
|
Adapted for Alpha AXP.
|
|
|
|
Nigel Haslock (haslock) 20-Apr-1995
|
|
|
|
Adjustments for additional EV4.5 and EV5 functionality
|
|
|
|
Kim Peterson (peterson) 4-Feb-1998
|
|
|
|
Corrections for denormal and double precision denormal processing.
|
|
Rounds denormal after shifting it into denormal format.
|
|
Preserves first operand NAN if second operand is not a NAN
|
|
(single precision was already correct).
|
|
|
|
--*/
|
|
|
|
#include "ki.h"
|
|
#pragma hdrstop
|
|
#include "alphaops.h"
|
|
|
|
#if DBG
|
|
|
|
extern ULONG RtlDebugFlags;
|
|
#define DBGPRINT ((RtlDebugFlags & 0x4) != 0) && DbgPrint
|
|
#define DBGPRINT2 ((RtlDebugFlags & 0x8) != 0) && DbgPrint
|
|
|
|
#else
|
|
|
|
#define DBGPRINT 0 && DbgPrint
|
|
#define DBGPRINT2 0 && DbgPrint
|
|
|
|
#endif
|
|
|
|
#define LOW_PART(Quad) ((ULONG)(Quad))
|
|
#define HIGH_PART(Quad) ((ULONG)(Quad >> 32))
|
|
#define MAKE_QUAD(Low, High) (((ULONGLONG)(High)) << 32 | ((ULONGLONG)(Low)))
|
|
|
|
|
|
// The hardware recognizes the new CVTST instruction by the kludged
|
|
// opcode function 16.2ac instead of the proper 16.00e (per ECO #46).
|
|
|
|
|
|
#define CVTST_FUNC_PROPER 0x00E
|
|
|
|
|
|
// Define unpacked format NaN mask values and boolean macros.
|
|
|
|
// N.B. The NaN bit is set for a quiet NaN and reset for a signaling NaN.
|
|
// This is the same as Intel, Sun, IBM and opposite of Mips, HP.
|
|
|
|
|
|
#define DOUBLE_NAN_BIT_HIGH (1 << (53 - 32))
|
|
#define SINGLE_NAN_BIT (1 << 24)
|
|
|
|
#define DoubleSignalNan(DoubleOperand) \
|
|
(((DoubleOperand)->Nan != FALSE) && \
|
|
(((DoubleOperand)->MantissaHigh & DOUBLE_NAN_BIT_HIGH) == 0))
|
|
|
|
#define DoubleQuietNan(DoubleOperand) \
|
|
(((DoubleOperand)->Nan != FALSE) && \
|
|
(((DoubleOperand)->MantissaHigh & DOUBLE_NAN_BIT_HIGH) != 0))
|
|
|
|
#define SingleSignalNan(SingleOperand) \
|
|
(((SingleOperand)->Nan != FALSE) && \
|
|
(((SingleOperand)->Mantissa & SINGLE_NAN_BIT) == 0))
|
|
|
|
#define SingleQuietNan(SingleOperand) \
|
|
(((SingleOperand)->Nan != FALSE) && \
|
|
(((SingleOperand)->Mantissa & SINGLE_NAN_BIT) != 0))
|
|
|
|
|
|
// Define context block structure.
|
|
|
|
|
|
typedef struct _FP_CONTEXT_BLOCK {
|
|
ULONG Fc;
|
|
PEXCEPTION_RECORD ExceptionRecord;
|
|
PKEXCEPTION_FRAME ExceptionFrame;
|
|
PKTRAP_FRAME TrapFrame;
|
|
PSW_FPCR SoftwareFpcr;
|
|
ULONG Round;
|
|
BOOLEAN IeeeMode;
|
|
BOOLEAN UnderflowEnable;
|
|
} FP_CONTEXT_BLOCK, *PFP_CONTEXT_BLOCK;
|
|
|
|
|
|
// Define single and double operand value structures.
|
|
|
|
|
|
typedef struct _FP_DOUBLE_OPERAND {
|
|
LONG MantissaHigh;
|
|
ULONG MantissaLow;
|
|
LONGLONG Mantissa; // ## Not fully used yet
|
|
LONG Exponent;
|
|
LONG Sign;
|
|
BOOLEAN Infinity;
|
|
BOOLEAN Nan;
|
|
BOOLEAN Normal;
|
|
} FP_DOUBLE_OPERAND, *PFP_DOUBLE_OPERAND;
|
|
|
|
typedef struct _FP_SINGLE_OPERAND {
|
|
LONG Mantissa;
|
|
LONG Exponent;
|
|
LONG Sign;
|
|
BOOLEAN Infinity;
|
|
BOOLEAN Nan;
|
|
BOOLEAN Normal;
|
|
} FP_SINGLE_OPERAND, *PFP_SINGLE_OPERAND;
|
|
|
|
|
|
// Define single and double IEEE floating point memory formats.
|
|
|
|
|
|
typedef struct _DOUBLE_FORMAT {
|
|
ULONGLONG Mantissa : 52;
|
|
ULONGLONG Exponent : 11;
|
|
ULONGLONG Sign : 1;
|
|
} DOUBLE_FORMAT, *PDOUBLE_FORMAT;
|
|
|
|
typedef struct _SINGLE_FORMAT {
|
|
ULONG Mantissa : 23;
|
|
ULONG Exponent : 8;
|
|
ULONG Sign : 1;
|
|
} SINGLE_FORMAT, *PSINGLE_FORMAT;
|
|
|
|
|
|
// Define forward referenced function prototypes.
|
|
|
|
|
|
ULONGLONG
|
|
KiConvertSingleOperandToRegister (
|
|
IN ULONG SingleValue
|
|
);
|
|
|
|
ULONG
|
|
KiConvertRegisterToSingleOperand (
|
|
IN ULONGLONG DoubleValue
|
|
);
|
|
|
|
BOOLEAN
|
|
KiConvertQuadwordToLongword (
|
|
IN PFP_CONTEXT_BLOCK ContextBlock,
|
|
IN LONGLONG Quadword
|
|
);
|
|
|
|
BOOLEAN
|
|
KiDivideByZeroDouble (
|
|
IN PFP_CONTEXT_BLOCK ContextBlock,
|
|
IN PFP_DOUBLE_OPERAND DoubleOperand1,
|
|
IN PFP_DOUBLE_OPERAND DoubleOperand2
|
|
);
|
|
|
|
BOOLEAN
|
|
KiDivideByZeroSingle (
|
|
IN PFP_CONTEXT_BLOCK ContextBlock,
|
|
IN PFP_SINGLE_OPERAND SingleOperand1,
|
|
IN PFP_SINGLE_OPERAND SingleOperand2
|
|
);
|
|
|
|
PFP_IEEE_VALUE
|
|
KiInitializeIeeeValue (
|
|
IN PEXCEPTION_RECORD ExceptionRecord
|
|
);
|
|
|
|
BOOLEAN
|
|
KiInvalidCompareDouble (
|
|
IN PFP_CONTEXT_BLOCK ContextBlock,
|
|
IN BOOLEAN CheckForSignalNan,
|
|
IN PFP_DOUBLE_OPERAND DoubleOperand1,
|
|
IN PFP_DOUBLE_OPERAND DoubleOperand2
|
|
);
|
|
|
|
BOOLEAN
|
|
KiInvalidOperationDouble (
|
|
IN PFP_CONTEXT_BLOCK ContextBlock,
|
|
IN BOOLEAN CheckForSignalNan,
|
|
IN PFP_DOUBLE_OPERAND DoubleOperand1,
|
|
IN PFP_DOUBLE_OPERAND DoubleOperand2
|
|
);
|
|
|
|
BOOLEAN
|
|
KiInvalidOperationQuadword (
|
|
IN PFP_CONTEXT_BLOCK ContextBlock,
|
|
IN ULONGLONG ResultValue
|
|
);
|
|
|
|
BOOLEAN
|
|
KiInvalidOperationSingle (
|
|
IN PFP_CONTEXT_BLOCK ContextBlock,
|
|
IN BOOLEAN CheckForSignalNan,
|
|
IN PFP_SINGLE_OPERAND SingleOperand1,
|
|
IN PFP_SINGLE_OPERAND SingleOperand2
|
|
);
|
|
|
|
BOOLEAN
|
|
KiNormalizeDouble (
|
|
IN PFP_CONTEXT_BLOCK ContextBlock,
|
|
IN PFP_DOUBLE_OPERAND ResultOperand,
|
|
IN ULONGLONG StickyBits
|
|
);
|
|
|
|
BOOLEAN
|
|
KiNormalizeQuadword (
|
|
IN PFP_CONTEXT_BLOCK ContextBlock,
|
|
IN PFP_DOUBLE_OPERAND ResultOperand
|
|
);
|
|
|
|
BOOLEAN
|
|
KiNormalizeSingle (
|
|
IN PFP_CONTEXT_BLOCK ContextBlock,
|
|
IN PFP_SINGLE_OPERAND ResultOperand,
|
|
IN ULONG StickyBits
|
|
);
|
|
|
|
VOID
|
|
KiUnpackDouble (
|
|
IN ULONG Source,
|
|
IN PFP_CONTEXT_BLOCK ContextBlock,
|
|
OUT PFP_DOUBLE_OPERAND DoubleOperand
|
|
);
|
|
|
|
VOID
|
|
KiUnpackSingle (
|
|
IN ULONG Source,
|
|
IN PFP_CONTEXT_BLOCK ContextBlock,
|
|
OUT PFP_SINGLE_OPERAND SingleOperand
|
|
);
|
|
|
|
BOOLEAN
|
|
KiEmulateFloating (
|
|
IN OUT PEXCEPTION_RECORD ExceptionRecord,
|
|
IN OUT PKEXCEPTION_FRAME ExceptionFrame,
|
|
IN OUT PKTRAP_FRAME TrapFrame,
|
|
IN OUT PSW_FPCR SoftwareFpcr
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called to emulate a floating operation and convert the
|
|
exception status to the proper value. If the exception is an unimplemented
|
|
operation, then the operation is emulated. Otherwise, the status code is
|
|
just converted to its proper value.
|
|
|
|
Arguments:
|
|
|
|
ExceptionRecord - Supplies a pointer to an exception record.
|
|
|
|
ExceptionFrame - Supplies a pointer to an exception frame.
|
|
|
|
TrapFrame - Supplies a pointer to a trap frame.
|
|
|
|
SoftwareFpcr - Supplies a pointer to a variable that contains a copy of
|
|
the software FPCR.
|
|
|
|
Return Value:
|
|
|
|
A value of TRUE is returned if the floating exception is successfully
|
|
emulated. Otherwise, a value of FALSE is returned.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULARGE_INTEGER AhighBhigh;
|
|
ULARGE_INTEGER AhighBlow;
|
|
ULARGE_INTEGER AlowBhigh;
|
|
ULARGE_INTEGER AlowBlow;
|
|
ULONG Carry1;
|
|
ULONG Carry2;
|
|
BOOLEAN CompareEqual;
|
|
BOOLEAN CompareLess;
|
|
BOOLEAN CompareResult;
|
|
FP_CONTEXT_BLOCK ContextBlock;
|
|
LARGE_INTEGER DoubleDividend;
|
|
LARGE_INTEGER DoubleDivisor;
|
|
ULONG DoubleMantissaLow;
|
|
LONG DoubleMantissaHigh;
|
|
FP_DOUBLE_OPERAND DoubleOperand1;
|
|
FP_DOUBLE_OPERAND DoubleOperand2;
|
|
FP_DOUBLE_OPERAND DoubleOperand3;
|
|
LARGE_INTEGER DoubleQuotient;
|
|
PVOID ExceptionAddress;
|
|
ULONG ExponentDifference;
|
|
ULONG Fa;
|
|
ULONG Fb;
|
|
ULONG Function;
|
|
ULONG Index;
|
|
ALPHA_INSTRUCTION Instruction;
|
|
ULARGE_INTEGER LargeResult;
|
|
LONG Negation;
|
|
LONGLONG Quadword;
|
|
LONG SingleMantissa;
|
|
FP_SINGLE_OPERAND SingleOperand1;
|
|
FP_SINGLE_OPERAND SingleOperand2;
|
|
FP_SINGLE_OPERAND SingleOperand3;
|
|
ULONG StickyBits;
|
|
BOOLEAN ValidOperation;
|
|
|
|
|
|
// Save the original exception address in case another exception
|
|
// occurs.
|
|
|
|
|
|
ExceptionAddress = ExceptionRecord->ExceptionAddress;
|
|
|
|
|
|
// Any exception that occurs during the attempted emulation of the
|
|
// floating operation causes the emulation to be aborted. The new
|
|
// exception code and information is copied to the original exception
|
|
// record and a value of FALSE is returned.
|
|
|
|
|
|
try {
|
|
|
|
|
|
// Fetch the faulting or trapping instruction. Check the opcode and
|
|
// function code (including the trap enable bits) for IEEE floating
|
|
// point operations that are expected to be emulated.
|
|
|
|
// N.B. Only a subset of the 2048 possible combinations of 11 bits
|
|
// in the function field are valid. A total of 88 functions
|
|
// are affected by missing plus and minus infinity rounding
|
|
// mode support in the EV4 chip.
|
|
|
|
|
|
Instruction = *((PALPHA_INSTRUCTION)ExceptionRecord->ExceptionAddress);
|
|
DBGPRINT("KiEmulateFloating: Instruction = %.8lx, Fpcr = %.16Lx\n",
|
|
Instruction.Long, TrapFrame->Fpcr);
|
|
Function = Instruction.FpOp.Function;
|
|
|
|
ValidOperation = FALSE;
|
|
if (Instruction.FpOp.Opcode == IEEEFP_OP) {
|
|
|
|
|
|
// Adjust the function code if the instruction is CVTST.
|
|
|
|
|
|
if (Function == CVTST_FUNC) {
|
|
Function = CVTST_FUNC_PROPER;
|
|
|
|
} else if (Function == CVTST_S_FUNC) {
|
|
Function = CVTST_FUNC_PROPER | FP_TRAP_ENABLE_S;
|
|
}
|
|
|
|
switch (Function & FP_FUNCTION_MASK) {
|
|
case ADDS_FUNC :
|
|
case SUBS_FUNC :
|
|
case MULS_FUNC :
|
|
case DIVS_FUNC :
|
|
case ADDT_FUNC :
|
|
case SUBT_FUNC :
|
|
case MULT_FUNC :
|
|
case DIVT_FUNC :
|
|
case CVTTQ_FUNC :
|
|
case CVTTS_FUNC :
|
|
|
|
switch (Function & FP_TRAP_ENABLE_MASK) {
|
|
case FP_TRAP_ENABLE_NONE :
|
|
case FP_TRAP_ENABLE_U :
|
|
case FP_TRAP_ENABLE_SU :
|
|
case FP_TRAP_ENABLE_SUI :
|
|
|
|
ValidOperation = TRUE;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case CVTQS_FUNC :
|
|
case CVTQT_FUNC :
|
|
|
|
switch (Function & FP_TRAP_ENABLE_MASK) {
|
|
case FP_TRAP_ENABLE_NONE :
|
|
case FP_TRAP_ENABLE_SUI :
|
|
|
|
ValidOperation = TRUE;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case CVTST_FUNC_PROPER :
|
|
|
|
switch (Function & FP_TRAP_ENABLE_MASK) {
|
|
case FP_TRAP_ENABLE_NONE :
|
|
case FP_TRAP_ENABLE_S :
|
|
|
|
ValidOperation = TRUE;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case CMPTEQ_FUNC :
|
|
case CMPTLE_FUNC :
|
|
case CMPTLT_FUNC :
|
|
case CMPTUN_FUNC :
|
|
|
|
ValidOperation = TRUE;
|
|
break;
|
|
}
|
|
|
|
} else if (Instruction.FpOp.Opcode == FPOP_OP) {
|
|
switch (Function) {
|
|
case CVTLQ_FUNC :
|
|
case CVTQL_FUNC :
|
|
case CVTQLV_FUNC :
|
|
case CVTQLSV_FUNC :
|
|
|
|
ValidOperation = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ValidOperation == FALSE) {
|
|
|
|
|
|
// An illegal instruction, function code, format value, or trap
|
|
// enable value was encountered. Generate an illegal instruction
|
|
// exception.
|
|
|
|
|
|
ExceptionRecord->ExceptionCode = STATUS_ILLEGAL_INSTRUCTION;
|
|
DBGPRINT("KiEmulateFloating: Invalid Function or Format\n");
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// Increment the floating emulation count.
|
|
|
|
|
|
KeGetCurrentPrcb()->KeFloatingEmulationCount += 1;
|
|
|
|
|
|
// Initialize the address of the exception record, exception frame,
|
|
// and trap frame in the context block used during the emulation of
|
|
// the floating point operation.
|
|
|
|
// N.B. The SoftwareFpcr and IEEE exception records are only used
|
|
// with IEEE mode instructions.
|
|
|
|
|
|
ContextBlock.ExceptionRecord = ExceptionRecord;
|
|
ContextBlock.ExceptionFrame = ExceptionFrame;
|
|
ContextBlock.TrapFrame = TrapFrame;
|
|
ContextBlock.SoftwareFpcr = SoftwareFpcr;
|
|
|
|
|
|
// Check if the /S bit is set in the instruction. This bit is always
|
|
// set in the case of a trigger instruction of an asynchronous trap
|
|
// (assuming valid trap shadow) but not necessarily always set in the
|
|
// case of an unimplemented floating instruction fault.
|
|
|
|
|
|
if ((Function & FP_TRAP_ENABLE_S) != 0) {
|
|
ContextBlock.IeeeMode = TRUE;
|
|
|
|
} else {
|
|
ContextBlock.IeeeMode = FALSE;
|
|
}
|
|
|
|
if ((Function & FP_TRAP_ENABLE_U) != 0) {
|
|
ContextBlock.UnderflowEnable = TRUE;
|
|
|
|
} else {
|
|
ContextBlock.UnderflowEnable = FALSE;
|
|
}
|
|
|
|
|
|
// Set the current rounding mode from the rounding mode specified in
|
|
// the instruction, or if dynamic rounding is specified, from the
|
|
// rounding mode specified in the FPCR.
|
|
// Set the emulation flag and emulate the floating point operation.
|
|
// The return value is dependent on the results of the emulation.
|
|
|
|
|
|
ContextBlock.Fc = Instruction.FpOp.Fc;
|
|
Fa = Instruction.FpOp.Fa;
|
|
Fb = Instruction.FpOp.Fb;
|
|
|
|
if ((Function & FP_ROUND_MASK) == FP_ROUND_D) {
|
|
ContextBlock.Round = ((PFPCR)&TrapFrame->Fpcr)->DynamicRoundingMode;
|
|
|
|
} else {
|
|
ContextBlock.Round = (Function & FP_ROUND_MASK) >> FP_ROUND_SHIFT;
|
|
}
|
|
|
|
SoftwareFpcr->EmulationOccurred = 1;
|
|
|
|
|
|
// Unpack operands and dispense with NaNs.
|
|
|
|
|
|
switch (Function & FP_FUNCTION_MASK) {
|
|
case ADDS_FUNC :
|
|
case SUBS_FUNC :
|
|
case MULS_FUNC :
|
|
case DIVS_FUNC :
|
|
|
|
|
|
// The function has two single operand values.
|
|
|
|
|
|
KiUnpackSingle(Fa, &ContextBlock, &SingleOperand1);
|
|
KiUnpackSingle(Fb, &ContextBlock, &SingleOperand2);
|
|
|
|
|
|
// Non-IEEE mode operate instructions trap on NaN, infinity, or
|
|
// denormal operands.
|
|
|
|
|
|
if ((ContextBlock.IeeeMode == FALSE) &&
|
|
((SingleOperand1.Normal == FALSE) ||
|
|
(SingleOperand2.Normal == FALSE))) {
|
|
ExceptionRecord->ExceptionCode = STATUS_FLOAT_INVALID_OPERATION;
|
|
return FALSE;
|
|
}
|
|
|
|
if ((SingleOperand1.Nan != FALSE) || (SingleOperand2.Nan != FALSE)) {
|
|
|
|
|
|
// Store a quiet NaN if the invalid operation trap
|
|
// is disabled, or raise an exception if the invalid
|
|
// operation trap is enabled and either of the NaNs
|
|
// is a signaling NaN.
|
|
|
|
|
|
return KiInvalidOperationSingle(&ContextBlock,
|
|
TRUE,
|
|
&SingleOperand1,
|
|
&SingleOperand2);
|
|
}
|
|
break;
|
|
|
|
case ADDT_FUNC :
|
|
case SUBT_FUNC :
|
|
case MULT_FUNC :
|
|
case DIVT_FUNC :
|
|
|
|
|
|
// The function has two double operand values.
|
|
|
|
|
|
KiUnpackDouble(Fa, &ContextBlock, &DoubleOperand1);
|
|
KiUnpackDouble(Fb, &ContextBlock, &DoubleOperand2);
|
|
|
|
|
|
// Non-IEEE mode operate instructions trap on NaN, infinity, or
|
|
// denormal operands.
|
|
|
|
|
|
if ((ContextBlock.IeeeMode == FALSE) &&
|
|
((DoubleOperand1.Normal == FALSE) ||
|
|
(DoubleOperand2.Normal == FALSE))) {
|
|
ExceptionRecord->ExceptionCode = STATUS_FLOAT_INVALID_OPERATION;
|
|
return FALSE;
|
|
}
|
|
if ((DoubleOperand1.Nan != FALSE) || (DoubleOperand2.Nan != FALSE)) {
|
|
|
|
|
|
// Store a quiet NaN if the invalid operation trap
|
|
// is disabled, or raise an exception if the invalid
|
|
// operation trap is enabled and either of the NaNs
|
|
// is a signaling NaN.
|
|
|
|
|
|
return KiInvalidOperationDouble(&ContextBlock,
|
|
TRUE,
|
|
&DoubleOperand1,
|
|
&DoubleOperand2);
|
|
}
|
|
break;
|
|
|
|
case CMPTEQ_FUNC :
|
|
case CMPTLE_FUNC :
|
|
case CMPTLT_FUNC :
|
|
case CMPTUN_FUNC :
|
|
|
|
|
|
// The function has two double operand values.
|
|
|
|
|
|
KiUnpackDouble(Fa, &ContextBlock, &DoubleOperand1);
|
|
KiUnpackDouble(Fb, &ContextBlock, &DoubleOperand2);
|
|
|
|
|
|
// Non-IEEE mode compare instructions trap on NaN or denormal
|
|
// operands.
|
|
|
|
|
|
if ((ContextBlock.IeeeMode == FALSE) &&
|
|
(((DoubleOperand1.Normal == FALSE) &&
|
|
(DoubleOperand1.Infinity == FALSE)) ||
|
|
((DoubleOperand2.Normal == FALSE) &&
|
|
(DoubleOperand2.Infinity == FALSE)))) {
|
|
ExceptionRecord->ExceptionCode = STATUS_FLOAT_INVALID_OPERATION;
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// Compare operation.
|
|
|
|
// If either operand is a NaN, then check the type of compare
|
|
// operation to determine the result value and if an exception
|
|
// should be raised. Otherwise, if the operation is a compare
|
|
// unordered operation, store a false result.
|
|
|
|
|
|
if ((DoubleOperand1.Nan != FALSE) || (DoubleOperand2.Nan != FALSE)) {
|
|
|
|
|
|
// If the compare is an unordered compare, then store a true
|
|
// result (a NaN compares unordered with everything, including
|
|
// itself). Raise an exception if the invalid operation trap
|
|
// is enabled and either of the NaNs is a signaling NaN.
|
|
|
|
// Otherwise, if the operation is compare equal, then store a
|
|
// false result. Raise an exception if the invalid operation
|
|
// trap is enabled and either of the NaNs is a signaling NaN.
|
|
|
|
// Otherwise store a false result and raise an exception if
|
|
// the invalid operation trap is enabled.
|
|
|
|
|
|
if ((Function & FP_FUNCTION_MASK) == CMPTUN_FUNC) {
|
|
KiSetRegisterValue(ContextBlock.Fc + 32,
|
|
FP_COMPARE_TRUE,
|
|
ExceptionFrame,
|
|
TrapFrame);
|
|
|
|
return KiInvalidCompareDouble(&ContextBlock,
|
|
TRUE,
|
|
&DoubleOperand1,
|
|
&DoubleOperand2);
|
|
|
|
} else if ((Function & FP_FUNCTION_MASK) == CMPTEQ_FUNC) {
|
|
KiSetRegisterValue(ContextBlock.Fc + 32,
|
|
FP_COMPARE_FALSE,
|
|
ExceptionFrame,
|
|
TrapFrame);
|
|
|
|
return KiInvalidCompareDouble(&ContextBlock,
|
|
TRUE,
|
|
&DoubleOperand1,
|
|
&DoubleOperand2);
|
|
|
|
} else {
|
|
KiSetRegisterValue(ContextBlock.Fc + 32,
|
|
FP_COMPARE_FALSE,
|
|
ExceptionFrame,
|
|
TrapFrame);
|
|
|
|
return KiInvalidCompareDouble(&ContextBlock,
|
|
FALSE,
|
|
&DoubleOperand1,
|
|
&DoubleOperand2);
|
|
}
|
|
|
|
} else {
|
|
if ((Function & FP_FUNCTION_MASK) == CMPTUN_FUNC) {
|
|
KiSetRegisterValue(ContextBlock.Fc + 32,
|
|
FP_COMPARE_FALSE,
|
|
ExceptionFrame,
|
|
TrapFrame);
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CVTST_FUNC_PROPER :
|
|
|
|
|
|
// The function has one single operand value which is found in
|
|
// the second operand.
|
|
|
|
|
|
KiUnpackSingle(Fb, &ContextBlock, &SingleOperand1);
|
|
|
|
|
|
// Non-IEEE mode convert instructions trap on NaN, infinity, or
|
|
// denormal operands.
|
|
|
|
|
|
if ((ContextBlock.IeeeMode == FALSE) &&
|
|
(SingleOperand1.Normal == FALSE)) {
|
|
ExceptionRecord->ExceptionCode = STATUS_FLOAT_INVALID_OPERATION;
|
|
return FALSE;
|
|
}
|
|
break;
|
|
|
|
case CVTTQ_FUNC :
|
|
case CVTTS_FUNC :
|
|
|
|
|
|
// The function has one double operand value which is found in
|
|
// the second operand.
|
|
|
|
|
|
KiUnpackDouble(Fb, &ContextBlock, &DoubleOperand1);
|
|
|
|
|
|
// Non-IEEE mode convert instructions trap on NaN, infinity, or
|
|
// denormal operands.
|
|
|
|
|
|
if ((ContextBlock.IeeeMode == FALSE) &&
|
|
(DoubleOperand1.Normal == FALSE)) {
|
|
ExceptionRecord->ExceptionCode = STATUS_FLOAT_INVALID_OPERATION;
|
|
return FALSE;
|
|
}
|
|
break;
|
|
|
|
case CVTLQ_FUNC :
|
|
case CVTQL_FUNC :
|
|
case CVTQS_FUNC :
|
|
case CVTQT_FUNC :
|
|
|
|
|
|
// The function has one quadword operand value which is found in
|
|
// the second operand.
|
|
|
|
|
|
Quadword = KiGetRegisterValue(Fb + 32,
|
|
ContextBlock.ExceptionFrame,
|
|
ContextBlock.TrapFrame);
|
|
break;
|
|
}
|
|
|
|
|
|
// Case to the proper function routine to emulate the operation.
|
|
|
|
|
|
Negation = 0;
|
|
switch (Function & FP_FUNCTION_MASK) {
|
|
|
|
|
|
// Floating subtract operation.
|
|
|
|
// Floating subtract is accomplished by complementing the sign
|
|
// of the second operand and then performing an add operation.
|
|
|
|
|
|
case SUBS_FUNC :
|
|
DBGPRINT2("subs\n");
|
|
Negation = 0x1;
|
|
|
|
|
|
// Floating add operation.
|
|
|
|
// Floating add is accomplished using signed magnitude addition.
|
|
|
|
// The exponent difference is calculated and the smaller number
|
|
// is right shifted by the specified amount, but no more than
|
|
// the width of the operand values (i.e., 26 for single and 55
|
|
// for double). The shifted out value is saved for rounding.
|
|
|
|
// If the signs of the two operands are the same, then they
|
|
// are added together after having performed the alignment
|
|
// shift.
|
|
|
|
// If the signs of the two operands are different, then the
|
|
// sign of the result is the sign of the larger operand and
|
|
// the smaller operand is subtracted from the larger operand.
|
|
// In order to avoid making a double level test (i.e., one on
|
|
// the exponents, and one on the mantissas if the exponents
|
|
// are equal), it is possible that the result of the subtract
|
|
// could be negative (if the exponents are equal). If this
|
|
// occurs, then the result sign and mantissa are complemented
|
|
// to obtain the correct result.
|
|
|
|
|
|
case ADDS_FUNC :
|
|
DBGPRINT2("adds\n");
|
|
|
|
|
|
// Complement the sign of the second operand if the operation
|
|
// is subtraction.
|
|
|
|
|
|
SingleOperand2.Sign ^= Negation;
|
|
|
|
|
|
// Reorder the operands according to their exponent value
|
|
// so that Operand1 exponent will be >= Operand2 exponent.
|
|
|
|
|
|
if (SingleOperand2.Exponent > SingleOperand1.Exponent) {
|
|
SingleOperand3 = SingleOperand2;
|
|
SingleOperand2 = SingleOperand1;
|
|
SingleOperand1 = SingleOperand3;
|
|
}
|
|
|
|
|
|
// Compute the exponent difference and shift the smaller
|
|
// mantissa right by the difference value or 26 which ever
|
|
// is smaller. The bits shifted out are termed the sticky
|
|
// bits and are used later in the rounding operation.
|
|
|
|
|
|
ExponentDifference =
|
|
SingleOperand1.Exponent - SingleOperand2.Exponent;
|
|
|
|
if (ExponentDifference > 26) {
|
|
ExponentDifference = 26;
|
|
}
|
|
|
|
StickyBits =
|
|
SingleOperand2.Mantissa & ((1 << ExponentDifference) - 1);
|
|
SingleMantissa = SingleOperand2.Mantissa >> ExponentDifference;
|
|
|
|
|
|
// If the operands both have the same sign, then perform the
|
|
// operation by adding the values together. Otherwise, if the
|
|
// operands are not infinity, perform the operation by
|
|
// subtracting the second operand from the first operand.
|
|
|
|
|
|
if ((SingleOperand1.Sign ^ SingleOperand2.Sign) == 0) {
|
|
SingleOperand1.Mantissa += SingleMantissa;
|
|
|
|
} else {
|
|
if ((SingleOperand1.Infinity != FALSE) &&
|
|
(SingleOperand2.Infinity != FALSE)) {
|
|
return KiInvalidOperationSingle(&ContextBlock,
|
|
FALSE,
|
|
&SingleOperand1,
|
|
&SingleOperand2);
|
|
|
|
} else if (SingleOperand1.Infinity == FALSE) {
|
|
if (StickyBits != 0) {
|
|
SingleOperand1.Mantissa -= 1;
|
|
}
|
|
|
|
SingleOperand1.Mantissa -= SingleMantissa;
|
|
if (SingleOperand1.Mantissa < 0) {
|
|
SingleOperand1.Mantissa = -SingleOperand1.Mantissa;
|
|
SingleOperand1.Sign ^= 0x1;
|
|
}
|
|
|
|
|
|
// If the result is exactly zero and the signs of the
|
|
// operands differ, then the result is plus zero except
|
|
// when the rounding mode is minus infinity.
|
|
|
|
|
|
if ((SingleOperand1.Mantissa == 0) && (StickyBits == 0)) {
|
|
if (ContextBlock.Round == ROUND_TO_MINUS_INFINITY) {
|
|
SingleOperand1.Sign = 0x1;
|
|
|
|
} else {
|
|
SingleOperand1.Sign = 0x0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Normalize and store the result value.
|
|
|
|
|
|
return KiNormalizeSingle(&ContextBlock,
|
|
&SingleOperand1,
|
|
StickyBits);
|
|
|
|
case SUBT_FUNC :
|
|
DBGPRINT2("subt\n");
|
|
Negation = 0x1;
|
|
|
|
case ADDT_FUNC :
|
|
DBGPRINT2("addt\n");
|
|
|
|
|
|
// Complement the sign of the second operand if the operation
|
|
// is subtraction.
|
|
|
|
|
|
DoubleOperand2.Sign ^= Negation;
|
|
|
|
|
|
// Reorder the operands according to their exponent value
|
|
// so that Operand1 exponent will be >= Operand2 exponent.
|
|
|
|
|
|
if (DoubleOperand2.Exponent > DoubleOperand1.Exponent) {
|
|
DoubleOperand3 = DoubleOperand2;
|
|
DoubleOperand2 = DoubleOperand1;
|
|
DoubleOperand1 = DoubleOperand3;
|
|
}
|
|
|
|
|
|
// Compute the exponent difference and shift the smaller
|
|
// mantissa right by the difference value or 55 which ever
|
|
// is smaller. The bits shifted out are termed the sticky
|
|
// bits and are used later in the rounding operation.
|
|
|
|
|
|
ExponentDifference =
|
|
DoubleOperand1.Exponent - DoubleOperand2.Exponent;
|
|
|
|
if (ExponentDifference > 55) {
|
|
ExponentDifference = 55;
|
|
}
|
|
|
|
if (ExponentDifference >= 32) {
|
|
ExponentDifference -= 32;
|
|
StickyBits = (DoubleOperand2.MantissaLow) |
|
|
(DoubleOperand2.MantissaHigh & ((1 << ExponentDifference) - 1));
|
|
|
|
DoubleMantissaLow =
|
|
DoubleOperand2.MantissaHigh >> ExponentDifference;
|
|
|
|
DoubleMantissaHigh = 0;
|
|
|
|
} else if (ExponentDifference > 0) {
|
|
StickyBits =
|
|
DoubleOperand2.MantissaLow & ((1 << ExponentDifference) - 1);
|
|
|
|
DoubleMantissaLow =
|
|
(DoubleOperand2.MantissaLow >> ExponentDifference) |
|
|
(DoubleOperand2.MantissaHigh << (32 - ExponentDifference));
|
|
|
|
DoubleMantissaHigh =
|
|
DoubleOperand2.MantissaHigh >> ExponentDifference;
|
|
|
|
} else {
|
|
StickyBits = 0;
|
|
DoubleMantissaLow = DoubleOperand2.MantissaLow;
|
|
DoubleMantissaHigh = DoubleOperand2.MantissaHigh;
|
|
}
|
|
|
|
|
|
// If the operands both have the same sign, then perform the
|
|
// operation by adding the values together. Otherwise, if the
|
|
// operands are not infinity, perform the operation by
|
|
// subtracting the second operand from the first operand.
|
|
|
|
|
|
if ((DoubleOperand1.Sign ^ DoubleOperand2.Sign) == 0) {
|
|
DoubleOperand1.MantissaLow += DoubleMantissaLow;
|
|
DoubleOperand1.MantissaHigh += DoubleMantissaHigh;
|
|
if (DoubleOperand1.MantissaLow < DoubleMantissaLow) {
|
|
DoubleOperand1.MantissaHigh += 1;
|
|
}
|
|
|
|
} else {
|
|
if ((DoubleOperand1.Infinity != FALSE) &&
|
|
(DoubleOperand2.Infinity != FALSE)) {
|
|
return KiInvalidOperationDouble(&ContextBlock,
|
|
FALSE,
|
|
&DoubleOperand1,
|
|
&DoubleOperand2);
|
|
|
|
} else if (DoubleOperand1.Infinity == FALSE) {
|
|
if (StickyBits != 0) {
|
|
if (DoubleOperand1.MantissaLow < 1) {
|
|
DoubleOperand1.MantissaHigh -= 1;
|
|
}
|
|
|
|
DoubleOperand1.MantissaLow -= 1;
|
|
}
|
|
|
|
if (DoubleOperand1.MantissaLow < DoubleMantissaLow) {
|
|
DoubleOperand1.MantissaHigh -= 1;
|
|
}
|
|
|
|
DoubleOperand1.MantissaLow -= DoubleMantissaLow;
|
|
DoubleOperand1.MantissaHigh -= DoubleMantissaHigh;
|
|
if (DoubleOperand1.MantissaHigh < 0) {
|
|
DoubleOperand1.MantissaLow = -(LONG)DoubleOperand1.MantissaLow;
|
|
DoubleOperand1.MantissaHigh = -DoubleOperand1.MantissaHigh;
|
|
if (DoubleOperand1.MantissaLow != 0) {
|
|
DoubleOperand1.MantissaHigh -= 1;
|
|
}
|
|
DoubleOperand1.Sign ^= 0x1;
|
|
}
|
|
|
|
|
|
// If the result is exactly zero and the signs of the
|
|
// operands differ, then the result is plus zero except
|
|
// when the rounding mode is minus infinity.
|
|
|
|
|
|
if ((DoubleOperand1.MantissaHigh == 0) &&
|
|
(DoubleOperand1.MantissaLow == 0) &&
|
|
(StickyBits == 0)) {
|
|
if (ContextBlock.Round == ROUND_TO_MINUS_INFINITY) {
|
|
DoubleOperand1.Sign = 0x1;
|
|
|
|
} else {
|
|
DoubleOperand1.Sign = 0x0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Normalize and store the result value.
|
|
|
|
|
|
return KiNormalizeDouble(&ContextBlock,
|
|
&DoubleOperand1,
|
|
StickyBits);
|
|
|
|
|
|
// Floating multiply operation.
|
|
|
|
// Floating multiply is accomplished using unsigned multiplies
|
|
// of the mantissa values, and adding the partial results together
|
|
// to form the total product.
|
|
|
|
// The two mantissa values are preshifted such that the final
|
|
// result is properly aligned.
|
|
|
|
|
|
case MULS_FUNC :
|
|
DBGPRINT2("muls\n");
|
|
|
|
|
|
// Reorder the operands according to their exponent value
|
|
// so that Operand1 exponent will be >= Operand2 exponent.
|
|
|
|
|
|
if (SingleOperand2.Exponent > SingleOperand1.Exponent) {
|
|
SingleOperand3 = SingleOperand2;
|
|
SingleOperand2 = SingleOperand1;
|
|
SingleOperand1 = SingleOperand3;
|
|
}
|
|
|
|
|
|
// If the first operand is infinite and the second operand is
|
|
// zero, then an invalid operation is specified.
|
|
|
|
|
|
if ((SingleOperand1.Infinity != FALSE) &&
|
|
(SingleOperand2.Infinity == FALSE) &&
|
|
(SingleOperand2.Mantissa == 0)) {
|
|
return KiInvalidOperationSingle(&ContextBlock,
|
|
FALSE,
|
|
&SingleOperand1,
|
|
&SingleOperand2);
|
|
}
|
|
|
|
|
|
// Preshift the operand mantissas so the result will be a
|
|
// properly aligned 64-bit value and then unsigned multiply
|
|
// the two mantissa values. The single result is the high part
|
|
// of the 64-bit product and the sticky bits are the low part
|
|
// of the 64-bit product.
|
|
|
|
// The size of the product will be (1+23+2)+(1+23+2) = 52 bits
|
|
// of which the high (1+1+23+2) = 27 bits are result and the
|
|
// remaining 25 bits are sticky. By preshifting the operands
|
|
// left 7 bits, the number of sticky bits is 32. This alignment
|
|
// is convenient.
|
|
|
|
// The 7 bit preshift amount must be applied in part to both
|
|
// operands because 26 of 32 bits of the mantissa are used and
|
|
// so neither operand can be safely shifted left by more than 6
|
|
// bits. Thus one operand is shifted the maximum of 6 bits and
|
|
// the other the remaining 1 bit.
|
|
|
|
|
|
LargeResult.QuadPart = ((ULONGLONG)((ULONG)(SingleOperand1.Mantissa << (32 - 26)))) *
|
|
((ULONGLONG)((ULONG)(SingleOperand2.Mantissa << 1)));
|
|
|
|
SingleOperand1.Mantissa = LargeResult.HighPart;
|
|
StickyBits = LargeResult.LowPart;
|
|
|
|
|
|
// Compute the sign and exponent of the result.
|
|
|
|
|
|
SingleOperand1.Sign ^= SingleOperand2.Sign;
|
|
SingleOperand1.Exponent +=
|
|
SingleOperand2.Exponent - SINGLE_EXPONENT_BIAS;
|
|
|
|
|
|
// Normalize and store the result value.
|
|
|
|
|
|
return KiNormalizeSingle(&ContextBlock,
|
|
&SingleOperand1,
|
|
StickyBits);
|
|
|
|
case MULT_FUNC :
|
|
DBGPRINT2("mult\n");
|
|
|
|
|
|
// Reorder the operands according to their exponent value
|
|
// so that Operand1 exponent will be >= Operand2 exponent.
|
|
|
|
|
|
if (DoubleOperand2.Exponent > DoubleOperand1.Exponent) {
|
|
DoubleOperand3 = DoubleOperand2;
|
|
DoubleOperand2 = DoubleOperand1;
|
|
DoubleOperand1 = DoubleOperand3;
|
|
}
|
|
|
|
|
|
// If the first operand is infinite and the second operand is
|
|
// zero, then an invalid operation is specified.
|
|
|
|
|
|
if ((DoubleOperand1.Infinity != FALSE) &&
|
|
(DoubleOperand2.Infinity == FALSE) &&
|
|
(DoubleOperand2.MantissaHigh == 0)) {
|
|
return KiInvalidOperationDouble(&ContextBlock,
|
|
FALSE,
|
|
&DoubleOperand1,
|
|
&DoubleOperand2);
|
|
}
|
|
|
|
|
|
// Preshift the operand mantissas so the result will be a
|
|
// properly aligned 128-bit value and then unsigned multiply
|
|
// the two mantissa values. The double result is the high part
|
|
// of the 128-bit product and the sticky bits are the low part
|
|
// of the 128-bit product.
|
|
|
|
// The size of the product will be (1+52+2)+(1+52+2) = 110 bits
|
|
// of which the high (1+1+52+2) = 56 bits are result and the
|
|
// remaining 54 bits are sticky. By preshifting the operands
|
|
// left 10 bits, the number of sticky bits is 64. This alignment
|
|
// is convenient.
|
|
|
|
// The 10 bit preshift amount must be applied in part to both
|
|
// operands because 55 of 64 bits of the mantissa are used and
|
|
// so neither operand can be safely shifted left by more than 9
|
|
// bits. Thus one operand is shifted the maximum of 9 bits and
|
|
// the other the remaining 1 bit.
|
|
|
|
|
|
DoubleOperand1.MantissaHigh =
|
|
(DoubleOperand1.MantissaHigh << 1) |
|
|
(DoubleOperand1.MantissaLow >> 31);
|
|
|
|
DoubleOperand1.MantissaLow <<= 1;
|
|
DoubleOperand2.MantissaHigh =
|
|
(DoubleOperand2.MantissaHigh << (64 - 55)) |
|
|
(DoubleOperand2.MantissaLow >> (32 - (64 - 55)));
|
|
|
|
DoubleOperand2.MantissaLow <<= (64 - 55);
|
|
|
|
|
|
// The 128-bit product is formed by multiplying and adding
|
|
// all the cross product values.
|
|
|
|
// Consider the operands (A and B) as being composed of two
|
|
// parts Ahigh, Alow, Bhigh, and Blow. The cross product sum
|
|
// is then:
|
|
|
|
// Ahigh * Bhigh * 2^64 +
|
|
// Ahigh * Blow * 2^32 +
|
|
// Alow * Bhigh * 2^32 +
|
|
// Alow * Blow
|
|
|
|
|
|
AhighBhigh.QuadPart = (ULONGLONG)(ULONG)DoubleOperand1.MantissaHigh *
|
|
(ULONGLONG)(ULONG)DoubleOperand2.MantissaHigh;
|
|
|
|
AhighBlow.QuadPart = (ULONGLONG)(ULONG)DoubleOperand1.MantissaHigh *
|
|
(ULONGLONG)DoubleOperand2.MantissaLow;
|
|
|
|
AlowBhigh.QuadPart = (ULONGLONG)DoubleOperand1.MantissaLow *
|
|
(ULONGLONG)(ULONG)DoubleOperand2.MantissaHigh;
|
|
|
|
AlowBlow.QuadPart = (ULONGLONG)DoubleOperand1.MantissaLow *
|
|
(ULONGLONG)DoubleOperand2.MantissaLow;
|
|
|
|
AlowBlow.HighPart += AhighBlow.LowPart;
|
|
if (AlowBlow.HighPart < AhighBlow.LowPart) {
|
|
Carry1 = 1;
|
|
|
|
} else {
|
|
Carry1 = 0;
|
|
}
|
|
|
|
AlowBlow.HighPart += AlowBhigh.LowPart;
|
|
if (AlowBlow.HighPart < AlowBhigh.LowPart) {
|
|
Carry1 += 1;
|
|
}
|
|
|
|
DoubleOperand1.MantissaLow = AhighBlow.HighPart + Carry1;
|
|
if (DoubleOperand1.MantissaLow < Carry1) {
|
|
Carry2 = 1;
|
|
|
|
} else {
|
|
Carry2 = 0;
|
|
}
|
|
|
|
DoubleOperand1.MantissaLow += AlowBhigh.HighPart;
|
|
if (DoubleOperand1.MantissaLow < AlowBhigh.HighPart) {
|
|
Carry2 += 1;
|
|
}
|
|
|
|
DoubleOperand1.MantissaLow += AhighBhigh.LowPart;
|
|
if (DoubleOperand1.MantissaLow < AhighBhigh.LowPart) {
|
|
Carry2 += 1;
|
|
}
|
|
|
|
DoubleOperand1.MantissaHigh = AhighBhigh.HighPart + Carry2;
|
|
StickyBits = AlowBlow.HighPart | AlowBlow.LowPart;
|
|
|
|
|
|
// Compute the sign and exponent of the result.
|
|
|
|
|
|
DoubleOperand1.Sign ^= DoubleOperand2.Sign;
|
|
DoubleOperand1.Exponent +=
|
|
DoubleOperand2.Exponent - DOUBLE_EXPONENT_BIAS;
|
|
|
|
|
|
// Normalize and store the result value.
|
|
|
|
|
|
return KiNormalizeDouble(&ContextBlock,
|
|
&DoubleOperand1,
|
|
StickyBits);
|
|
|
|
|
|
// Floating divide operation.
|
|
|
|
// Floating division is accomplished by repeated subtract using
|
|
// a single one-bit-at-a-time algorithm. The number of division
|
|
// steps performed is equal to the mantissa size plus one guard
|
|
// bit.
|
|
|
|
// The sticky bits are the remainder after the specified number
|
|
// of division steps.
|
|
|
|
|
|
case DIVS_FUNC :
|
|
DBGPRINT2("divs\n");
|
|
|
|
|
|
// If the first operand is infinite and the second operand
|
|
// is infinite, or both operands are zero, then an invalid
|
|
// operation is specified.
|
|
|
|
|
|
if (((SingleOperand1.Infinity != FALSE) &&
|
|
(SingleOperand2.Infinity != FALSE)) ||
|
|
((SingleOperand1.Infinity == FALSE) &&
|
|
(SingleOperand1.Mantissa == 0) &&
|
|
(SingleOperand2.Infinity == FALSE) &&
|
|
(SingleOperand2.Mantissa == 0))) {
|
|
return KiInvalidOperationSingle(&ContextBlock,
|
|
FALSE,
|
|
&SingleOperand1,
|
|
&SingleOperand2);
|
|
}
|
|
|
|
|
|
// If the second operand is zero, then a divide by zero
|
|
// operation is specified.
|
|
|
|
|
|
if ((SingleOperand2.Infinity == FALSE) &&
|
|
(SingleOperand2.Mantissa == 0)) {
|
|
return KiDivideByZeroSingle(&ContextBlock,
|
|
&SingleOperand1,
|
|
&SingleOperand2);
|
|
}
|
|
|
|
|
|
// If the first operand is infinite, then the result is
|
|
// infinite. Otherwise, if the second operand is infinite,
|
|
// then the result is zero (note that both operands cannot
|
|
// be infinite).
|
|
|
|
|
|
if (SingleOperand1.Infinity != FALSE) {
|
|
SingleOperand1.Sign ^= SingleOperand2.Sign;
|
|
return KiNormalizeSingle(&ContextBlock,
|
|
&SingleOperand1,
|
|
0);
|
|
|
|
} else if (SingleOperand2.Infinity != FALSE) {
|
|
SingleOperand1.Sign ^= SingleOperand2.Sign;
|
|
SingleOperand1.Exponent = 0;
|
|
SingleOperand1.Mantissa = 0;
|
|
return KiNormalizeSingle(&ContextBlock,
|
|
&SingleOperand1,
|
|
0);
|
|
}
|
|
|
|
|
|
// Perform divide operation by repeating a single bit
|
|
// divide step 26 iterations.
|
|
|
|
|
|
SingleOperand3.Mantissa = 0;
|
|
for (Index = 0; Index < 26; Index += 1) {
|
|
SingleOperand3.Mantissa <<= 1;
|
|
if (SingleOperand1.Mantissa >= SingleOperand2.Mantissa) {
|
|
SingleOperand1.Mantissa -= SingleOperand2.Mantissa;
|
|
SingleOperand3.Mantissa |= 1;
|
|
}
|
|
|
|
SingleOperand1.Mantissa <<= 1;
|
|
}
|
|
|
|
|
|
// Compute the sign and exponent of the result.
|
|
|
|
|
|
SingleOperand3.Sign = SingleOperand1.Sign ^ SingleOperand2.Sign;
|
|
SingleOperand3.Exponent = SingleOperand1.Exponent -
|
|
SingleOperand2.Exponent + SINGLE_EXPONENT_BIAS;
|
|
|
|
|
|
// Normalize and store the result value.
|
|
|
|
|
|
SingleOperand3.Infinity = FALSE;
|
|
SingleOperand3.Nan = FALSE;
|
|
return KiNormalizeSingle(&ContextBlock,
|
|
&SingleOperand3,
|
|
SingleOperand1.Mantissa);
|
|
|
|
case DIVT_FUNC :
|
|
DBGPRINT2("divt\n");
|
|
|
|
|
|
// If the first operand is infinite and the second operand
|
|
// is infinite, or both operands are zero, then an invalid
|
|
// operation is specified.
|
|
|
|
|
|
if (((DoubleOperand1.Infinity != FALSE) &&
|
|
(DoubleOperand2.Infinity != FALSE)) ||
|
|
((DoubleOperand1.Infinity == FALSE) &&
|
|
(DoubleOperand1.MantissaHigh == 0) &&
|
|
(DoubleOperand2.Infinity == FALSE) &&
|
|
(DoubleOperand2.MantissaHigh == 0))) {
|
|
return KiInvalidOperationDouble(&ContextBlock,
|
|
FALSE,
|
|
&DoubleOperand1,
|
|
&DoubleOperand2);
|
|
}
|
|
|
|
|
|
// If the second operand is zero, then a divide by zero
|
|
// operation is specified.
|
|
|
|
|
|
if ((DoubleOperand2.Infinity == FALSE) &&
|
|
(DoubleOperand2.MantissaHigh == 0)) {
|
|
return KiDivideByZeroDouble(&ContextBlock,
|
|
&DoubleOperand1,
|
|
&DoubleOperand2);
|
|
}
|
|
|
|
|
|
// If the first operand is infinite, then the result is
|
|
// infinite. Otherwise, if the second operand is infinite,
|
|
// then the result is zero (note that both operands cannot
|
|
// be infinite).
|
|
|
|
|
|
if (DoubleOperand1.Infinity != FALSE) {
|
|
DoubleOperand1.Sign ^= DoubleOperand2.Sign;
|
|
return KiNormalizeDouble(&ContextBlock,
|
|
&DoubleOperand1,
|
|
0);
|
|
|
|
} else if (DoubleOperand2.Infinity != FALSE) {
|
|
DoubleOperand1.Sign ^= DoubleOperand2.Sign;
|
|
DoubleOperand1.Exponent = 0;
|
|
DoubleOperand1.MantissaHigh = 0;
|
|
DoubleOperand1.MantissaLow = 0;
|
|
return KiNormalizeDouble(&ContextBlock,
|
|
&DoubleOperand1,
|
|
0);
|
|
}
|
|
|
|
|
|
// Perform divide operation by repeating a single bit
|
|
// divide step 55 iterations.
|
|
|
|
|
|
DoubleDividend.LowPart = DoubleOperand1.MantissaLow;
|
|
DoubleDividend.HighPart = DoubleOperand1.MantissaHigh;
|
|
DoubleDivisor.LowPart = DoubleOperand2.MantissaLow;
|
|
DoubleDivisor.HighPart = DoubleOperand2.MantissaHigh;
|
|
DoubleQuotient.LowPart = 0;
|
|
DoubleQuotient.HighPart = 0;
|
|
for (Index = 0; Index < 55; Index += 1) {
|
|
DoubleQuotient.HighPart =
|
|
(DoubleQuotient.HighPart << 1) |
|
|
DoubleQuotient.LowPart >> 31;
|
|
|
|
DoubleQuotient.LowPart <<= 1;
|
|
if (DoubleDividend.QuadPart >= DoubleDivisor.QuadPart) {
|
|
DoubleDividend.QuadPart = DoubleDividend.QuadPart - DoubleDivisor.QuadPart;
|
|
DoubleQuotient.LowPart |= 1;
|
|
}
|
|
|
|
DoubleDividend.HighPart =
|
|
(DoubleDividend.HighPart << 1) |
|
|
DoubleDividend.LowPart >> 31;
|
|
|
|
DoubleDividend.LowPart <<= 1;
|
|
}
|
|
|
|
DoubleOperand3.MantissaLow = DoubleQuotient.LowPart;
|
|
DoubleOperand3.MantissaHigh = DoubleQuotient.HighPart;
|
|
|
|
|
|
// Compute the sign and exponent of the result.
|
|
|
|
|
|
DoubleOperand3.Sign = DoubleOperand1.Sign ^ DoubleOperand2.Sign;
|
|
DoubleOperand3.Exponent = DoubleOperand1.Exponent -
|
|
DoubleOperand2.Exponent + DOUBLE_EXPONENT_BIAS;
|
|
|
|
|
|
// Normalize and store the result value.
|
|
|
|
|
|
DoubleOperand3.Infinity = FALSE;
|
|
DoubleOperand3.Nan = FALSE;
|
|
return KiNormalizeDouble(&ContextBlock,
|
|
&DoubleOperand3,
|
|
DoubleDividend.LowPart | DoubleDividend.HighPart);
|
|
|
|
|
|
// Floating compare double.
|
|
|
|
// This operation is performed after having separated out NaNs,
|
|
// and therefore the only comparison predicates left are equal
|
|
// and less.
|
|
|
|
// Floating compare double is accomplished by comparing signs,
|
|
// then exponents, and finally the mantissa if necessary.
|
|
|
|
// N.B. The sign of zero is ignored.
|
|
|
|
|
|
case CMPTEQ_FUNC :
|
|
case CMPTLE_FUNC :
|
|
case CMPTLT_FUNC :
|
|
|
|
|
|
// If either operand is zero, then set the sign of the operand
|
|
// positive and the exponent to a value less than the minimum
|
|
// denormal number.
|
|
|
|
|
|
if ((DoubleOperand1.Infinity == FALSE) &&
|
|
(DoubleOperand1.MantissaHigh == 0)) {
|
|
DoubleOperand1.Sign = 0;
|
|
DoubleOperand1.Exponent = -52;
|
|
}
|
|
|
|
if ((DoubleOperand2.Infinity == FALSE) &&
|
|
(DoubleOperand2.MantissaHigh == 0)) {
|
|
DoubleOperand2.Sign = 0;
|
|
DoubleOperand2.Exponent = -52;
|
|
}
|
|
|
|
|
|
// Compare signs first.
|
|
|
|
|
|
if (DoubleOperand1.Sign < DoubleOperand2.Sign) {
|
|
|
|
|
|
// The first operand is greater than the second operand.
|
|
|
|
|
|
CompareEqual = FALSE;
|
|
CompareLess = FALSE;
|
|
|
|
} else if (DoubleOperand1.Sign > DoubleOperand2.Sign) {
|
|
|
|
|
|
// The first operand is less than the second operand.
|
|
|
|
|
|
CompareEqual = FALSE;
|
|
CompareLess = TRUE;
|
|
|
|
} else {
|
|
|
|
|
|
// The operand signs are equal.
|
|
|
|
// If the sign of the operand is negative, then the sense of
|
|
// the comparison is reversed.
|
|
|
|
|
|
if (DoubleOperand1.Sign == 0) {
|
|
|
|
|
|
// Compare positive operand with positive operand.
|
|
|
|
|
|
if (DoubleOperand1.Exponent > DoubleOperand2.Exponent) {
|
|
CompareEqual = FALSE;
|
|
CompareLess = FALSE;
|
|
|
|
} else if (DoubleOperand1.Exponent < DoubleOperand2.Exponent) {
|
|
CompareEqual = FALSE;
|
|
CompareLess = TRUE;
|
|
|
|
} else {
|
|
if (DoubleOperand1.MantissaHigh >
|
|
DoubleOperand2.MantissaHigh) {
|
|
CompareEqual = FALSE;
|
|
CompareLess = FALSE;
|
|
|
|
} else if (DoubleOperand1.MantissaHigh <
|
|
DoubleOperand2.MantissaHigh) {
|
|
CompareEqual = FALSE;
|
|
CompareLess = TRUE;
|
|
|
|
} else {
|
|
if (DoubleOperand1.MantissaLow >
|
|
DoubleOperand2.MantissaLow) {
|
|
CompareEqual = FALSE;
|
|
CompareLess = FALSE;
|
|
|
|
} else if (DoubleOperand1.MantissaLow <
|
|
DoubleOperand2.MantissaLow) {
|
|
CompareEqual = FALSE;
|
|
CompareLess = TRUE;
|
|
|
|
} else {
|
|
CompareEqual = TRUE;
|
|
CompareLess = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
|
|
// Compare negative operand with negative operand.
|
|
|
|
|
|
if (DoubleOperand2.Exponent > DoubleOperand1.Exponent) {
|
|
CompareEqual = FALSE;
|
|
CompareLess = FALSE;
|
|
|
|
} else if (DoubleOperand2.Exponent < DoubleOperand1.Exponent) {
|
|
CompareEqual = FALSE;
|
|
CompareLess = TRUE;
|
|
|
|
} else {
|
|
if (DoubleOperand2.MantissaHigh >
|
|
DoubleOperand1.MantissaHigh) {
|
|
CompareEqual = FALSE;
|
|
CompareLess = FALSE;
|
|
|
|
} else if (DoubleOperand2.MantissaHigh <
|
|
DoubleOperand1.MantissaHigh) {
|
|
CompareEqual = FALSE;
|
|
CompareLess = TRUE;
|
|
|
|
} else {
|
|
if (DoubleOperand2.MantissaLow >
|
|
DoubleOperand1.MantissaLow) {
|
|
CompareEqual = FALSE;
|
|
CompareLess = FALSE;
|
|
|
|
} else if (DoubleOperand2.MantissaLow <
|
|
DoubleOperand1.MantissaLow) {
|
|
CompareEqual = FALSE;
|
|
CompareLess = TRUE;
|
|
|
|
} else {
|
|
CompareEqual = TRUE;
|
|
CompareLess = FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Form the condition code result value using the comparison
|
|
// information and the compare function codes.
|
|
|
|
|
|
switch (Function & FP_FUNCTION_MASK) {
|
|
case CMPTEQ_FUNC :
|
|
CompareResult = CompareEqual;
|
|
DBGPRINT2("cmpteq\n");
|
|
break;
|
|
|
|
case CMPTLE_FUNC :
|
|
CompareResult = (CompareLess | CompareEqual);
|
|
DBGPRINT2("cmptle\n");
|
|
break;
|
|
|
|
case CMPTLT_FUNC :
|
|
CompareResult = CompareLess;
|
|
DBGPRINT2("cmptlt\n");
|
|
break;
|
|
}
|
|
|
|
|
|
// Set the result operand to 2.0 if the comparison is true,
|
|
// otherwise store 0.0.
|
|
|
|
|
|
if (CompareResult != FALSE) {
|
|
KiSetRegisterValue(ContextBlock.Fc + 32,
|
|
FP_COMPARE_TRUE,
|
|
ExceptionFrame,
|
|
TrapFrame);
|
|
|
|
} else {
|
|
KiSetRegisterValue(ContextBlock.Fc + 32,
|
|
FP_COMPARE_FALSE,
|
|
ExceptionFrame,
|
|
TrapFrame);
|
|
}
|
|
return TRUE;
|
|
|
|
|
|
// Floating convert single to double.
|
|
|
|
// Floating conversion to double is accomplished by forming a
|
|
// double floating operand and then normalizing and storing
|
|
// the result value.
|
|
|
|
|
|
case CVTST_FUNC_PROPER :
|
|
DBGPRINT2("cvtst\n");
|
|
|
|
|
|
// If the operand is a NaN, then store a quiet NaN if the
|
|
// invalid operation trap is disabled, or raise an exception
|
|
// if the invalid operation trap is enabled and the operand
|
|
// is a signaling NaN.
|
|
|
|
|
|
if (SingleOperand1.Nan != FALSE) {
|
|
DoubleOperand1.MantissaHigh =
|
|
SingleOperand1.Mantissa >> (26 - (55 - 32));
|
|
DoubleOperand1.MantissaLow =
|
|
SingleOperand1.Mantissa << (32 - (26 - (55 - 32)));
|
|
DoubleOperand1.Exponent = DOUBLE_MAXIMUM_EXPONENT;
|
|
DoubleOperand1.Sign = SingleOperand1.Sign;
|
|
DoubleOperand1.Infinity = FALSE;
|
|
DoubleOperand1.Nan = TRUE;
|
|
return KiInvalidOperationDouble(&ContextBlock,
|
|
TRUE,
|
|
&DoubleOperand1,
|
|
&DoubleOperand1);
|
|
}
|
|
|
|
|
|
// Transform the single operand to double format.
|
|
|
|
|
|
DoubleOperand1.MantissaHigh =
|
|
SingleOperand1.Mantissa >> (26 - (55 - 32));
|
|
DoubleOperand1.MantissaLow =
|
|
SingleOperand1.Mantissa << (32 - (26 - (55 - 32)));
|
|
DoubleOperand1.Exponent = SingleOperand1.Exponent +
|
|
DOUBLE_EXPONENT_BIAS - SINGLE_EXPONENT_BIAS;
|
|
DoubleOperand1.Sign = SingleOperand1.Sign;
|
|
DoubleOperand1.Infinity = SingleOperand1.Infinity;
|
|
DoubleOperand1.Nan = FALSE;
|
|
|
|
|
|
// Normalize and store the result value.
|
|
|
|
|
|
return KiNormalizeDouble(&ContextBlock,
|
|
&DoubleOperand1,
|
|
0);
|
|
|
|
|
|
// Floating convert double to single.
|
|
|
|
// Floating conversion to single is accomplished by forming a
|
|
// single floating operand and then normalizing and storing the
|
|
// result value.
|
|
|
|
|
|
case CVTTS_FUNC :
|
|
DBGPRINT2("cvtts\n");
|
|
|
|
|
|
// If the operand is a NaN, then store a quiet NaN if the
|
|
// invalid operation trap is disabled, or raise an exception
|
|
// if the invalid operation trap is enabled and the operand
|
|
// is a signaling NaN.
|
|
|
|
|
|
if (DoubleOperand1.Nan != FALSE) {
|
|
SingleOperand1.Mantissa =
|
|
(DoubleOperand1.MantissaHigh << (26 - (55 - 32))) |
|
|
(DoubleOperand1.MantissaLow >> (32 - (26 - (55 - 32))));
|
|
SingleOperand1.Exponent = SINGLE_MAXIMUM_EXPONENT;
|
|
SingleOperand1.Sign = DoubleOperand1.Sign;
|
|
SingleOperand1.Infinity = FALSE;
|
|
SingleOperand1.Nan = TRUE;
|
|
return KiInvalidOperationSingle(&ContextBlock,
|
|
TRUE,
|
|
&SingleOperand1,
|
|
&SingleOperand1);
|
|
}
|
|
|
|
|
|
// Transform the double operand to single format.
|
|
|
|
|
|
SingleOperand1.Mantissa =
|
|
(DoubleOperand1.MantissaHigh << (26 - (55 - 32))) |
|
|
(DoubleOperand1.MantissaLow >> (32 - (26 - (55 - 32))));
|
|
StickyBits = DoubleOperand1.MantissaLow << (26 - (55 - 32));
|
|
SingleOperand1.Exponent = DoubleOperand1.Exponent +
|
|
SINGLE_EXPONENT_BIAS - DOUBLE_EXPONENT_BIAS;
|
|
SingleOperand1.Sign = DoubleOperand1.Sign;
|
|
SingleOperand1.Infinity = DoubleOperand1.Infinity;
|
|
SingleOperand1.Nan = FALSE;
|
|
|
|
|
|
// Normalize and store the result value.
|
|
|
|
|
|
return KiNormalizeSingle(&ContextBlock,
|
|
&SingleOperand1,
|
|
StickyBits);
|
|
|
|
|
|
// Floating convert longword to quadword.
|
|
|
|
// Floating conversion from longword to quadword is accomplished by
|
|
// a repositioning of 32 bits of the operand, with sign extension.
|
|
|
|
|
|
case CVTLQ_FUNC :
|
|
DBGPRINT2("cvtlq\n");
|
|
|
|
|
|
// Pack floating register longword format into upper 32-bits
|
|
// by keeping bits 63..62 and 58..29, eliminating unused bits
|
|
// 61..59. Then right justify and sign extend the 32 bits into
|
|
// 64 bits.
|
|
|
|
|
|
Quadword = ((Quadword >> 62) << 62) | ((ULONGLONG)(Quadword << 5) >> 2);
|
|
KiSetRegisterValue(ContextBlock.Fc + 32,
|
|
Quadword >> 32,
|
|
ExceptionFrame,
|
|
TrapFrame);
|
|
|
|
return TRUE;
|
|
|
|
|
|
// Floating convert quadword to longword.
|
|
|
|
// Floating conversion from quadword to longword is accomplished by
|
|
// truncating the high order 32 bits of the quadword after checking
|
|
// for overflow.
|
|
|
|
|
|
case CVTQL_FUNC :
|
|
DBGPRINT2("cvtql\n");
|
|
|
|
return KiConvertQuadwordToLongword(&ContextBlock, Quadword);
|
|
|
|
|
|
// Floating convert quadword to single.
|
|
|
|
// Floating conversion to single is accomplished by forming a
|
|
// single floating operand and then normalizing and storing the
|
|
// result value.
|
|
|
|
|
|
case CVTQS_FUNC :
|
|
DBGPRINT2("cvtqs\n");
|
|
|
|
|
|
// Compute the sign of the result.
|
|
|
|
|
|
if (Quadword < 0) {
|
|
SingleOperand1.Sign = 0x1;
|
|
Quadword = -Quadword;
|
|
|
|
} else {
|
|
SingleOperand1.Sign = 0;
|
|
}
|
|
|
|
|
|
// Initialize the infinity and NaN values.
|
|
|
|
|
|
SingleOperand1.Infinity = FALSE;
|
|
SingleOperand1.Nan = FALSE;
|
|
|
|
|
|
// Compute the exponent value and normalize the quadword
|
|
// value.
|
|
|
|
|
|
if (Quadword != 0) {
|
|
SingleOperand1.Exponent = SINGLE_EXPONENT_BIAS + 63;
|
|
while (Quadword > 0) {
|
|
Quadword <<= 1;
|
|
SingleOperand1.Exponent -= 1;
|
|
}
|
|
|
|
SingleOperand1.Mantissa = (LONG)((ULONGLONG)Quadword >> (64 - 26));
|
|
if (Quadword & (((ULONGLONG)1 << (64 - 26)) - 1)) {
|
|
StickyBits = 1;
|
|
|
|
} else {
|
|
StickyBits = 0;
|
|
}
|
|
|
|
} else {
|
|
SingleOperand1.Exponent = 0;
|
|
SingleOperand1.Mantissa = 0;
|
|
StickyBits = 0;
|
|
}
|
|
|
|
|
|
// Normalize and store the result value.
|
|
|
|
|
|
return KiNormalizeSingle(&ContextBlock,
|
|
&SingleOperand1,
|
|
StickyBits);
|
|
|
|
|
|
// Floating convert quadword to double.
|
|
|
|
// Floating conversion to double is accomplished by forming a
|
|
// double floating operand and then normalizing and storing the
|
|
// result value.
|
|
|
|
|
|
case CVTQT_FUNC :
|
|
DBGPRINT2("cvtqt\n");
|
|
|
|
|
|
// Compute the sign of the result.
|
|
|
|
|
|
if (Quadword < 0) {
|
|
DoubleOperand1.Sign = 0x1;
|
|
Quadword = -Quadword;
|
|
|
|
} else {
|
|
DoubleOperand1.Sign = 0;
|
|
}
|
|
|
|
|
|
// Initialize the infinity and NaN values.
|
|
|
|
|
|
DoubleOperand1.Infinity = FALSE;
|
|
DoubleOperand1.Nan = FALSE;
|
|
|
|
|
|
// Compute the exponent value and normalize the quadword
|
|
// value.
|
|
|
|
|
|
if (Quadword != 0) {
|
|
DoubleOperand1.Exponent = DOUBLE_EXPONENT_BIAS + 63;
|
|
while (Quadword > 0) {
|
|
Quadword <<= 1;
|
|
DoubleOperand1.Exponent -= 1;
|
|
}
|
|
|
|
DoubleOperand1.MantissaHigh = (LONG)((ULONGLONG)Quadword >> ((64 - 55) + 32));
|
|
DoubleOperand1.MantissaLow = (LONG)((ULONGLONG)Quadword >> (64 - 55));
|
|
if (Quadword & (((ULONGLONG)1 << (64 - 55)) - 1)) {
|
|
StickyBits = 1;
|
|
|
|
} else {
|
|
StickyBits = 0;
|
|
}
|
|
|
|
} else {
|
|
DoubleOperand1.MantissaHigh = 0;
|
|
DoubleOperand1.MantissaLow = 0;
|
|
DoubleOperand1.Exponent = 0;
|
|
StickyBits = 0;
|
|
}
|
|
|
|
|
|
// Normalize and store the result value.
|
|
|
|
|
|
return KiNormalizeDouble(&ContextBlock,
|
|
&DoubleOperand1,
|
|
StickyBits);
|
|
|
|
|
|
// Floating convert double to quadword.
|
|
|
|
// Floating conversion to quadword is accomplished by forming
|
|
// a quadword value from a double floating value.
|
|
|
|
|
|
case CVTTQ_FUNC :
|
|
DBGPRINT2("cvttq\n");
|
|
|
|
|
|
// If the operand is infinite or is a NaN, then store a
|
|
// quiet NaN or an appropriate infinity if the invalid
|
|
// operation trap is disabled, or raise an exception if
|
|
// the invalid trap is enabled.
|
|
|
|
|
|
if ((DoubleOperand1.Infinity != FALSE) ||
|
|
(DoubleOperand1.Nan != FALSE)) {
|
|
return KiInvalidOperationQuadword(&ContextBlock, 0);
|
|
}
|
|
|
|
|
|
// Convert double to quadword and store the result value.
|
|
|
|
|
|
return KiNormalizeQuadword(&ContextBlock, &DoubleOperand1);
|
|
}
|
|
|
|
|
|
// If an exception occurs, then copy the new exception information to the
|
|
// original exception record and handle the exception.
|
|
|
|
|
|
} except (KiCopyInformation(ExceptionRecord,
|
|
(GetExceptionInformation())->ExceptionRecord)) {
|
|
|
|
|
|
// Preserve the original exception address.
|
|
|
|
|
|
ExceptionRecord->ExceptionAddress = ExceptionAddress;
|
|
DBGPRINT("KiEmulateFloating: Exception\n");
|
|
return FALSE;
|
|
}
|
|
|
|
DBGPRINT("KiEmulateFloating: Invalid Instruction\n");
|
|
return FALSE;
|
|
}
|
|
|
|
ULONGLONG
|
|
KiConvertSingleOperandToRegister (
|
|
IN ULONG SingleValue
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function converts a 32-bit single format floating point value to
|
|
the 64-bit, double format used within floating point registers. Alpha
|
|
floating point registers are 64-bits wide and single format values are
|
|
transformed to 64-bits when stored or loaded from memory.
|
|
|
|
Arguments:
|
|
|
|
SingleValue - Supplies the 32-bit single operand value as an integer.
|
|
|
|
Return Value:
|
|
|
|
The 64-bit register format operand value is returned as the function
|
|
value.
|
|
|
|
--*/
|
|
|
|
{
|
|
PDOUBLE_FORMAT DoubleFormat;
|
|
ULONGLONG Result;
|
|
PSINGLE_FORMAT SingleFormat;
|
|
|
|
SingleFormat = (PSINGLE_FORMAT)&SingleValue;
|
|
DoubleFormat = (PDOUBLE_FORMAT)&Result;
|
|
|
|
DoubleFormat->Sign = SingleFormat->Sign;
|
|
DoubleFormat->Mantissa = ((ULONGLONG)SingleFormat->Mantissa) << (52 - 23);
|
|
if (SingleFormat->Exponent == SINGLE_MAXIMUM_EXPONENT) {
|
|
DoubleFormat->Exponent = DOUBLE_MAXIMUM_EXPONENT;
|
|
|
|
} else if (SingleFormat->Exponent == SINGLE_MINIMUM_EXPONENT) {
|
|
DoubleFormat->Exponent = DOUBLE_MINIMUM_EXPONENT;
|
|
|
|
} else {
|
|
DoubleFormat->Exponent = SingleFormat->Exponent - SINGLE_EXPONENT_BIAS +
|
|
DOUBLE_EXPONENT_BIAS;
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
ULONG
|
|
KiConvertRegisterToSingleOperand (
|
|
IN ULONGLONG DoubleValue
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function converts the 64-bit, double format floating point value
|
|
used within the floating point registers to a 32-bit, single format
|
|
floating point value.
|
|
|
|
Arguments:
|
|
|
|
DoubleValue - Supplies the 64-bit double operand value as an integer.
|
|
|
|
Return Value:
|
|
|
|
The 32-bit register format operand value is returned as the function
|
|
value.
|
|
|
|
--*/
|
|
|
|
{
|
|
PDOUBLE_FORMAT DoubleFormat;
|
|
ULONG Result;
|
|
PSINGLE_FORMAT SingleFormat;
|
|
|
|
SingleFormat = (PSINGLE_FORMAT)&Result;
|
|
DoubleFormat = (PDOUBLE_FORMAT)&DoubleValue;
|
|
|
|
SingleFormat->Sign = (ULONG)DoubleFormat->Sign;
|
|
SingleFormat->Mantissa = (ULONG)(DoubleFormat->Mantissa >> (52 - 23));
|
|
if (DoubleFormat->Exponent == DOUBLE_MAXIMUM_EXPONENT) {
|
|
SingleFormat->Exponent = SINGLE_MAXIMUM_EXPONENT;
|
|
|
|
} else if (DoubleFormat->Exponent == DOUBLE_MINIMUM_EXPONENT) {
|
|
SingleFormat->Exponent = SINGLE_MINIMUM_EXPONENT;
|
|
|
|
} else {
|
|
SingleFormat->Exponent = (ULONG)(DoubleFormat->Exponent - DOUBLE_EXPONENT_BIAS +
|
|
SINGLE_EXPONENT_BIAS);
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
BOOLEAN
|
|
KiConvertQuadwordToLongword (
|
|
IN PFP_CONTEXT_BLOCK ContextBlock,
|
|
IN LONGLONG Quadword
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called to convert a quadword operand to a longword
|
|
result.
|
|
|
|
Arguments:
|
|
|
|
ContextBlock - Supplies a pointer to the emulation context block.
|
|
|
|
Operand - Supplies the quadword operand value.
|
|
|
|
Return Value:
|
|
|
|
If the quadword value would overflow the longword result and the invalid
|
|
trap is enabled then a value of FALSE is returned. Otherwise, the quadword
|
|
is truncated to a longword and a value of TRUE is returned.
|
|
|
|
--*/
|
|
|
|
{
|
|
PEXCEPTION_RECORD ExceptionRecord;
|
|
PFPCR Fpcr;
|
|
PFP_IEEE_VALUE IeeeValue;
|
|
ULONGLONG ResultValue;
|
|
PSW_FPCR SoftwareFpcr;
|
|
|
|
|
|
// Truncate the quadword to a longword and convert the longword integer
|
|
// to floating register longword integer format.
|
|
|
|
|
|
ResultValue = ((Quadword & (ULONGLONG)0xc0000000) << 32) |
|
|
((Quadword & (ULONGLONG)0x3fffffff) << 29);
|
|
|
|
|
|
// Check to determine if an exception should be delivered or the result
|
|
// should be written to the destination register.
|
|
|
|
|
|
if ((Quadword < (LONG)0x80000000) || (Quadword > (LONG)0x7fffffff)) {
|
|
Fpcr = (PFPCR)&ContextBlock->TrapFrame->Fpcr;
|
|
Fpcr->InvalidOperation = 1;
|
|
Fpcr->SummaryBit = 1;
|
|
if (ContextBlock->IeeeMode == FALSE) {
|
|
ExceptionRecord = ContextBlock->ExceptionRecord;
|
|
ExceptionRecord->ExceptionCode = STATUS_FLOAT_INVALID_OPERATION;
|
|
return FALSE;
|
|
}
|
|
SoftwareFpcr = ContextBlock->SoftwareFpcr;
|
|
SoftwareFpcr->StatusInvalid = 1;
|
|
if (SoftwareFpcr->EnableInvalid != 0) {
|
|
ExceptionRecord = ContextBlock->ExceptionRecord;
|
|
ExceptionRecord->ExceptionCode = STATUS_FLOAT_INVALID_OPERATION;
|
|
IeeeValue = KiInitializeIeeeValue(ExceptionRecord);
|
|
IeeeValue->Value.U64Value.LowPart = LOW_PART(ResultValue);
|
|
IeeeValue->Value.U64Value.HighPart = HIGH_PART(ResultValue);
|
|
return FALSE;
|
|
}
|
|
|
|
Fpcr->DisableInvalid = 1;
|
|
}
|
|
|
|
|
|
// Set the destination register value and return a value of TRUE.
|
|
|
|
|
|
KiSetRegisterValue(ContextBlock->Fc + 32,
|
|
ResultValue,
|
|
ContextBlock->ExceptionFrame,
|
|
ContextBlock->TrapFrame);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
KiDivideByZeroDouble (
|
|
IN PFP_CONTEXT_BLOCK ContextBlock,
|
|
IN PFP_DOUBLE_OPERAND DoubleOperand1,
|
|
IN PFP_DOUBLE_OPERAND DoubleOperand2
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called to either raise an exception or store a
|
|
quiet NaN or properly signed infinity for a divide by zero double
|
|
floating operation.
|
|
|
|
Arguments:
|
|
|
|
ContextBlock - Supplies a pointer to the emulation context block.
|
|
|
|
DoubleOperand1 - Supplies a pointer to the first operand value.
|
|
|
|
DoubleOperand2 - Supplies a pointer ot the second operand value.
|
|
|
|
Return Value:
|
|
|
|
If the divide by zero trap is enabled and the dividend is not infinite,
|
|
then a value of FALSE is returned. Otherwise, a quiet NaN or a properly
|
|
signed infinity is stored as the destination result and a value of TRUE
|
|
is returned.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PEXCEPTION_RECORD ExceptionRecord;
|
|
PFPCR Fpcr;
|
|
PFP_IEEE_VALUE IeeeValue;
|
|
ULONG ResultSign;
|
|
ULONG ResultValueHigh;
|
|
ULONG ResultValueLow;
|
|
PSW_FPCR SoftwareFpcr;
|
|
|
|
|
|
// The result value is a properly signed infinity.
|
|
|
|
|
|
ResultSign = DoubleOperand1->Sign ^ DoubleOperand2->Sign;
|
|
ResultValueHigh = DOUBLE_INFINITY_VALUE_HIGH | (ResultSign << 31);
|
|
ResultValueLow = DOUBLE_INFINITY_VALUE_LOW;
|
|
|
|
|
|
// If the first operand is not infinite and the divide by zero trap is
|
|
// enabled, then store the proper exception code and exception flags
|
|
// and return a value of FALSE. Otherwise, store the appropriately signed
|
|
// infinity and return a value of TRUE.
|
|
|
|
|
|
if (DoubleOperand1->Infinity == FALSE) {
|
|
|
|
Fpcr = (PFPCR)&ContextBlock->TrapFrame->Fpcr;
|
|
Fpcr->DivisionByZero = 1;
|
|
Fpcr->SummaryBit = 1;
|
|
if (ContextBlock->IeeeMode == FALSE) {
|
|
ExceptionRecord = ContextBlock->ExceptionRecord;
|
|
ExceptionRecord->ExceptionCode = STATUS_FLOAT_DIVIDE_BY_ZERO;
|
|
return FALSE;
|
|
}
|
|
SoftwareFpcr = ContextBlock->SoftwareFpcr;
|
|
SoftwareFpcr->StatusDivisionByZero = 1;
|
|
if (SoftwareFpcr->EnableDivisionByZero != 0) {
|
|
ExceptionRecord = ContextBlock->ExceptionRecord;
|
|
ExceptionRecord->ExceptionCode = STATUS_FLOAT_DIVIDE_BY_ZERO;
|
|
IeeeValue = KiInitializeIeeeValue(ExceptionRecord);
|
|
IeeeValue->Value.Fp64Value.W[0] = ResultValueLow;
|
|
IeeeValue->Value.Fp64Value.W[1] = ResultValueHigh;
|
|
return FALSE;
|
|
}
|
|
|
|
Fpcr->DisableDivisionByZero = 1;
|
|
}
|
|
|
|
KiSetRegisterValue(ContextBlock->Fc + 32,
|
|
MAKE_QUAD(ResultValueLow, ResultValueHigh),
|
|
ContextBlock->ExceptionFrame,
|
|
ContextBlock->TrapFrame);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
KiDivideByZeroSingle (
|
|
IN PFP_CONTEXT_BLOCK ContextBlock,
|
|
IN PFP_SINGLE_OPERAND SingleOperand1,
|
|
IN PFP_SINGLE_OPERAND SingleOperand2
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called to either raise an exception or store a
|
|
quiet NaN or properly signed infinity for a divide by zero single
|
|
floating operation.
|
|
|
|
Arguments:
|
|
|
|
ContextBlock - Supplies a pointer to the emulation context block.
|
|
|
|
SingleOperand1 - Supplies a pointer to the first operand value.
|
|
|
|
SingleOperand2 - Supplies a pointer ot the second operand value.
|
|
|
|
Return Value:
|
|
|
|
If the divide by zero trap is enabled and the dividend is not infinite,
|
|
then a value of FALSE is returned. Otherwise, a quiet NaN or a properly
|
|
signed infinity is stored as the destination result and a value of TRUE
|
|
is returned.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PEXCEPTION_RECORD ExceptionRecord;
|
|
PFPCR Fpcr;
|
|
PFP_IEEE_VALUE IeeeValue;
|
|
ULONG ResultSign;
|
|
ULONG ResultValue;
|
|
PSW_FPCR SoftwareFpcr;
|
|
|
|
|
|
// The result value is a properly signed infinity.
|
|
|
|
|
|
ResultSign = SingleOperand1->Sign ^ SingleOperand2->Sign;
|
|
ResultValue = SINGLE_INFINITY_VALUE | (ResultSign << 31);
|
|
|
|
|
|
// If the first operand is not infinite and the divide by zero trap is
|
|
// enabled, then store the proper exception code and exception flags
|
|
// and return a value of FALSE. Otherwise, store the appropriately signed
|
|
// infinity and return a value of TRUE.
|
|
|
|
|
|
if (SingleOperand1->Infinity == FALSE) {
|
|
|
|
Fpcr = (PFPCR)&ContextBlock->TrapFrame->Fpcr;
|
|
Fpcr->DivisionByZero = 1;
|
|
Fpcr->SummaryBit = 1;
|
|
if (ContextBlock->IeeeMode == FALSE) {
|
|
ExceptionRecord = ContextBlock->ExceptionRecord;
|
|
ExceptionRecord->ExceptionCode = STATUS_FLOAT_DIVIDE_BY_ZERO;
|
|
return FALSE;
|
|
}
|
|
SoftwareFpcr = ContextBlock->SoftwareFpcr;
|
|
SoftwareFpcr->StatusDivisionByZero = 1;
|
|
if (SoftwareFpcr->EnableDivisionByZero != 0) {
|
|
ExceptionRecord = ContextBlock->ExceptionRecord;
|
|
ExceptionRecord->ExceptionCode = STATUS_FLOAT_DIVIDE_BY_ZERO;
|
|
IeeeValue = KiInitializeIeeeValue(ExceptionRecord);
|
|
IeeeValue->Value.Fp32Value.W[0] = ResultValue;
|
|
return FALSE;
|
|
}
|
|
|
|
Fpcr->DisableDivisionByZero = 1;
|
|
}
|
|
|
|
KiSetRegisterValue(ContextBlock->Fc + 32,
|
|
KiConvertSingleOperandToRegister(ResultValue),
|
|
ContextBlock->ExceptionFrame,
|
|
ContextBlock->TrapFrame);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
PFP_IEEE_VALUE
|
|
KiInitializeIeeeValue (
|
|
IN PEXCEPTION_RECORD ExceptionRecord
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called to initialize an IEEE exception record.
|
|
|
|
N.B. The original hardware exception record should be overwritten with an
|
|
IEEE exception record only when it is known for certain that an IEEE
|
|
exception must be generated.
|
|
|
|
Arguments:
|
|
|
|
ExceptionRecord - Supplies a pointer to the exception record.
|
|
|
|
Return Value:
|
|
|
|
The address of the IEEE value portion of the exception record is returned
|
|
as the function value.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
|
|
// Initialize the number of exception information parameters, zero
|
|
// the first parameter to indicate a hardware initiated exception,
|
|
// set the continuation address, and clear the IEEE exception value.
|
|
|
|
|
|
ExceptionRecord->NumberParameters = 6;
|
|
ExceptionRecord->ExceptionInformation[0] = 0;
|
|
ExceptionRecord->ExceptionInformation[1] =
|
|
((ULONG_PTR)(ExceptionRecord)->ExceptionAddress) + 4;
|
|
ExceptionRecord->ExceptionInformation[2] = 0;
|
|
ExceptionRecord->ExceptionInformation[3] = 0;
|
|
ExceptionRecord->ExceptionInformation[4] = 0;
|
|
ExceptionRecord->ExceptionInformation[5] = 0;
|
|
|
|
|
|
// Return address of IEEE exception value.
|
|
|
|
|
|
return (PFP_IEEE_VALUE)&ExceptionRecord->ExceptionInformation[2];
|
|
}
|
|
|
|
BOOLEAN
|
|
KiInvalidCompareDouble (
|
|
IN PFP_CONTEXT_BLOCK ContextBlock,
|
|
IN BOOLEAN CheckForSignalNan,
|
|
IN PFP_DOUBLE_OPERAND DoubleOperand1,
|
|
IN PFP_DOUBLE_OPERAND DoubleOperand2
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called to determine whether an invalid operation
|
|
exception should be raised for a double compare operation.
|
|
|
|
Arguments:
|
|
|
|
ContextBlock - Supplies a pointer to the emulation context block.
|
|
|
|
CheckForSignalNan - Supplies a boolean value that determines whether the
|
|
operand values should be checked for a signaling NaN.
|
|
|
|
DoubleOperand1 - Supplies a pointer to the first operand value.
|
|
|
|
DoubleOperand2 - Supplies a pointer ot the second operand value.
|
|
|
|
Return Value:
|
|
|
|
If the invalid operation trap is enabled and either the operation is
|
|
invalid or one of the operands in a signaling NaN, then a value of
|
|
FALSE is returned. Otherwise, no operation is performed and a value
|
|
of TRUE is returned.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PEXCEPTION_RECORD ExceptionRecord;
|
|
PFPCR Fpcr;
|
|
PFP_IEEE_VALUE IeeeValue;
|
|
PSW_FPCR SoftwareFpcr;
|
|
|
|
|
|
// If an invalid operation is specified or one of the operands is a
|
|
// signaling NaN and the invalid operation trap is enabled, then
|
|
// store the proper exception code and exception flags and return
|
|
// a value of FALSE. Otherwise, perform no operation and return a
|
|
// value of TRUE.
|
|
|
|
|
|
if ((CheckForSignalNan == FALSE) ||
|
|
(DoubleSignalNan(DoubleOperand1) != FALSE) ||
|
|
(DoubleSignalNan(DoubleOperand2) != FALSE)) {
|
|
|
|
Fpcr = (PFPCR)&ContextBlock->TrapFrame->Fpcr;
|
|
Fpcr->InvalidOperation = 1;
|
|
Fpcr->SummaryBit = 1;
|
|
if (ContextBlock->IeeeMode == FALSE) {
|
|
ExceptionRecord = ContextBlock->ExceptionRecord;
|
|
ExceptionRecord->ExceptionCode = STATUS_FLOAT_INVALID_OPERATION;
|
|
return FALSE;
|
|
}
|
|
SoftwareFpcr = ContextBlock->SoftwareFpcr;
|
|
SoftwareFpcr->StatusInvalid = 1;
|
|
if (SoftwareFpcr->EnableInvalid != 0) {
|
|
ExceptionRecord = ContextBlock->ExceptionRecord;
|
|
ExceptionRecord->ExceptionCode = STATUS_FLOAT_INVALID_OPERATION;
|
|
IeeeValue = KiInitializeIeeeValue(ExceptionRecord);
|
|
IeeeValue->Value.CompareValue = FpCompareUnordered;
|
|
return FALSE;
|
|
}
|
|
|
|
Fpcr->DisableInvalid = 1;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
KiInvalidOperationDouble (
|
|
IN PFP_CONTEXT_BLOCK ContextBlock,
|
|
IN BOOLEAN CheckForSignalNan,
|
|
IN PFP_DOUBLE_OPERAND DoubleOperand1,
|
|
IN PFP_DOUBLE_OPERAND DoubleOperand2
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called to either raise an exception or store a
|
|
quiet NaN for an invalid double floating operation.
|
|
|
|
Arguments:
|
|
|
|
ContextBlock - Supplies a pointer to the emulation context block.
|
|
|
|
CheckForSignalNan - Supplies a boolean value that determines whether the
|
|
operand values should be checked for a signaling NaN.
|
|
|
|
DoubleOperand1 - Supplies a pointer to the first operand value.
|
|
|
|
DoubleOperand2 - Supplies a pointer ot the second operand value.
|
|
|
|
Return Value:
|
|
|
|
If the invalid operation trap is enabled and either the operation is
|
|
invalid or one of the operands in a signaling NaN, then a value of
|
|
FALSE is returned. Otherwise, a quiet NaN is stored as the destination
|
|
result and a value of TRUE is returned.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PEXCEPTION_RECORD ExceptionRecord;
|
|
PFPCR Fpcr;
|
|
PFP_IEEE_VALUE IeeeValue;
|
|
ULONG ResultValueHigh;
|
|
ULONG ResultValueLow;
|
|
PSW_FPCR SoftwareFpcr;
|
|
|
|
|
|
// If the second operand is a NaN, then compute a quiet NaN from its
|
|
// value. Otherwise, if the first operand is a NaN, then compute a
|
|
// quiet NaN from its value. Otherwise, the result value is a quiet
|
|
// (real indefinite) NaN.
|
|
|
|
|
|
DBGPRINT("Operand1: Inf=%d NaN=%d Sign=%d Exponent=%d Mantissa=%.8x%.8x\n",
|
|
DoubleOperand1->Infinity, DoubleOperand1->Nan,
|
|
DoubleOperand1->Sign,
|
|
DoubleOperand1->Exponent,
|
|
DoubleOperand1->MantissaHigh, DoubleOperand1->MantissaLow);
|
|
DBGPRINT("Operand2: Inf=%d NaN=%d Sign=%d Exponent=%d Mantissa=%.8x%.8x\n",
|
|
DoubleOperand2->Infinity, DoubleOperand2->Nan,
|
|
DoubleOperand2->Sign,
|
|
DoubleOperand2->Exponent,
|
|
DoubleOperand2->MantissaHigh, DoubleOperand2->MantissaLow);
|
|
|
|
if (DoubleOperand2->Nan != FALSE) {
|
|
ResultValueLow = DoubleOperand2->MantissaLow >> 2;
|
|
ResultValueLow |= DoubleOperand2->MantissaHigh << 30;
|
|
ResultValueHigh = DoubleOperand2->MantissaHigh >> 2;
|
|
ResultValueHigh |= DOUBLE_QUIET_NAN_PREFIX_HIGH;
|
|
ResultValueHigh |= DoubleOperand2->Sign << 31;
|
|
|
|
} else if (DoubleOperand1->Nan != FALSE) {
|
|
ResultValueLow = DoubleOperand1->MantissaLow >> 2;
|
|
ResultValueLow |= DoubleOperand1->MantissaHigh << 30;
|
|
ResultValueHigh = DoubleOperand1->MantissaHigh >> 2;
|
|
ResultValueHigh |= DOUBLE_QUIET_NAN_PREFIX_HIGH;
|
|
ResultValueHigh |= DoubleOperand1->Sign << 31;
|
|
|
|
} else {
|
|
ResultValueLow = DOUBLE_QUIET_NAN_VALUE_LOW;
|
|
ResultValueHigh = DOUBLE_QUIET_NAN_VALUE_HIGH;
|
|
}
|
|
|
|
|
|
// If an invalid operation is specified or one of the operands is a
|
|
// signaling NaN and the invalid operation trap is enabled, then
|
|
// store the proper exception code and exception flags and return
|
|
// a value of FALSE. Otherwise, store a quiet NaN as the destination
|
|
// result and return a value of TRUE.
|
|
|
|
|
|
if ((CheckForSignalNan == FALSE) ||
|
|
(DoubleSignalNan(DoubleOperand1) != FALSE) ||
|
|
(DoubleSignalNan(DoubleOperand2) != FALSE)) {
|
|
|
|
Fpcr = (PFPCR)&ContextBlock->TrapFrame->Fpcr;
|
|
Fpcr->InvalidOperation = 1;
|
|
Fpcr->SummaryBit = 1;
|
|
if (ContextBlock->IeeeMode == FALSE) {
|
|
ExceptionRecord = ContextBlock->ExceptionRecord;
|
|
ExceptionRecord->ExceptionCode = STATUS_FLOAT_INVALID_OPERATION;
|
|
return FALSE;
|
|
}
|
|
SoftwareFpcr = ContextBlock->SoftwareFpcr;
|
|
SoftwareFpcr->StatusInvalid = 1;
|
|
if (SoftwareFpcr->EnableInvalid != 0) {
|
|
ExceptionRecord = ContextBlock->ExceptionRecord;
|
|
ExceptionRecord->ExceptionCode = STATUS_FLOAT_INVALID_OPERATION;
|
|
IeeeValue = KiInitializeIeeeValue(ExceptionRecord);
|
|
IeeeValue->Value.Fp64Value.W[0] = ResultValueLow;
|
|
IeeeValue->Value.Fp64Value.W[1] = ResultValueHigh;
|
|
return FALSE;
|
|
}
|
|
|
|
Fpcr->DisableInvalid = 1;
|
|
}
|
|
|
|
KiSetRegisterValue(ContextBlock->Fc + 32,
|
|
MAKE_QUAD(ResultValueLow, ResultValueHigh),
|
|
ContextBlock->ExceptionFrame,
|
|
ContextBlock->TrapFrame);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
KiInvalidOperationQuadword (
|
|
IN PFP_CONTEXT_BLOCK ContextBlock,
|
|
IN ULONGLONG ResultValue
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called to either raise an exception or store a
|
|
quiet NaN for an invalid conversion to quadword.
|
|
|
|
Arguments:
|
|
|
|
ContextBlock - Supplies a pointer to the emulation context block.
|
|
|
|
ResultValue - Suplies a quadword result value to be stored.
|
|
|
|
Return Value:
|
|
|
|
If the invalid operation trap is enabled, then a value of FALSE is
|
|
returned. Otherwise, an appropriate quadword value is stored as the
|
|
destination result and a value of TRUE is returned.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PEXCEPTION_RECORD ExceptionRecord;
|
|
PFPCR Fpcr;
|
|
PFP_IEEE_VALUE IeeeValue;
|
|
PSW_FPCR SoftwareFpcr;
|
|
|
|
|
|
// If the invalid operation trap is enabled then store the proper
|
|
// exception code and exception flags and return a value of FALSE.
|
|
// Otherwise, store a quiet NaN as the destination result and return
|
|
// a value of TRUE.
|
|
|
|
|
|
Fpcr = (PFPCR)&ContextBlock->TrapFrame->Fpcr;
|
|
Fpcr->InvalidOperation = 1;
|
|
Fpcr->SummaryBit = 1;
|
|
if (ContextBlock->IeeeMode == FALSE) {
|
|
ExceptionRecord = ContextBlock->ExceptionRecord;
|
|
ExceptionRecord->ExceptionCode = STATUS_FLOAT_INVALID_OPERATION;
|
|
return FALSE;
|
|
}
|
|
SoftwareFpcr = ContextBlock->SoftwareFpcr;
|
|
SoftwareFpcr->StatusInvalid = 1;
|
|
if (SoftwareFpcr->EnableInvalid != 0) {
|
|
ExceptionRecord = ContextBlock->ExceptionRecord;
|
|
ExceptionRecord->ExceptionCode = STATUS_FLOAT_INVALID_OPERATION;
|
|
IeeeValue = KiInitializeIeeeValue(ExceptionRecord);
|
|
IeeeValue->Value.U64Value.LowPart = LOW_PART(ResultValue);
|
|
IeeeValue->Value.U64Value.HighPart = HIGH_PART(ResultValue);
|
|
return FALSE;
|
|
}
|
|
|
|
Fpcr->DisableInvalid = 1;
|
|
|
|
KiSetRegisterValue(ContextBlock->Fc + 32,
|
|
ResultValue,
|
|
ContextBlock->ExceptionFrame,
|
|
ContextBlock->TrapFrame);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
KiInvalidOperationSingle (
|
|
IN PFP_CONTEXT_BLOCK ContextBlock,
|
|
IN BOOLEAN CheckForSignalNan,
|
|
IN PFP_SINGLE_OPERAND SingleOperand1,
|
|
IN PFP_SINGLE_OPERAND SingleOperand2
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called to either raise an exception or store a
|
|
quiet NaN for an invalid single floating operation.
|
|
|
|
Arguments:
|
|
|
|
ContextBlock - Supplies a pointer to the emulation context block.
|
|
|
|
CheckForSignalNan - Supplies a boolean value that determines whether the
|
|
operand values should be checked for a signaling NaN.
|
|
|
|
SingleOperand1 - Supplies a pointer to the first operand value.
|
|
|
|
SingleOperand2 - Supplies a pointer ot the second operand value.
|
|
|
|
Return Value:
|
|
|
|
If the invalid operation trap is enabled and either the operation is
|
|
invalid or one of the operands in a signaling NaN, then a value of
|
|
FALSE is returned. Otherwise, a quiet NaN is stored as the destination
|
|
result and a value of TRUE is returned.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PEXCEPTION_RECORD ExceptionRecord;
|
|
PFPCR Fpcr;
|
|
PFP_IEEE_VALUE IeeeValue;
|
|
ULONG ResultValue;
|
|
PSW_FPCR SoftwareFpcr;
|
|
|
|
|
|
// If the second operand is a NaN, then compute a quiet NaN from its
|
|
// value. Otherwise, if the first operand is a NaN, then compute a
|
|
// quiet NaN from its value. Otherwise, the result value is a quiet
|
|
// (real indefinite) NaN.
|
|
|
|
|
|
if (SingleOperand2->Nan != FALSE) {
|
|
ResultValue = SingleOperand2->Mantissa >> 2;
|
|
ResultValue |= SINGLE_QUIET_NAN_PREFIX;
|
|
ResultValue |= SingleOperand2->Sign << 31;
|
|
|
|
} else if (SingleOperand1->Nan != FALSE) {
|
|
ResultValue = SingleOperand1->Mantissa >> 2;
|
|
ResultValue |= SINGLE_QUIET_NAN_PREFIX;
|
|
ResultValue |= SingleOperand1->Sign << 31;
|
|
|
|
} else {
|
|
ResultValue = SINGLE_QUIET_NAN_VALUE;
|
|
}
|
|
|
|
|
|
// If an invalid operation is specified or one of the operands is a
|
|
// signaling NaN and the invalid operation trap is enabled, then
|
|
// store the proper exception code and exception flags and return
|
|
// a value of FALSE. Otherwise, store a quiet NaN as the destination
|
|
// result and return a value of TRUE.
|
|
|
|
|
|
if ((CheckForSignalNan == FALSE) ||
|
|
(SingleSignalNan(SingleOperand1) != FALSE) ||
|
|
(SingleSignalNan(SingleOperand2) != FALSE)) {
|
|
|
|
Fpcr = (PFPCR)&ContextBlock->TrapFrame->Fpcr;
|
|
Fpcr->InvalidOperation = 1;
|
|
Fpcr->SummaryBit = 1;
|
|
if (ContextBlock->IeeeMode == FALSE) {
|
|
ExceptionRecord = ContextBlock->ExceptionRecord;
|
|
ExceptionRecord->ExceptionCode = STATUS_FLOAT_INVALID_OPERATION;
|
|
return FALSE;
|
|
}
|
|
SoftwareFpcr = ContextBlock->SoftwareFpcr;
|
|
SoftwareFpcr->StatusInvalid = 1;
|
|
if (SoftwareFpcr->EnableInvalid != 0) {
|
|
ExceptionRecord = ContextBlock->ExceptionRecord;
|
|
ExceptionRecord->ExceptionCode = STATUS_FLOAT_INVALID_OPERATION;
|
|
IeeeValue = KiInitializeIeeeValue(ExceptionRecord);
|
|
IeeeValue->Value.Fp32Value.W[0] = ResultValue;
|
|
return FALSE;
|
|
}
|
|
|
|
Fpcr->DisableInvalid = 1;
|
|
}
|
|
|
|
KiSetRegisterValue(ContextBlock->Fc + 32,
|
|
KiConvertSingleOperandToRegister(ResultValue),
|
|
ContextBlock->ExceptionFrame,
|
|
ContextBlock->TrapFrame);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
KiNormalizeDouble (
|
|
IN PFP_CONTEXT_BLOCK ContextBlock,
|
|
IN PFP_DOUBLE_OPERAND ResultOperand,
|
|
IN ULONGLONG StickyBits
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called to normalize a double floating result.
|
|
|
|
N.B. The result value is specified with a guard bit on the right,
|
|
the hidden bit (if appropriate), and a possible overflow bit.
|
|
The result format is:
|
|
|
|
<63:56> - zero
|
|
<55> - overflow bit
|
|
<54> - hidden bit
|
|
<53:2> - mantissa
|
|
<1> - guard bit
|
|
<0> - round bit
|
|
|
|
The sticky bits specify bits that were lost during the computation.
|
|
|
|
Arguments:
|
|
|
|
ContextBlock - Supplies a pointer to the emulation context block.
|
|
|
|
ResultOperand - Supplies a pointer to the result operand value.
|
|
|
|
StickyBits - Supplies the value of the sticky bits.
|
|
|
|
Return Value:
|
|
|
|
If there is not an exception, or the exception is handled, then a proper
|
|
result is stored in the destination result, the continuation address is
|
|
set, and a value of TRUE is returned. Otherwise, a proper value is stored and
|
|
a value of FALSE is returned.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONGLONG DenormalizeShift;
|
|
PEXCEPTION_RECORD ExceptionRecord;
|
|
ULONGLONG ExceptionResult;
|
|
PFPCR Fpcr;
|
|
PFP_IEEE_VALUE IeeeValue;
|
|
BOOLEAN Inexact;
|
|
ULONGLONG Mantissa;
|
|
BOOLEAN Overflow;
|
|
ULONGLONG ResultValue;
|
|
ULONG RoundBit;
|
|
PSW_FPCR SoftwareFpcr;
|
|
BOOLEAN Underflow;
|
|
ULONGLONG ResultStickyBits;
|
|
ULONGLONG ResultMantissa;
|
|
ULONG ResultRoundBit;
|
|
LONG ResultExponent;
|
|
BOOLEAN ReturnValue = TRUE;
|
|
|
|
|
|
// If the result is infinite, then store a properly signed infinity
|
|
// in the destination register and return a value of TRUE. Otherwise,
|
|
// round and normalize the result and check for overflow and underflow.
|
|
|
|
|
|
DBGPRINT("KiNormalizeDouble: Inf=%d NaN=%d Sign=%d Exponent=%d Mantissa=%.8x%.8x\n",
|
|
ResultOperand->Infinity, ResultOperand->Nan, ResultOperand->Sign,
|
|
ResultOperand->Exponent,
|
|
ResultOperand->MantissaHigh, ResultOperand->MantissaLow);
|
|
DBGPRINT("KiNormalizeDouble: StickyBits=%.16Lx\n", StickyBits);
|
|
|
|
if (ResultOperand->Infinity != FALSE) {
|
|
KiSetRegisterValue(ContextBlock->Fc + 32,
|
|
MAKE_QUAD(DOUBLE_INFINITY_VALUE_LOW,
|
|
DOUBLE_INFINITY_VALUE_HIGH |
|
|
(ResultOperand->Sign << 31)),
|
|
ContextBlock->ExceptionFrame,
|
|
ContextBlock->TrapFrame);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
Mantissa = MAKE_QUAD(ResultOperand->MantissaLow,
|
|
ResultOperand->MantissaHigh);
|
|
Fpcr = (PFPCR)&ContextBlock->TrapFrame->Fpcr;
|
|
SoftwareFpcr = ContextBlock->SoftwareFpcr;
|
|
|
|
|
|
// If the overflow bit is set, then right shift the mantissa one bit,
|
|
// accumulate the lost bit with the sticky bits, and adjust the exponent
|
|
// value.
|
|
|
|
|
|
if ((Mantissa & ((ULONGLONG)1 << 55)) != 0) {
|
|
StickyBits |= (Mantissa & 0x1);
|
|
Mantissa >>= 1;
|
|
ResultOperand->Exponent += 1;
|
|
}
|
|
|
|
|
|
// If the mantissa is nonzero, then normalize the mantissa by left
|
|
// shifting one bit at a time until there is a one bit in bit 54.
|
|
|
|
|
|
if (Mantissa != 0) {
|
|
while ((Mantissa & ((ULONGLONG)1 << 54)) == 0) {
|
|
Mantissa <<= 1;
|
|
ResultOperand->Exponent -= 1;
|
|
}
|
|
}
|
|
|
|
|
|
// Right shift the mantissa two bits, set the round bit, and accumulate
|
|
// the other lost bit with the sticky bits.
|
|
|
|
|
|
StickyBits |= (Mantissa & 0x1);
|
|
RoundBit = (ULONG)(Mantissa & 0x2);
|
|
Mantissa >>= 2;
|
|
|
|
|
|
// Convert to denormal format before rounding to allow underflow to
|
|
// be detected on rounded result. Save context to calculate IEEE
|
|
// exception record, if needed.
|
|
|
|
|
|
if (ResultOperand->Exponent <= DOUBLE_MINIMUM_EXPONENT && Mantissa != 0) {
|
|
|
|
|
|
// Save everything needed for calculating IEEE exception record value
|
|
|
|
|
|
ResultMantissa = Mantissa;
|
|
ResultExponent = ResultOperand->Exponent;
|
|
ResultStickyBits = StickyBits;
|
|
ResultRoundBit = RoundBit;
|
|
|
|
|
|
// Right shift the mantissa to set the minimum exponent plus an extra
|
|
// bit for the denormal format
|
|
|
|
|
|
DenormalizeShift = 1 - ResultOperand->Exponent;
|
|
|
|
|
|
// The maximum denormal shift is 52 bits for the mantissa plus 1 bit for the round
|
|
// A denormal shift of 54 guarantees 0 mantissa and 0 round bit and preserves all sticky bits
|
|
|
|
|
|
if (DenormalizeShift > 54) {
|
|
DenormalizeShift = 54;
|
|
}
|
|
|
|
|
|
// The denormalized result will be rounded after it is
|
|
// shifted. Preserve existing Round and Sticky Bits.
|
|
|
|
|
|
StickyBits |= RoundBit;
|
|
StickyBits |= (Mantissa << 1) << (64 - DenormalizeShift);
|
|
RoundBit = (ULONG)(Mantissa >> (DenormalizeShift - 1)) & 1;
|
|
Mantissa = Mantissa >> DenormalizeShift;
|
|
ResultOperand->Exponent = DOUBLE_MINIMUM_EXPONENT;
|
|
}
|
|
|
|
|
|
// Round the result value using the mantissa, the round bit, and the sticky bits.
|
|
|
|
|
|
switch (ContextBlock->Round) {
|
|
|
|
|
|
// Round to nearest representable number.
|
|
|
|
|
|
case ROUND_TO_NEAREST:
|
|
if (RoundBit != 0) {
|
|
if ((StickyBits != 0) || ((Mantissa & 0x1) != 0)) {
|
|
Mantissa += 1;
|
|
}
|
|
}
|
|
break;
|
|
|
|
|
|
// Round toward zero.
|
|
|
|
|
|
case ROUND_TO_ZERO:
|
|
break;
|
|
|
|
|
|
// Round toward plus infinity.
|
|
|
|
|
|
case ROUND_TO_PLUS_INFINITY:
|
|
if ((ResultOperand->Sign == 0) &&
|
|
((StickyBits != 0) || (RoundBit != 0))) {
|
|
Mantissa += 1;
|
|
}
|
|
break;
|
|
|
|
|
|
// Round toward minus infinity.
|
|
|
|
|
|
case ROUND_TO_MINUS_INFINITY:
|
|
if ((ResultOperand->Sign != 0) &&
|
|
((StickyBits != 0) || (RoundBit != 0))) {
|
|
Mantissa += 1;
|
|
}
|
|
break;
|
|
}
|
|
|
|
|
|
// If rounding resulted in a carry into bit 53, then right shift the
|
|
// mantissa one bit and adjust the exponent.
|
|
|
|
|
|
if ((Mantissa & ((ULONGLONG)1 << 53)) != 0) {
|
|
Mantissa >>= 1;
|
|
ResultOperand->Exponent += 1;
|
|
}
|
|
|
|
|
|
// If rounding resulted in a carry into bit 52 in denormal format, then
|
|
// adjust the exponent.
|
|
|
|
|
|
if ((ResultOperand->Exponent == DOUBLE_MINIMUM_EXPONENT) &&
|
|
(Mantissa & ((ULONGLONG)1 << 52)) != 0) {
|
|
ResultOperand->Exponent += 1;
|
|
}
|
|
|
|
|
|
// If the exponent value is greater than or equal to the maximum
|
|
// exponent value, then overflow has occurred. This results in both
|
|
// the inexact and overflow sticky bits being set in the FPCR.
|
|
|
|
// If the exponent value is less than or equal to the minimum exponent
|
|
// value, the mantissa is nonzero, and the denormalized result is inexact,
|
|
// then underflow has occurred. This results in both the inexact and
|
|
// underflow sticky bits being set in the FPCR.
|
|
|
|
// Or if underflow exceptions are enabled, underflow occurs for all denormal
|
|
// numbers. This results in the underflow sticky bit always being set in the
|
|
// FPCR and the inexact sticky bit is set when the denormalized result is
|
|
// also inexact.
|
|
|
|
// Otherwise, a normal result can be delivered, but it may be inexact.
|
|
// If the result is inexact, then the inexact sticky bit is set in the
|
|
// FPCR.
|
|
|
|
|
|
if (ResultOperand->Exponent >= DOUBLE_MAXIMUM_EXPONENT) {
|
|
Inexact = TRUE;
|
|
Overflow = TRUE;
|
|
Underflow = FALSE;
|
|
|
|
|
|
// The overflow value is dependent on the rounding mode.
|
|
|
|
|
|
switch (ContextBlock->Round) {
|
|
|
|
|
|
// Round to nearest representable number.
|
|
|
|
// The result value is infinity with the sign of the result.
|
|
|
|
|
|
case ROUND_TO_NEAREST:
|
|
ResultValue = MAKE_QUAD(DOUBLE_INFINITY_VALUE_LOW,
|
|
DOUBLE_INFINITY_VALUE_HIGH |
|
|
(ResultOperand->Sign << 31));
|
|
break;
|
|
|
|
|
|
// Round toward zero.
|
|
|
|
// The result is the maximum number with the sign of the result.
|
|
|
|
|
|
case ROUND_TO_ZERO:
|
|
ResultValue = MAKE_QUAD(DOUBLE_MAXIMUM_VALUE_LOW,
|
|
DOUBLE_MAXIMUM_VALUE_HIGH |
|
|
(ResultOperand->Sign << 31));
|
|
break;
|
|
|
|
|
|
// Round toward plus infinity.
|
|
|
|
// If the sign of the result is positive, then the result is
|
|
// plus infinity. Otherwise, the result is the maximum negative
|
|
// number.
|
|
|
|
|
|
case ROUND_TO_PLUS_INFINITY:
|
|
if (ResultOperand->Sign == 0) {
|
|
ResultValue = MAKE_QUAD(DOUBLE_INFINITY_VALUE_LOW,
|
|
DOUBLE_INFINITY_VALUE_HIGH);
|
|
|
|
} else {
|
|
ResultValue = MAKE_QUAD(DOUBLE_MAXIMUM_VALUE_LOW,
|
|
DOUBLE_MAXIMUM_VALUE_HIGH |
|
|
(1 << 31));
|
|
}
|
|
break;
|
|
|
|
|
|
// Round toward minus infinity.
|
|
|
|
// If the sign of the result is negative, then the result is
|
|
// negative infinity. Otherwise, the result is the maximum
|
|
// positive number.
|
|
|
|
|
|
|
|
case ROUND_TO_MINUS_INFINITY:
|
|
if (ResultOperand->Sign != 0) {
|
|
ResultValue = MAKE_QUAD(DOUBLE_INFINITY_VALUE_LOW,
|
|
DOUBLE_INFINITY_VALUE_HIGH |
|
|
(1 << 31));
|
|
|
|
} else {
|
|
ResultValue = MAKE_QUAD(DOUBLE_MAXIMUM_VALUE_LOW,
|
|
DOUBLE_MAXIMUM_VALUE_HIGH);
|
|
}
|
|
break;
|
|
}
|
|
|
|
|
|
// Compute the overflow exception result value by subtracting 1536
|
|
// from the exponent.
|
|
|
|
|
|
ExceptionResult = Mantissa & (((ULONGLONG)1 << 52) - 1);
|
|
ExceptionResult |= (((ULONGLONG)ResultOperand->Exponent - 1536) << 52);
|
|
ExceptionResult |= ((ULONGLONG)ResultOperand->Sign << 63);
|
|
|
|
} else {
|
|
|
|
|
|
// After rounding if the exponent value is equal to
|
|
// the minimum exponent value and the result was nonzero, then
|
|
// underflow has occurred.
|
|
|
|
|
|
if ((ResultOperand->Exponent == DOUBLE_MINIMUM_EXPONENT) &&
|
|
(Mantissa != 0 || RoundBit != 00 || StickyBits != 0)) {
|
|
|
|
|
|
// If the FPCR underflow to zero (denormal enable) control bit
|
|
// is set, then flush the denormalized result to zero and do
|
|
// not set an underflow status or generate an exception.
|
|
|
|
|
|
if ((ContextBlock->IeeeMode == FALSE) ||
|
|
(SoftwareFpcr->DenormalResultEnable == 0)) {
|
|
DBGPRINT("SoftwareFpcr->DenormalResultEnable == 0\n");
|
|
ResultValue = 0;
|
|
Inexact = FALSE;
|
|
Overflow = FALSE;
|
|
Underflow = FALSE;
|
|
|
|
} else {
|
|
|
|
ResultValue = Mantissa;
|
|
ResultValue |= (ULONGLONG)ResultOperand->Sign << 63;
|
|
|
|
|
|
|
|
// Compute the underflow exception result value by recalculating the
|
|
// full precision answer and adding 1536 to the exponent.
|
|
|
|
|
|
|
|
// Round the result value using the mantissa, the round bit, and the sticky bits.
|
|
|
|
|
|
switch (ContextBlock->Round) {
|
|
|
|
|
|
// Round to nearest representable number.
|
|
|
|
|
|
case ROUND_TO_NEAREST:
|
|
if (ResultRoundBit != 0) {
|
|
if ((ResultStickyBits != 0) || ((ResultMantissa & 0x1) != 0)) {
|
|
ResultMantissa += 1;
|
|
}
|
|
}
|
|
break;
|
|
|
|
|
|
// Round toward zero.
|
|
|
|
|
|
case ROUND_TO_ZERO:
|
|
break;
|
|
|
|
|
|
// Round toward plus infinity.
|
|
|
|
|
|
case ROUND_TO_PLUS_INFINITY:
|
|
if ((ResultOperand->Sign == 0) &&
|
|
((ResultStickyBits != 0) || (ResultRoundBit != 0))) {
|
|
ResultMantissa += 1;
|
|
}
|
|
break;
|
|
|
|
|
|
// Round toward minus infinity.
|
|
|
|
|
|
case ROUND_TO_MINUS_INFINITY:
|
|
if ((ResultOperand->Sign != 0) &&
|
|
((ResultStickyBits != 0) || (ResultRoundBit != 0))) {
|
|
ResultMantissa += 1;
|
|
}
|
|
break;
|
|
}
|
|
|
|
|
|
// If rounding resulted in a carry into bit 53, then right shift the
|
|
// mantissa one bit and adjust the exponent.
|
|
|
|
|
|
if ((ResultMantissa & ((ULONGLONG)1 << 53)) != 0) {
|
|
ResultMantissa >>= 1;
|
|
ResultExponent += 1;
|
|
}
|
|
|
|
// Compute the underflow exception result value by adding
|
|
// 1536 to the exponent.
|
|
|
|
|
|
ExceptionResult = ResultMantissa & (((ULONGLONG)1 << 52) - 1);
|
|
ExceptionResult |= (((ULONGLONG)ResultExponent + 1536) << 52);
|
|
ExceptionResult |= ((ULONGLONG)ResultOperand->Sign << 63);
|
|
|
|
|
|
// If the denormalized result is inexact, then set underflow.
|
|
// Otherwise, for exact denormals do not set the underflow
|
|
// sticky bit unless underflow exception is enabled.
|
|
|
|
|
|
Overflow = FALSE;
|
|
Underflow = TRUE;
|
|
if ((StickyBits != 0) || (RoundBit != 0)) {
|
|
Inexact = TRUE;
|
|
|
|
} else {
|
|
Inexact = FALSE;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
|
|
// If the result is zero, then set the proper sign for zero.
|
|
|
|
|
|
if (Mantissa == 0) {
|
|
ResultOperand->Exponent = 0;
|
|
}
|
|
|
|
ResultValue = Mantissa & (((ULONGLONG)1 << 52) - 1);
|
|
ResultValue |= (ULONGLONG)ResultOperand->Exponent << 52;
|
|
ResultValue |= (ULONGLONG)ResultOperand->Sign << 63;
|
|
if ((StickyBits != 0) || (RoundBit != 0)) {
|
|
Inexact = TRUE;
|
|
|
|
} else {
|
|
Inexact = FALSE;
|
|
}
|
|
Overflow = FALSE;
|
|
Underflow = FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
// Check to determine if an exception should be delivered.
|
|
|
|
|
|
ExceptionRecord = ContextBlock->ExceptionRecord;
|
|
|
|
if (Overflow != FALSE) {
|
|
Fpcr->Overflow = 1;
|
|
Fpcr->InexactResult = 1;
|
|
Fpcr->SummaryBit = 1;
|
|
if (ContextBlock->IeeeMode == FALSE) {
|
|
ExceptionRecord->ExceptionCode = STATUS_FLOAT_OVERFLOW;
|
|
return FALSE;
|
|
}
|
|
IeeeValue = KiInitializeIeeeValue(ExceptionRecord);
|
|
SoftwareFpcr->StatusOverflow = 1;
|
|
SoftwareFpcr->StatusInexact = 1;
|
|
if (SoftwareFpcr->EnableOverflow != 0) {
|
|
ExceptionRecord->ExceptionCode = STATUS_FLOAT_OVERFLOW;
|
|
IeeeValue->Value.Fp64Value.W[0] = LOW_PART(ExceptionResult);
|
|
IeeeValue->Value.Fp64Value.W[1] = HIGH_PART(ExceptionResult);
|
|
ReturnValue = FALSE;
|
|
} else if (SoftwareFpcr->EnableInexact != 0) {
|
|
ExceptionRecord->ExceptionCode = STATUS_FLOAT_INEXACT_RESULT;
|
|
IeeeValue->Value.Fp64Value.W[0] = LOW_PART(ExceptionResult);
|
|
IeeeValue->Value.Fp64Value.W[1] = HIGH_PART(ExceptionResult);
|
|
ReturnValue = FALSE;
|
|
} else {
|
|
Fpcr->DisableOverflow = 1;
|
|
Fpcr->DisableInexact = 1;
|
|
}
|
|
|
|
} else if (Underflow != FALSE) {
|
|
|
|
|
|
// Non-IEEE instruction always forces underflow to zero
|
|
|
|
|
|
if (ContextBlock->IeeeMode == FALSE) {
|
|
Fpcr->Underflow = 1;
|
|
Fpcr->SummaryBit = 1;
|
|
Fpcr->InexactResult = 1;
|
|
if (ContextBlock->UnderflowEnable != FALSE) {
|
|
ExceptionRecord->ExceptionCode = STATUS_FLOAT_UNDERFLOW;
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// IEEE instructions don't report underflow unless the results are
|
|
// inexact or underflow exceptions are enabled
|
|
|
|
|
|
} else {
|
|
IeeeValue = KiInitializeIeeeValue(ExceptionRecord);
|
|
if (Inexact != FALSE) {
|
|
Fpcr->Underflow = 1;
|
|
Fpcr->SummaryBit = 1;
|
|
Fpcr->InexactResult = 1;
|
|
SoftwareFpcr->StatusUnderflow = 1;
|
|
SoftwareFpcr->StatusInexact = 1;
|
|
}
|
|
if (SoftwareFpcr->EnableUnderflow != 0) {
|
|
Fpcr->Underflow = 1;
|
|
Fpcr->SummaryBit = 1;
|
|
SoftwareFpcr->StatusUnderflow = 1;
|
|
ExceptionRecord->ExceptionCode = STATUS_FLOAT_UNDERFLOW;
|
|
IeeeValue->Value.Fp64Value.W[0] = LOW_PART(ExceptionResult);
|
|
IeeeValue->Value.Fp64Value.W[1] = HIGH_PART(ExceptionResult);
|
|
ReturnValue = FALSE;
|
|
} else if (Inexact != FALSE && SoftwareFpcr->EnableInexact != 0) {
|
|
ExceptionRecord->ExceptionCode = STATUS_FLOAT_INEXACT_RESULT;
|
|
IeeeValue->Value.Fp64Value.W[0] = LOW_PART(ExceptionResult);
|
|
IeeeValue->Value.Fp64Value.W[1] = HIGH_PART(ExceptionResult);
|
|
ReturnValue = FALSE;
|
|
} else if (Inexact != FALSE) {
|
|
Fpcr->DisableUnderflow = 1;
|
|
Fpcr->DisableInexact = 1;
|
|
}
|
|
}
|
|
|
|
} else if (Inexact != FALSE) {
|
|
Fpcr->InexactResult = 1;
|
|
Fpcr->SummaryBit = 1;
|
|
if (ContextBlock->IeeeMode != FALSE) {
|
|
IeeeValue = KiInitializeIeeeValue(ExceptionRecord);
|
|
SoftwareFpcr->StatusInexact = 1;
|
|
if (SoftwareFpcr->EnableInexact != 0) {
|
|
ExceptionRecord->ExceptionCode = STATUS_FLOAT_INEXACT_RESULT;
|
|
IeeeValue->Value.Fp64Value.W[0] = LOW_PART(ResultValue);
|
|
IeeeValue->Value.Fp64Value.W[1] = HIGH_PART(ResultValue);
|
|
ReturnValue = FALSE;
|
|
} else {
|
|
Fpcr->DisableInexact = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Always write the destination register. If an exception is delivered, and
|
|
// then dismissed, the correct value must be in the register.
|
|
|
|
|
|
KiSetRegisterValue(ContextBlock->Fc + 32,
|
|
ResultValue,
|
|
ContextBlock->ExceptionFrame,
|
|
ContextBlock->TrapFrame);
|
|
|
|
|
|
// Return a value of TRUE.unless an exception should be generated
|
|
|
|
|
|
return ReturnValue;
|
|
}
|
|
|
|
BOOLEAN
|
|
KiNormalizeQuadword (
|
|
IN PFP_CONTEXT_BLOCK ContextBlock,
|
|
IN PFP_DOUBLE_OPERAND ResultOperand
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called to convert a result value to a quadword result.
|
|
|
|
N.B. The result value is specified with a guard bit on the right,
|
|
the hidden bit (if appropriate), and an overflow bit of zero.
|
|
As called above, the guard bit and the round bit are also zero.
|
|
The result format is:
|
|
|
|
<63:55> - zero
|
|
<54 - hidden bit
|
|
<53:2> - mantissa
|
|
<1> - guard bit
|
|
<0> - round bit
|
|
|
|
There are no sticky bits.
|
|
|
|
Arguments:
|
|
|
|
ContextBlock - Supplies a pointer to the emulation context block.
|
|
|
|
ResultOperand - Supplies a pointer to the result operand value.
|
|
|
|
Return Value:
|
|
|
|
If there is not an exception, or the exception is handled, then a proper
|
|
result is stored in the destination result, the continuation address is
|
|
set, and a value of TRUE is returned. Otherwise, no value is stored and
|
|
a value of FALSE is returned.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PEXCEPTION_RECORD ExceptionRecord;
|
|
LONGLONG ExponentShift;
|
|
PFPCR Fpcr;
|
|
PFP_IEEE_VALUE IeeeValue;
|
|
ULONGLONG Mantissa;
|
|
BOOLEAN Overflow;
|
|
ULONGLONG ResultValue;
|
|
ULONG RoundBit;
|
|
ULONGLONG StickyBits;
|
|
PSW_FPCR SoftwareFpcr;
|
|
|
|
|
|
// Subtract out the exponent bias and divide the cases into right
|
|
// and left shifts.
|
|
|
|
|
|
ExponentShift = ResultOperand->Exponent - DOUBLE_EXPONENT_BIAS;
|
|
DBGPRINT("KiNormalizeQuadword: Inf=%d NaN=%d Sign=%d Exponent=%d Mantissa=%.8x%.8x\n",
|
|
ResultOperand->Infinity, ResultOperand->Nan, ResultOperand->Sign,
|
|
ResultOperand->Exponent,
|
|
ResultOperand->MantissaHigh, ResultOperand->MantissaLow);
|
|
DBGPRINT(".. ExponentShift = %d\n", ExponentShift);
|
|
Mantissa = MAKE_QUAD(ResultOperand->MantissaLow,
|
|
ResultOperand->MantissaHigh);
|
|
|
|
if (ExponentShift < 54) {
|
|
|
|
|
|
// The integer result value is less than 2**54 and so a right shift
|
|
// must be performed.
|
|
|
|
|
|
ExponentShift = 54 - ExponentShift;
|
|
if (ExponentShift < 64) {
|
|
StickyBits = Mantissa << (64 - ExponentShift);
|
|
ResultValue = Mantissa >> ExponentShift;
|
|
|
|
} else {
|
|
StickyBits = Mantissa;
|
|
ResultValue = 0;
|
|
}
|
|
Overflow = FALSE;
|
|
|
|
} else if (ExponentShift > 54) {
|
|
ExponentShift -= 54;
|
|
|
|
|
|
// The integer result value is 2**54 or greater and so a left shift
|
|
// must be performed. If the unsigned integer result value is 2**64
|
|
// or greater, then overflow has occurred and store the low order 64
|
|
// bits of the true result.
|
|
|
|
|
|
if (ExponentShift < (64 - 54)) {
|
|
StickyBits = Mantissa >> (64 - ExponentShift);
|
|
ResultValue = Mantissa << ExponentShift;
|
|
Overflow = FALSE;
|
|
|
|
} else {
|
|
StickyBits = 0;
|
|
if (ExponentShift < 64) {
|
|
ResultValue = Mantissa << ExponentShift;
|
|
|
|
} else {
|
|
ResultValue = 0;
|
|
}
|
|
Overflow = TRUE;
|
|
}
|
|
|
|
} else {
|
|
StickyBits = 0;
|
|
ResultValue = Mantissa;
|
|
Overflow = FALSE;
|
|
}
|
|
DBGPRINT(".. ResultValue = %.16Lx, StickyBits = %.16Lx\n",
|
|
ResultValue, StickyBits);
|
|
|
|
|
|
// Round the result value using the mantissa, the round bit, and the
|
|
// sticky bits.
|
|
|
|
|
|
RoundBit = (ULONG)(StickyBits >> 63);
|
|
StickyBits <<= 1;
|
|
DBGPRINT(".. ResultValue = %.16Lx, StickyBits = %.16Lx, RoundBit = %lx\n",
|
|
ResultValue, StickyBits, RoundBit);
|
|
switch (ContextBlock->Round) {
|
|
|
|
|
|
// Round to nearest representable number.
|
|
|
|
|
|
case ROUND_TO_NEAREST:
|
|
if (RoundBit != 0) {
|
|
if ((StickyBits != 0) || ((ResultValue & 0x1) != 0)) {
|
|
ResultValue += 1;
|
|
if (ResultValue == 0) {
|
|
Overflow = TRUE;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
|
|
// Round toward zero.
|
|
|
|
|
|
case ROUND_TO_ZERO:
|
|
break;
|
|
|
|
|
|
// Round toward plus infinity.
|
|
|
|
|
|
case ROUND_TO_PLUS_INFINITY:
|
|
if ((ResultOperand->Sign == 0) &&
|
|
((StickyBits != 0) || (RoundBit != 0))) {
|
|
ResultValue += 1;
|
|
if (ResultValue == 0) {
|
|
Overflow = TRUE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
|
|
// Round toward minus infinity.
|
|
|
|
|
|
case ROUND_TO_MINUS_INFINITY:
|
|
if ((ResultOperand->Sign != 0) &&
|
|
((StickyBits != 0) || (RoundBit != 0))) {
|
|
ResultValue += 1;
|
|
if (ResultValue == 0) {
|
|
Overflow = TRUE;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
|
|
// If the result value is positive and the result is negative, then
|
|
// overflow has occurred. Otherwise, negate the result value and
|
|
// check if the result is negative. If the result is positive, then
|
|
// overflow has occurred.
|
|
|
|
|
|
if (ResultOperand->Sign == 0) {
|
|
if ((LONGLONG)ResultValue < 0) {
|
|
Overflow = TRUE;
|
|
}
|
|
|
|
} else {
|
|
ResultValue = -(LONGLONG)ResultValue;
|
|
if ((LONGLONG)ResultValue > 0) {
|
|
Overflow = TRUE;
|
|
}
|
|
}
|
|
DBGPRINT(".. ResultValue = %.16Lx, StickyBits = %.16Lx\n",
|
|
ResultValue, StickyBits);
|
|
|
|
|
|
// Check to determine if an exception should be delivered or the result
|
|
// should be written to the destination register.
|
|
|
|
|
|
if (Overflow != FALSE) {
|
|
return KiInvalidOperationQuadword(ContextBlock, ResultValue);
|
|
|
|
} else if ((StickyBits | RoundBit) != 0) {
|
|
Fpcr = (PFPCR)&ContextBlock->TrapFrame->Fpcr;
|
|
Fpcr->InexactResult = 1;
|
|
Fpcr->SummaryBit = 1;
|
|
if (ContextBlock->IeeeMode != FALSE) {
|
|
SoftwareFpcr = ContextBlock->SoftwareFpcr;
|
|
SoftwareFpcr->StatusInexact = 1;
|
|
if (SoftwareFpcr->EnableInexact != 0) {
|
|
ExceptionRecord = ContextBlock->ExceptionRecord;
|
|
ExceptionRecord->ExceptionCode = STATUS_FLOAT_INEXACT_RESULT;
|
|
IeeeValue = KiInitializeIeeeValue(ExceptionRecord);
|
|
IeeeValue->Value.U64Value.LowPart = LOW_PART(ResultValue);
|
|
IeeeValue->Value.U64Value.HighPart = HIGH_PART(ResultValue);
|
|
return FALSE;
|
|
}
|
|
|
|
Fpcr->DisableInexact = 1;
|
|
}
|
|
}
|
|
|
|
|
|
// Set the destination register value and return a value of TRUE.
|
|
|
|
|
|
KiSetRegisterValue(ContextBlock->Fc + 32,
|
|
ResultValue,
|
|
ContextBlock->ExceptionFrame,
|
|
ContextBlock->TrapFrame);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
KiNormalizeSingle (
|
|
IN PFP_CONTEXT_BLOCK ContextBlock,
|
|
IN PFP_SINGLE_OPERAND ResultOperand,
|
|
IN ULONG StickyBits
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called to normalize a single floating result.
|
|
|
|
N.B. The result value is specified with a guard bit on the right,
|
|
the hidden bit (if appropriate), and a possible overflow bit.
|
|
The result format is:
|
|
|
|
<31:27> - zero
|
|
<26> - overflow bit
|
|
<25> - hidden bit
|
|
<24:2> - mantissa
|
|
<1> - guard bit
|
|
<0> - round bit
|
|
|
|
The sticky bits specify bits that were lost during the computation.
|
|
|
|
Arguments:
|
|
|
|
ContextBlock - Supplies a pointer to the emulation context block.
|
|
|
|
ResultOperand - Supplies a pointer to the result operand value.
|
|
|
|
StickyBits - Supplies the value of the sticky bits.
|
|
|
|
Return Value:
|
|
|
|
If there is not an exception, or the exception is handled, then a proper
|
|
result is stored in the destination result, the continuation address is
|
|
set, and a value of TRUE is returned. Otherwise, a proper value is stored and
|
|
a value of FALSE is returned.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONG DenormalizeShift;
|
|
PEXCEPTION_RECORD ExceptionRecord;
|
|
ULONG ExceptionResult;
|
|
PFPCR Fpcr;
|
|
PFP_IEEE_VALUE IeeeValue;
|
|
BOOLEAN Inexact;
|
|
ULONG Mantissa;
|
|
BOOLEAN Overflow;
|
|
ULONG ResultValue;
|
|
ULONG RoundBit;
|
|
PSW_FPCR SoftwareFpcr;
|
|
BOOLEAN Underflow;
|
|
ULONG ResultStickyBits;
|
|
ULONG ResultMantissa;
|
|
ULONG ResultRoundBit;
|
|
LONG ResultExponent;
|
|
BOOLEAN ReturnValue = TRUE;
|
|
|
|
|
|
// If the result is infinite, then store a properly signed infinity
|
|
// in the destination register and return a value of TRUE. Otherwise,
|
|
// round and normalize the result and check for overflow and underflow.
|
|
|
|
|
|
DBGPRINT("KiNormalizeSingle: Inf=%d NaN=%d Sign=%d Exponent=%d Mantissa=%.8x\n",
|
|
ResultOperand->Infinity, ResultOperand->Nan, ResultOperand->Sign,
|
|
ResultOperand->Exponent, ResultOperand->Mantissa);
|
|
DBGPRINT("KiNormalizeSingle: StickyBits=%.8lx\n", StickyBits);
|
|
|
|
if (ResultOperand->Infinity != FALSE) {
|
|
ResultValue = SINGLE_INFINITY_VALUE | (ResultOperand->Sign << 31);
|
|
KiSetRegisterValue(ContextBlock->Fc + 32,
|
|
KiConvertSingleOperandToRegister(ResultValue),
|
|
ContextBlock->ExceptionFrame,
|
|
ContextBlock->TrapFrame);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
Mantissa = ResultOperand->Mantissa;
|
|
Fpcr = (PFPCR)&ContextBlock->TrapFrame->Fpcr;
|
|
SoftwareFpcr = ContextBlock->SoftwareFpcr;
|
|
|
|
|
|
// If the overflow bit is set, then right shift the mantissa one bit,
|
|
// accumulate the lost bit with the sticky bits, and adjust the exponent
|
|
// value.
|
|
|
|
|
|
if ((Mantissa & (1 << 26)) != 0) {
|
|
StickyBits |= (Mantissa & 0x1);
|
|
Mantissa >>= 1;
|
|
ResultOperand->Exponent += 1;
|
|
}
|
|
|
|
|
|
// If the mantissa is nonzero, then normalize the mantissa by left
|
|
// shifting one bit at a time until there is a one bit in bit 25.
|
|
|
|
|
|
if (Mantissa != 0) {
|
|
while ((Mantissa & (1 << 25)) == 0) {
|
|
Mantissa <<= 1;
|
|
ResultOperand->Exponent -= 1;
|
|
}
|
|
}
|
|
|
|
|
|
// Right shift the mantissa two bits, set the round bit, and accumulate
|
|
// the other lost bit with the sticky bits.
|
|
|
|
|
|
StickyBits |= (Mantissa & 0x1);
|
|
RoundBit = (Mantissa & 0x2);
|
|
Mantissa >>= 2;
|
|
|
|
|
|
// Convert to denormal format before rounding to allow underflow to
|
|
// be detected on rounded result. Save context to calculate IEEE
|
|
// exception record, if needed.
|
|
|
|
|
|
if (ResultOperand->Exponent <= SINGLE_MINIMUM_EXPONENT && Mantissa != 0) {
|
|
|
|
|
|
// Save everything needed for calculating IEEE exception record value
|
|
|
|
|
|
ResultMantissa = Mantissa;
|
|
ResultExponent = ResultOperand->Exponent;
|
|
ResultStickyBits = StickyBits;
|
|
ResultRoundBit = RoundBit;
|
|
|
|
|
|
// Right shift the mantissa to set the minimum exponent plus an extra
|
|
// bit for the denormal format
|
|
|
|
|
|
DenormalizeShift = 1 - ResultOperand->Exponent;
|
|
|
|
|
|
// The maximum denormal shift is 23 bits for the mantissa plus 1 bit for the round
|
|
// A denormal shift of 25 guarantees 0 mantissa and 0 round bit and preserves all sticky bits
|
|
|
|
|
|
if (DenormalizeShift > 25) {
|
|
DenormalizeShift = 25;
|
|
}
|
|
|
|
|
|
// The denormalized result will be rounded after it is
|
|
// shifted. Preserve existing Round and Sticky Bits.
|
|
|
|
|
|
StickyBits |= RoundBit;
|
|
StickyBits |= (Mantissa << 1) << (32 - DenormalizeShift);
|
|
RoundBit = (Mantissa >> (DenormalizeShift - 1)) & 1;
|
|
Mantissa = Mantissa >> DenormalizeShift;
|
|
ResultOperand->Exponent = SINGLE_MINIMUM_EXPONENT;
|
|
}
|
|
|
|
|
|
// Round the result value using the mantissa, the round bit, and the sticky bits.
|
|
|
|
|
|
switch (ContextBlock->Round) {
|
|
|
|
|
|
// Round to nearest representable number.
|
|
|
|
|
|
case ROUND_TO_NEAREST:
|
|
if (RoundBit != 0) {
|
|
if ((StickyBits != 0) || ((Mantissa & 0x1) != 0)) {
|
|
Mantissa += 1;
|
|
}
|
|
}
|
|
break;
|
|
|
|
|
|
// Round toward zero.
|
|
|
|
|
|
case ROUND_TO_ZERO:
|
|
break;
|
|
|
|
|
|
// Round toward plus infinity.
|
|
|
|
|
|
case ROUND_TO_PLUS_INFINITY:
|
|
if ((ResultOperand->Sign == 0) &&
|
|
((StickyBits != 0) || (RoundBit != 0))) {
|
|
Mantissa += 1;
|
|
}
|
|
break;
|
|
|
|
|
|
// Round toward minus infinity.
|
|
|
|
|
|
case ROUND_TO_MINUS_INFINITY:
|
|
if ((ResultOperand->Sign != 0) &&
|
|
((StickyBits != 0) || (RoundBit != 0))) {
|
|
Mantissa += 1;
|
|
}
|
|
break;
|
|
}
|
|
|
|
|
|
// If rounding resulted in a carry into bit 24, then right shift the
|
|
// mantissa one bit and adjust the exponent.
|
|
|
|
|
|
if ((Mantissa & (1 << 24)) != 0) {
|
|
Mantissa >>= 1;
|
|
ResultOperand->Exponent += 1;
|
|
}
|
|
|
|
|
|
// If rounding resulted in a carry into bit 23 in denormal format, then
|
|
// adjust the exponent.
|
|
|
|
|
|
if ((ResultOperand->Exponent == SINGLE_MINIMUM_EXPONENT) &&
|
|
(Mantissa & (1 << 23)) != 0) {
|
|
ResultOperand->Exponent += 1;
|
|
}
|
|
|
|
|
|
// If the exponent value is greater than or equal to the maximum
|
|
// exponent value, then overflow has occurred. This results in both
|
|
// the inexact and overflow sticky bits being set in the FPCR.
|
|
|
|
// If the exponent value is less than or equal to the minimum exponent
|
|
// value, the mantissa is nonzero, and the denormalized result is inexact,
|
|
// then underflow has occurred. This results in both the inexact and
|
|
// underflow sticky bits being set in the FPCR.
|
|
|
|
// Or if underflow exceptions are enabled, underflow occurs for all denormal
|
|
// numbers. This results in the underflow sticky bit always being set in the
|
|
// FPCR and the inexact sticky bit is set when the denormalized result is
|
|
// also inexact.
|
|
|
|
// Otherwise, a normal result can be delivered, but it may be inexact.
|
|
// If the result is inexact, then the inexact sticky bit is set in the
|
|
// FPCR.
|
|
|
|
|
|
if (ResultOperand->Exponent >= SINGLE_MAXIMUM_EXPONENT) {
|
|
Inexact = TRUE;
|
|
Overflow = TRUE;
|
|
Underflow = FALSE;
|
|
|
|
|
|
// The overflow value is dependent on the rounding mode.
|
|
|
|
|
|
switch (ContextBlock->Round) {
|
|
|
|
|
|
// Round to nearest representable number.
|
|
|
|
// The result value is infinity with the sign of the result.
|
|
|
|
|
|
case ROUND_TO_NEAREST:
|
|
ResultValue = SINGLE_INFINITY_VALUE | (ResultOperand->Sign << 31);
|
|
break;
|
|
|
|
|
|
// Round toward zero.
|
|
|
|
// The result is the maximum number with the sign of the result.
|
|
|
|
|
|
case ROUND_TO_ZERO:
|
|
ResultValue = SINGLE_MAXIMUM_VALUE | (ResultOperand->Sign << 31);
|
|
break;
|
|
|
|
|
|
// Round toward plus infinity.
|
|
|
|
// If the sign of the result is positive, then the result is
|
|
// plus infinity. Otherwise, the result is the maximum negative
|
|
// number.
|
|
|
|
|
|
case ROUND_TO_PLUS_INFINITY:
|
|
if (ResultOperand->Sign == 0) {
|
|
ResultValue = SINGLE_INFINITY_VALUE;
|
|
|
|
} else {
|
|
ResultValue = (ULONG)(SINGLE_MAXIMUM_VALUE | (1 << 31));
|
|
}
|
|
break;
|
|
|
|
|
|
// Round toward minus infinity.
|
|
|
|
// If the sign of the result is negative, then the result is
|
|
// negative infinity. Otherwise, the result is the maximum
|
|
// positive number.
|
|
|
|
|
|
case ROUND_TO_MINUS_INFINITY:
|
|
if (ResultOperand->Sign != 0) {
|
|
ResultValue = (ULONG)(SINGLE_INFINITY_VALUE | (1 << 31));
|
|
|
|
} else {
|
|
ResultValue = SINGLE_MAXIMUM_VALUE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
|
|
// Compute the overflow exception result value by subtracting 192
|
|
// from the exponent.
|
|
|
|
|
|
ExceptionResult = Mantissa & ((1 << 23) - 1);
|
|
ExceptionResult |= ((ResultOperand->Exponent - 192) << 23);
|
|
ExceptionResult |= (ResultOperand->Sign << 31);
|
|
|
|
} else {
|
|
|
|
|
|
// After rounding if the exponent value is equal to
|
|
// the minimum exponent value and the result was nonzero, then
|
|
// underflow has occurred.
|
|
|
|
|
|
if ((ResultOperand->Exponent == SINGLE_MINIMUM_EXPONENT) &&
|
|
(Mantissa != 0 || RoundBit != 00 || StickyBits != 0)) {
|
|
|
|
|
|
// If the FPCR underflow to zero (denormal enable) control bit
|
|
// is set, then flush the denormalized result to zero and do
|
|
// not set an underflow status or generate an exception.
|
|
|
|
|
|
if ((ContextBlock->IeeeMode == FALSE) ||
|
|
(SoftwareFpcr->DenormalResultEnable == 0)) {
|
|
DBGPRINT("SoftwareFpcr->DenormalResultEnable == 0\n");
|
|
ResultValue = 0;
|
|
Inexact = FALSE;
|
|
Overflow = FALSE;
|
|
Underflow = FALSE;
|
|
|
|
} else {
|
|
|
|
ResultValue = Mantissa;
|
|
ResultValue |= ResultOperand->Sign << 31;
|
|
|
|
|
|
|
|
// Compute the underflow exception result value by first recalculating the
|
|
// full precision answer.
|
|
|
|
|
|
|
|
// Round the result value using the mantissa, the round bit, and the sticky bits.
|
|
|
|
|
|
switch (ContextBlock->Round) {
|
|
|
|
|
|
// Round to nearest representable number.
|
|
|
|
|
|
case ROUND_TO_NEAREST:
|
|
if (ResultRoundBit != 0) {
|
|
if ((ResultStickyBits != 0) || ((ResultMantissa & 0x1) != 0)) {
|
|
ResultMantissa += 1;
|
|
}
|
|
}
|
|
break;
|
|
|
|
|
|
// Round toward zero.
|
|
|
|
|
|
case ROUND_TO_ZERO:
|
|
break;
|
|
|
|
|
|
// Round toward plus infinity.
|
|
|
|
|
|
case ROUND_TO_PLUS_INFINITY:
|
|
if ((ResultOperand->Sign == 0) &&
|
|
((ResultStickyBits != 0) || (ResultRoundBit != 0))) {
|
|
ResultMantissa += 1;
|
|
}
|
|
break;
|
|
|
|
|
|
// Round toward minus infinity.
|
|
|
|
|
|
case ROUND_TO_MINUS_INFINITY:
|
|
if ((ResultOperand->Sign != 0) &&
|
|
((ResultStickyBits != 0) || (ResultRoundBit != 0))) {
|
|
ResultMantissa += 1;
|
|
}
|
|
break;
|
|
}
|
|
|
|
|
|
// If rounding resulted in a carry into bit 24, then right shift the
|
|
// mantissa one bit and adjust the exponent.
|
|
|
|
|
|
if ((ResultMantissa & (1 << 24)) != 0) {
|
|
ResultMantissa >>= 1;
|
|
ResultExponent += 1;
|
|
}
|
|
|
|
|
|
// Compute the underflow exception result value by adding
|
|
// 192 to the exponent.
|
|
|
|
|
|
ExceptionResult = ResultMantissa & ((1 << 23) - 1);
|
|
ExceptionResult |= ((ResultExponent + 192) << 23);
|
|
ExceptionResult |= (ResultOperand->Sign << 31);
|
|
|
|
|
|
// If the denormalized result is inexact, then set underflow.
|
|
// Otherwise, for exact denormals do not set the underflow
|
|
// sticky bit unless underflow exception is enabled.
|
|
|
|
|
|
Overflow = FALSE;
|
|
Underflow = TRUE;
|
|
if ((StickyBits != 0) || (RoundBit != 0)) {
|
|
Inexact = TRUE;
|
|
|
|
} else {
|
|
Inexact = FALSE;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
|
|
// If the result is zero, then set the proper sign for zero.
|
|
|
|
|
|
if (Mantissa == 0) {
|
|
ResultOperand->Exponent = 0;
|
|
}
|
|
|
|
ResultValue = Mantissa & ((1 << 23) - 1);
|
|
ResultValue |= (ResultOperand->Exponent << 23);
|
|
ResultValue |= (ResultOperand->Sign << 31);
|
|
if ((StickyBits != 0) || (RoundBit != 0)) {
|
|
Inexact = TRUE;
|
|
|
|
} else {
|
|
Inexact = FALSE;
|
|
}
|
|
Overflow = FALSE;
|
|
Underflow = FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
// Check to determine if an exception should be delivered.
|
|
|
|
|
|
ExceptionRecord = ContextBlock->ExceptionRecord;
|
|
|
|
if (Overflow != FALSE) {
|
|
Fpcr->Overflow = 1;
|
|
Fpcr->InexactResult = 1;
|
|
Fpcr->SummaryBit = 1;
|
|
if (ContextBlock->IeeeMode == FALSE) {
|
|
ExceptionRecord->ExceptionCode = STATUS_FLOAT_OVERFLOW;
|
|
return FALSE;
|
|
}
|
|
IeeeValue = KiInitializeIeeeValue(ExceptionRecord);
|
|
SoftwareFpcr->StatusOverflow = 1;
|
|
SoftwareFpcr->StatusInexact = 1;
|
|
if (SoftwareFpcr->EnableOverflow != 0) {
|
|
ExceptionRecord->ExceptionCode = STATUS_FLOAT_OVERFLOW;
|
|
IeeeValue->Value.Fp32Value.W[0] = ExceptionResult;
|
|
ReturnValue = FALSE;
|
|
} else if (SoftwareFpcr->EnableInexact != 0) {
|
|
ExceptionRecord->ExceptionCode = STATUS_FLOAT_INEXACT_RESULT;
|
|
IeeeValue->Value.Fp32Value.W[0] = ExceptionResult;
|
|
ReturnValue = FALSE;
|
|
} else {
|
|
Fpcr->DisableOverflow = 1;
|
|
Fpcr->DisableInexact = 1;
|
|
}
|
|
|
|
} else if (Underflow != FALSE) {
|
|
|
|
|
|
// Non-IEEE instruction always forces underflow to zero
|
|
|
|
|
|
if (ContextBlock->IeeeMode == FALSE) {
|
|
Fpcr->Underflow = 1;
|
|
Fpcr->SummaryBit = 1;
|
|
Fpcr->InexactResult = 1;
|
|
if (ContextBlock->UnderflowEnable != FALSE) {
|
|
ExceptionRecord->ExceptionCode = STATUS_FLOAT_UNDERFLOW;
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// IEEE instructions don't report underflow unless the results are
|
|
// inexact or underflow exceptions are enabled
|
|
|
|
|
|
} else {
|
|
IeeeValue = KiInitializeIeeeValue(ExceptionRecord);
|
|
if (Inexact != FALSE) {
|
|
Fpcr->Underflow = 1;
|
|
Fpcr->InexactResult = 1;
|
|
Fpcr->SummaryBit = 1;
|
|
SoftwareFpcr->StatusUnderflow = 1;
|
|
SoftwareFpcr->StatusInexact = 1;
|
|
}
|
|
if (SoftwareFpcr->EnableUnderflow != 0) {
|
|
Fpcr->Underflow = 1;
|
|
Fpcr->SummaryBit = 1;
|
|
SoftwareFpcr->StatusUnderflow = 1;
|
|
ExceptionRecord->ExceptionCode = STATUS_FLOAT_UNDERFLOW;
|
|
IeeeValue->Value.Fp32Value.W[0] = ExceptionResult;
|
|
ReturnValue = FALSE;
|
|
} else if (Inexact != FALSE && SoftwareFpcr->EnableInexact != 0) {
|
|
ExceptionRecord->ExceptionCode = STATUS_FLOAT_INEXACT_RESULT;
|
|
IeeeValue->Value.Fp32Value.W[0] = ExceptionResult;
|
|
ReturnValue = FALSE;
|
|
} else if (Inexact != FALSE) {
|
|
Fpcr->DisableUnderflow = 1;
|
|
Fpcr->DisableInexact = 1;
|
|
}
|
|
}
|
|
|
|
} else if (Inexact != FALSE) {
|
|
Fpcr->InexactResult = 1;
|
|
Fpcr->SummaryBit = 1;
|
|
if (ContextBlock->IeeeMode != FALSE) {
|
|
IeeeValue = KiInitializeIeeeValue(ExceptionRecord);
|
|
SoftwareFpcr->StatusInexact = 1;
|
|
if (SoftwareFpcr->EnableInexact != 0) {
|
|
ExceptionRecord->ExceptionCode = STATUS_FLOAT_INEXACT_RESULT;
|
|
IeeeValue->Value.Fp32Value.W[0] = ResultValue;
|
|
ReturnValue = FALSE;
|
|
} else {
|
|
Fpcr->DisableInexact = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Always write the destination register. If an exception is delivered, and
|
|
// then dismissed, the correct value must be in the register.
|
|
|
|
|
|
KiSetRegisterValue(ContextBlock->Fc + 32,
|
|
KiConvertSingleOperandToRegister(ResultValue),
|
|
ContextBlock->ExceptionFrame,
|
|
ContextBlock->TrapFrame);
|
|
|
|
|
|
// Return a value of TRUE.unless an exception should be generated
|
|
|
|
|
|
return ReturnValue;
|
|
}
|
|
|
|
VOID
|
|
KiUnpackDouble (
|
|
IN ULONG Source,
|
|
IN PFP_CONTEXT_BLOCK ContextBlock,
|
|
OUT PFP_DOUBLE_OPERAND DoubleOperand
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called to unpack a double floating value from the
|
|
specified source register.
|
|
|
|
N.B. The unpacked mantissa value is returned with a guard bit and a
|
|
round bit on the right and the hidden bit inserted if appropriate.
|
|
The format of the returned value is:
|
|
|
|
<63:55> - zero
|
|
<54> - hidden bit
|
|
<53:2> - mantissa
|
|
<1> - guard bit
|
|
<0> - round bit
|
|
|
|
Arguments:
|
|
|
|
Source - Supplies the number of the register that contains the operand.
|
|
|
|
ContextBlock - Supplies a pointer to the emulation context block.
|
|
|
|
DoubleOperand - Supplies a pointer to a structure that is to receive the
|
|
operand value.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONGLONG Value;
|
|
ULONG Value1;
|
|
ULONG Value2;
|
|
|
|
|
|
// Get the source register value and unpack the sign, exponent, and
|
|
// mantissa value.
|
|
|
|
|
|
Value = KiGetRegisterValue(Source + 32,
|
|
ContextBlock->ExceptionFrame,
|
|
ContextBlock->TrapFrame);
|
|
Value1 = (ULONG)Value;
|
|
Value2 = (ULONG)(Value >> 32);
|
|
|
|
DoubleOperand->Sign = Value2 >> 31;
|
|
DoubleOperand->Exponent = (Value2 >> (52 - 32)) & 0x7ff;
|
|
DoubleOperand->MantissaHigh = Value2 & 0xfffff;
|
|
DoubleOperand->MantissaLow = Value1;
|
|
|
|
|
|
// If the exponent is the largest possible value, then the number is
|
|
// either a NaN or an infinity. Otherwise if the exponent is the smallest
|
|
// possible value and the mantissa is nonzero, then the number is
|
|
// denormalized. Otherwise the number is finite and normal.
|
|
|
|
|
|
if (DoubleOperand->Exponent == DOUBLE_MAXIMUM_EXPONENT) {
|
|
DoubleOperand->Normal = FALSE;
|
|
if ((DoubleOperand->MantissaLow | DoubleOperand->MantissaHigh) != 0) {
|
|
DoubleOperand->Infinity = FALSE;
|
|
DoubleOperand->Nan = TRUE;
|
|
|
|
} else {
|
|
DoubleOperand->Infinity = TRUE;
|
|
DoubleOperand->Nan = FALSE;
|
|
}
|
|
|
|
} else {
|
|
DoubleOperand->Infinity = FALSE;
|
|
DoubleOperand->Nan = FALSE;
|
|
DoubleOperand->Normal = TRUE;
|
|
if (DoubleOperand->Exponent == DOUBLE_MINIMUM_EXPONENT) {
|
|
if ((DoubleOperand->MantissaHigh | DoubleOperand->MantissaLow) != 0) {
|
|
if (ContextBlock->SoftwareFpcr->DenormalOperandsEnable == 0) {
|
|
DBGPRINT("SoftwareFpcr->DenormalOperandsEnable == 0\n");
|
|
DoubleOperand->MantissaHigh = 0;
|
|
DoubleOperand->MantissaLow = 0;
|
|
DoubleOperand->Exponent = 0;
|
|
} else {
|
|
DoubleOperand->Normal = FALSE;
|
|
DoubleOperand->Exponent += 1;
|
|
while ((DoubleOperand->MantissaHigh & (1 << 20)) == 0) {
|
|
DoubleOperand->MantissaHigh =
|
|
(DoubleOperand->MantissaHigh << 1) |
|
|
(DoubleOperand->MantissaLow >> 31);
|
|
DoubleOperand->MantissaLow <<= 1;
|
|
DoubleOperand->Exponent -= 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
} else {
|
|
DoubleOperand->MantissaHigh |= (1 << 20);
|
|
}
|
|
}
|
|
|
|
|
|
// Left shift the mantissa 2-bits to provide for a guard bit and a round
|
|
// bit.
|
|
|
|
|
|
DoubleOperand->MantissaHigh =
|
|
(DoubleOperand->MantissaHigh << 2) | (DoubleOperand->MantissaLow >> 30);
|
|
DoubleOperand->MantissaLow <<= 2;
|
|
DBGPRINT("KiUnpackDouble: Inf=%d NaN=%d Sign=%d Exponent=%d Mantissa=%.8x%.8x\n",
|
|
DoubleOperand->Infinity, DoubleOperand->Nan, DoubleOperand->Sign,
|
|
DoubleOperand->Exponent,
|
|
DoubleOperand->MantissaHigh, DoubleOperand->MantissaLow);
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
KiUnpackSingle (
|
|
IN ULONG Source,
|
|
IN PFP_CONTEXT_BLOCK ContextBlock,
|
|
OUT PFP_SINGLE_OPERAND SingleOperand
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called to unpack a single floating value from the
|
|
specified source register.
|
|
|
|
N.B. The unpacked mantissa value is returned with a guard bit and a
|
|
round bit on the right and the hidden bit inserted if appropriate.
|
|
The format of the returned value is:
|
|
|
|
<31:26> - zero
|
|
<25> - hidden bit
|
|
<24:2> - mantissa
|
|
<1> - guard bit
|
|
<0> - round bit
|
|
|
|
Arguments:
|
|
|
|
Source - Supplies the number of the register that contains the operand.
|
|
|
|
ContextBlock - Supplies a pointer to the emulation context block.
|
|
|
|
SingleOperand - Supplies a pointer to a structure that is to receive the
|
|
operand value.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONG Value;
|
|
|
|
|
|
// Get the source register value and unpack the sign, exponent, and
|
|
// mantissa value.
|
|
|
|
|
|
Value = KiConvertRegisterToSingleOperand(
|
|
KiGetRegisterValue(Source + 32,
|
|
ContextBlock->ExceptionFrame,
|
|
ContextBlock->TrapFrame));
|
|
|
|
SingleOperand->Sign = Value >> 31;
|
|
SingleOperand->Exponent = (Value >> 23) & 0xff;
|
|
SingleOperand->Mantissa = Value & 0x7fffff;
|
|
|
|
|
|
// If the exponent is the largest possible value, then the number is
|
|
// either a NaN or an infinity. Otherwise if the exponent is the smallest
|
|
// possible value and the mantissa is nonzero, then the number is
|
|
// denormalized. Otherwise the number is finite and normal.
|
|
|
|
|
|
if (SingleOperand->Exponent == SINGLE_MAXIMUM_EXPONENT) {
|
|
SingleOperand->Normal = FALSE;
|
|
if (SingleOperand->Mantissa != 0) {
|
|
SingleOperand->Infinity = FALSE;
|
|
SingleOperand->Nan = TRUE;
|
|
|
|
} else {
|
|
SingleOperand->Infinity = TRUE;
|
|
SingleOperand->Nan = FALSE;
|
|
}
|
|
|
|
} else {
|
|
SingleOperand->Infinity = FALSE;
|
|
SingleOperand->Nan = FALSE;
|
|
SingleOperand->Normal = TRUE;
|
|
if (SingleOperand->Exponent == SINGLE_MINIMUM_EXPONENT) {
|
|
if (SingleOperand->Mantissa != 0) {
|
|
if (ContextBlock->SoftwareFpcr->DenormalOperandsEnable == 0) {
|
|
DBGPRINT("SoftwareFpcr->DenormalOperandsEnable == 0\n");
|
|
SingleOperand->Mantissa = 0;
|
|
SingleOperand->Exponent = 0;
|
|
} else {
|
|
SingleOperand->Normal = FALSE;
|
|
SingleOperand->Exponent += 1;
|
|
while ((SingleOperand->Mantissa & (1 << 23)) == 0) {
|
|
SingleOperand->Mantissa <<= 1;
|
|
SingleOperand->Exponent -= 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
} else {
|
|
SingleOperand->Mantissa |= (1 << 23);
|
|
}
|
|
}
|
|
|
|
|
|
// Left shift the mantissa 2-bits to provide for a guard bit and a round
|
|
// bit.
|
|
|
|
|
|
SingleOperand->Mantissa <<= 2;
|
|
DBGPRINT("KiUnpackSingle: Inf=%d NaN=%d Sign=%d Exponent=%d Mantissa=%.8x\n",
|
|
SingleOperand->Infinity, SingleOperand->Nan, SingleOperand->Sign,
|
|
SingleOperand->Exponent, SingleOperand->Mantissa);
|
|
return;
|
|
}
|