📄 ccmmath_cpu.s
字号:
orrne MANT1, MANT1, #20 cmp EXP1, #1 bge _floatRoundResult /* Go round the result and exit. */ b _fmulDoGradualUnderflowLABEL(_fdivFloatCheckForNaNOrInfinity) /* Check if float1 is NaN or infinity: */ cmp EXP1, #0xff /* Check for infinity or nan. */ beq _fdivFloat1CheckForNaNOrInfinity /* Else, float2 is NaN or infinity: */LABEL(_fdivFloat2CheckForNaNOrInfinity) /* If we get here, then float1 is not nan nor infinity: */ cmp MANT2, #0 /* Check for infinity. */ bne _floatReturnNaN /* finite / nan => nan. */ /* Else, float2 is an infinity. Result is 0 */ FLOAT_RETURN_TO_CALLER /* Return the result. */LABEL(_fdivFloat1CheckForNaNOrInfinity) cmp MANT1, #0 /* Check for infinity. */ bne _floatReturnNaN /* nan / ? => nan. */ /* Else, float1 is an infinity. Check float2 for nan or infinity: */ cmp EXP2, #0xff bne _floatReturnInfinity /* inf / finite => inf */ b _floatReturnNaN /* inf / {nan or inf} => nan. */#ifndef __RVCT__#define FLOAT_NORMALIZE_LOOP( _MANT, _EXP ) \ mov _EXP, #1; \1: \ mov _MANT, _MANT, LSL #1; \ sub _EXP, _EXP, #1; \ cmp _MANT, #0x800000; \ blt 1b#else MACRO FLOAT_NORMALIZE_LOOP0 $_MANT, $_EXP mov $_EXP, #11 mov $_MANT, $_MANT, LSL #1 sub $_EXP, $_EXP, #1 cmp $_MANT, #0x800000 blt %b1 MEND#define FLOAT_NORMALIZE_LOOP( _MANT, _EXP ) \ FLOAT_NORMALIZE_LOOP0 _MANT, _EXP#endifLABEL(_fdivCheckFloat1ForZero) /* If we get here, then float1 and float2 are finite: */ cmp MANT1, #0 /* Check for 0. */ beq _fdivFloat1IsZero FLOAT_NORMALIZE_LOOP( MANT1, EXP1 ) b _fdivFloat1IsNotZeroLABEL(_fdivFloat1IsZero) cmp EXP2, #0 cmpeq MANT2, #0 FLOAT_RETURN_TO_CALLER_IF(ne) /* result = sign | 0. Return to caller. */ b _floatReturnNaN /* 0 / 0 => NaN */LABEL(_fdivCheckFloat2ForZero) /* If we get here, then float1 is finite and non-zero: */ cmp MANT2, #0 /* Check for 0. */ beq _floatReturnInfinity FLOAT_NORMALIZE_LOOP( MANT2, EXP2 ) b _fdivFloat2IsNotZero#undef FLOAT1#undef FLOAT2#undef EXP1#undef EXP2#undef MANT1#undef MANT2#undef EMASK#undef MMASK#undef ITER#undef QUOT/* * Entry point for converting floats to doubles. * NOTE: The result is in FLOAT (high word) and MANT (low word). */ ENTRY(CVMCCMruntimeF2D)ENTRY1 ( CVMCCMruntimeF2D ) ENTRY(CVMCCMruntimeF2D_C)ENTRY1 ( CVMCCMruntimeF2D_C ) /* r0 = a1 = float1 * v1 = jfp * v2 = jsp * sp = ccee */#if CVM_DOUBLE_ENDIANNESS == CVM_BIG_ENDIAN#define FLOAT r0#define MANT r1#elif CVM_DOUBLE_ENDIANNESS == CVM_LITTLE_ENDIAN#define FLOAT r1#define MANT r0#endif#define EXP r2#define EMASK r3#define MMASK r3 ldr MMASK, floatMantissaMask#if CVM_DOUBLE_ENDIANNESS == CVM_LITTLE_ENDIAN mov FLOAT, r0#endif and MANT, FLOAT, MMASK /* Extract the mantissa. */ mov EMASK, #0xff and EXP, FLOAT, EMASK, LSL #23 /* Extract the exponent. */ /* Check for NaNs or infinities: */ cmp EXP, EMASK, LSL #23 beq _f2dHandleNaNOrInfinity /* Go handle the nan or infinity. */ /* Prepare the mantissa for conversion: */ mov MANT, MANT, LSL #9 /* Remove the leading zeroes. */ cmp EXP, #0 /* Check for a denormalized number. */ beq _f2dHandleDenormalized /* Set the new exponent: */ mov EXP, EXP, LSR #3 /* The new exponent is 11 bits. */ add EXP, EXP, #0x38000000 /* Add the difference in the bias. */LABEL(_f2dSetMantissaAndSignAndReturn) /* Set the new mantissa: */ orr EXP, EXP, MANT, LSR #12 /* Mask in the mantissa high bits. */ mov MANT, MANT, LSL #20 /* Set the low bits. */LABEL(_f2dSetSignAndReturn) /* Set the sign of the result: */ and FLOAT, FLOAT, #0x80000000 /* Copy the sign. */ orr FLOAT, FLOAT, EXP /* Add the exponent and high mant. */ mov pc, lr /* Return to caller. */LABEL(_f2dHandleNaNOrInfinity) ldr EXP, doubleExponentMask /* Set the special exponent. */ /* Note: If the mantissa is 0, then we have an infinity which requires that we return 0 in MANT. If the mantissa is not zero, then we have a NaN which requires a non zero mantissa which we already have. Hence, there is nothing to do. */ b _f2dSetSignAndReturn /* Return to caller. */LABEL(_f2dHandleDenormalized) cmp MANT, #0 /* Check if float is 0. */ /* If the mantissa is 0, then we have a 0 float which requires 0 in MANT. */ beq _f2dSetSignAndReturn /* Return to caller. */ /* If we get here, then there must be a non zero bit somewhere in the mantissa. Just shift left until we get it normalized. Not that we also don't have to check for underflow because every non-zero finite float number can be expressed as a normalized double. */ /* Convert the exponent. NOTE: float exponent 1 = double exponent 1 - 127 + 1023 = 897 = 0x381 = 0x380 + 1: */ mov EXP, #0x38000000 add EXP, EXP, #0x00100000 /* Normalize the mantissa: */LABEL(_f2dNormalizing) sub EXP, EXP, #0x00100000 movs MANT, MANT, LSL #1 /* Shift left until high bit is seen. */ bcc _f2dNormalizing /* High bit not seen yet, continue. */ b _f2dSetMantissaAndSignAndReturn#undef FLOAT#undef EXP#undef EMASK#undef MMASK#undef MANT/* * Entry point for comparing doubles. * NOTE: The result is in the condition codes that have been set by various * comparisons. Even though the C prototype for this helper indicates * that the helper is to return an integer status in a register, this * assembly version returns the result in the CPU condition code * register (thus effectively making the return type of the function * void). This is OK because the ARM specific rules which emits calls * to this helper function will be expecting the result to be in the * condition code register. This method of returning the result is * done for optimization purposes. */ ENTRY(CVMCCMruntimeDCmpg)ENTRY1 ( CVMCCMruntimeDCmpg ) ENTRY(CVMCCMruntimeDCmpg_C)ENTRY1 ( CVMCCMruntimeDCmpg_C ) /* r0 = a1 = double1 high * r1 = a2 = double1 low * r2 = a3 = double2 high * r3 = a4 = double2 low * v1 = jfp * v2 = jsp * sp = ccee */ orr lr, lr, #0x2 /* NaN returns 'greater than' status.*/ /* Fall through to _dcmpStart: */ ENTRY(CVMCCMruntimeDCmpl)ENTRY1 ( CVMCCMruntimeDCmpl ) ENTRY(CVMCCMruntimeDCmpl_C)ENTRY1 ( CVMCCMruntimeDCmpl_C ) /* r0 = a1 = double1 high * r1 = a2 = double1 low * r2 = a3 = double2 high * r3 = a4 = double2 low * v1 = jfp * v2 = jsp * sp = ccee */ /* NaN returns 'less than' status. */ /* uses r0, r1, r2, r3, r12 */LABEL(_dcmpStart)/* Registers definition for different endianness. */#if CVM_DOUBLE_ENDIANNESS == CVM_BIG_ENDIAN#define DBL1LO r1#define DBL1HI r0#define DBL2LO r3#define DBL2HI r2#elif CVM_DOUBLE_ENDIANNESS == CVM_LITTLE_ENDIAN#define DBL1LO r0#define DBL1HI r1#define DBL2LO r2#define DBL2HI r3#endif /* Check for NaN in double1 and double2. Note that the double value can only be a NaN if the exponent value is 0x7ff00000. This means that adding 0x00100000 to it will result in a negative value i.e. 0x80000000. We can check for this without using yet another register: */ /* Check double1 for a NaN: */ ldr r12, doubleExponentMask /* load the exponent mask. */ and r12, DBL1HI, r12 /* Extract exponent1. */ adds r12, r12, #0x00100000 /* Check for infinity or nan. */ bmi _dcmpDouble1CheckForNanLABEL(_dcmpDouble1IsNotNan) /* Check double2 for a NaN: */ ldr r12, doubleExponentMask /* load the exponent mask. */ and r12, DBL2HI, r12 /* Extract exponent2. */ adds r12, r12, #0x00100000 /* Check for infinity or nan. */ bmi _dcmpDouble2CheckForNanLABEL(_dcmpDouble2IsNotNan) /* Check if the 2 doubles have the same sign bit: */ eor r12, DBL1HI, DBL2HI /* Check to see if the sign bit is the */ tst r12, #0x80000000 /* same. */ bne _dcmpEvaluateResultBasedOnSigns /* If we get here, then the sign bits are the same. Next, check if the sign bits are negative: */ tst DBL1HI, #0x80000000 /* Check for negative sign bit. */ bic DBL1HI, DBL1HI, #0x80000000 /* Clear the sign bit. */ bic DBL2HI, DBL2HI, #0x80000000 /* Clear the sign bit. */ bne _dcmpDoNegativeChecks /* Do positive version of checks: */ /* Compare high word: */ cmp DBL1HI, DBL2HI bne _dcmpReturnToCaller /* If not equal, we have our result. */ /* Compare the mantissas: */ eors r12, DBL1LO, DBL2LO bmi _dcmpPositiveRevLowTest cmp DBL1LO, DBL2LO b _dcmpReturnToCallerLABEL(_dcmpPositiveRevLowTest) cmp DBL2LO, DBL1LO /* Fall thru to _dcmpReturnToCaller. */LABEL(_dcmpReturnToCaller) bic lr, lr, #0x3 /* Clear the low bits set above. */ mov pc, lr /* Return to the caller. */LABEL(_dcmpDoNegativeChecks) /* Do negative version of checks: */ /* Compare high word: */ cmp DBL2HI, DBL1HI bne _dcmpReturnToCaller /* If not equal, we have our result. */ /* Compare the mantissa upper low bits: */ mov r12, DBL2LO, LSR #16 cmp r12, DBL1LO, LSR #16 bne _dcmpReturnToCaller /* If not equal, we have our answer. */ /* Compare the mantissa lower low bits: */ mvn r12, #0 /* r12 = 0xffffffff. */ and DBL1LO, DBL1LO, r12, LSR #16 /* mask with 0xffff. */ and DBL2LO, DBL2LO, r12, LSR #16 /* mask with 0xffff. */ cmp DBL2LO, DBL1LO b _dcmpReturnToCaller /* Return the result. */LABEL(_dcmpEvaluateResultBasedOnSigns) /* Check for the special case where the 2 numbers are zeroes. If so, the two are still equal even if their signs are not: */ orrs r12, DBL1LO, DBL1HI, LSL #1 /* See if double1 is 0. */ bne _dcmpNotBothZeroes orrs r12, DBL2LO, DBL2HI, LSL #1 /* See if double2 is 0. */ beq _dcmpReturnToCaller /* Return the result. */LABEL(_dcmpNotBothZeroes) cmp DBL1HI, DBL2HI /* Compare the signs. */ b _dcmpReturnToCaller /* Return the result. */LABEL(_dcmpDouble1CheckForNan) /* Check if the mantissa is 0 i.e. the double is an infinity: */ orrs r12, DBL1LO, DBL1HI, LSL #12 beq _dcmpDouble1IsNotNan /* If is infinity, resume in main code. */ b _dcmpNanFoundLABEL(_dcmpDouble2CheckForNan) /* Check if the mantissa is 0 i.e. the double is an infinity: */ orrs r12, DBL2LO, DBL2HI, LSL #12 beq _dcmpDouble2IsNotNan /* If is infinity, resume in main code. */LABEL(_dcmpNanFound) /* The return value for NaN is encoded in the low 2 bits of the lr which is normally 0: */ and r12, lr, #0x3 /* Else, is NaN. Return the desired */ cmp r12, #1 /* condition code result. */ b _dcmpReturnToCaller #undef DBL1LO#undef DBL1HI#undef DBL1LO#undef DBL1HI ENTRY(CVMCCMruntimeF2I)ENTRY1 ( CVMCCMruntimeF2I ) ENTRY(CVMCCMruntimeF2I_C)ENTRY1 ( CVMCCMruntimeF2I_C ) /* * Keep the original argument in r0 (it has the sign) * Working registers are F (Fraction) and EXP (exponent) */#define F r1#define EXP r2 bic F, r0, #0x80000000 /* Strip sign */ subs EXP, F, #0x3f800000 /* De-bias exponent */ blt _f2iTooLittle /* If exponent small, number is < 1 */ cmp EXP, #(31<<23) /* If debiased exponent is > 31 */ bhs _f2iTooBig /* ...then the number is > max int. */ mov F, F, LSL #8 /* Shift fraction far to the left */ orr F, F, #0x80000000 /* ...& insert implicit high order bit */ mov EXP, EXP, LSR #23 /* Shift the exponent down. */ /* now need to shift F right by 31 - exponent */ /* we know that 31 > EXP >= 0 */ rsb EXP, EXP, #31 mov F, F, LSR EXP /* apply the sign and return */ cmp r0, #0 rsblt F, F, #0 mov r0, F mov pc, lr LABEL(_f2iTooBig) /* test for Nan, which returns a zero */ cmp EXP, #(0x7f800000-0x3f800000) /* (comparing after de-biasing) */ bhi _f2iTooLittle ands r0, r0, #0x80000000 /* check the original sign */ mvnpl r0, #0x80000000 /* deliver maxint or minint accordingly */ mov pc, lrLABEL(_f2iTooLittle) mov r0, #0 mov pc, lr
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -