windows-nt/Source/XPSP1/NT/base/ntos/ke/alpha/floatem.c
2020-09-26 16:20:57 +08:00

4449 lines
142 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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;
}