📄 float.c
字号:
//
// If the exception PC is equal to the fault instruction address
// plus four, then the floating exception occurred in the delay
// slot of a branch instruction and the continuation address must
// be computed by emulating the branch instruction. Note that it
// is possible for an exception to occur when the branch instruction
// is read from user memory.
//
if (cause.BD)
ContextBlock.BranchAddress = KiEmulateBranch(pctx);
else
ContextBlock.BranchAddress = pctx->Fir + 4;
//
// 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.
//
ContextBlock.ExceptionRecord = ExceptionRecord;
ContextBlock.pctx = pctx;
ContextBlock.Round = ((PFSR)&pctx->Fsr)->RM;
//
// Initialize the number of exception information parameters, set
// the branch address, and clear the IEEE exception value.
//
ExceptionRecord->NumberParameters = 6;
ExceptionRecord->ExceptionInformation[0] = 0;
ExceptionRecord->ExceptionInformation[1] = ContextBlock.BranchAddress;
ExceptionRecord->ExceptionInformation[2] = 0;
ExceptionRecord->ExceptionInformation[3] = 0;
ExceptionRecord->ExceptionInformation[4] = 0;
ExceptionRecord->ExceptionInformation[5] = 0;
//
// Clear all exception flags and emulate the floating point operation
// The return value is dependent on the results of the emulation.
//
pctx->Fsr &= ~(0x3f << 12);
Instruction = *((PMIPS_INSTRUCTION)ExceptionAddress + (cause.BD ? 1 : 0));
Function = Instruction.c_format.Function;
ContextBlock.Fd = Instruction.c_format.Fd;
Fs = Instruction.c_format.Fs;
Ft = Instruction.c_format.Ft;
Format = Instruction.c_format.Format;
Negation = 0;
//
// Check for illegal register specification or format code.
//
if (((ContextBlock.Fd & 0x1) != 0) || ((Fs & 0x1) != 0) || ((Ft & 0x1) != 0) ||
((Format != FORMAT_LONGWORD) && (Format != FORMAT_QUADWORD) && (Format > FORMAT_DOUBLE))) {
Function = FLOAT_ILLEGAL;
}
//
// Decode operand values and dispose with NaNs.
//
if ((Function <= FLOAT_DIVIDE) || (Function >= FLOAT_COMPARE)) {
//
// The function has two operand values.
//
if (Format == FORMAT_SINGLE) {
KiUnpackSingle(Fs, &ContextBlock, &SingleOperand1);
KiUnpackSingle(Ft, &ContextBlock, &SingleOperand2);
//
// If either operand is a NaN, then check to determine if a
// compare instruction or other dyadic operation is being
// performed.
//
if ((SingleOperand1.Nan != FALSE) || (SingleOperand2.Nan != FALSE)) {
if (Function < FLOAT_COMPARE) {
//
// Dyadic operation.
//
// Store a quite 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 signally NaN.
//
return KiInvalidOperationSingle(&ContextBlock,
TRUE,
&SingleOperand1,
&SingleOperand2);
} else {
//
// Compare operation.
//
// Set the condition based on the predicate of
// the floating comparison.
//
// If the compare is a signaling compare, then
// raise an exception if the invalid operation
// trap is enabled. Otherwise, raise an exception
// if one of the operands is a signaling NaN.
//
if ((Function & COMPARE_UNORDERED_MASK) != 0) {
((PFSR)&pctx->Fsr)->CC = 1;
} else {
((PFSR)&pctx->Fsr)->CC = 0;
}
if ((Function & COMPARE_ORDERED_MASK) != 0) {
return KiInvalidCompareSingle(&ContextBlock,
FALSE,
&SingleOperand1,
&SingleOperand2);
} else {
return KiInvalidCompareSingle(&ContextBlock,
TRUE,
&SingleOperand1,
&SingleOperand2);
}
}
} else if (Function >= FLOAT_COMPARE) {
CompareFunction = Function;
Function = FLOAT_COMPARE_SINGLE;
}
} else if (Format == FORMAT_DOUBLE) {
KiUnpackDouble(Fs, &ContextBlock, &DoubleOperand1);
KiUnpackDouble(Ft, &ContextBlock, &DoubleOperand2);
//
// If either operand is a NaN, then check to determine if a
// compare instruction or other dyadic operation is being
// performed.
//
if ((DoubleOperand1.Nan != FALSE) || (DoubleOperand2.Nan != FALSE)) {
if (Function < FLOAT_COMPARE) {
//
// Dyadic operation.
//
// Store a quite 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 signally NaN.
//
return KiInvalidOperationDouble(&ContextBlock,
TRUE,
&DoubleOperand1,
&DoubleOperand2);
} else {
//
// Compare operation.
//
// Set the condition based on the predicate of
// the floating comparison.
//
// If the compare is a signaling compare, then
// raise an exception if the invalid operation
// trap is enabled. Othersie, raise an exception
// if one of the operands is a signaling NaN.
//
if ((Function & COMPARE_UNORDERED_MASK) != 0) {
((PFSR)&pctx->Fsr)->CC = 1;
} else {
((PFSR)&pctx->Fsr)->CC = 0;
}
if ((Function & COMPARE_ORDERED_MASK) != 0) {
return KiInvalidCompareDouble(&ContextBlock,
FALSE,
&DoubleOperand1,
&DoubleOperand2);
} else {
return KiInvalidCompareDouble(&ContextBlock,
TRUE,
&DoubleOperand1,
&DoubleOperand2);
}
}
} else if (Function >= FLOAT_COMPARE) {
CompareFunction = Function;
Function = FLOAT_COMPARE_DOUBLE;
}
} else {
Function = FLOAT_ILLEGAL;
}
} else {
//
// The function has one operand value.
//
if (Format == FORMAT_SINGLE) {
KiUnpackSingle(Fs, &ContextBlock, &SingleOperand1);
//
// If the operand is a NaN and the function is not a convert
// operation, 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) &&
(Function < FLOAT_ROUND_QUADWORD) ||
(Function > FLOAT_CONVERT_QUADWORD) ||
((Function > FLOAT_FLOOR_LONGWORD) &&
(Function < FLOAT_CONVERT_SINGLE))) {
return KiInvalidOperationSingle(&ContextBlock,
TRUE,
&SingleOperand1,
&SingleOperand1);
}
} else if (Format == FORMAT_DOUBLE) {
KiUnpackDouble(Fs, &ContextBlock, &DoubleOperand1);
//
// If the operand is a NaN and the function is not a convert
// operation, 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) &&
(Function < FLOAT_ROUND_QUADWORD) ||
(Function > FLOAT_CONVERT_QUADWORD) ||
((Function > FLOAT_FLOOR_LONGWORD) &&
(Function < FLOAT_CONVERT_SINGLE))) {
return KiInvalidOperationDouble(&ContextBlock,
TRUE,
&DoubleOperand1,
&DoubleOperand1);
}
} else if ((Format == FORMAT_LONGWORD) &&
(Function >= FLOAT_CONVERT_SINGLE)) {
Longword = KiGetRegisterValue(Fs + 32,
ContextBlock.pctx);
} else if ((Format == FORMAT_QUADWORD) &&
(Function >= FLOAT_CONVERT_SINGLE)) {
u.LargeValue.LowPart = KiGetRegisterValue(Fs + 32,
ContextBlock.pctx);
u.LargeValue.HighPart = KiGetRegisterValue(Fs + 33,
ContextBlock.pctx);
} else {
Function = FLOAT_ILLEGAL;
}
}
//
// Case to the proper function routine to emulate the operation.
//
switch (Function) {
//
// Floating subtract operation.
//
// Floating subtract is accomplished by complementing the sign
// of the second operand and then performing an add operation.
//
case FLOAT_SUBTRACT:
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 posible 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 FLOAT_ADD:
if (Format == FORMAT_SINGLE) {
//
// Complement the sign of the second operand if the operation
// is subtraction.
//
SingleOperand2.Sign ^= Negation;
//
// Reorder then operands according to their exponent value.
//
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;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -