📄 float.c
字号:
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; } 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, 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,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -