diff -r 000000000000 -r bde4ae8d615e os/kernelhwsrv/kernel/eka/euser/epoc/arm/uc_realx.cia --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/os/kernelhwsrv/kernel/eka/euser/epoc/arm/uc_realx.cia Fri Jun 15 03:10:57 2012 +0200 @@ -0,0 +1,4386 @@ +// Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// e32\euser\epoc\arm\uc_realx.cia +// +// + +#include +#include +#include +#ifdef __USE_VFP_MATH +#include +#endif + +#if defined(__USE_VFP_MATH) && !defined(__CPU_HAS_VFP) +#error __USE_VFP_MATH was defined but not __CPU_HAS_VFP - impossible combination, check variant.mmh +#endif + +#ifndef __EABI_CTORS__ +__NAKED__ EXPORT_C TRealX::TRealX() +/** +Constructs a default extended precision object. + +This sets the value to zero. +*/ + { + asm("mov r1, #0 "); + asm("str r1, [r0] "); + asm("str r1, [r0, #4] "); + asm("str r1, [r0, #8] "); + __JUMP(,lr); + } + + + + +__NAKED__ EXPORT_C TRealX::TRealX(TUint /*anExp*/, TUint /*aMantHi*/, TUint /*aMantLo*/) +/** +Constructs an extended precision object from an explicit exponent and +a 64 bit mantissa. + +@param anExp The exponent +@param aMantHi The high order 32 bits of the 64 bit mantissa +@param aMantLo The low order 32 bits of the 64 bit mantissa +*/ + { + asm("str r1, [r0, #8] "); + asm("str r2, [r0, #4] "); + asm("str r3, [r0, #0] "); + __JUMP(,lr); + } +#endif + + + + + +__NAKED__ EXPORT_C TInt TRealX::Set(TInt /*anInt*/) +/** +Gives this extended precision object a new value taken +from a signed integer. + +@param anInt The signed integer value. + +@return KErrNone, always. +*/ + { + asm("stmfd sp!, {lr} "); + asm("mov r2, r1 "); + asm("bl ConvertIntToTRealX "); + asm("stmia r0, {r1,r2,r3} "); + asm("mov r0, #0 "); // return KErrNone + __POPRET(""); + } + + + + +#ifndef __EABI_CTORS__ +__NAKED__ EXPORT_C TRealX::TRealX(TInt /*anInt*/) +/** +Constructs an extended precision object from a signed integer value. + +@param anInt The signed integer value. +*/ + { + // fall through + } +#endif + + + + +__NAKED__ EXPORT_C TRealX& TRealX::operator=(TInt /*anInt*/) +/** +Assigns the specified signed integer value to this extended precision object. + +@param anInt The signed integer value. + +@return A reference to this extended precision object. +*/ + { + asm("stmfd sp!, {lr} "); + asm("mov r2, r1 "); + asm("bl ConvertIntToTRealX "); + asm("stmia r0, {r1,r2,r3} "); + __POPRET(""); + + asm("ConvertIntToTRealX: "); + asm("cmp r2, #0 "); + asm("movpl r3, #0 "); // if int>0, r3=0 + asm("beq ConvertIntToTRealX0 "); // if int=0, return 0 + asm("movmi r3, #1 "); // if int<0, r3=1 + asm("rsbmi r2, r2, #0 "); // if int -ve, negate it + asm("orr r3, r3, #0x001E0000 "); + asm("orr r3, r3, #0x80000000 "); // r3=exponent 801E + sign bit +#ifdef __CPU_ARM_HAS_CLZ + CLZ(12,2); + asm("mov r2, r2, lsl r12 "); + asm("sub r3, r3, r12, lsl #16 "); +#else + asm("cmp r2, #0x10000 "); // normalise mantissa, decrementing exponent as needed + asm("movcc r2, r2, lsl #16 "); + asm("subcc r3, r3, #0x100000 "); + asm("cmp r2, #0x1000000 "); + asm("movcc r2, r2, lsl #8 "); + asm("subcc r3, r3, #0x080000 "); + asm("cmp r2, #0x10000000 "); + asm("movcc r2, r2, lsl #4 "); + asm("subcc r3, r3, #0x040000 "); + asm("cmp r2, #0x40000000 "); + asm("movcc r2, r2, lsl #2 "); + asm("subcc r3, r3, #0x020000 "); + asm("cmp r2, #0x80000000 "); + asm("movcc r2, r2, lsl #1 "); + asm("subcc r3, r3, #0x010000 "); +#endif + asm("ConvertIntToTRealX0: "); + asm("mov r1, #0 "); // low order word of mantissa = 0 + __JUMP(,lr); + } + + + + +__NAKED__ EXPORT_C TInt TRealX::Set(const TInt64& /*anInt*/) +/** +Gives this extended precision object a new value taken from +a 64 bit integer. + +@param anInt The 64 bit integer value. + +@return KErrNone, always. +*/ + { + asm("stmfd sp!, {lr} "); + asm("ldmia r1, {r1,r2} "); + asm("bl ConvertInt64ToTRealX "); + asm("stmia r0, {r1,r2,r3} "); + asm("mov r0, #0 "); // return KErrNone + __POPRET(""); + } + + + + +#ifndef __EABI_CTORS__ +__NAKED__ EXPORT_C TRealX::TRealX(const TInt64& /*anInt*/) +/** +Constructs an extended precision object from a 64 bit integer. + +@param anInt A reference to a 64 bit integer. +*/ + { + // fall through + } +#endif + + + + +__NAKED__ EXPORT_C TRealX& TRealX::operator=(const TInt64& /*anInt*/) +/** +Assigns the specified 64 bit integer value to this extended precision object. + +@param anInt A reference to a 64 bit integer. + +@return A reference to this extended precision object. +*/ + { + asm("stmfd sp!, {lr} "); + asm("ldmia r1, {r1,r2} "); + asm("bl ConvertInt64ToTRealX "); + asm("stmia r0, {r1,r2,r3} "); + __POPRET(""); + + asm("ConvertInt64ToTRealX: "); + asm("movs r3, r2, lsr #31 "); // sign bit into r3 bit 0 + asm("beq ConvertInt64ToTRealX1 "); // skip if plus + asm("rsbs r1, r1, #0 "); // take absolute value + asm("rsc r2, r2, #0 "); + asm("ConvertInt64ToTRealX1: "); + asm("cmp r2, #0 "); // does it fit into 32 bits? + asm("moveq r2, r1 "); // if it does, do 32 bit conversion + asm("beq ConvertUintToTRealX1 "); +#ifdef __CPU_ARM_HAS_CLZ + CLZ(12,2); + asm("mov r2, r2, lsl r12 "); + asm("rsb r12, r12, #32 "); + asm("orr r2, r2, r1, lsr r12 "); + asm("rsb r12, r12, #32 "); +#else + asm("mov r12, #32 "); // 32-number of left-shifts needed to normalise + asm("cmp r2, #0x10000 "); // calculate number required + asm("movcc r2, r2, lsl #16 "); + asm("subcc r12, r12, #16 "); + asm("cmp r2, #0x1000000 "); + asm("movcc r2, r2, lsl #8 "); + asm("subcc r12, r12, #8 "); + asm("cmp r2, #0x10000000 "); + asm("movcc r2, r2, lsl #4 "); + asm("subcc r12, r12, #4 "); + asm("cmp r2, #0x40000000 "); + asm("movcc r2, r2, lsl #2 "); + asm("subcc r12, r12, #2 "); + asm("cmp r2, #0x80000000 "); + asm("movcc r2, r2, lsl #1 "); + asm("subcc r12, r12, #1 "); // r2 is now normalised + asm("orr r2, r2, r1, lsr r12 "); // shift r1 left into r2 + asm("rsb r12, r12, #32 "); +#endif + asm("mov r1, r1, lsl r12 "); + asm("add r3, r3, #0x80000000 "); // exponent = 803E-r12 + asm("add r3, r3, #0x003E0000 "); + asm("sub r3, r3, r12, lsl #16 "); + __JUMP(,lr); + } + + + + +__NAKED__ EXPORT_C TInt TRealX::Set(TUint /*anInt*/) +/** +Gives this extended precision object a new value taken from +an unsigned integer. + +@param The unsigned integer value. + +@return KErrNone, always. +*/ + { + asm("stmfd sp!, {lr} "); + asm("mov r2, r1 "); + asm("bl ConvertUintToTRealX "); + asm("stmia r0, {r1,r2,r3} "); + asm("mov r0, #0 "); // return KErrNone + __POPRET(""); + } + + + + +#ifndef __EABI_CTORS__ +__NAKED__ EXPORT_C TRealX::TRealX(TUint /*anInt*/) +/** +Constructs an extended precision object from an unsigned integer value. + +@param anInt The unsigned integer value. +*/ + { + // fall through + } +#endif + + + + +__NAKED__ EXPORT_C TRealX& TRealX::operator=(TUint /*anInt*/) +/** +Assigns the specified unsigned integer value to this extended precision object. + +@param anInt The unsigned integer value. + +@return A reference to this extended precision object. +*/ + { + asm("stmfd sp!, {lr} "); + asm("mov r2, r1 "); + asm("bl ConvertUintToTRealX "); + asm("stmia r0, {r1,r2,r3} "); + __POPRET(""); + + asm("ConvertUintToTRealX: "); + asm("mov r3, #0 "); + asm("ConvertUintToTRealX1: "); + asm("cmp r2, #0 "); // check for zero + asm("beq ConvertUintToTRealX0 "); + asm("orr r3, r3, #0x001E0000 "); + asm("orr r3, r3, #0x80000000 "); // r3=exponent 801E +#ifdef __CPU_ARM_HAS_CLZ + CLZ(12,2); + asm("mov r2, r2, lsl r12 "); + asm("sub r3, r3, r12, lsl #16 "); +#else + asm("cmp r2, #0x10000 "); // normalise mantissa, decrementing exponent as needed + asm("movcc r2, r2, lsl #16 "); + asm("subcc r3, r3, #0x100000 "); + asm("cmp r2, #0x1000000 "); + asm("movcc r2, r2, lsl #8 "); + asm("subcc r3, r3, #0x080000 "); + asm("cmp r2, #0x10000000 "); + asm("movcc r2, r2, lsl #4 "); + asm("subcc r3, r3, #0x040000 "); + asm("cmp r2, #0x40000000 "); + asm("movcc r2, r2, lsl #2 "); + asm("subcc r3, r3, #0x020000 "); + asm("cmp r2, #0x80000000 "); + asm("movcc r2, r2, lsl #1 "); + asm("subcc r3, r3, #0x010000 "); +#endif + asm("ConvertUintToTRealX0: "); + asm("mov r1, #0 "); // low order word of mantissa = 0 + __JUMP(,lr); + } + + + + +__NAKED__ EXPORT_C void TRealX::SetZero(TBool /*aNegative*/) +/** +Sets the value of this extended precision object to zero. + +@param aNegative ETrue, the value is a negative zero; + EFalse, the value is a positive zero, this is the default. +*/ + { + asm("mov r3, #0 "); + asm("cmp r1, #0 "); + asm("movne r3, #1 "); + asm("mov r2, #0 "); + asm("mov r1, #0 "); + asm("stmia r0, {r1,r2,r3} "); + __JUMP(,lr); + } + + + + +__NAKED__ EXPORT_C void TRealX::SetNaN() +/** +Sets the value of this extended precision object to 'not a number'. +*/ + { + asm("ldr r3, [pc, #__RealIndefiniteExponent-.-8] "); + asm("mov r2, #0xC0000000 "); + asm("mov r1, #0 "); + asm("stmia r0, {r1,r2,r3} "); + __JUMP(,lr); + asm("__RealIndefiniteExponent: "); + asm(".word 0xFFFF0001 "); + } + + + + + +__NAKED__ EXPORT_C void TRealX::SetInfinite(TBool /*aNegative*/) +/** +Sets the value of this extended precision object to infinity. + +@param aNegative ETrue, the value is a negative zero; + EFalse, the value is a positive zero. +*/ + { + asm("ldr r3, [pc, #__InfiniteExponent-.-8] "); + asm("cmp r1, #0 "); + asm("orrne r3, r3, #1 "); + asm("mov r2, #0x80000000 "); + asm("mov r1, #0 "); + asm("stmia r0, {r1,r2,r3} "); + __JUMP(,lr); + asm("__InfiniteExponent: "); + asm(".word 0xFFFF0000 "); + } + + + + +__NAKED__ EXPORT_C TBool TRealX::IsZero() const +/** +Determines whether the extended precision value is zero. + +@return True, if the extended precision value is zero, false, otherwise. +*/ + { + asm("ldr r1, [r0, #8] "); // get exponent word + asm("mov r0, #0 "); // default return value is 0 + asm("cmp r1, #0x10000 "); // is exponent=0 ? + asm("movcc r0, #1 "); // if so return 1 + __JUMP(,lr); + } + + + + +__NAKED__ EXPORT_C TBool TRealX::IsNaN() const +/** +Determines whether the extended precision value is 'not a number'. + +@return True, if the extended precision value is 'not a number', + false, otherwise. +*/ + { + asm("ldmia r0, {r1,r2,r3} "); + asm("mov r0, #0 "); // default return value is 0 + asm("cmn r3, #0x10000 "); // check for exponent 65535 + asm("bcc 1f "); // branch if not + asm("cmp r2, #0x80000000 "); // check if infinity + asm("cmpeq r1, #0 "); + asm("movne r0, #1 "); // if not, return 1 + asm("1: "); + __JUMP(,lr); + } + + + + +__NAKED__ EXPORT_C TBool TRealX::IsInfinite() const +/** +Determines whether the extended precision value has a finite value. + +@return True, if the extended precision value is finite, + false, if the value is 'not a number' or is infinite, +*/ + { + asm("ldmia r0, {r1,r2,r3} "); + asm("mov r0, #0 "); // default return value is 0 + asm("cmn r3, #0x10000 "); // check for exponent 65535 + asm("bcc 1f "); // branch if not + asm("cmp r2, #0x80000000 "); // check if infinity + asm("cmpeq r1, #0 "); + asm("moveq r0, #1 "); // if it is, return 1 + asm("1: "); + __JUMP(,lr); + } + + + + +__NAKED__ EXPORT_C TBool TRealX::IsFinite() const +/** +Determines whether the extended precision value has a finite value. + +@return True, if the extended precision value is finite, + false, if the value is 'not a number' or is infinite, +*/ + { + asm("ldr r1, [r0, #8] "); // get exponent word + asm("mov r0, #0 "); // default return value is 0 + asm("cmn r1, #0x10000 "); // is exponent=65535 (infinity or NaN) ? + asm("movcc r0, #1 "); // if not return 1 + __JUMP(,lr); + } + + + + +#ifndef __EABI_CTORS__ +__NAKED__ EXPORT_C TRealX::TRealX(TReal32 /*aReal*/) __SOFTFP +/** +Constructs an extended precision object from +a single precision floating point number. + +@param aReal The single precision floating point value. +*/ + { + // fall through + } +#endif + + + + +__NAKED__ EXPORT_C TRealX& TRealX::operator=(TReal32 /*aReal*/) __SOFTFP +/** +Assigns the specified single precision floating point number to +this extended precision object. + +@param aReal The single precision floating point value. + +@return A reference to this extended precision object. +*/ + { + asm("stmfd sp!, {lr} "); + asm("bl ConvertTReal32ToTRealX "); + asm("stmia r0, {r1,r2,r3} "); + __POPRET(""); + } + + + + +__NAKED__ EXPORT_C TInt TRealX::Set(TReal32 /*aReal*/) __SOFTFP +/** +Gives this extended precision object a new value taken from +a single precision floating point number. + +@param aReal The single precision floating point value. + +@return KErrNone, if a valid number; + KErrOverflow, if the number is infinite; + KErrArgument, if not a number. +*/ + { + // aReal is in r1 on entry + // sign in bit 31, exponent in 30-23, mantissa (non-integer bits) in 22-0 + asm("stmfd sp!, {lr} "); + asm("bl ConvertTReal32ToTRealX "); + asm("stmia r0, {r1,r2,r3} "); + asm("cmn r3, #0x10000 "); // check for infinity or NaN + asm("movcc r0, #0 "); // if neither, return KErrNone + asm("bcc trealx_set_treal32_0 "); + asm("cmp r2, #0x80000000 "); // check for infinity + asm("mvneq r0, #8 "); // if so, return KErrOverflow + asm("mvnne r0, #5 "); // else return KErrArgument + asm("trealx_set_treal32_0: "); + __POPRET(""); + + // Convert 32-bit real in r1 to TRealX in r1,r2,r3 + // r0 unmodified, r1,r2,r3,r12 modified + asm("ConvertTReal32ToTRealX: "); + asm("mov r3, r1, lsr #7 "); // r3 bits 16-31 = TReal32 exponent + asm("ands r3, r3, #0x00FF0000 "); + asm("mov r2, r1, lsl #8 "); // r2 = TReal32 mantissa << 8, bit 31 not yet in + asm("orrne r2, r2, #0x80000000 "); // if not zero/denormal, put in implied integer bit + asm("orr r3, r3, r1, lsr #31 "); // r3 bit 0 = sign bit + asm("mov r1, #0 "); // low word of mantissa = 0 + asm("beq ConvertTReal32ToTRealX0 "); // branch if zero/denormal + asm("cmp r3, #0x00FF0000 "); // check for infinity or NaN + asm("orrcs r3, r3, #0xFF000000 "); // if infinity or NaN, exponent = FFFF + asm("addcc r3, r3, #0x7F000000 "); // else exponent = TReal32 exponent + 7F80 + asm("addcc r3, r3, #0x00800000 "); + __JUMP(,lr); + asm("ConvertTReal32ToTRealX0: "); // come here if zero or denormal + asm("adds r2, r2, r2 "); // shift mantissa left one more and check if zero + __JUMP(eq,lr); + asm("add r3, r3, #0x7F000000 "); // else exponent = 7F80 (highest denormal exponent) + asm("add r3, r3, #0x00800000 "); +#ifdef __CPU_ARM_HAS_CLZ + CLZ(12,2); + asm("mov r2, r2, lsl r12 "); + asm("sub r3, r3, r12, lsl #16 "); +#else + asm("cmp r2, #0x10000 "); // normalise mantissa, decrementing exponent as needed + asm("movcc r2, r2, lsl #16 "); + asm("subcc r3, r3, #0x100000 "); + asm("cmp r2, #0x1000000 "); + asm("movcc r2, r2, lsl #8 "); + asm("subcc r3, r3, #0x080000 "); + asm("cmp r2, #0x10000000 "); + asm("movcc r2, r2, lsl #4 "); + asm("subcc r3, r3, #0x040000 "); + asm("cmp r2, #0x40000000 "); + asm("movcc r2, r2, lsl #2 "); + asm("subcc r3, r3, #0x020000 "); + asm("cmp r2, #0x80000000 "); + asm("movcc r2, r2, lsl #1 "); + asm("subcc r3, r3, #0x010000 "); +#endif + __JUMP(,lr); + } + + + + +#ifndef __EABI_CTORS__ +__NAKED__ EXPORT_C TRealX::TRealX(TReal64 /*aReal*/) __SOFTFP +/** +Constructs an extended precision object from +a double precision floating point number. + +@param aReal The double precision floating point value. +*/ + { + // fall through + } +#endif + + + + +__NAKED__ EXPORT_C TRealX& TRealX::operator=(TReal64 /*aReal*/) __SOFTFP +/** +Assigns the specified double precision floating point number to +this extended precision object. + +@param aReal The double precision floating point value. + +@return A reference to this extended precision object. +*/ + { + asm("stmfd sp!, {lr} "); + asm("bl ConvertTReal64ToTRealX "); + asm("stmia r0, {r1,r2,r3} "); + __POPRET(""); + } + + + + +__NAKED__ EXPORT_C TInt TRealX::Set(TReal64 /*aReal*/) __SOFTFP +/** +Gives this extended precision object a new value taken from +a double precision floating point number. + +@param aReal The double precision floating point value. + +@return KErrNone, if a valid number; + KErrOverflow, if the number is infinite; + KErrArgument, if not a number. +*/ + { + // aReal is in r1,r2 on entry + // sign in bit 31 of r1, exponent in 30-20 of r1 + // mantissa (non-integer bits) in 19-0 of r1 (high) and r2 (low) + asm("stmfd sp!, {lr} "); + asm("bl ConvertTReal64ToTRealX "); + asm("stmia r0, {r1,r2,r3} "); + asm("cmn r3, #0x10000 "); // check for infinity or NaN + asm("movcc r0, #0 "); // if neither, return KErrNone + asm("bcc trealx_set_treal64_0 "); + asm("cmp r2, #0x80000000 "); // check for infinity + asm("cmpeq r1, #0 "); + asm("mvneq r0, #8 "); // if so, return KErrOverflow + asm("mvnne r0, #5 "); // else return KErrArgument + asm("trealx_set_treal64_0: "); + __POPRET(""); + + // convert TReal64 in r1,r2 in GCC and r2 and r3 in RVCT + // if __DOUBLE_WORDS_SWAPPED__ r1=sign,exp,high mant, r2=low mant + // else r1 unused , r2=low mant, r3=sign,exp,high mant (as a result of EABI alignment reqs) + // into TRealX in r1,r2,r3 (r2,r1=mant high,low r3=exp,flag,sign) + // r0 unmodified, r1,r2,r3,r12 modified + asm("ConvertTReal64ToTRealX: "); +#ifdef __DOUBLE_WORDS_SWAPPED__ + asm("mov r12, r2 "); // ls word of mantissa into r12 +#else + asm("mov r12, r2 "); // ls word of mantissa into r12 + asm("mov r1, r3 "); +#endif + asm("mov r3, r1, lsr #20 "); // sign and exp into bottom 12 bits of r3 + asm("mov r2, r1, lsl #11 "); // left justify mantissa in r2,r1 + asm("mov r3, r3, lsl #16 "); // and into bits 16-27 + asm("bics r3, r3, #0x08000000 "); // remove sign, leaving exponent in bits 16-26 + asm("orr r2, r2, r12, lsr #21 "); + asm("orrne r2, r2, #0x80000000 "); // if not zero/denormal, put in implied integer bit + asm("orr r3, r3, r1, lsr #31 "); // sign bit into bit 0 of r3 + asm("mov r1, r12, lsl #11 "); + asm("beq ConvertTReal64ToTRealX0 "); // branch if zero or denormal + asm("mov r12, r3, lsl #5 "); // exponent into bits 21-31 of r12 + asm("cmn r12, #0x00200000 "); // check if exponent=7FF (infinity or NaN) + asm("addcs r3, r3, #0xF8000000 "); // if so, result exponent=FFFF + asm("addcc r3, r3, #0x7C000000 "); // else result exponent = TReal64 exponent + 7C00 + __JUMP(,lr); + asm("ConvertTReal64ToTRealX0: "); // come here if zero or denormal + asm("adds r1, r1, r1 "); // shift mantissa left one more bit + asm("adcs r2, r2, r2 "); + asm("cmpeq r1, #0 "); // and test for zero + __JUMP(eq,lr); + asm("add r3, r3, #0x7C000000 "); // else exponent=7C00 (highest denormal exponent) + asm("cmp r2, #0 "); // normalise - first check if r2=0 + asm("moveq r2, r1 "); // if so, shift up by 32 + asm("moveq r1, #0 "); + asm("subeq r3, r3, #0x200000 "); // and subtract 32 from exponent +#ifdef __CPU_ARM_HAS_CLZ + CLZ(12,2); + asm("mov r2, r2, lsl r12 "); + asm("rsb r12, r12, #32 "); + asm("orr r2, r2, r1, lsr r12 "); + asm("rsb r12, r12, #32 "); +#else + asm("mov r12, #32 "); // 32-number of left-shifts needed to normalise + asm("cmp r2, #0x10000 "); // calculate number required + asm("movcc r2, r2, lsl #16 "); + asm("subcc r12, r12, #16 "); + asm("cmp r2, #0x1000000 "); + asm("movcc r2, r2, lsl #8 "); + asm("subcc r12, r12, #8 "); + asm("cmp r2, #0x10000000 "); + asm("movcc r2, r2, lsl #4 "); + asm("subcc r12, r12, #4 "); + asm("cmp r2, #0x40000000 "); + asm("movcc r2, r2, lsl #2 "); + asm("subcc r12, r12, #2 "); + asm("cmp r2, #0x80000000 "); + asm("movcc r2, r2, lsl #1 "); + asm("subcc r12, r12, #1 "); // r2 is now normalised + asm("orr r2, r2, r1, lsr r12 "); // shift r1 left into r2 + asm("rsb r12, r12, #32 "); +#endif + asm("mov r1, r1, lsl r12 "); + asm("sub r3, r3, r12, lsl #16 "); // exponent -= number of left shifts + __JUMP(,lr); + } + + + + + +__NAKED__ EXPORT_C TRealX::operator TInt() const +/** +Gets the extended precision value as a signed integer value. + +The operator returns: + +1. zero , if the extended precision value is not a number + +2. 0x7FFFFFFF, if the value is positive and too big to fit into a TInt. + +3. 0x80000000, if the value is negative and too big to fit into a TInt. +*/ + { + asm("ldmia r0, {r1,r2,r3} "); // get value into r1,r2,r3 + + asm("ConvertTRealXToInt: "); + asm("mov r12, #0x8000 "); // r12=0x801E + asm("orr r12, r12, #0x001E "); + asm("subs r12, r12, r3, lsr #16 "); // r12=801E-exponent + asm("bls ConvertTRealXToInt1 "); // branch if exponent>=801E + asm("cmp r12, #31 "); // test if exponent<7FFF + asm("movhi r0, #0 "); // if so, underflow result to zero + __JUMP(hi,lr); + asm("mov r0, r2, lsr r12 "); // shift mantissa right to form integer + asm("tst r3, #1 "); // check sign bit + asm("rsbne r0, r0, #0 "); // if negative, r0=-r0 + __JUMP(,lr); + asm("ConvertTRealXToInt1: "); + asm("cmn r3, #0x10000 "); // check for infinity or NaN + asm("bcc ConvertTRealXToInt2 "); // branch if neither + asm("cmp r2, #0x80000000 "); // check for infinity + asm("cmpeq r1, #0 "); + asm("movne r0, #0 "); // if NaN, return 0 + __JUMP(ne,lr); + asm("ConvertTRealXToInt2: "); + asm("mov r0, #0x80000000 "); // return 0x80000000 if -ve overflow, 0x7FFFFFFF if +ve + asm("movs r3, r3, lsr #1 "); + asm("sbc r0, r0, #0 "); + __JUMP(,lr); + } + + + + +__NAKED__ EXPORT_C TRealX::operator TUint() const +/** +Returns the extended precision value as an unsigned signed integer value. + +The operator returns: + +1. zero, if the extended precision value is not a number + +2. 0xFFFFFFFF, if the value is positive and too big to fit into a TUint. + +3. zero, if the value is negative and too big to fit into a TUint. +*/ + { + asm("ldmia r0, {r1,r2,r3} "); // get value into r1,r2,r3 + + asm("ConvertTRealXToUint: "); + asm("mov r12, #0x8000 "); // r12=0x801E + asm("orr r12, r12, #0x001E "); + asm("subs r12, r12, r3, lsr #16 "); // r12=801E-exponent + asm("bcc ConvertTRealXToUint1 "); // branch if exponent>801E + asm("cmp r12, #31 "); // test if exponent<7FFF + asm("movhi r0, #0 "); // if so, underflow result to zero + __JUMP(hi,lr); + asm("tst r3, #1 "); // check sign bit + asm("moveq r0, r2, lsr r12 "); // if +ve, shift mantissa right to form integer + asm("movne r0, #0 "); // if negative, r0=0 + __JUMP(,lr); + asm("ConvertTRealXToUint1: "); + asm("mov r0, #0 "); // r0=0 initially + asm("cmn r3, #0x10000 "); // check for infinity or NaN + asm("bcc ConvertTRealXToUint2 "); // branch if neither + asm("cmp r2, #0x80000000 "); // check for infinity + asm("cmpeq r1, #0 "); + __JUMP(ne,lr); + asm("ConvertTRealXToUint2: "); + asm("movs r3, r3, lsr #1 "); // sign bit into carry + asm("sbc r0, r0, #0 "); // r0=0 if -ve, 0xFFFFFFFF if +ve + __JUMP(,lr); + } + + + + +__NAKED__ EXPORT_C TRealX::operator TInt64() const +/** +Returns the extended precision value as a 64 bit integer value. + +The operator returns: + +1. zero, if the extended precision value is not a number + +2. 0x7FFFFFFF FFFFFFFF, if the value is positive and too big to fit + into a TInt64 + +3. 0x80000000 00000000, if the value is negative and too big to fit + into a TInt. +*/ + { + // r0 = this, result in r1:r0 + asm("ldmia r0, {r0,r1,r2} "); // get value into r0,r1,r2 + asm("ConvertTRealXToInt64: "); + asm("mov r3, #0x8000 "); // r3=0x803E + asm("orr r3, r3, #0x003E "); + asm("subs r3, r3, r2, lsr #16 "); // r3=803E-exponent + asm("bls ConvertTRealXToInt64a "); // branch if exponent>=803E + asm("cmp r3, #63 "); // test if exponent<7FFF + asm("movhi r1, #0 "); // if so, underflow result to zero + asm("movhi r0, #0 "); + __JUMP(hi,lr); + asm("cmp r3, #32 "); // >=32 shifts required? + asm("subcs r3, r3, #32 "); // if so, r3-=32 + asm("movcs r0, r1, lsr r3 "); // r1:r0 >>= (r3+32) + asm("movcs r1, #0 "); + asm("movcc r0, r0, lsr r3 "); // else r1:r0>>=r3 + asm("rsbcc r3, r3, #32 "); + asm("orrcc r0, r0, r1, lsl r3 "); + asm("rsbcc r3, r3, #32 "); + asm("movcc r1, r1, lsr r3 "); // r1:r0 = absolute integer + asm("tst r2, #1 "); // check sign bit + __JUMP(eq,lr); + asm("rsbs r0, r0, #0 "); // else negate answer + asm("rsc r1, r1, #0 "); + __JUMP(,lr); + asm("ConvertTRealXToInt64a: "); + asm("cmn r2, #0x10000 "); // check for infinity or NaN + asm("bcc ConvertTRealXToInt64b "); // branch if neither + asm("cmp r1, #0x80000000 "); // check for infinity + asm("cmpeq r0, #0 "); + asm("movne r1, #0 "); // if NaN, return 0 + asm("movne r0, #0 "); + __JUMP(ne,lr); + asm("ConvertTRealXToInt64b: "); + asm("mov r1, #0x80000000 "); // return KMaxTInt64/KMinTInt64 depending on sign + asm("mov r0, #0 "); + asm("movs r2, r2, lsr #1 "); + asm("sbcs r0, r0, #0 "); + asm("sbc r1, r1, #0 "); + __JUMP(,lr); + } + + + + +__NAKED__ EXPORT_C TRealX::operator TReal32() const __SOFTFP +/** +Returns the extended precision value as +a single precision floating point value. +*/ + { + asm("ldmia r0, {r1,r2,r3} "); // r1,r2,r3=input value + + // Convert TRealX in r1,r2,r3 to TReal32 in r0 + asm("ConvertTRealXToTReal32: "); + asm("mov r12, #0x8000 "); + asm("orr r12, r12, #0x007F "); // r12=0x807F + asm("cmp r3, r12, lsl #16 "); // check if exponent>=807F + asm("bcs ConvertTRealXToTReal32a "); // branch if it is + asm("sub r12, r12, #0x00FF "); // r12=0x7F80 + asm("rsbs r12, r12, r3, lsr #16 "); // r12=exp in - 7F80 = result exponent if in range + asm("bgt ConvertTRealXToTReal32b "); // branch if normalised result + asm("cmn r12, #23 "); // check for total underflow or zero + asm("movlt r0, r3, lsl #31 "); // in this case, return zero with appropriate sign + __JUMP(lt,lr); + asm("add r12, r12, #31 "); // r12=32-mantissa shift required = 32-(1-r12) + asm("movs r0, r1, lsl r12 "); // r0=lost bits when r2:r1 is shifted + asm("bicne r3, r3, #0x300 "); // if these are not zero, set rounded down flag + asm("orrne r3, r3, #0x100 "); + asm("rsb r0, r12, #32 "); + asm("mov r1, r1, lsr r0 "); + asm("orr r1, r1, r2, lsl r12 "); + asm("mov r2, r2, lsr r0 "); // r2 top 24 bits now give unrounded result mantissa + asm("mov r12, #0 "); // result exponent will be zero + asm("ConvertTRealXToTReal32b: "); + asm("movs r0, r2, lsl #24 "); // top 8 truncated bits into top byte of r0 + asm("bpl ConvertTRealXToTReal32c "); // if top bit clear, truncate + asm("cmp r0, #0x80000000 "); + asm("cmpeq r1, #0 "); // compare rounding bits to 1000... + asm("bhi ConvertTRealXToTReal32d "); // if >, round up + asm("movs r0, r3, lsl #23 "); // round up flag into C, round down flag into N + asm("bcs ConvertTRealXToTReal32c "); // if rounded up, truncate + asm("bmi ConvertTRealXToTReal32d "); // if rounded down, round up + asm("tst r2, #0x100 "); // else round to even - test LSB of result mantissa + asm("beq ConvertTRealXToTReal32c "); // if zero, truncate, else round up + asm("ConvertTRealXToTReal32d: "); // come here to round up + asm("adds r2, r2, #0x100 "); // increment the mantissa + asm("movcs r2, #0x80000000 "); // if carry, mantissa=800000 + asm("addcs r12, r12, #1 "); // and increment exponent + asm("cmpmi r12, #1 "); // if mantissa normalised, check exponent>0 + asm("movmi r12, #1 "); // if normalised and exponent=0, set exponent to 1 + asm("ConvertTRealXToTReal32c: "); // come here to truncate + asm("mov r0, r3, lsl #31 "); // r0 bit 31 = sign bit + asm("orr r0, r0, r12, lsl #23 "); // exponent into r0 bits 23-30 + asm("bic r2, r2, #0x80000000 "); // remove integer bit from mantissa + asm("orr r0, r0, r2, lsr #8 "); // non-integer mantissa bits into r0 bits 0-22 + __JUMP(,lr); + asm("ConvertTRealXToTReal32a: "); // come here if overflow, infinity or NaN + asm("cmn r3, #0x10000 "); // check for infinity or NaN + asm("movcc r2, #0 "); // if not, set mantissa to 0 for infinity result + asm("bic r2, r2, #0x80000000 "); // remove integer bit from mantissa + asm("mov r0, r3, lsl #31 "); // r0 bit 31 = sign bit + asm("orr r0, r0, #0x7F000000 "); // r0 bits 23-30 = FF = exponent + asm("orr r0, r0, #0x00800000 "); + asm("orr r0, r0, r2, lsr #8 "); // r0 bits 0-22 = result mantissa + __JUMP(,lr); + } + + + + +__NAKED__ EXPORT_C TRealX::operator TReal64() const __SOFTFP +/** +Returns the extended precision value as +a double precision floating point value. +*/ + { + asm("ldmia r0, {r1,r2,r3} "); // r1,r2,r3=input value + + // Convert TRealX in r1,r2,r3 to TReal64 in r0,r1 + // if __DOUBLE_WORDS_SWAPPED__ r0=sign,exp,high mant, r1=low mant + // else r0, r1 reversed + asm("ConvertTRealXToTReal64: "); + asm("mov r12, #0x8300 "); + asm("orr r12, r12, #0x00FF "); // r12=0x83FF + asm("cmp r3, r12, lsl #16 "); // check if exponent>=83FF + asm("bcs ConvertTRealXToTReal64a "); // branch if it is + asm("mov r12, #0x7C00 "); + asm("rsbs r12, r12, r3, lsr #16 "); // r12=exp in - 7C00 = result exponent if in range + asm("bgt ConvertTRealXToTReal64b "); // branch if normalised result + asm("cmn r12, #52 "); // check for total underflow or zero + asm("movlt r0, r3, lsl #31 "); // in this case, return zero with appropriate sign + asm("movlt r1, #0 "); + asm("blt ConvertTRealXToTReal64_end "); + + asm("adds r12, r12, #31 "); // check if >=32 shifts needed, r12=32-shift count + asm("ble ConvertTRealXToTReal64e "); // branch if >=32 shifts needed + asm("movs r0, r1, lsl r12 "); // r0=lost bits when r2:r1 is shifted + asm("bicne r3, r3, #0x300 "); // if these are not zero, set rounded down flag + asm("orrne r3, r3, #0x100 "); + asm("rsb r0, r12, #32 "); // r0=shift count + asm("mov r1, r1, lsr r0 "); + asm("orr r1, r1, r2, lsl r12 "); + asm("mov r2, r2, lsr r0 "); // r2:r1 top 53 bits = unrounded result mantissa + asm("b ConvertTRealXToTReal64f "); + asm("ConvertTRealXToTReal64e: "); + asm("add r12, r12, #32 "); // r12=64-shift count + asm("cmp r1, #0 "); // r1 bits are all lost - test them + asm("moveqs r0, r2, lsl r12 "); // if zero, test lost bits from r2 + asm("bicne r3, r3, #0x300 "); // if lost bits not all zero, set rounded down flag + asm("orrne r3, r3, #0x100 "); + asm("rsb r0, r12, #32 "); // r0=shift count-32 + asm("mov r1, r2, lsr r0 "); // shift r2:r1 right + asm("mov r2, #0 "); + asm("ConvertTRealXToTReal64f: "); + asm("mov r12, #0 "); // result exponent will be zero for denormals + asm("ConvertTRealXToTReal64b: "); + asm("movs r0, r1, lsl #21 "); // 11 rounding bits to top of r0 + asm("bpl ConvertTRealXToTReal64c "); // if top bit clear, truncate + asm("cmp r0, #0x80000000 "); // compare rounding bits to 10000000000 + asm("bhi ConvertTRealXToTReal64d "); // if >, round up + asm("movs r0, r3, lsl #23 "); // round up flag into C, round down flag into N + asm("bcs ConvertTRealXToTReal64c "); // if rounded up, truncate + asm("bmi ConvertTRealXToTReal64d "); // if rounded down, round up + asm("tst r1, #0x800 "); // else round to even - test LSB of result mantissa + asm("beq ConvertTRealXToTReal64c "); // if zero, truncate, else round up + asm("ConvertTRealXToTReal64d: "); // come here to round up + asm("adds r1, r1, #0x800 "); // increment the mantissa + asm("adcs r2, r2, #0 "); + asm("movcs r2, #0x80000000 "); // if carry, mantissa=10000...0 + asm("addcs r12, r12, #1 "); // and increment exponent + asm("cmpmi r12, #1 "); // if mantissa normalised, check exponent>0 + asm("movmi r12, #1 "); // if normalised and exponent=0, set exponent to 1 + asm("ConvertTRealXToTReal64c: "); // come here to truncate + asm("mov r0, r3, lsl #31 "); // r0 bit 31 = sign bit + asm("orr r0, r0, r12, lsl #20 "); // exponent into r0 bits 20-30 + asm("bic r2, r2, #0x80000000 "); // remove integer bit from mantissa + asm("orr r0, r0, r2, lsr #11 "); // non-integer mantissa bits into r0 bits 0-19 + asm("mov r1, r1, lsr #11 "); // and r1 + asm("orr r1, r1, r2, lsl #21 "); + asm("b ConvertTRealXToTReal64_end "); + + asm("ConvertTRealXToTReal64a: "); // come here if overflow, infinity or NaN + asm("cmn r3, #0x10000 "); // check for infinity or NaN + asm("movcc r2, #0 "); // if not, set mantissa to 0 for infinity result + asm("movcc r1, #0 "); + asm("bic r2, r2, #0x80000000 "); // remove integer bit from mantissa + asm("mov r0, r3, lsl #31 "); // r0 bit 31 = sign bit + asm("orr r0, r0, #0x7F000000 "); // r0 bits 20-30 = 7FF = exponent + asm("orr r0, r0, #0x00F00000 "); + asm("orr r0, r0, r2, lsr #11 "); // r0 bits 0-19 = result mantissa high bits + asm("mov r1, r1, lsr #11 "); // and r1=result mantissa low bits + asm("orr r1, r1, r2, lsl #21 "); + asm("ConvertTRealXToTReal64_end: "); +#ifndef __DOUBLE_WORDS_SWAPPED__ + asm("mov r2, r0 "); + asm("mov r0, r1 "); + asm("mov r1, r2 "); +#endif + __JUMP(,lr); + } + + + + +__NAKED__ EXPORT_C TInt TRealX::GetTReal(TReal32& /*aVal*/) const +/** +Extracts the extended precision value as +a single precision floating point value. + +@param aVal A reference to a single precision object which contains + the result of the operation. + +@return KErrNone, if the operation is successful; + KErrOverflow, if the operation results in overflow; + KErrUnderflow, if the operation results in underflow. +*/ + { + asm("stmfd sp!, {r4,lr} "); + asm("mov r4, r1 "); + asm("ldmia r0, {r1,r2,r3} "); // r1,r2,r3=input value + asm("bl TRealXGetTReal32 "); + asm("str r0, [r4] "); // store converted TReal32 + asm("mov r0, r12 "); // return value into r0 + __POPRET("r4,"); + + // Convert TRealX in r1,r2,r3 to TReal32 in r0 + // Return error code in r12 + // r0-r3, r12 modified + asm("TRealXGetTReal32: "); + asm("mov r12, #0x8000 "); + asm("orr r12, r12, #0x007F "); // r12=0x807F + asm("cmp r3, r12, lsl #16 "); // check if exponent>=807F + asm("bcs TRealXGetTReal32a "); // branch if it is + asm("sub r12, r12, #0x00FF "); // r12=0x7F80 + asm("rsbs r12, r12, r3, lsr #16 "); // r12=exp in - 7F80 = result exponent if in range + asm("bgt TRealXGetTReal32b "); // branch if normalised result + asm("cmn r12, #23 "); // check for total underflow or zero + asm("bge TRealXGetTReal32e "); // skip if not + asm("mov r0, r3, lsl #31 "); // else return zero with appropriate sign + asm("mov r1, #0 "); + asm("cmp r3, #0x10000 "); // check for zero + asm("movcc r12, #0 "); // if zero return KErrNone + asm("mvncs r12, #9 "); // else return KErrUnderflow + __JUMP(,lr); + asm("TRealXGetTReal32e: "); + asm("add r12, r12, #31 "); // r12=32-mantissa shift required = 32-(1-r12) + asm("movs r0, r1, lsl r12 "); // r0=lost bits when r2:r1 is shifted + asm("bicne r3, r3, #0x300 "); // if these are not zero, set rounded down flag + asm("orrne r3, r3, #0x100 "); + asm("rsb r0, r12, #32 "); + asm("mov r1, r1, lsr r0 "); + asm("orr r1, r1, r2, lsl r12 "); + asm("mov r2, r2, lsr r0 "); // r2 top 24 bits now give unrounded result mantissa + asm("mov r12, #0 "); // result exponent will be zero + asm("TRealXGetTReal32b: "); + asm("movs r0, r2, lsl #24 "); // top 8 truncated bits into top byte of r0 + asm("bpl TRealXGetTReal32c "); // if top bit clear, truncate + asm("cmp r0, #0x80000000 "); + asm("cmpeq r1, #0 "); // compare rounding bits to 1000... + asm("bhi TRealXGetTReal32d "); // if >, round up + asm("movs r0, r3, lsl #23 "); // round up flag into C, round down flag into N + asm("bcs TRealXGetTReal32c "); // if rounded up, truncate + asm("bmi TRealXGetTReal32d "); // if rounded down, round up + asm("tst r2, #0x100 "); // else round to even - test LSB of result mantissa + asm("beq TRealXGetTReal32c "); // if zero, truncate, else round up + asm("TRealXGetTReal32d: "); // come here to round up + asm("adds r2, r2, #0x100 "); // increment the mantissa + asm("movcs r2, #0x80000000 "); // if carry, mantissa=800000 + asm("addcs r12, r12, #1 "); // and increment exponent + asm("cmpmi r12, #1 "); // if mantissa normalised, check exponent>0 + asm("movmi r12, #1 "); // if normalised and exponent=0, set exponent to 1 + asm("TRealXGetTReal32c: "); // come here to truncate + asm("mov r0, r3, lsl #31 "); // r0 bit 31 = sign bit + asm("orr r0, r0, r12, lsl #23 "); // exponent into r0 bits 23-30 + asm("bic r2, r2, #0x80000000 "); // remove integer bit from mantissa + asm("orr r0, r0, r2, lsr #8 "); // non-integer mantissa bits into r0 bits 0-22 + asm("cmp r12, #0xFF "); // check for overflow + asm("mvneq r12, #8 "); // if overflow, return KErrOverflow + __JUMP(eq,lr); + asm("bics r1, r0, #0x80000000 "); // check for underflow + asm("mvneq r12, #9 "); // if underflow return KErrUnderflow + asm("movne r12, #0 "); // else return KErrNone + __JUMP(,lr); + asm("TRealXGetTReal32a: "); // come here if overflow, infinity or NaN + asm("cmn r3, #0x10000 "); // check for infinity or NaN + asm("movcc r2, #0 "); // if not, set mantissa to 0 for infinity result + asm("bic r2, r2, #0x80000000 "); // remove integer bit from mantissa + asm("mov r0, r3, lsl #31 "); // r0 bit 31 = sign bit + asm("orr r0, r0, #0x7F000000 "); // r0 bits 23-30 = FF = exponent + asm("orr r0, r0, #0x00800000 "); + asm("orr r0, r0, r2, lsr #8 "); // r0 bits 0-22 = result mantissa + asm("movs r12, r0, lsl #9 "); // check if result is infinity or NaN + asm("mvneq r12, #8 "); // if infinity return KErrOverflow + asm("mvnne r12, #5 "); // else return KErrArgument + __JUMP(,lr); + } + + + + +__NAKED__ EXPORT_C TInt TRealX::GetTReal(TReal64& /*aVal*/) const +/** +Extracts the extended precision value as +a double precision floating point value. + +@param aVal A reference to a double precision object which + contains the result of the operation. + +@return KErrNone, if the operation is successful; + KErrOverflow, if the operation results in overflow; + KErrUnderflow, if the operation results in underflow. +*/ + { + asm("stmfd sp!, {r4,lr} "); + asm("mov r4, r1 "); + asm("ldmia r0, {r1,r2,r3} "); // r1,r2,r3=input value + asm("bl TRealXGetTReal64 "); + asm("stmia r4, {r0,r1} "); // store converted TReal64 + asm("mov r0, r12 "); // return value into r0 + __POPRET("r4,"); + + // Convert TRealX in r1,r2,r3 to TReal64 in r0,r1 + // Return error code in r12 + // r0-r3, r12 modified + asm("TRealXGetTReal64: "); + asm("mov r12, #0x8300 "); + asm("orr r12, r12, #0x00FF "); // r12=0x83FF + asm("cmp r3, r12, lsl #16 "); // check if exponent>=83FF + asm("bcs TRealXGetTReal64a "); // branch if it is + asm("mov r12, #0x7C00 "); + asm("rsbs r12, r12, r3, lsr #16 "); // r12=exp in - 7C00 = result exponent if in range + asm("bgt TRealXGetTReal64b "); // branch if normalised result + asm("cmn r12, #52 "); // check for total underflow or zero + asm("bge TRealXGetTReal64g "); // skip if not + asm("mov r0, r3, lsl #31 "); // else return zero with appropriate sign + asm("mov r1, #0 "); + asm("cmp r3, #0x10000 "); // check for zero + asm("movcc r12, #0 "); // if zero return KErrNone + asm("mvncs r12, #9 "); // else return KErrUnderflow + asm("b TRealXGetTReal64_end "); + + asm("TRealXGetTReal64g: "); + asm("adds r12, r12, #31 "); // check if >=32 shifts needed, r12=32-shift count + asm("ble TRealXGetTReal64e "); // branch if >=32 shifts needed + asm("movs r0, r1, lsl r12 "); // r0=lost bits when r2:r1 is shifted + asm("bicne r3, r3, #0x300 "); // if these are not zero, set rounded down flag + asm("orrne r3, r3, #0x100 "); + asm("rsb r0, r12, #32 "); // r0=shift count + asm("mov r1, r1, lsr r0 "); + asm("orr r1, r1, r2, lsl r12 "); + asm("mov r2, r2, lsr r0 "); // r2:r1 top 53 bits = unrounded result mantissa + asm("b TRealXGetTReal64f "); + asm("TRealXGetTReal64e: "); + asm("add r12, r12, #32 "); // r12=64-shift count + asm("cmp r1, #0 "); // r1 bits are all lost - test them + asm("moveqs r0, r2, lsl r12 "); // if zero, test lost bits from r2 + asm("bicne r3, r3, #0x300 "); // if lost bits not all zero, set rounded down flag + asm("orrne r3, r3, #0x100 "); + asm("rsb r0, r12, #32 "); // r0=shift count-32 + asm("mov r1, r2, lsr r0 "); // shift r2:r1 right + asm("mov r2, #0 "); + asm("TRealXGetTReal64f: "); + asm("mov r12, #0 "); // result exponent will be zero for denormals + asm("TRealXGetTReal64b: "); + asm("movs r0, r1, lsl #21 "); // 11 rounding bits to top of r0 + asm("bpl TRealXGetTReal64c "); // if top bit clear, truncate + asm("cmp r0, #0x80000000 "); // compare rounding bits to 10000000000 + asm("bhi TRealXGetTReal64d "); // if >, round up + asm("movs r0, r3, lsl #23 "); // round up flag into C, round down flag into N + asm("bcs TRealXGetTReal64c "); // if rounded up, truncate + asm("bmi TRealXGetTReal64d "); // if rounded down, round up + asm("tst r1, #0x800 "); // else round to even - test LSB of result mantissa + asm("beq TRealXGetTReal64c "); // if zero, truncate, else round up + asm("TRealXGetTReal64d: "); // come here to round up + asm("adds r1, r1, #0x800 "); // increment the mantissa + asm("adcs r2, r2, #0 "); + asm("movcs r2, #0x80000000 "); // if carry, mantissa=10000...0 + asm("addcs r12, r12, #1 "); // and increment exponent + asm("cmpmi r12, #1 "); // if mantissa normalised, check exponent>0 + asm("movmi r12, #1 "); // if normalised and exponent=0, set exponent to 1 + asm("TRealXGetTReal64c: "); // come here to truncate + asm("mov r0, r3, lsl #31 "); // r0 bit 31 = sign bit + asm("orr r0, r0, r12, lsl #20 "); // exponent into r0 bits 20-30 + asm("bic r2, r2, #0x80000000 "); // remove integer bit from mantissa + asm("orr r0, r0, r2, lsr #11 "); // non-integer mantissa bits into r0 bits 0-19 + asm("mov r1, r1, lsr #11 "); // and r1 + asm("orr r1, r1, r2, lsl #21 "); + asm("add r12, r12, #1 "); + asm("cmp r12, #0x800 "); // check for overflow + asm("mvneq r12, #8 "); // if overflow, return KErrOverflow + asm("beq TRealXGetTReal64_end "); + + asm("bics r12, r0, #0x80000000 "); // check for underflow + asm("cmpeq r1, #0 "); + asm("mvneq r12, #9 "); // if underflow return KErrUnderflow + asm("movne r12, #0 "); // else return KErrNone + asm("b TRealXGetTReal64_end "); + + asm("TRealXGetTReal64a: "); // come here if overflow, infinity or NaN + asm("cmn r3, #0x10000 "); // check for infinity or NaN + asm("movcc r2, #0 "); // if not, set mantissa to 0 for infinity result + asm("movcc r1, #0 "); + asm("bic r2, r2, #0x80000000 "); // remove integer bit from mantissa + asm("mov r0, r3, lsl #31 "); // r0 bit 31 = sign bit + asm("orr r0, r0, #0x7F000000 "); // r0 bits 20-30 = 7FF = exponent + asm("orr r0, r0, #0x00F00000 "); + asm("orr r0, r0, r2, lsr #11 "); // r0 bits 0-19 = result mantissa high bits + asm("mov r1, r1, lsr #11 "); // and r1=result mantissa low bits + asm("orr r1, r1, r2, lsl #21 "); + asm("movs r12, r0, lsl #12 "); // check if result is infinity or NaN + asm("cmpeq r1, #0 "); + asm("mvneq r12, #8 "); // if infinity return KErrOverflow + asm("mvnne r12, #5 "); // else return KErrArgument + asm("TRealXGetTReal64_end: "); +#ifndef __DOUBLE_WORDS_SWAPPED__ + asm("mov r2, r0 "); + asm("mov r0, r1 "); + asm("mov r1, r2 "); +#endif + __JUMP(,lr); + } + + + + +__NAKED__ EXPORT_C TRealX TRealX::operator+() const +/** +Returns this extended precision number unchanged. + +Note that this may also be referred to as a unary plus operator. + +@return The extended precision number. +*/ + { + asm("ldmia r1, {r2,r3,r12} "); + asm("stmia r0, {r2,r3,r12} "); + __JUMP(,lr); + } + + + + +__NAKED__ EXPORT_C TRealX TRealX::operator-() const +/** +Negates this extended precision number. + +This may also be referred to as a unary minus operator. + +@return The negative of the extended precision number. +*/ + { + asm("ldmia r1, {r2,r3,r12} "); + asm("eor r12, r12, #1 "); // unary - changes sign bit + asm("stmia r0, {r2,r3,r12} "); + __JUMP(,lr); + } + + + + +__NAKED__ EXPORT_C TRealX::TRealXOrder TRealX::Compare(const TRealX& /*aVal*/) const +/** +*/ + { + asm("stmfd sp!, {r4,r5,r6,lr} "); + asm("ldmia r1, {r4,r5,r6} "); + asm("ldmia r0, {r1,r2,r3} "); + asm("bl TRealXCompare "); + __POPRET("r4-r6,"); + + // Compare TRealX in r1,r2,r3 to TRealX in r4,r5,r6 + // Return TRealXOrder result in r0 + asm("TRealXCompare: "); + asm("cmn r3, #0x10000 "); // check for NaNs/infinity + asm("bcs TRealXCompare1 "); + asm("TRealXCompare6: "); // will come back here if infinity + asm("cmn r6, #0x10000 "); + asm("bcs TRealXCompare2 "); + asm("TRealXCompare7: "); // will come back here if infinity + asm("cmp r3, #0x10000 "); // check for zeros + asm("bcc TRealXCompare3 "); + asm("cmp r6, #0x10000 "); + asm("bcc TRealXCompare4 "); + asm("mov r12, r6, lsl #31 "); + asm("cmp r12, r3, lsl #31 "); // compare signs + asm("movne r0, #4 "); + asm("bne TRealXCompare5 "); // branch if signs different + asm("mov r12, r3, lsr #16 "); // r12=first exponent + asm("cmp r12, r6, lsr #16 "); // compare exponents + asm("cmpeq r2, r5 "); // if equal compare high words of mantissa + asm("cmpeq r1, r4 "); // if equal compare low words of mantissa + asm("moveq r0, #2 "); // if equal return 2 + __JUMP(eq,lr); + asm("movhi r0, #4 "); // r0=4 if first exp bigger + asm("movcc r0, #1 "); // else r0=1 + asm("TRealXCompare5: "); + asm("tst r3, #1 "); // if signs negative + asm("eorne r0, r0, #5 "); // then switch 1 and 4 + __JUMP(,lr); + asm("TRealXCompare3: "); // first operand zero + asm("cmp r6, #0x10000 "); // check if second also zero + asm("movcc r0, #2 "); // if so, return 2 + __JUMP(cc,lr); + asm("tst r6, #1 "); // else check sign of operand 2 + asm("moveq r0, #1 "); // if +, return 1 + asm("movne r0, #4 "); // else return 4 + __JUMP(,lr); + asm("TRealXCompare4: "); // second operand zero, first nonzero + asm("tst r3, #1 "); // check sign of operand 1 + asm("moveq r0, #4 "); // if +, return 4 + asm("movne r0, #1 "); // else return 1 + __JUMP(,lr); + asm("TRealXCompare1: "); // first operand NaN or infinity + asm("cmp r2, #0x80000000 "); // check for infinity + asm("cmpeq r1, #0 "); + asm("beq TRealXCompare6 "); // if infinity, can handle normally + asm("mov r0, #8 "); // if NaN, return 8 (unordered) + __JUMP(,lr); + asm("TRealXCompare2: "); // second operand NaN or infinity + asm("cmp r5, #0x80000000 "); // check for infinity + asm("cmpeq r4, #0 "); + asm("beq TRealXCompare7 "); // if infinity, can handle normally + asm("mov r0, #8 "); // if NaN, return 8 (unordered) + __JUMP(,lr); + } + + + + +__NAKED__ EXPORT_C TInt TRealX::SubEq(const TRealX& /*aVal*/) +/** +Subtracts an extended precision value from this extended precision number. + +@param aVal The extended precision value to be subtracted. + +@return KErrNone, if the operation is successful; + KErrOverflow, if the operation results in overflow; + KErrUnderflow, if the operation results in underflow. +*/ + { + asm("stmfd sp!, {r0,r4-r8,lr} "); + asm("ldmia r1, {r4,r5,r6} "); + asm("ldmia r0, {r1,r2,r3} "); + asm("bl TRealXSubtract "); + asm("ldmfd sp!, {r0,r4-r8,lr} "); + asm("stmia r0, {r1,r2,r3} "); + asm("mov r0, r12 "); + __JUMP(,lr); + } + + + + +__NAKED__ EXPORT_C TInt TRealX::AddEq(const TRealX& /*aVal*/) +/** +Adds an extended precision value to this extended precision number. + +@param aVal The extended precision value to be added. + +@return KErrNone, if the operation is successful; + KErrOverflow,if the operation results in overflow; + KErrUnderflow, if the operation results in underflow. +*/ + { + asm("stmfd sp!, {r0,r4-r8,lr} "); + asm("ldmia r1, {r4,r5,r6} "); + asm("ldmia r0, {r1,r2,r3} "); + asm("bl TRealXAdd "); + asm("ldmfd sp!, {r0,r4-r8,lr} "); + asm("stmia r0, {r1,r2,r3} "); + asm("mov r0, r12 "); + __JUMP(,lr); + + // TRealX subtraction r1,r2,r3 - r4,r5,r6 result in r1,r2,r3 + // Error code returned in r12 + // Registers r0-r8,r12 modified + // NB This function is purely internal to EUSER and therefore IS ONLY EVER CALLED IN ARM MODE. + asm("TRealXSubtract: "); + asm("eor r6, r6, #1 "); // negate second operand and add + + // TRealX addition r1,r2,r3 + r4,r5,r6 result in r1,r2,r3 + // Error code returned in r12 + // Registers r0-r8,r12 modified + // NB This function is purely internal to EUSER and therefore IS ONLY EVER CALLED IN ARM MODE. + // Note: +0 + +0 = +0, -0 + -0 = -0, +0 + -0 = -0 + +0 = +0, + // +/-0 + X = X + +/-0 = X, X + -X = -X + X = +0 + asm("TRealXAdd: "); + asm("mov r12, #0 "); // initialise return value to KErrNone + asm("bic r3, r3, #0x300 "); // clear rounding flags + asm("bic r6, r6, #0x300 "); // clear rounding flags + asm("cmn r3, #0x10000 "); // check if first operand is NaN or infinity + asm("bcs TRealXAdd1 "); // branch if it is + asm("cmn r6, #0x10000 "); // check if second operand is NaN or infinity + asm("bcs TRealXAdd2 "); // branch if it is + asm("cmp r6, #0x10000 "); // check if second operand zero + asm("bcc TRealXAdd3a "); // branch if it is + asm("cmp r3, #0x10000 "); // check if first operand zero + asm("bcc TRealXAdd3 "); // branch if it is + asm("mov r7, #0 "); // r7 will be rounding word + asm("mov r0, r3, lsr #16 "); // r0 = first operand exponent + asm("subs r0, r0, r6, lsr #16 "); // r0 = first exponent - second exponent + asm("beq TRealXAdd8 "); // if equal, no mantissa shifting needed + asm("bhi TRealXAdd4 "); // skip if first exponent bigger + asm("rsb r0, r0, #0 "); // need to shift first mantissa right by r0 to align + asm("mov r8, r1 "); // swap the numbers to the one to be shifted is 2nd + asm("mov r1, r4 "); + asm("mov r4, r8 "); + asm("mov r8, r2 "); + asm("mov r2, r5 "); + asm("mov r5, r8 "); + asm("mov r8, r3 "); + asm("mov r3, r6 "); + asm("mov r6, r8 "); + asm("TRealXAdd4: "); // need to shift 2nd mantissa right by r0 to align + asm("cmp r0, #64 "); // more than 64 shifts needed? + asm("bhi TRealXAdd6 "); // if so, smaller number cannot affect larger + asm("cmp r0, #32 "); + asm("bhi TRealXAdd7 "); // branch if shift count>32 + asm("rsb r8, r0, #32 "); + asm("mov r7, r4, lsl r8 "); // shift r5:r4 right into r7 + asm("mov r4, r4, lsr r0 "); + asm("orr r4, r4, r5, lsl r8 "); + asm("mov r5, r5, lsr r0 "); + asm("b TRealXAdd8 "); + asm("TRealXAdd7: "); // 64 >= shift count > 32 + asm("sub r0, r0, #32 "); + asm("rsb r8, r0, #32 "); + asm("movs r7, r4, lsl r8 "); // test bits lost in shift + asm("orrne r6, r6, #0x100 "); // if not all zero, flag 2nd mantissa rounded down + asm("mov r7, r4, lsr r0 "); // shift r5:r4 right into r7 by 32+r0 + asm("orr r7, r7, r5, lsl r8 "); + asm("mov r4, r5, lsr r0 "); + asm("mov r5, #0 "); + asm("TRealXAdd8: "); // mantissas are now aligned + asm("mov r8, r3, lsl #31 "); // r8=sign of first operand + asm("cmp r8, r6, lsl #31 "); // compare signs + asm("bne TRealXSub1 "); // if different, need to do a subtraction + asm("adds r1, r1, r4 "); // signs the same - add mantissas + asm("adcs r2, r2, r5 "); + asm("bcc TRealXAdd9 "); // skip if no carry + asm(".word 0xE1B02062 "); // movs r2, r2, rrx shift carry into mantissa + asm(".word 0xE1B01061 "); // movs r1, r1, rrx + asm(".word 0xE1B07067 "); // movs r7, r7, rrx + asm("orrcs r6, r6, #0x100 "); // if 1 shifted out, flag 2nd mantissa rounded down + asm("add r3, r3, #0x10000 "); // increment exponent + asm("TRealXAdd9: "); + asm("cmp r7, #0x80000000 "); // check rounding word + asm("bcc TRealXAdd10 "); // if <0x80000000 round down + asm("bhi TRealXAdd11 "); // if >0x80000000 round up + asm("tst r6, #0x100 "); // if =0x80000000 check if 2nd mantissa rounded down + asm("bne TRealXAdd11 "); // if so, round up + asm("tst r6, #0x200 "); // if =0x80000000 check if 2nd mantissa rounded up + asm("bne TRealXAdd10 "); // if so, round down + asm("tst r1, #1 "); // else round to even - check LSB + asm("beq TRealXAdd10 "); // if zero, round down + asm("TRealXAdd11: "); // come here to round up + asm("adds r1, r1, #1 "); // increment mantissa + asm("adcs r2, r2, #0 "); + asm("movcs r2, #0x80000000 "); // if carry, mantissa = 80000000 00000000 + asm("addcs r3, r3, #0x10000 "); // and increment exponent + asm("cmn r3, #0x10000 "); // check overflow + asm("orrcc r3, r3, #0x200 "); // if no overflow, set rounded-up flag ... + __JUMP(cc,lr); + asm("b TRealXAdd12 "); // if overflow, return infinity + asm("TRealXAdd10: "); // come here to round down + asm("cmn r3, #0x10000 "); // check overflow + asm("bcs TRealXAdd12 "); // if overflow, return infinity + asm("cmp r7, #0 "); // if no overflow check if rounding word is zero + asm("orrne r3, r3, #0x100 "); // if not, set rounded-down flag ... + __JUMP(ne,lr); + asm("and r6, r6, #0x300 "); // else transfer 2nd mantissa rounding flags + asm("orr r3, r3, r6 "); // to result + __JUMP(,lr); + + asm("TRealXAdd12: "); // come here if overflow - return infinity + asm("mov r2, #0x80000000 "); + asm("mov r1, #0 "); + asm("mvn r12, #8 "); // and return KErrOverflow + __JUMP(,lr); + + asm("TRealXSub1: "); // come here if operand signs differ + asm("tst r6, #0x300 "); // check if 2nd mantissa rounded + asm("eorne r6, r6, #0x300 "); // if so, change rounding + asm("rsbs r7, r7, #0 "); // subtract mantissas r2:r1:0 -= r5:r4:r7 + asm("sbcs r1, r1, r4 "); + asm("sbcs r2, r2, r5 "); + asm("bcs TRealXSub2 "); // skip if no borrow + asm("tst r6, #0x300 "); // check if 2nd mantissa rounded + asm("eorne r6, r6, #0x300 "); // if so, change rounding + asm("rsbs r7, r7, #0 "); // negate result + asm("rscs r1, r1, #0 "); + asm("rscs r2, r2, #0 "); + asm("eor r3, r3, #1 "); // and change result sign + asm("TRealXSub2: "); + asm("bne TRealXSub3 "); // skip if mantissa top word is not zero + asm("movs r2, r1 "); // else shift up by 32 + asm("mov r1, r7 "); + asm("mov r7, #0 "); + asm("bne TRealXSub3a "); // skip if mantissa top word is not zero now + asm("movs r2, r1 "); // else shift up by 32 again + asm("mov r1, #0 "); + asm("moveq r3, #0 "); // if r2 still zero, result is zero - return +0 + __JUMP(eq,lr); + asm("subs r3, r3, #0x00400000 "); // else, decrement exponent by 64 + asm("bcs TRealXSub3 "); // if no borrow, proceed + asm("b TRealXSub4 "); // if borrow, underflow + asm("TRealXSub3a: "); // needed one 32-bit shift + asm("subs r3, r3, #0x00200000 "); // so decrement exponent by 32 + asm("bcc TRealXSub4 "); // if borrow, underflow + asm("TRealXSub3: "); // r2 is now non-zero; still may need up to 31 shifts +#ifdef __CPU_ARM_HAS_CLZ + CLZ(0,2); + asm("mov r2, r2, lsl r0 "); +#else + asm("mov r0, #0 "); // r0 will be shift count + asm("cmp r2, #0x00010000 "); + asm("movcc r2, r2, lsl #16 "); + asm("addcc r0, r0, #16 "); + asm("cmp r2, #0x01000000 "); + asm("movcc r2, r2, lsl #8 "); + asm("addcc r0, r0, #8 "); + asm("cmp r2, #0x10000000 "); + asm("movcc r2, r2, lsl #4 "); + asm("addcc r0, r0, #4 "); + asm("cmp r2, #0x40000000 "); + asm("movcc r2, r2, lsl #2 "); + asm("addcc r0, r0, #2 "); + asm("cmp r2, #0x80000000 "); + asm("movcc r2, r2, lsl #1 "); + asm("addcc r0, r0, #1 "); +#endif + asm("rsb r8, r0, #32 "); + asm("subs r3, r3, r0, lsl #16 "); // subtract shift count from exponent + asm("bcc TRealXSub4 "); // if borrow, underflow + asm("orr r2, r2, r1, lsr r8 "); // else shift mantissa up + asm("mov r1, r1, lsl r0 "); + asm("orr r1, r1, r7, lsr r8 "); + asm("mov r7, r7, lsl r0 "); + asm("cmp r3, #0x10000 "); // check for underflow + asm("bcs TRealXAdd9 "); // if no underflow, branch to round result + + asm("TRealXSub4: "); // come here if underflow + asm("and r3, r3, #1 "); // set exponent to zero, leave sign + asm("mov r2, #0 "); + asm("mov r1, #0 "); + asm("mvn r12, #9 "); // return KErrUnderflow + __JUMP(,lr); + + asm("TRealXAdd6: "); // come here if exponents differ by more than 64 + asm("mov r8, r3, lsl #31 "); // r8=sign of first operand + asm("cmp r8, r6, lsl #31 "); // compare signs + asm("orreq r3, r3, #0x100 "); // if same, result has been rounded down + asm("orrne r3, r3, #0x200 "); // else result has been rounded up + __JUMP(,lr); + + asm("TRealXAdd3a: "); // come here if second operand zero + asm("cmp r3, #0x10000 "); // check if first operand also zero + asm("andcc r3, r3, r6 "); // if so, result is negative iff both zeros negative + asm("andcc r3, r3, #1 "); + __JUMP(,lr); + + asm("TRealXAdd3: "); // come here if first operand zero, second nonzero + asm("mov r1, r4 "); // return second operand unchanged + asm("mov r2, r5 "); + asm("mov r3, r6 "); + __JUMP(,lr); + + asm("TRealXAdd1: "); // come here if first operand NaN or infinity + asm("cmp r2, #0x80000000 "); // check for infinity + asm("cmpeq r1, #0 "); + asm("bne TRealXBinOpNan "); // branch if NaN + asm("cmn r6, #0x10000 "); // check 2nd operand for NaN/infinity + asm("mvncc r12, #8 "); // if neither, return KErrOverflow + __JUMP(cc,lr); + asm("cmp r5, #0x80000000 "); // check 2nd operand for infinity + asm("cmpeq r4, #0 "); + asm("bne TRealXBinOpNan "); // branch if NaN + asm("mov r0, r3, lsl #31 "); // both operands are infinity - check signs + asm("cmp r0, r6, lsl #31 "); + asm("mvneq r12, #8 "); // if same, return KErrOverflow + __JUMP(eq,lr); + + // Return 'real indefinite' + asm("TRealXRealIndefinite: "); + asm("ldr r3, [pc, #__RealIndefiniteExponent-.-8] "); + asm("mov r2, #0xC0000000 "); + asm("mov r1, #0 "); + asm("mvn r12, #5 "); // return KErrArgument + __JUMP(,lr); + + asm("TRealXAdd2: "); // come here if 2nd operand NaN/infinity, first finite + asm("cmp r5, #0x80000000 "); // check for infinity + asm("cmpeq r4, #0 "); + asm("bne TRealXBinOpNan "); // branch if NaN + asm("mov r1, r4 "); // else return 2nd operand (infinity) + asm("mov r2, r5 "); + asm("mov r3, r6 "); + asm("mvn r12, #8 "); // return KErrOverflow + __JUMP(,lr); + + asm("TRealXBinOpNan: "); // generic routine to process NaNs in binary + // operations + asm("cmn r3, #0x10000 "); // check if first operand is NaN + asm("movcc r0, r1 "); // if not, swap the operands + asm("movcc r1, r4 "); + asm("movcc r4, r0 "); + asm("movcc r0, r2 "); + asm("movcc r2, r5 "); + asm("movcc r5, r0 "); + asm("movcc r0, r3 "); + asm("movcc r3, r6 "); + asm("movcc r6, r0 "); + asm("cmn r6, #0x10000 "); // both operands NaNs? + asm("bcc TRealXBinOpNan1 "); // skip if not + asm("cmp r2, r5 "); // if so, compare the significands + asm("cmpeq r1, r4 "); + asm("movcc r1, r4 "); // r1,r2,r3 will get NaN with larger significand + asm("movcc r2, r5 "); + asm("movcc r3, r6 "); + asm("TRealXBinOpNan1: "); + asm("orr r2, r2, #0x40000000 "); // convert an SNaN to a QNaN + asm("mvn r12, #5 "); // return KErrArgument + __JUMP(,lr); + } + + + + +__NAKED__ EXPORT_C TInt TRealX::MultEq(const TRealX& /*aVal*/) +/** +Multiplies this extended precision number by an extended precision value. + +@param aVal The extended precision value to be used as the multiplier. + +@return KErrNone, if the operation is successful; + KErrOverflow, if the operation results in overflow; + KErrUnderflow, if the operation results in underflow +*/ + { + // Version for ARM 3M or later + // Uses umull/umlal + asm("stmfd sp!, {r0,r4-r7,lr} "); + asm("ldmia r1, {r4,r5,r6} "); + asm("ldmia r0, {r1,r2,r3} "); + asm("bl TRealXMultiply "); + asm("ldmfd sp!, {r0,r4-r7,lr} "); + asm("stmia r0, {r1,r2,r3} "); + asm("mov r0, r12 "); + __JUMP(,lr); + + // TRealX multiplication r1,r2,r3 * r4,r5,r6 result in r1,r2,r3 + // Error code returned in r12 + // Registers r0-r7,r12 modified + // NB This function is purely internal to EUSER and therefore IS ONLY EVER CALLED IN ARM MODE. + asm("TRealXMultiply: "); + asm("mov r12, #0 "); // initialise return value to KErrNone + asm("bic r3, r3, #0x300 "); // clear rounding flags + asm("tst r6, #1 "); + asm("eorne r3, r3, #1 "); // Exclusive-OR signs + asm("cmn r3, #0x10000 "); // check if first operand is NaN or infinity + asm("bcs TRealXMultiply1 "); // branch if it is + asm("cmn r6, #0x10000 "); // check if second operand is NaN or infinity + asm("bcs TRealXMultiply2 "); // branch if it is + asm("cmp r3, #0x10000 "); // check if first operand zero + __JUMP(cc,lr); // if so, exit + + // Multiply mantissas in r2:r1 and r5:r4, result in r2:r1:r12:r7 + asm("umull r7, r12, r1, r4 "); // r7:r12=m1.low*m2.low + asm("movs r0, r6, lsr #16 "); // r0=2nd operand exponent + asm("beq TRealXMultiply3 "); // if zero, return zero + asm("mov r6, #0 "); // clear r6 initially + asm("umlal r12, r6, r1, r5 "); // r6:r12:r7=m1.low*m2, r1 no longer needed + asm("add r0, r0, r3, lsr #16 "); // r0=sum of exponents + asm("tst r3, #1 "); + asm("mov r3, #0 "); // clear r3 initially + asm("umlal r6, r3, r2, r5 "); // r3:r6:r12:r7=m2.low*m1+m2.high*m1.high<<64 + // r1,r5 no longer required + asm("orrne lr, lr, #1 "); // save sign in bottom bit of lr + asm("sub r0, r0, #0x7F00 "); + asm("sub r0, r0, #0x00FE "); // r0 now contains result exponent + asm("umull r1, r5, r2, r4 "); // r5:r1=m2.high*m1.low + asm("adds r12, r12, r1 "); // shift left by 32 and add to give final result + asm("adcs r1, r6, r5 "); + asm("adcs r2, r3, #0 "); // final result now in r2:r1:r12:r7 + // set flags on final value of r2 (ms word of result) + + // normalise the result mantissa + asm("bmi TRealXMultiply4 "); // skip if already normalised + asm("adds r7, r7, r7 "); // else shift left (will only ever need one shift) + asm("adcs r12, r12, r12 "); + asm("adcs r1, r1, r1 "); + asm("adcs r2, r2, r2 "); + asm("sub r0, r0, #1 "); // and decrement exponent by one + + // round the result mantissa + asm("TRealXMultiply4: "); + asm("and r3, lr, #1 "); // result sign bit back into r3 + asm("orrs r4, r7, r12 "); // check for exact result + asm("beq TRealXMultiply5 "); // skip if exact + asm("cmp r12, #0x80000000 "); // compare bottom 64 bits to 80000000 00000000 + asm("cmpeq r7, #0 "); + asm("moveqs r4, r1, lsr #1 "); // if exactly equal, set carry=lsb of result + // so we round up if lsb=1 + asm("orrcc r3, r3, #0x100 "); // if rounding down, set rounded-down flag + asm("orrcs r3, r3, #0x200 "); // if rounding up, set rounded-up flag + asm("adcs r1, r1, #0 "); // increment mantissa if necessary + asm("adcs r2, r2, #0 "); + asm("movcs r2, #0x80000000 "); // if carry, set mantissa to 80000000 00000000 + asm("addcs r0, r0, #1 "); // and increment result exponent + + // check for overflow or underflow and assemble final result + asm("TRealXMultiply5: "); + asm("add r4, r0, #1 "); // need to add 1 to get usable threshold + asm("cmp r4, #0x10000 "); // check if exponent >= 0xFFFF + asm("bge TRealXMultiply6 "); // if so, overflow + asm("cmp r0, #0 "); // check for underflow + asm("orrgt r3, r3, r0, lsl #16 "); // if no underflow, result exponent into r3, ... + asm("movgt r12, #0 "); // ... return KErrNone ... + asm("bicgt pc, lr, #3 "); + + // underflow + asm("mvn r12, #9 "); // return KErrUnderflow + asm("bic pc, lr, #3 "); + + // overflow + asm("TRealXMultiply6: "); + asm("bic r3, r3, #0x0000FF00 "); // clear rounding flags + asm("orr r3, r3, #0xFF000000 "); // make exponent FFFF for infinity + asm("orr r3, r3, #0x00FF0000 "); + asm("mov r2, #0x80000000 "); // mantissa = 80000000 00000000 + asm("mov r1, #0 "); + asm("mvn r12, #8 "); // return KErrOverflow + asm("bic pc, lr, #3 "); + + // come here if second operand zero + asm("TRealXMultiply3: "); + asm("mov r1, #0 "); + asm("mov r2, #0 "); + asm("and r3, r3, #1 "); // zero exponent, keep xor sign + asm("mov r12, #0 "); // return KErrNone + asm("bic pc, lr, #3 "); + + // First operand NaN or infinity + asm("TRealXMultiply1: "); + asm("cmp r2, #0x80000000 "); // check for infinity + asm("cmpeq r1, #0 "); + asm("bne TRealXBinOpNan "); // branch if NaN + asm("cmn r6, #0x10000 "); // check 2nd operand for NaN/infinity + asm("bcs TRealXMultiply1a "); // branch if it is + asm("cmp r6, #0x10000 "); // else check if second operand zero + asm("mvncs r12, #8 "); // if not, return infinity and KErrOverflow + asm("biccs pc, lr, #3 "); + asm("b TRealXRealIndefinite "); // else return 'real indefinite' + + asm("TRealXMultiply1a: "); + asm("cmp r5, #0x80000000 "); // check 2nd operand for infinity + asm("cmpeq r4, #0 "); + asm("bne TRealXBinOpNan "); // branch if NaN + asm("mvn r12, #8 "); // else (infinity), return KErrOverflow + asm("bic pc, lr, #3 "); + + // Second operand NaN or infinity, first operand finite + asm("TRealXMultiply2: "); + asm("cmp r5, #0x80000000 "); // check for infinity + asm("cmpeq r4, #0 "); + asm("bne TRealXBinOpNan "); // branch if NaN + asm("cmp r3, #0x10000 "); // if infinity, check if first operand zero + asm("bcc TRealXRealIndefinite "); // if it is, return 'real indefinite' + asm("orr r3, r3, #0xFF000000 "); // else return infinity with xor sign + asm("orr r3, r3, #0x00FF0000 "); + asm("mov r2, #0x80000000 "); + asm("mov r1, #0 "); + asm("mvn r12, #8 "); // return KErrOverflow + asm("bic pc, lr, #3 "); + } + + + + +__NAKED__ EXPORT_C TInt TRealX::DivEq(const TRealX& /*aVal*/) +/** +Divides this extended precision number by an extended precision value. + +@param aVal The extended precision value to be used as the divisor. + +@return KErrNone, if the operation is successful; + KErrOverflow, if the operation results in overflow; + KErrUnderflow, if the operation results in underflow; + KErrDivideByZero, if the divisor is zero. +*/ + { + asm("stmfd sp!, {r0,r4-r9,lr} "); + asm("ldmia r1, {r4,r5,r6} "); + asm("ldmia r0, {r1,r2,r3} "); + asm("bl TRealXDivide "); + asm("ldmfd sp!, {r0,r4-r9,lr} "); + asm("stmia r0, {r1,r2,r3} "); + asm("mov r0, r12 "); + __JUMP(,lr); + + // TRealX division r1,r2,r3 / r4,r5,r6 result in r1,r2,r3 + // Error code returned in r12 + // Registers r0-r9,r12 modified + // NB This function is purely internal to EUSER and therefore IS ONLY EVER CALLED IN ARM MODE. + asm("TRealXDivide: "); + asm("mov r12, #0 "); // initialise return value to KErrNone + asm("bic r3, r3, #0x300 "); // clear rounding flags + asm("tst r6, #1 "); + asm("eorne r3, r3, #1 "); // Exclusive-OR signs + asm("cmn r3, #0x10000 "); // check if dividend is NaN or infinity + asm("bcs TRealXDivide1 "); // branch if it is + asm("cmn r6, #0x10000 "); // check if divisor is NaN or infinity + asm("bcs TRealXDivide2 "); // branch if it is + asm("cmp r6, #0x10000 "); // check if divisor zero + asm("bcc TRealXDivide3 "); // branch if it is + asm("cmp r3, #0x10000 "); // check if dividend zero + __JUMP(cc,lr); // if zero, exit + asm("tst r3, #1 "); + asm("orrne lr, lr, #1 "); // save sign in bottom bit of lr + + // calculate result exponent + asm("mov r0, r3, lsr #16 "); // r0=dividend exponent + asm("sub r0, r0, r6, lsr #16 "); // r0=dividend exponent - divisor exponent + asm("add r0, r0, #0x7F00 "); + asm("add r0, r0, #0x00FF "); // r0 now contains result exponent + asm("mov r6, r1 "); // move dividend into r6,r7,r8 + asm("mov r7, r2 "); + asm("mov r8, #0 "); // use r8 to hold extra bit shifted up + // r2:r1 will hold result mantissa + asm("mov r2, #1 "); // we will make sure first bit is 1 + asm("cmp r7, r5 "); // compare dividend mantissa to divisor mantissa + asm("cmpeq r6, r4 "); + asm("bcs TRealXDivide4 "); // branch if dividend >= divisor + asm("adds r6, r6, r6 "); // else shift dividend left one + asm("adcs r7, r7, r7 "); // ignore carry here + asm("sub r0, r0, #1 "); // decrement result exponent by one + asm("TRealXDivide4: "); + asm("subs r6, r6, r4 "); // subtract divisor from dividend + asm("sbcs r7, r7, r5 "); + + // Main mantissa division code + // First calculate the top 32 bits of the result + // Top bit is 1, do 10 lots of 3 bits the one more bit + asm("mov r12, #10 "); + asm("TRealXDivide5: "); + asm("adds r6, r6, r6 "); // shift accumulator left by one + asm("adcs r7, r7, r7 "); + asm("adcs r8, r8, r8 "); + asm("subs r9, r6, r4 "); // subtract divisor from accumulator, result in r9,r3 + asm("sbcs r3, r7, r5 "); + asm("movccs r8, r8, lsr #1 "); // if borrow, check for carry from shift + asm("movcs r6, r9 "); // if no borrow, replace accumulator with result + asm("movcs r7, r3 "); + asm("adcs r2, r2, r2 "); // shift in new result bit + asm("adds r6, r6, r6 "); // shift accumulator left by one + asm("adcs r7, r7, r7 "); + asm("adcs r8, r8, r8 "); + asm("subs r9, r6, r4 "); // subtract divisor from accumulator, result in r9,r3 + asm("sbcs r3, r7, r5 "); + asm("movccs r8, r8, lsr #1 "); // if borrow, check for carry from shift + asm("movcs r6, r9 "); // if no borrow, replace accumulator with result + asm("movcs r7, r3 "); + asm("adcs r2, r2, r2 "); // shift in new result bit + asm("adds r6, r6, r6 "); // shift accumulator left by one + asm("adcs r7, r7, r7 "); + asm("adcs r8, r8, r8 "); + asm("subs r9, r6, r4 "); // subtract divisor from accumulator, result in r9,r3 + asm("sbcs r3, r7, r5 "); + asm("movccs r8, r8, lsr #1 "); // if borrow, check for carry from shift + asm("movcs r6, r9 "); // if no borrow, replace accumulator with result + asm("movcs r7, r3 "); + asm("adcs r2, r2, r2 "); // shift in new result bit + asm("subs r12, r12, #1 "); + asm("bne TRealXDivide5 "); // iterate the loop + asm("adds r6, r6, r6 "); // shift accumulator left by one + asm("adcs r7, r7, r7 "); + asm("adcs r8, r8, r8 "); + asm("subs r9, r6, r4 "); // subtract divisor from accumulator, result in r9,r3 + asm("sbcs r3, r7, r5 "); + asm("movccs r8, r8, lsr #1 "); // if borrow, check for carry from shift + asm("movcs r6, r9 "); // if no borrow, replace accumulator with result + asm("movcs r7, r3 "); + asm("adcs r2, r2, r2 "); // shift in new result bit - now have 32 bits + + // Now calculate the bottom 32 bits of the result + // Do 8 lots of 4 bits + asm("mov r12, #8 "); + asm("TRealXDivide5a: "); + asm("adds r6, r6, r6 "); // shift accumulator left by one + asm("adcs r7, r7, r7 "); + asm("adcs r8, r8, r8 "); + asm("subs r9, r6, r4 "); // subtract divisor from accumulator, result in r9,r3 + asm("sbcs r3, r7, r5 "); + asm("movccs r8, r8, lsr #1 "); // if borrow, check for carry from shift + asm("movcs r6, r9 "); // if no borrow, replace accumulator with result + asm("movcs r7, r3 "); + asm("adcs r1, r1, r1 "); // shift in new result bit + asm("adds r6, r6, r6 "); // shift accumulator left by one + asm("adcs r7, r7, r7 "); + asm("adcs r8, r8, r8 "); + asm("subs r9, r6, r4 "); // subtract divisor from accumulator, result in r9,r3 + asm("sbcs r3, r7, r5 "); + asm("movccs r8, r8, lsr #1 "); // if borrow, check for carry from shift + asm("movcs r6, r9 "); // if no borrow, replace accumulator with result + asm("movcs r7, r3 "); + asm("adcs r1, r1, r1 "); // shift in new result bit + asm("adds r6, r6, r6 "); // shift accumulator left by one + asm("adcs r7, r7, r7 "); + asm("adcs r8, r8, r8 "); + asm("subs r9, r6, r4 "); // subtract divisor from accumulator, result in r9,r3 + asm("sbcs r3, r7, r5 "); + asm("movccs r8, r8, lsr #1 "); // if borrow, check for carry from shift + asm("movcs r6, r9 "); // if no borrow, replace accumulator with result + asm("movcs r7, r3 "); + asm("adcs r1, r1, r1 "); // shift in new result bit + asm("adds r6, r6, r6 "); // shift accumulator left by one + asm("adcs r7, r7, r7 "); + asm("adcs r8, r8, r8 "); + asm("subs r9, r6, r4 "); // subtract divisor from accumulator, result in r9,r3 + asm("sbcs r3, r7, r5 "); + asm("movccs r8, r8, lsr #1 "); // if borrow, check for carry from shift + asm("movcs r6, r9 "); // if no borrow, replace accumulator with result + asm("movcs r7, r3 "); + asm("adcs r1, r1, r1 "); // shift in new result bit + asm("subs r12, r12, #1 "); + asm("bne TRealXDivide5a "); // iterate the loop + + // r2:r1 now contains a 64-bit normalised mantissa + // need to do rounding now + asm("and r3, lr, #1 "); // result sign back into r3 + asm("orrs r9, r6, r7 "); // check if accumulator zero + asm("beq TRealXDivide6 "); // if it is, result is exact, else generate next bit + asm("adds r6, r6, r6 "); // shift accumulator left by one + asm("adcs r7, r7, r7 "); + asm("adcs r8, r8, r8 "); + asm("subs r6, r6, r4 "); // subtract divisor from accumulator + asm("sbcs r7, r7, r5 "); + asm("movccs r8, r8, lsr #1 "); // if borrow, check for carry from shift + asm("orrcc r3, r3, #0x100 "); // if borrow, round down and set round-down flag + asm("bcc TRealXDivide6 "); + asm("orrs r9, r6, r7 "); // if no borrow, check if exactly half-way + asm("moveqs r9, r1, lsr #1 "); // if exactly half-way, round to even + asm("orrcc r3, r3, #0x100 "); // if C=0, round result down and set round-down flag + asm("bcc TRealXDivide6 "); + asm("orr r3, r3, #0x200 "); // else set round-up flag + asm("adds r1, r1, #1 "); // and round mantissa up + asm("adcs r2, r2, #0 "); + asm("movcs r2, #0x80000000 "); // if carry, mantissa = 80000000 00000000 + asm("addcs r0, r0, #1 "); // and increment exponent + + // check for overflow or underflow and assemble final result + asm("TRealXDivide6: "); + asm("add r4, r0, #1 "); // need to add 1 to get usable threshold + asm("cmp r4, #0x10000 "); // check if exponent >= 0xFFFF + asm("bge TRealXMultiply6 "); // if so, overflow + asm("cmp r0, #0 "); // check for underflow + asm("orrgt r3, r3, r0, lsl #16 "); // if no underflow, result exponent into r3, ... + asm("movgt r12, #0 "); // ... return KErrNone ... + asm("bicgt pc, lr, #3 "); + + // underflow + asm("and r3, r3, #1 "); // set exponent=0, keep sign + asm("mvn r12, #9 "); // return KErrUnderflow + asm("bic pc, lr, #3 "); + + // come here if divisor is zero, dividend finite + asm("TRealXDivide3: "); + asm("cmp r3, #0x10000 "); // check if dividend also zero + asm("bcc TRealXRealIndefinite "); // if so, return 'real indefinite' + asm("orr r3, r3, #0xFF000000 "); // else return infinity with xor sign + asm("orr r3, r3, #0x00FF0000 "); + asm("mov r2, #0x80000000 "); + asm("mov r1, #0 "); + asm("mvn r12, #40 "); // return KErrDivideByZero + asm("bic pc, lr, #3 "); + + // Dividend is NaN or infinity + asm("TRealXDivide1: "); + asm("cmp r2, #0x80000000 "); // check for infinity + asm("cmpeq r1, #0 "); + asm("bne TRealXBinOpNan "); // branch if NaN + asm("cmn r6, #0x10000 "); // check 2nd operand for NaN/infinity + asm("mvncc r12, #8 "); // if not, return KErrOverflow + asm("biccc pc, lr, #3 "); + + // Dividend=infinity, divisor=NaN or infinity + asm("cmp r5, #0x80000000 "); // check 2nd operand for infinity + asm("cmpeq r4, #0 "); + asm("bne TRealXBinOpNan "); // branch if NaN + asm("b TRealXRealIndefinite "); // else return 'real indefinite' + + // Divisor is NaN or infinity, dividend finite + asm("TRealXDivide2: "); + asm("cmp r5, #0x80000000 "); // check for infinity + asm("cmpeq r4, #0 "); + asm("bne TRealXBinOpNan "); // branch if NaN + asm("and r3, r3, #1 "); // else return zero with xor sign + asm("bic pc, lr, #3 "); + } + + + + +__NAKED__ EXPORT_C TInt TRealX::ModEq(const TRealX& /*aVal*/) +/** +Modulo-divides this extended precision number by an extended precision value. + +@param aVal The extended precision value to be used as the divisor. + +@return KErrNone, if the operation is successful; + KErrTotalLossOfPrecision, if precision is lost; + KErrUnderflow, if the operation results in underflow. +*/ + { + asm("stmfd sp!, {r0,r4-r7,lr} "); + asm("ldmia r1, {r4,r5,r6} "); + asm("ldmia r0, {r1,r2,r3} "); + asm("bl TRealXModulo "); + asm("ldmfd sp!, {r0,r4-r7,lr} "); + asm("stmia r0, {r1,r2,r3} "); + asm("mov r0, r12 "); + __JUMP(,lr); + + // TRealX remainder r1,r2,r3 % r4,r5,r6 result in r1,r2,r3 + // Error code returned in r12 + // Registers r0-r7,r12 modified + // NB This function is purely internal to EUSER and therefore IS ONLY EVER CALLED IN ARM MODE. + asm("TRealXModulo: "); + asm("mov r12, #0 "); // initialise return value to KErrNone + asm("cmn r3, #0x10000 "); // check if dividend is NaN or infinity + asm("bcs TRealXModulo1 "); // branch if it is + asm("cmn r6, #0x10000 "); // check if divisor is NaN or infinity + asm("bcs TRealXModulo2 "); // branch if it is + asm("cmp r6, #0x10000 "); // check if divisor zero + asm("bcc TRealXRealIndefinite "); // if it is, return 'real indefinite' + asm("mov r0, r3, lsr #16 "); // r0=dividend exponent + asm("subs r0, r0, r6, lsr #16 "); // r0=dividend exponent-divisor exponent + __JUMP(lt,lr); + asm("cmp r0, #64 "); // check if difference >= 64 bits + asm("bcs TRealXModuloLp "); // if so, underflow + asm("b TRealXModulo4 "); // skip left shift on first iteration + + asm("TRealXModulo3: "); + asm("adds r1, r1, r1 "); // shift dividend mantissa left one bit + asm("adcs r2, r2, r2 "); + asm("bcs TRealXModulo5 "); // if one shifted out, override comparison + asm("TRealXModulo4: "); + asm("cmp r2, r5 "); // compare dividend to divisor + asm("cmpeq r1, r4 "); + asm("bcc TRealXModulo6 "); // if dividend=divisor, dividend-=divisor + asm("sbcs r2, r2, r5 "); + asm("TRealXModulo6: "); + asm("subs r0, r0, #1 "); // decrement loop count + asm("bpl TRealXModulo3 "); // if more bits to do, loop + + asm("orrs r0, r1, r2 "); // test for exact zero result + asm("andeq r3, r3, #1 "); // if so, return zero with same sign as dividend + __JUMP(eq,lr); + asm("and r7, r3, #1 "); // dividend sign bit into r7 + asm("mov r3, r6, lsr #16 "); // r3 lower 16 bits=result exponent=divisor exponent + asm("cmp r2, #0 "); // test if upper 32 bits zero + asm("moveq r2, r1 "); // if so, shift left by 32 + asm("moveq r1, #0 "); + asm("subeqs r3, r3, #32 "); // and subtract 32 from exponent + asm("bls TRealXModuloUnderflow "); // if borrow from exponent or exponent 0, underflow + asm("mov r0, #32 "); // r0 will hold 32-number of shifts to normalise + asm("cmp r2, #0x00010000 "); // normalise + asm("movcc r2, r2, lsl #16 "); + asm("subcc r0, r0, #16 "); + asm("cmp r2, #0x01000000 "); + asm("movcc r2, r2, lsl #8 "); + asm("subcc r0, r0, #8 "); + asm("cmp r2, #0x10000000 "); + asm("movcc r2, r2, lsl #4 "); + asm("subcc r0, r0, #4 "); + asm("cmp r2, #0x40000000 "); + asm("movcc r2, r2, lsl #2 "); + asm("subcc r0, r0, #2 "); + asm("cmp r2, #0x80000000 "); + asm("movcc r2, r2, lsl #1 "); // top bit of r2 is now set + asm("subcc r0, r0, #1 "); + asm("orr r2, r2, r1, lsr r0 "); // top bits of r1 into bottom bits of r2 + asm("rsb r0, r0, #32 "); // r0=number of shifts to normalise + asm("mov r1, r1, lsl r0 "); // shift r1 left - mantissa now normalised + asm("subs r3, r3, r0 "); // subtract r0 from exponent + asm("bls TRealXModuloUnderflow "); // if borrow from exponent or exponent 0, underflow + asm("orr r3, r7, r3, lsl #16 "); // else r3=result exponent and sign + __JUMP(,lr); + + // dividend=NaN or infinity + asm("TRealXModulo1: "); + asm("cmp r2, #0x80000000 "); // check for infinity + asm("cmpeq r1, #0 "); + asm("bne TRealXBinOpNan "); // branch if NaN + asm("cmn r6, #0x10000 "); // check 2nd operand for NaN/infinity + asm("bcc TRealXRealIndefinite "); // infinity%finite - return 'real indefinite' + asm("cmp r5, #0x80000000 "); // check if divisor=infinity + asm("cmpeq r4, #0 "); + asm("bne TRealXBinOpNan "); // branch if NaN + asm("b TRealXRealIndefinite "); // else infinity%infinity - return 'real indefinite' + + // divisor=NaN or infinity, dividend finite + asm("TRealXModulo2: "); + asm("cmp r5, #0x80000000 "); // check for infinity + asm("cmpeq r4, #0 "); + asm("bne TRealXBinOpNan "); // branch if NaN + __JUMP(,lr); + + asm("TRealXModuloLp: "); + asm("mvn r12, #%a0" : : "i" ((TInt)~KErrTotalLossOfPrecision)); + asm("mov r1, #0 "); + asm("mov r2, #0 "); + asm("and r3, r3, #1 "); + __JUMP(,lr); + + asm("TRealXModuloUnderflow: "); + asm("mvn r12, #%a0" : : "i" ((TInt)~KErrUnderflow)); + asm("mov r1, #0 "); + asm("mov r2, #0 "); + asm("and r3, r3, #1 "); + __JUMP(,lr); + } + + + + +__NAKED__ EXPORT_C TInt TRealX::Add(TRealX& /*aResult*/,const TRealX& /*aVal*/) const +/** +Adds an extended precision value to this extended precision number. + +@param aResult On return, a reference to an extended precision object + containing the result of the operation. +@param aVal The extended precision value to be added. + +@return KErrNone, if the operation is successful; + KErrOverflow, if the operation results in overflow; + KErrUnderflow, if the operation results in underflow. +*/ + { + // r0=this, r1=&aResult, r2=&aVal + asm("stmfd sp!, {r1,r4-r8,lr} "); + asm("ldmia r2, {r4,r5,r6} "); + asm("ldmia r0, {r1,r2,r3} "); + asm("bl TRealXAdd "); + asm("ldmfd sp!, {lr} "); // lr=&aResult + asm("stmia lr, {r1,r2,r3} "); + asm("mov r0, r12 "); // return value into r0 + __POPRET("r4-r8,"); + } + + + + +__NAKED__ EXPORT_C TInt TRealX::Sub(TRealX& /*aResult*/,const TRealX& /*aVal*/) const +/** +Subtracts an extended precision value from this extended precision number. + +@param aResult On return, a reference to an extended precision object + containing the result of the operation. +@param aVal The extended precision value to be subtracted. + +@return KErrNone, if the operation is successful; + KErrOverflow, if the operation results in overflow; + KErrUnderflow, if the operation results in underflow. +*/ + { + // r0=this, r1=&aResult, r2=&aVal + asm("stmfd sp!, {r1,r4-r8,lr} "); + asm("ldmia r2, {r4,r5,r6} "); + asm("ldmia r0, {r1,r2,r3} "); + asm("bl TRealXSubtract "); + asm("ldmfd sp!, {lr} "); // lr=&aResult + asm("stmia lr, {r1,r2,r3} "); + asm("mov r0, r12 "); // return value into r0 + __POPRET("r4-r8,"); + } + + + + +__NAKED__ EXPORT_C TInt TRealX::Mult(TRealX& /*aResult*/,const TRealX& /*aVal*/) const +/** +Multiplies this extended precision number by an extended precision value. + +@param aResult On return, a reference to an extended precision object + containing the result of the operation. +@param aVal The extended precision value to be used as the multiplier. + +@return KErrNone, if the operation is successful; + KErrOverflow, if the operation results in overflow; + KErrUnderflow, if the operation results in underflow. +*/ + { + // r0=this, r1=&aResult, r2=&aVal + asm("stmfd sp!, {r1,r4-r7,lr} "); + asm("ldmia r2, {r4,r5,r6} "); + asm("ldmia r0, {r1,r2,r3} "); + asm("bl TRealXMultiply "); + asm("ldmfd sp!, {lr} "); // lr=&aResult + asm("stmia lr, {r1,r2,r3} "); + asm("mov r0, r12 "); // return value into r0 + __POPRET("r4-r7,"); + } + + + + +__NAKED__ EXPORT_C TInt TRealX::Div(TRealX& /*aResult*/,const TRealX& /*aVal*/) const +/** +Divides this extended precision number by an extended precision value. + +@param aResult On return, a reference to an extended precision object + containing the result of the operation. +@param aVal The extended precision value to be used as the divisor. + +@return KErrNone, if the operation is successful; + KErrOverflow, if the operation results in overflow; + KErrUnderflow, if the operation results in underflow; + KErrDivideByZero, if the divisor is zero. +*/ + { + // r0=this, r1=&aResult, r2=&aVal + asm("stmfd sp!, {r1,r4-r9,lr} "); + asm("ldmia r2, {r4,r5,r6} "); + asm("ldmia r0, {r1,r2,r3} "); + asm("bl TRealXDivide "); + asm("ldmfd sp!, {lr} "); // lr=&aResult + asm("stmia lr, {r1,r2,r3} "); + asm("mov r0, r12 "); // return value into r0 + __POPRET("r4-r9,"); + } + + + + +__NAKED__ EXPORT_C TInt TRealX::Mod(TRealX& /*aResult*/,const TRealX& /*aVal*/) const +/** +Modulo-divides this extended precision number by an extended precision value. + +@param aResult On return, a reference to an extended precision object + containing the result of the operation. + +@param aVal The extended precision value to be used as the divisor. + +@return KErrNone, if the operation is successful; + KErrTotalLossOfPrecision, if precision is lost; + KErrUnderflow, if the operation results in underflow. +*/ + { + // r0=this, r1=&aResult, r2=&aVal + asm("stmfd sp!, {r1,r4-r7,lr} "); + asm("ldmia r2, {r4,r5,r6} "); + asm("ldmia r0, {r1,r2,r3} "); + asm("bl TRealXModulo "); + asm("ldmfd sp!, {lr} "); // lr=&aResult + asm("stmia lr, {r1,r2,r3} "); + asm("mov r0, r12 "); // return value into r0 + __POPRET("r4-r7,"); + } + +extern void PanicOverUnderflowDividebyZero(const TInt aErr); + + + + +__NAKED__ EXPORT_C const TRealX& TRealX::operator+=(const TRealX& /*aVal*/) +/** +Adds an extended precision value to this extended precision number. + +@param aVal The extended precision value to be added. + +@return A reference to this object. + +@panic MATHX KErrOverflow if the operation results in overflow. +@panic MATHX KErrUnderflow if the operation results in underflow. +*/ + { + asm("stmfd sp!, {r0,r4-r8,lr} "); + asm("ldmia r1, {r4,r5,r6} "); + asm("ldmia r0, {r1,r2,r3} "); + asm("bl TRealXAdd "); + asm("ldmfd sp!, {r0,r4-r8,lr} "); + asm("stmia r0, {r1,r2,r3} "); + asm("cmp r12, #0 "); // check the error code + __JUMP(eq,lr); + asm("mov r0, r12 "); + asm("b " CSM_Z30PanicOverUnderflowDividebyZeroi); // else panic + } + + + + +__NAKED__ EXPORT_C const TRealX& TRealX::operator-=(const TRealX& /*aVal*/) +/** +Subtracts an extended precision value from this extended precision number. + +@param aVal The extended precision value to be subtracted. + +@return A reference to this object. + +@panic MATHX KErrOverflow if the operation results in overflow. +@panic MATHX KErrUnderflow if the operation results in underflow. +*/ + { + asm("stmfd sp!, {r0,r4-r8,lr} "); + asm("ldmia r1, {r4,r5,r6} "); + asm("ldmia r0, {r1,r2,r3} "); + asm("bl TRealXSubtract "); + asm("ldmfd sp!, {r0,r4-r8,lr} "); + asm("stmia r0, {r1,r2,r3} "); + asm("cmp r12, #0 "); // check the error code + __JUMP(eq,lr); + asm("mov r0, r12 "); + asm("b " CSM_Z30PanicOverUnderflowDividebyZeroi); // else panic + } + + + + +__NAKED__ EXPORT_C const TRealX& TRealX::operator*=(const TRealX& /*aVal*/) +/** +Multiplies this extended precision number by an extended precision value. + +@param aVal The extended precision value to be subtracted. + +@return A reference to this object. + +@panic MATHX KErrOverflow if the operation results in overflow. +@panic MATHX KErrUnderflow if the operation results in underflow. +*/ + { + asm("stmfd sp!, {r0,r4-r7,lr} "); + asm("ldmia r1, {r4,r5,r6} "); + asm("ldmia r0, {r1,r2,r3} "); + asm("bl TRealXMultiply "); + asm("ldmfd sp!, {r0,r4-r7,lr} "); + asm("stmia r0, {r1,r2,r3} "); + asm("cmp r12, #0 "); // check the error code + __JUMP(eq,lr); + asm("mov r0, r12 "); + asm("b " CSM_Z30PanicOverUnderflowDividebyZeroi); // else panic + } + + + + +__NAKED__ EXPORT_C const TRealX& TRealX::operator/=(const TRealX& /*aVal*/) +/** +Divides this extended precision number by an extended precision value. + +@param aVal The extended precision value to be used as the divisor. + +@return A reference to this object. + +@panic MATHX KErrOverflow if the operation results in overflow. +@panic MATHX KErrUnderflow if the operation results in underflow. +@panic MATHX KErrDivideByZero if the divisor is zero. +*/ + { + asm("stmfd sp!, {r0,r4-r9,lr} "); + asm("ldmia r1, {r4,r5,r6} "); + asm("ldmia r0, {r1,r2,r3} "); + asm("bl TRealXDivide "); + asm("ldmfd sp!, {r0,r4-r9,lr} "); + asm("stmia r0, {r1,r2,r3} "); + asm("cmp r12, #0 "); // check the error code + __JUMP(eq,lr); + asm("mov r0, r12 "); + asm("b " CSM_Z30PanicOverUnderflowDividebyZeroi); // else panic + } + + + + +__NAKED__ EXPORT_C const TRealX& TRealX::operator%=(const TRealX& /*aVal*/) +/** +Modulo-divides this extended precision number by an extended precision value. + +@param aVal The extended precision value to be used as the divisor. + +@return A reference to this object. + +@panic MATHX KErrTotalLossOfPrecision panic if precision is lost. +@panic MATHX KErrUnderflow if the operation results in underflow. +*/ + { + asm("stmfd sp!, {r0,r4-r7,lr} "); + asm("ldmia r1, {r4,r5,r6} "); + asm("ldmia r0, {r1,r2,r3} "); + asm("bl TRealXModulo "); + asm("ldmfd sp!, {r0,r4-r7,lr} "); + asm("stmia r0, {r1,r2,r3} "); + asm("cmp r12, #0 "); // check the error code + asm("cmpne r12, #%a0" : : "i" ((TInt)KErrTotalLossOfPrecision)); + __JUMP(eq,lr); + asm("mov r0, r12 "); + asm("b " CSM_Z30PanicOverUnderflowDividebyZeroi); // else panic + } + + + + +__NAKED__ EXPORT_C TRealX& TRealX::operator++() +/** +Increments this extended precision number by one, +and then returns a reference to it. + +This is also referred to as a prefix operator. + +@return A reference to this object. + +@panic MATHX KErrOverflow if the operation results in overflow. +@panic MATHX KErrUnderflow if the operation results in underflow. +*/ + { + // pre-increment + asm("stmfd sp!, {r0,r4-r8,lr} "); + asm("ldmia r0, {r1,r2,r3} "); + asm("add r4, pc, #__TRealXOne-.-8 "); + asm("ldmia r4, {r4,r5,r6} "); // r4,r5,r6=1.0 + asm("bl TRealXAdd "); + asm("ldmfd sp!, {r0,r4-r8,lr} "); + asm("stmia r0, {r1,r2,r3} "); + asm("cmp r12, #0 "); // check the error code + __JUMP(eq,lr); + asm("mov r0, r12 "); + asm("b " CSM_Z30PanicOverUnderflowDividebyZeroi); // else panic + + asm("__TRealXOne: "); + asm(".word 0x00000000 "); + asm(".word 0x80000000 "); + asm(".word 0x7FFF0000 "); + } + + + + +__NAKED__ EXPORT_C TRealX TRealX::operator++(TInt) +/** +Returns this extended precision number before incrementing it by one. + +This is also referred to as a postfix operator. + +@return A reference to this object. + +@panic MATHX KErrOverflow if the operation results in overflow. +@panic MATHX KErrUnderflow if the operation results in underflow. +*/ + { + // post-increment + // r0=address of return value, r1=this + asm("stmfd sp!, {r0,r1,r4-r8,lr} "); + asm("ldmia r1, {r1,r2,r3} "); + asm("stmia r0, {r1,r2,r3} "); // store old value + asm("add r4, pc, #__TRealXOne-.-8 "); + asm("ldmia r4, {r4,r5,r6} "); // r4,r5,r6=1.0 + asm("bl TRealXAdd "); + asm("ldmfd sp!, {r0,lr} "); // restore r0, lr=this + asm("stmia lr, {r1,r2,r3} "); // store incremented value + asm("ldmfd sp!, {r4-r8,lr} "); + asm("cmp r12, #0 "); // check the error code + __JUMP(eq,lr); + asm("mov r0, r12 "); + asm("b " CSM_Z30PanicOverUnderflowDividebyZeroi); // else panic + } + + + + +__NAKED__ EXPORT_C TRealX& TRealX::operator--() +/** +Decrements this extended precision number by one, +and then returns a reference to it. + +This is also referred to as a prefix operator. + +@return A reference to this object. + +@panic MATHX KErrOverflow if the operation results in overflow. +@panic MATHX KErrUnderflow if the operation results in underflow. +*/ + { + // pre-decrement + asm("stmfd sp!, {r0,r4-r8,lr} "); + asm("ldmia r0, {r1,r2,r3} "); + asm("add r4, pc, #__TRealXOne-.-8 "); + asm("ldmia r4, {r4,r5,r6} "); // r4,r5,r6=1.0 + asm("bl TRealXSubtract "); + asm("ldmfd sp!, {r0,r4-r8,lr} "); + asm("stmia r0, {r1,r2,r3} "); + asm("cmp r12, #0 "); // check the error code + __JUMP(eq,lr); + asm("mov r0, r12 "); + asm("b " CSM_Z30PanicOverUnderflowDividebyZeroi); // else panic + } + + + + +__NAKED__ EXPORT_C TRealX TRealX::operator--(TInt) +/** +Returns this extended precision number before decrementing it by one. + +This is also referred to as a postfix operator. + +@return A reference to this object. + +@panic MATHX KErrOverflow if the operation results in overflow. +@panic MATHX KErrUnderflow if the operation results in underflow. +*/ + { + // post-decrement + // r0=address of return value, r1=this + asm("stmfd sp!, {r0,r1,r4-r8,lr} "); + asm("ldmia r1, {r1,r2,r3} "); + asm("stmia r0, {r1,r2,r3} "); // store old value + asm("add r4, pc, #__TRealXOne-.-8 "); + asm("ldmia r4, {r4,r5,r6} "); // r4,r5,r6=1.0 + asm("bl TRealXSubtract "); + asm("ldmfd sp!, {r0,lr} "); // restore r0, lr=this + asm("stmia lr, {r1,r2,r3} "); // store decremented value + asm("ldmfd sp!, {r4-r8,lr} "); + asm("cmp r12, #0 "); // check the error code + __JUMP(eq,lr); + asm("mov r0, r12 "); + asm("b " CSM_Z30PanicOverUnderflowDividebyZeroi); // else panic + } + + + + +__NAKED__ EXPORT_C TRealX TRealX::operator+(const TRealX& /*aVal*/) const +/** +Adds an extended precision value to this extended precision number. + +@param aVal The extended precision value to be added. + +@return An extended precision object containing the result. + +@panic MATHX KErrOverflow if the operation results in overflow. +@panic MATHX KErrUnderflow if the operation results in underflow. +*/ + { + // r0=address of return value, r1=this, r2=&aVal + asm("stmfd sp!, {r0,r4-r8,lr} "); + asm("ldmia r2, {r4,r5,r6} "); + asm("ldmia r1, {r1,r2,r3} "); + asm("bl TRealXAdd "); + asm("ldmfd sp!, {r0,r4-r8,lr} "); + asm("stmia r0, {r1,r2,r3} "); + asm("cmp r12, #0 "); // check the error code + __JUMP(eq,lr); + asm("mov r0, r12 "); + asm("b " CSM_Z30PanicOverUnderflowDividebyZeroi); // else panic + } + + + + +__NAKED__ EXPORT_C TRealX TRealX::operator-(const TRealX& /*aVal*/) const +/** +Subtracts an extended precision value from this extended precision number. + +@param aVal The extended precision value to be subtracted. + +@return An extended precision object containing the result. + +@panic MATHX KErrOverflow if the operation results in overflow. +@panic MATHX KErrUnderflow if the operation results in underflow. +*/ + { + // r0=address of return value, r1=this, r2=&aVal + asm("stmfd sp!, {r0,r4-r8,lr} "); + asm("ldmia r2, {r4,r5,r6} "); + asm("ldmia r1, {r1,r2,r3} "); + asm("bl TRealXSubtract "); + asm("ldmfd sp!, {r0,r4-r8,lr} "); + asm("stmia r0, {r1,r2,r3} "); + asm("cmp r12, #0 "); // check the error code + __JUMP(eq,lr); + asm("mov r0, r12 "); + asm("b " CSM_Z30PanicOverUnderflowDividebyZeroi); // else panic + } + + + + +__NAKED__ EXPORT_C TRealX TRealX::operator*(const TRealX& /*aVal*/) const +/** +Multiplies this extended precision number by an extended precision value. + +@param aVal The extended precision value to be used as the multiplier. + +@return An extended precision object containing the result. + +@panic MATHX KErrOverflow if the operation results in overflow. +@panic MATHX KErrUnderflow if the operation results in underflow. +*/ + { + // r0=address of return value, r1=this, r2=&aVal + asm("stmfd sp!, {r0,r4-r7,lr} "); + asm("ldmia r2, {r4,r5,r6} "); + asm("ldmia r1, {r1,r2,r3} "); + asm("bl TRealXMultiply "); + asm("ldmfd sp!, {r0,r4-r7,lr} "); + asm("stmia r0, {r1,r2,r3} "); + asm("cmp r12, #0 "); // check the error code + __JUMP(eq,lr); + asm("mov r0, r12 "); + asm("b " CSM_Z30PanicOverUnderflowDividebyZeroi); // else panic + } + + + + +__NAKED__ EXPORT_C TRealX TRealX::operator/(const TRealX& /*aVal*/) const +/** +Divides this extended precision number by an extended precision value. + +@param aVal The extended precision value to be used as the divisor. + +@return An extended precision object containing the result. + +@panic MATHX KErrOverflow if the operation results in overflow. +@panic MATHX KErrUnderflow if the operation results in underflow. +@panic MATHX KErrDivideByZero if the divisor is zero. +*/ + { + // r0=address of return value, r1=this, r2=&aVal + asm("stmfd sp!, {r0,r4-r9,lr} "); + asm("ldmia r2, {r4,r5,r6} "); + asm("ldmia r1, {r1,r2,r3} "); + asm("bl TRealXDivide "); + asm("ldmfd sp!, {r0,r4-r9,lr} "); + asm("stmia r0, {r1,r2,r3} "); + asm("cmp r12, #0 "); // check the error code + __JUMP(eq,lr); + asm("mov r0, r12 "); + asm("b " CSM_Z30PanicOverUnderflowDividebyZeroi); // else panic + } + + + + +__NAKED__ EXPORT_C TRealX TRealX::operator%(const TRealX& /*aVal*/) const +/** +Modulo-divides this extended precision number by an extended precision value. + +@param aVal The extended precision value to be used as the divisor. + +@return An extended precision object containing the result. + +@panic MATHX KErrTotalLossOfPrecision if precision is lost. +@panic MATHX KErrUnderflow if the operation results in underflow. +*/ + { + // r0=address of return value, r1=this, r2=&aVal + asm("stmfd sp!, {r0,r4-r7,lr} "); + asm("ldmia r2, {r4,r5,r6} "); + asm("ldmia r1, {r1,r2,r3} "); + asm("bl TRealXModulo "); + asm("ldmfd sp!, {r0,r4-r7,lr} "); + asm("stmia r0, {r1,r2,r3} "); + asm("cmp r12, #0 "); // check the error code + asm("cmpne r12, #%a0" : : "i" ((TInt)KErrTotalLossOfPrecision)); + __JUMP(eq,lr); + asm("mov r0, r12 "); + asm("b " CSM_Z30PanicOverUnderflowDividebyZeroi); // else panic + } + + + + +#ifdef __REALS_MACHINE_CODED__ +__NAKED__ EXPORT_C TInt Math::Sqrt( TReal &/*aDest*/, const TReal &/*aSrc*/ ) +/** +Calculates the square root of a number. + +@param aDest A reference containing the result. +@param aSrc The number whose square-root is required. + +@return KErrNone if successful, otherwise another of + the system-wide error codes. +*/ + { + // r0=address of aDest, r1=address of aSrc + + +#ifdef __USE_VFP_MATH + VFP_FLDD(CC_AL,0,1,0); + VFP_FSQRTD(,0,0); + VFP_FMRRD(CC_AL,3,2,0); + asm("bic r1, r2, #0x80000000 "); // remove sign bit + asm("cmn r1, #0x00100000 "); // check if exp=7FF + asm("movpl r1, #0 "); // if not return KErrNone + asm("bpl donesqrt "); + asm("movs r1, r1, lsl #12 "); // if exp=7FF, check mantissa + asm("cmpeq r3, #0 "); + asm("moveq r1, #-9 "); // if exp=7FF, mant=0, return KErrOverflow + asm("mvnne r2, #0x80000000 "); // else set NaN + asm("mvnne r3, #0 "); + asm("movne r1, #-6 "); // and return KErrArgument + asm("donesqrt: "); +#ifdef __DOUBLE_WORDS_SWAPPED__ + asm("stmia r0, {r2,r3} "); // store the result +#else + asm("str r2, [r0, #4] "); + asm("str r3, [r0, #0] "); +#endif + asm("mov r0, r1 "); + __JUMP(,lr); +#else // __USE_VFP_MATH + asm("stmfd sp!, {r4-r10,lr} "); +#ifdef __DOUBLE_WORDS_SWAPPED__ + asm("ldmia r1, {r3,r4} "); // low mant into r4, sign:exp:high mant into r3 +#else + asm("ldr r3, [r1, #4] "); + asm("ldr r4, [r1, #0] "); +#endif + asm("bic r5, r3, #0xFF000000 "); + asm("bic r5, r5, #0x00F00000 "); // high word of mantissa into r5 + asm("mov r2, r3, lsr #20 "); + asm("bics r2, r2, #0x800 "); // exponent now in r2 + asm("beq fastsqrt1 "); // branch if exponent zero (zero or denormal) + asm("mov r6, #0xFF "); + asm("orr r6, r6, #0x700 "); + asm("cmp r2, r6 "); // check for infinity or NaN + asm("beq fastsqrt2 "); // branch if infinity or NaN + asm("movs r3, r3 "); // test sign + asm("bmi fastsqrtn "); // branch if negative + asm("sub r2, r2, #0xFF "); // unbias the exponent + asm("sub r2, r2, #0x300 "); // + asm("fastsqrtd1: "); + asm("mov r1, #0x40000000 "); // value for comparison + asm("mov r3, #27 "); // loop counter (number of bits/2) + asm("movs r2, r2, asr #1 "); // divide exponent by 2, LSB into CF + asm("movcs r7, r5, lsl #11 "); // mantissa into r6,r7 with MSB in MSB of r7 + asm("orrcs r7, r7, r4, lsr #21 "); + asm("movcs r6, r4, lsl #11 "); + asm("movcs r4, #0 "); // r4, r5 will hold result mantissa + asm("orrcs r7, r7, #0x80000000 "); // if exponent odd, restore MSB of mantissa + asm("movcc r7, r5, lsl #12 "); // mantissa into r6,r7 with MSB in MSB of r7 + asm("orrcc r7, r7, r4, lsr #20 "); // if exponent even, shift mantissa left an extra + asm("movcc r6, r4, lsl #12 "); // place, lose top bit, and + asm("movcc r4, #1 "); // set MSB of result, and + asm("mov r5, #0 "); // r4, r5 will hold result mantissa + asm("mov r8, #0 "); // r8, r9 will be comparison accumulator + asm("mov r9, #0 "); + asm("bcc fastsqrt4 "); // if exponent even, calculate one less bit + // as result MSB already known + + // Main mantissa square-root loop + asm("fastsqrt3: "); // START OF MAIN LOOP + asm("subs r10, r7, r1 "); // subtract result:01 from acc:mant + asm("sbcs r12, r8, r4 "); // result into r14:r12:r10 + asm("sbcs r14, r9, r5 "); + asm("movcs r7, r10 "); // if no borrow replace accumulator with result + asm("movcs r8, r12 "); + asm("movcs r9, r14 "); + asm("adcs r4, r4, r4 "); // shift result left one, putting in next bit + asm("adcs r5, r5, r5 "); + asm("mov r9, r9, lsl #2 "); // shift acc:mant left by 2 bits + asm("orr r9, r9, r8, lsr #30 "); + asm("mov r8, r8, lsl #2 "); + asm("orr r8, r8, r7, lsr #30 "); + asm("mov r7, r7, lsl #2 "); + asm("orr r7, r7, r6, lsr #30 "); + asm("mov r6, r6, lsl #2 "); + asm("fastsqrt4: "); // Come in here if we need to do one less iteration + asm("subs r10, r7, r1 "); // subtract result:01 from acc:mant + asm("sbcs r12, r8, r4 "); // result into r14:r12:r10 + asm("sbcs r14, r9, r5 "); + asm("movcs r7, r10 "); // if no borrow replace accumulator with result + asm("movcs r8, r12 "); + asm("movcs r9, r14 "); + asm("adcs r4, r4, r4 "); // shift result left one, putting in next bit + asm("adcs r5, r5, r5 "); + asm("mov r9, r9, lsl #2 "); // shift acc:mant left by 2 bits + asm("orr r9, r9, r8, lsr #30 "); + asm("mov r8, r8, lsl #2 "); + asm("orr r8, r8, r7, lsr #30 "); + asm("mov r7, r7, lsl #2 "); + asm("orr r7, r7, r6, lsr #30 "); + asm("mov r6, r6, lsl #2 "); + asm("subs r3, r3, #1 "); // decrement loop counter + asm("bne fastsqrt3 "); // do necessary number of iterations + + asm("movs r4, r4, lsr #1 "); // shift result mantissa right 1 place + asm("orr r4, r4, r5, lsl #31 "); // LSB (=rounding bit) into carry + asm("mov r5, r5, lsr #1 "); + asm("adcs r4, r4, #0 "); // round the mantissa to 53 bits + asm("adcs r5, r5, #0 "); + asm("cmp r5, #0x00200000 "); // check for mantissa overflow + asm("addeq r2, r2, #1 "); // if so, increment exponent - can never overflow + asm("bic r5, r5, #0x00300000 "); // remove top bit of mantissa - it is implicit + asm("add r2, r2, #0xFF "); // re-bias the exponent + asm("add r3, r2, #0x300 "); // and move into r3 + asm("orr r3, r5, r3, lsl #20 "); // r3 now contains exponent + top of mantissa + asm("fastsqrt_ok: "); +#ifdef __DOUBLE_WORDS_SWAPPED__ + asm("stmia r0, {r3,r4} "); // store the result +#else + asm("str r3, [r0, #4] "); + asm("str r4, [r0, #0] "); +#endif + asm("mov r0, #0 "); // error code KErrNone + __POPRET("r4-r10,"); + + asm("fastsqrt1: "); + asm("orrs r6, r5, r4 "); // exponent zero - test mantissa + asm("beq fastsqrt_ok "); // if zero, return 0 + + asm("movs r3, r3 "); // denormal - test sign + asm("bmi fastsqrtn "); // branch out if negative + asm("sub r2, r2, #0xFE "); // unbias the exponent + asm("sub r2, r2, #0x300 "); // + asm("fastsqrtd: "); + asm("adds r4, r4, r4 "); // shift mantissa left + asm("adcs r5, r5, r5 "); + asm("sub r2, r2, #1 "); // and decrement exponent + asm("tst r5, #0x00100000 "); // test if normalised + asm("beq fastsqrtd "); // loop until normalised + asm("b fastsqrtd1 "); // now treat as a normalised number + asm("fastsqrt2: "); // get here if infinity or NaN + asm("orrs r6, r5, r4 "); // if mantissa zero, infinity + asm("bne fastsqrtnan "); // branch if not - must be NaN + asm("movs r3, r3 "); // test sign of infinity + asm("bmi fastsqrtn "); // branch if -ve +#ifdef __DOUBLE_WORDS_SWAPPED__ + asm("stmia r0, {r3,r4} "); // store the result +#else + asm("str r3, [r0, #4] "); + asm("str r4, [r0, #0] "); +#endif + asm("mov r0, #-9 "); // return KErrOverflow + asm("b fastsqrt_end "); + + asm("fastsqrtn: "); // get here if negative or QNaN operand + asm("mov r3, #0xFF000000 "); // generate "real indefinite" QNaN + asm("orr r3, r3, #0x00F80000 "); // sign=1, exp=7FF, mantissa = 1000...0 + asm("mov r4, #0 "); + asm("fastsqrtxa: "); +#ifdef __DOUBLE_WORDS_SWAPPED__ + asm("stmia r0, {r3,r4} "); // store the result +#else + asm("str r3, [r0, #4] "); + asm("str r4, [r0, #0] "); +#endif + asm("mov r0, #-6 "); // return KErrArgument + asm("fastsqrt_end: "); + __POPRET("r4-r10,"); + + asm("fastsqrtnan: "); // operand is a NaN + asm("tst r5, #0x00080000 "); // test MSB of mantissa + asm("bne fastsqrtn "); // if set it is a QNaN - so return "real indefinite" + asm("bic r3, r3, #0x00080000 "); // else convert SNaN to QNaN + asm("b fastsqrtxa "); // and return KErrArgument +#endif // __USE_VFP_MATH + } + + + + +__NAKED__ EXPORT_C TReal Math::Poly(TReal /*aX*/,const SPoly* /*aPoly*/) __SOFTFP +/** +Evaluates the polynomial: +{a[n]X^n + a[n-1]X^(n-1) + ... + a[2]X^2 + a[1]X^1 + a[0]}. + + +@param aX The value of the x-variable +@param aPoly A pointer to the structure containing the set of coefficients + in the order: a[0], a[1], ..., a[n-1], a[n]. + +@return The result of the evaluation. +*/ +// +// Evaluate a power series in x for a P_POLY coefficient table. +// Changed to use TRealX throughout the calculation +// + { + // On entry r0,r1=aX, r2=aPoly + asm("stmfd sp!, {r4-r11,lr} "); + asm("mov r11, r2 "); + asm("ldr r10, [r11], #4 "); // r10=number of coefficients, r11=first coeff addr + asm("add r11, r11, r10, lsl #3 "); // r11=address of last coefficient+8 + asm("mov r2, r1 "); // aX into r1,r2 + asm("mov r1, r0 "); + asm("bl ConvertTReal64ToTRealX "); // convert to TRealX in r1,r2,r3 + asm("mov r4, r1 "); // move into r4,r5,r6 + asm("mov r5, r2 "); + asm("mov r6, r3 "); + asm("ldmdb r11!, {r1,r2} "); // last coefficient into r1,r2 + asm("bl ConvertTReal64ToTRealX "); // convert to TRealX in r1,r2,r3 + asm("subs r10, r10, #1 "); + asm("beq polynomial0 "); // if no more coefficients, exit + + asm("polynomial1: "); + asm("stmfd sp!, {r4,r5,r6} "); // save value of aX + asm("bl TRealXMultiply "); // r *= aX + asm("mov r4, r1 "); // move result into r4,r5,r6 + asm("mov r5, r2 "); + asm("mov r6, r3 "); + asm("ldmdb r11!, {r1,r2} "); // next coefficient into r1,r2 + asm("bl ConvertTReal64ToTRealX "); // convert to TRealX in r1,r2,r3 + asm("bl TRealXAdd "); // r += *--pR + asm("ldmfd sp!, {r4,r5,r6} "); // aX back into r4,r5,r6 + asm("subs r10, r10, #1 "); // iterate until all coefficients processed + asm("bne polynomial1 "); + + asm("polynomial0: "); // result now in r1,r2,r3 + asm("bl ConvertTRealXToTReal64 "); // convert back to TReal64 + __POPRET("r4-r11,"); + } + + + + +__NAKED__ EXPORT_C void Math::PolyX(TRealX& /*aY*/,const TRealX& /*aX*/,TInt /*aDeg*/,const TRealX* /*aCoef*/) +/** +Evaluates the polynomial: +{a[n]X^n + a[n-1]X^(n-1) + ... + a[2]X^2 + a[1]X^1 + a[0]}. + +@param aY A reference containing the result. +@param aX The value of the x-variable. +@param aDeg The degree of the polynomial (the highest power of x + which is present). +@param aCoef A pointer to a contiguous set of TRealX values containing + the coefficients. + They must be in the order: a[0], a[1], ..., a[n-1], a[n]. +*/ +// +// Evaluate a polynomial with TRealX argument, coefficients and result +// + { + // On entry r0=&aY, r1=&aX, r2=aDeg, r3=aCoef + asm("stmfd sp!, {r0,r4-r11,lr} "); + asm("add r11, r3, r2, lsl #3 "); // r11=address of last coefficient + asm("add r11, r11, r2, lsl #2 "); + asm("mov r9, r1 "); // r9=address of argument + asm("movs r10, r2 "); // r10=number of coefficients-1 + asm("ldmia r11, {r1,r2,r3} "); // last coefficient into r1,r2,r3 + asm("beq polyx0 "); // if no more coefficients, exit + + asm("polyx1: "); + asm("ldmia r9, {r4,r5,r6} "); // aX into r4,r5,r6 + asm("bl TRealXMultiply "); // result *= aX + asm("ldmdb r11!, {r4,r5,r6} "); // next coefficient into r4,r5,r6 + asm("bl TRealXAdd "); // result += next coeff + asm("subs r10, r10, #1 "); // iterate until all coefficients processed + asm("bne polyx1 "); + + asm("polyx0: "); // result now in r1,r2,r3 + asm("ldmfd sp!, {r0,r4-r11,lr} "); // restore registers, including destination address in r0 + asm("stmia r0, {r1,r2,r3} "); // store result + __JUMP(,lr); + } + + + + +#ifndef __USE_VFP_MATH +__NAKED__ EXPORT_C TInt Math::Int(TReal& /*aTrg*/, const TReal& /*aSrc*/) +/** +Calculates the integer part of a number. + +The integer part is that before a decimal point. +Truncation is toward zero, so that +int(2.4)=2, int(2)=2, int(-1)=-1, int(-1.4)=-1, int(-1.999)=-1. + + +@param aTrg A reference containing the result. +@param aSrc The number whose integer part is required. + +@return KErrNone if successful, otherwise another of + the system-wide error codes. +*/ +// +// Write the integer part of aSrc to the TReal at aTrg +// Negative numbers are rounded towards zero. +// + { + // r0=&aTrg, r1=&aSrc, return value in r0 + asm("stmfd sp!, {lr} "); + asm("mov r12, r0 "); // r12=&aTrg +#ifdef __DOUBLE_WORDS_SWAPPED__ + asm("ldmia r1, {r0,r1} "); // input value into r0,r1 +#else + asm("ldr r0, [r1, #4] "); + asm("ldr r1, [r1, #0] "); +#endif + asm("bl TReal64Int "); +#ifdef __DOUBLE_WORDS_SWAPPED__ + asm("stmia r12, {r0,r1} "); // store result +#else + asm("str r0, [r12, #4] "); + asm("str r1, [r12, #0] "); +#endif + asm("bic r0, r0, #0x80000000 "); // remove sign bit + asm("cmn r0, #0x00100000 "); // check for NaN or infinity + asm("movpl r0, #0 "); // if neither, return KErrNone + asm("bpl math_int_0 "); + asm("movs r0, r0, lsl #12 "); // check for infinity + asm("cmpeq r1, #0 "); + asm("mvneq r0, #8 "); // if infinity return KErrOverflow + asm("mvnne r0, #5 "); // else return KErrArgument + asm("math_int_0: "); + __POPRET(""); + + // Take integer part of TReal64 in r0,r1 + // Infinity and NaNs are unaffected + // r0-r3 modified + asm("TReal64Int: "); + asm("mov r2, r0, lsr #20 "); + asm("bic r2, r2, #0x800 "); // r2=exponent + asm("mov r3, #0x300 "); + asm("orr r3, r3, #0xFF "); // r3=0x3FF + asm("subs r2, r2, r3 "); // r2=exponent-3FF=number of integer bits-1 + asm("ble TReal64Int1 "); // branch if <=1 integer bits + asm("cmp r2, #52 "); + __JUMP(ge,lr); + asm("cmp r2, #20 "); + asm("bgt TReal64Int2 "); // jump if >21 integer bits (r0 will be unaffected) + asm("rsb r2, r2, #20 "); // r2=number of bits to clear at bottom end of r0 + asm("mov r0, r0, lsr r2 "); // clear them + asm("mov r0, r0, lsl r2 "); + asm("mov r1, #0 "); // clear r1 + __JUMP(,lr); + asm("TReal64Int2: "); + asm("rsb r2, r2, #52 "); // r2=number of bits to clear at bottom end of r1 + asm("mov r1, r1, lsr r2 "); // clear them + asm("mov r1, r1, lsl r2 "); + __JUMP(,lr); + asm("TReal64Int1: "); // result is either 0 or 1 + asm("mov r1, #0 "); // lower mantissa bits of result will be zero + asm("moveq r0, r0, lsr #20 "); // if result is 1, clear mantissa but leave exponent + asm("moveq r0, r0, lsl #20 "); + asm("andlt r0, r0, #0x80000000 "); // if result is 0, clear mantissa and exponent + __JUMP(,lr); + } + + + + +__NAKED__ EXPORT_C TInt Math::Int(TInt16& /*aTrg*/, const TReal& /*aSrc*/) +/** +Calculates the integer part of a number. + +The integer part is that before a decimal point. +Truncation is toward zero, so that: +int(2.4)=2, int(2)=2, int(-1)=-1, int(-1.4)=-1, int(-1.999)=-1. + +This function is suitable when the result is known to be small enough +for a 16-bit signed integer. + +@param aTrg A reference containing the result. +@param aSrc The number whose integer part is required. + +@return KErrNone if successful, otherwise another of + the system-wide error codes. +*/ +// +// If the integer part of aSrc is in the range -32768 to +32767 +// inclusive, write the integer part to the TInt16 at aTrg +// Negative numbers are rounded towards zero. +// If an overflow or underflow occurs, aTrg is set to the max/min value +// + { + // r0=&aTrg, r1=&aSrc + asm("stmfd sp!, {lr} "); + asm("mov r3, r0 "); // r3=&aTrg +#ifdef __DOUBLE_WORDS_SWAPPED__ + asm("ldmia r1, {r0,r1} "); // input value into r0,r1 +#else + asm("ldr r0, [r1, #4] "); + asm("ldr r1, [r1, #0] "); +#endif + asm("bl TReal64GetTInt "); // do the conversion + asm("cmp r0, #0x8000 "); // limit answer to TInt16 range + asm("movge r0, #0x7F00 "); + asm("orrge r0, r0, #0xFF "); + asm("mvnge r12, #8 "); // set error code if limiting occurred + asm("cmn r0, #0x8000 "); + asm("movlt r0, #0x8000 "); + asm("mvnlt r12, #9 "); // set error code if limiting occurred + asm("mov r1, r0, lsr #8 "); // top byte of answer into r1 + asm("strb r0, [r3] "); // store result in aTrg + asm("strb r1, [r3, #1] "); + asm("mov r0, r12 "); // return error code in r0 + __POPRET(""); + } + + + +__NAKED__ EXPORT_C TInt Math::Int(TInt32& /*aTrg*/, const TReal& /*aSrc*/) +/** +Calculates the integer part of a number. + +The integer part is that before a decimal point. +Truncation is toward zero, so that +int(2.4)=2, int(2)=2, int(-1)=-1, int(-1.4)=-1, int(-1.999)=-1. + +This function is suitable when the result is known to be small enough +for a 32-bit signed integer. + +@param aTrg A reference containing the result. +@param aSrc The number whose integer part is required. + +@return KErrNone if successful, otherwise another of + the system-wide error codes. +*/ +// +// If the integer part of the float is in the range -2147483648 to +2147483647 +// inclusive, write the integer part to the TInt32 at aTrg +// Negative numbers are rounded towards zero. +// If an overflow or underflow occurs, aTrg is set to the max/min value +// + { + // r0=&aTrg, r1=&aSrc + asm("stmfd sp!, {lr} "); + asm("mov r3, r0 "); // r3=&aTrg +#ifdef __DOUBLE_WORDS_SWAPPED__ + asm("ldmia r1, {r0,r1} "); // input value into r0,r1 +#else + asm("ldr r0, [r1, #4] "); + asm("ldr r1, [r1, #0] "); +#endif + asm("bl TReal64GetTInt "); // do the conversion + asm("str r0, [r3] "); // store result in aTrg + asm("mov r0, r12 "); // return error code in r0 + __POPRET(""); + + // Convert double in r0,r1 to int in r0 + // Return error code in r12 + // Registers r0,r1,r2,r12 modified + asm("TReal64GetTInt: "); + asm("mov r2, r0, lsr #20 "); + asm("bic r2, r2, #0x800 "); // r1=exponent + asm("add r12, r2, #1 "); + asm("cmp r12, #0x800 "); // check for NaN + asm("bne TReal64GetTInt1 "); + asm("movs r12, r0, lsl #12 "); // exponent=FF, check mantissa + asm("cmpeq r1, #0 "); + asm("movne r0, #0 "); // if non-zero, input is a NaN so return 0 + asm("mvnne r12, #5 "); // and return KErrArgument + __JUMP(ne,lr); + asm("TReal64GetTInt1: "); + asm("mov r12, #0x400 "); + asm("orr r12, r12, #0x1E "); // r12=0x41E (exponent of 2^31) + asm("subs r2, r12, r2 "); // r2=number of shifts to produce integer + asm("mov r12, #0 "); // set return code to KErrNone + asm("ble TReal64GetTInt2 "); // if <=0, saturate result + asm("cmp r2, #31 "); // check if more than 31 shifts needed + asm("movhi r0, #0 "); // if so, underflow result to 0 + __JUMP(hi,lr); + asm("cmp r0, #0 "); // check sign bit + asm("orr r0, r0, #0x00100000 "); // set implicit integer bit + asm("mov r0, r0, lsl #11 "); // shift mantissa up so MSB is in MSB of r0 + asm("orr r0, r0, r1, lsr #21 "); // put in bits from r1 + asm("mov r0, r0, lsr r2 "); // r0=absolute integer + asm("rsbmi r0, r0, #0 "); // if negative, negate + __JUMP(,lr); + asm("TReal64GetTInt2: "); + asm("blt TReal64GetTInt3 "); // if exponent>0x41E, definitely an overflow + asm("cmp r0, #0 "); // check sign bit + asm("bpl TReal64GetTInt3 "); // if positive, definitely an overflow + asm("orr r0, r0, #0x00100000 "); // set implicit integer bit + asm("mov r0, r0, lsl #11 "); // shift mantissa up so MSB is in MSB of r0 + asm("orr r0, r0, r1, lsr #21 "); // put in bits from r1 + asm("cmp r0, #0x80000000 "); // check if value is = -2^31 + __JUMP(eq,lr); + asm("TReal64GetTInt3: "); + asm("cmp r0, #0 "); // check sign + asm("mov r0, #0x80000000 "); + asm("subpl r0, r0, #1 "); // if -ve return 80000000, if +ve return 7FFFFFFF + asm("mvnpl r12, #8 "); // if +ve return KErrOverflow + asm("mvnmi r12, #9 "); // if -ve return KErrUnderflow + __JUMP(,lr); + } +#endif // __USE_VFP_MATH + + + + +__NAKED__ EXPORT_C TBool Math::IsZero(const TReal& /*aVal*/) +/** +Determines whether a value is zero. + +@param aVal A reference to the value to be checked. + +@return True, if aVal is zero; false, otherwise. +*/ + { +#ifdef __DOUBLE_WORDS_SWAPPED__ + asm("ldmia r0, {r1,r2} "); // input value into r0,r1 +#else + asm("ldr r2, [r0, #0] "); + asm("ldr r1, [r0, #4] "); +#endif + asm("TReal64IsZero: "); + asm("mov r0, #0 "); // default return value is 0 + asm("bics r1, r1, #0x80000000 "); // remove sign bit + asm("cmpeq r2, #0 "); // and check both exponent and mantissa are zero + asm("moveq r0, #1 "); // return 1 if zero + __JUMP(,lr); + } + + + + +__NAKED__ EXPORT_C TBool Math::IsNaN(const TReal& /*aVal*/) +/** +Determines whether a value is not a number. + +@param aVal A reference to the value to be checked. + +@return True, if aVal is not a number; false, otherwise. +*/ + { +#ifdef __DOUBLE_WORDS_SWAPPED__ + asm("ldmia r0, {r1,r2} "); // input value into r0,r1 +#else + asm("ldr r2, [r0, #0] "); + asm("ldr r1, [r0, #4] "); +#endif + asm("TReal64IsNaN: "); + asm("mov r0, #0 "); // default return value is 0 + asm("bic r1, r1, #0x80000000 "); // remove sign bit + asm("cmn r1, #0x00100000 "); // check if exponent=7FF + __JUMP(pl,lr); + asm("movs r1, r1, lsl #12 "); // exponent=7FF, check mantissa + asm("cmpeq r2, #0 "); + asm("movne r0, #1 "); // if mantissa nonzero, return 1 + __JUMP(,lr); + } + + + + +__NAKED__ EXPORT_C TBool Math::IsInfinite(const TReal& /*aVal*/) +/** +Determines whether a value is infinite. + +@param aVal A reference to the value to be checked. + +@return True, if aVal is infinite; false, otherwise. +*/ + { +#ifdef __DOUBLE_WORDS_SWAPPED__ + asm("ldmia r0, {r1,r2} "); // input value into r0,r1 +#else + asm("ldr r2, [r0, #0] "); + asm("ldr r1, [r0, #4] "); +#endif + asm("TReal64IsInfinite: "); + asm("mov r0, #0 "); // default return value is 0 + asm("mov r3, #0x00200000 "); // r3 == - (0x7ff00000 << 1) + asm("cmp r2, #0 "); + asm("cmneq r3, r1, lsl #1 "); // check exp=7FF && mant=0 + asm("moveq r0, #1 "); // if so, return 1 + __JUMP(,lr); + } + + + + +__NAKED__ EXPORT_C TBool Math::IsFinite(const TReal& /*aVal*/) +/** +Determines whether a value is finite. + +In this context, a value is finite if it is a valid number and +is not infinite. + +@param aVal A reference to the value to be checked. + +@return True, if aVal is finite; false, otherwise. +*/ + { +#ifdef __DOUBLE_WORDS_SWAPPED__ + asm("ldr r1, [r0, #0] "); // only need exponent - get it into r0 +#else + asm("ldr r1, [r0, #4] "); // only need exponent - get it into r0 +#endif + asm("TReal64IsFinite: "); + asm("mov r0, #0 "); // default return value is 0 + asm("bic r1, r1, #0x80000000 "); // remove sign bit + asm("cmn r1, #0x00100000 "); // check if exponent=7FF + asm("movpl r0, #1 "); // else return 1 + __JUMP(,lr); + } + + + + +__NAKED__ EXPORT_C void Math::SetZero(TReal& /*aVal*/, TInt /*aSign*/) +// +// Constructs zeros, assuming default sign is positive +// + { + asm("cmp r1, #0 "); // test aSign + asm("movne r1, #0x80000000 "); // if nonzero, set sign bit + asm("mov r2, #0 "); // mantissa=0 +#ifdef __DOUBLE_WORDS_SWAPPED__ + asm("stmia r0, {r1,r2} "); +#else + asm("str r2, [r0, #0] "); + asm("str r1, [r0, #4] "); +#endif + __JUMP(,lr); + } + + + + +__NAKED__ EXPORT_C void Math::SetNaN(TReal& /*aVal*/) +// +// Constructs NaN (+ve sign for Java) +// + { +#ifdef __DOUBLE_WORDS_SWAPPED__ + asm("mvn r1, #0x80000000 "); // r1=7FFFFFFF + asm("mvn r2, #0 "); // r2=FFFFFFFF +#else + asm("mvn r2, #0x80000000 "); // r2=7FFFFFFF + asm("mvn r1, #0 "); // r1=FFFFFFFF +#endif + asm("stmia r0, {r1,r2} "); + __JUMP(,lr); + } + + + + +__NAKED__ EXPORT_C void Math::SetInfinite(TReal& /*aVal*/, TInt /*aSign*/) +// +// Constructs infinities +// + { + asm("cmp r1, #0 "); // test aSign + asm("movne r1, #0x80000000 "); // if nonzero, set sign bit + asm("orr r1, r1, #0x70000000 "); // set exponent to 7FF + asm("orr r1, r1, #0x0FF00000 "); + asm("mov r2, #0 "); // mantissa=0 +#ifdef __DOUBLE_WORDS_SWAPPED__ + asm("stmia r0, {r1,r2} "); +#else + asm("str r2, [r0, #0] "); + asm("str r1, [r0, #4] "); +#endif + __JUMP(,lr); + } + + + +#ifndef __USE_VFP_MATH +__NAKED__ EXPORT_C TInt Math::Frac(TReal& /*aTrg*/, const TReal& /*aSrc*/) +/** +Calculates the fractional part of a number. + +The fractional part is that after a decimal point. +Truncation is toward zero, so that +Frac(2.4)=0.4, Frac(2)=0, Frac(-1)=0, Frac(-1.4)=0.4. + +@param aTrg A reference containing the result. +@param aSrc The number whose fractional part is required. + +@return KErrNone if successful, otherwise another of + the system-wide error codes. +*/ + { + // on entry r0=aTrg, r1=&Src + // on exit r0=return code +#ifdef __DOUBLE_WORDS_SWAPPED__ + asm("ldmia r1, {r1,r2} "); // r1,r2=aSrc +#else + asm("ldr r2, [r1, #0] "); + asm("ldr r1, [r1, #4] "); +#endif + asm("and r3, r1, #0x80000000 "); + asm("str r3, [sp, #-4]! "); // save sign + asm("mov r3, r1, lsr #20 "); + asm("bic r3, r3, #0x800 "); // r3=exponent of aSrc + asm("mov r12, #0x300 "); + asm("orr r12, r12, #0xFE "); // r12=0x3FE + asm("subs r3, r3, r12 "); // r3=exponent of aSrc-0x3FE=number of integer bits + asm("ble MathFrac0 "); // if <=0, return aSrc unaltered + asm("cmp r3, #53 "); + asm("bge MathFrac1 "); // if >=53 integer bits, there is no fractional part + asm("mov r1, r1, lsl #11 "); // left-justify mantissa in r1,r2 + asm("orr r1, r1, r2, lsr #21 "); + asm("mov r2, r2, lsl #11 "); + asm("cmp r3, #32 "); // check for >=32 integer bits + asm("bge MathFrac2 "); + asm("rsb r12, r3, #32 "); + asm("mov r1, r1, lsl r3 "); // shift mantissa left by number of integer bits + asm("orrs r1, r1, r2, lsr r12 "); + asm("mov r2, r2, lsl r3 "); + asm("mov r3, #0x300 "); // r3 holds exponent = 0x3FE initially + asm("orr r3, r3, #0xFE "); + asm("beq MathFrac3 "); // branch if >=32 shifts to normalise +#ifdef __CPU_ARM_HAS_CLZ + CLZ(12,1); + asm("mov r1, r1, lsl r12 "); + asm("rsb r12, r12, #32 "); + asm("orr r1, r1, r2, lsr r12 "); + asm("rsb r12, r12, #32 "); +#else + asm("mov r12, #32 "); // else r12=32-number of shifts needed + asm("cmp r1, #0x10000 "); // calculate shift count + asm("movcc r1, r1, lsl #16 "); + asm("subcc r12, r12, #16 "); + asm("cmp r1, #0x1000000 "); + asm("movcc r1, r1, lsl #8 "); + asm("subcc r12, r12, #8 "); + asm("cmp r1, #0x10000000 "); + asm("movcc r1, r1, lsl #4 "); + asm("subcc r12, r12, #4 "); + asm("cmp r1, #0x40000000 "); + asm("movcc r1, r1, lsl #2 "); + asm("subcc r12, r12, #2 "); + asm("cmp r1, #0x80000000 "); + asm("movcc r1, r1, lsl #1 "); + asm("subcc r12, r12, #1 "); + asm("orr r1, r1, r2, lsr r12 "); // normalise + asm("rsb r12, r12, #32 "); // r12=shift count +#endif + asm("mov r2, r2, lsl r12 "); + asm("sub r3, r3, r12 "); // exponent-=shift count + asm("b MathFrac4 "); // branch to assemble and store result + + // come here if >=32 shifts to normalise + asm("MathFrac3: "); + asm("sub r3, r3, #32 "); // decrement exponent by 32 + asm("movs r1, r2 "); // shift left by 32, set Z if result zero + asm("mov r2, #0 "); + asm("bne MathFrac6 "); // if result nonzero, normalise + asm("beq MathFrac5 "); // branch if result zero + + // come here if >=32 integer bits + asm("MathFrac2: "); + asm("sub r3, r3, #32 "); + asm("movs r1, r2, lsl r3 "); // shift left by number of integer bits, set Z if result zero + asm("mov r2, #0 "); + asm("mov r3, #0x300 "); // r3 holds exponent = 0x3FE initially + asm("orr r3, r3, #0xFE "); + asm("beq MathFrac5 "); // branch if result zero + asm("MathFrac6: "); + asm("cmp r1, #0x10000 "); // else normalise + asm("movcc r1, r1, lsl #16 "); + asm("subcc r3, r3, #16 "); + asm("cmp r1, #0x1000000 "); + asm("movcc r1, r1, lsl #8 "); + asm("subcc r3, r3, #8 "); + asm("cmp r1, #0x10000000 "); + asm("movcc r1, r1, lsl #4 "); + asm("subcc r3, r3, #4 "); + asm("cmp r1, #0x40000000 "); + asm("movcc r1, r1, lsl #2 "); + asm("subcc r3, r3, #2 "); + asm("cmp r1, #0x80000000 "); + asm("movcc r1, r1, lsl #1 "); + asm("subcc r3, r3, #1 "); + + // come here to assemble and store result + asm("MathFrac4: "); + asm("bic r1, r1, #0x80000000 "); // remove integer bit + asm("mov r2, r2, lsr #11 "); // shift mantissa right by 11 + asm("orr r2, r2, r1, lsl #21 "); + asm("mov r1, r1, lsr #11 "); + asm("ldr r12, [sp] "); + asm("orr r1, r1, r3, lsl #20 "); // exponent into r1 bits 20-30 + asm("orr r1, r1, r12 "); // sign bit into r1 bit 31 + + // come here to return source unaltered + asm("MathFrac0: "); + asm("add sp, sp, #4 "); + asm("MathFrac_ok: "); +#ifdef __DOUBLE_WORDS_SWAPPED__ + asm("stmia r0, {r1,r2} "); // store result +#else + asm("str r2, [r0, #0] "); + asm("str r1, [r0, #4] "); +#endif + asm("mov r0, #0 "); // return KErrNone + __JUMP(,lr); + + // come here if infinity, NaN or >=53 integer bits + asm("MathFrac1: "); + asm("cmp r3, #0x400 "); // check for infinity/NaN + asm("bhi MathFrac7 "); // branch if so + + // come here to return zero + asm("MathFrac5: "); + asm("ldr r1, [sp], #4 "); // r1 bit 31=sign, rest zero + asm("mov r2, #0 "); + asm("b MathFrac_ok "); + + // come here if infinity/NaN + asm("MathFrac7: "); + asm("movs r12, r1, lsl #12 "); // check for infinity + asm("cmpeq r2, #0 "); + asm("bne MathFrac8 "); // branch if NaN + asm("ldr r1, [sp], #4 "); // r1 bit 31=sign, rest zero + asm("mov r2, #0 "); +#ifdef __DOUBLE_WORDS_SWAPPED__ + asm("stmia r0, {r1,r2} "); // store zero result +#else + asm("str r2, [r0, #0] "); + asm("str r1, [r0, #4] "); +#endif + asm("mvn r0, #8 "); // return KErrOverflow + __JUMP(,lr); + asm("MathFrac8: "); // NaN + asm("add sp, sp, #4 "); +#ifdef __DOUBLE_WORDS_SWAPPED__ + asm("stmia r0, {r1,r2} "); // store NaN unchanged +#else + asm("str r2, [r0, #0] "); + asm("str r1, [r0, #4] "); +#endif + asm("mvn r0, #5 "); // return KErrArgument + __JUMP(,lr); + } +#endif // __USE_VFP_MATH +#endif + +#ifdef __REALS_MACHINE_CODED__ +#ifndef __ARMCC__ +extern "C" { + +extern "C" void __math_exception(TInt aErrType); +__NAKED__ EXPORT_C TReal32 __addsf3(TReal32 /*a1*/, TReal32 /*a2*/) +// +// Add two floats +// + { + // a1 is in r0, a2 in r1 on entry; return with answer in r0 + asm("stmfd sp!, {r4-r8,lr} "); + asm("bl ConvertTReal32ToTRealX "); // convert a2 to TRealX in r1,r2,r3 + asm("mov r4, r1 "); // move into r4,r5,r6 + asm("mov r5, r2 "); + asm("mov r6, r3 "); + asm("mov r1, r0 "); // a1 into r1 + asm("bl ConvertTReal32ToTRealX "); // convert a1 to TRealX in r1,r2,r3 + asm("bl TRealXAdd "); // add a1+a2, result in r1,r2,r3 + asm("bl TRealXGetTReal32 "); // convert result to TReal32 in r0, error code in r12 + asm("cmp r12, #0 "); // check error code + __CPOPRET(eq,"r4-r8,"); + asm("stmfd sp!, {r0} "); // save result + asm("mov r0, r12 "); // error code into r0 + asm("bl __math_exception "); // raise exception + __POPRET("r0,r4-r8,"); + } + +__NAKED__ EXPORT_C TReal64 __adddf3(TReal64 /*a1*/, TReal64 /*a2*/) +// +// Add two doubles +// + { + // a1 is in r0,r1 a2 in r2,r3 on entry; return with answer in r0,r1 + asm("stmfd sp!, {r4-r8,lr} "); + asm("mov r7, r2 "); // save a2 + asm("mov r8, r3 "); + asm("mov r2, r1 "); // a1 into r1,r2 + asm("mov r1, r0 "); + asm("bl ConvertTReal64ToTRealX "); // convert a1 to TRealX in r1,r2,r3 + asm("mov r4, r1 "); // move into r4,r5,r6 + asm("mov r5, r2 "); + asm("mov r6, r3 "); + asm("mov r1, r7 "); // a2 into r1,r2 + asm("mov r2, r8 "); + asm("bl ConvertTReal64ToTRealX "); // convert a2 to TRealX in r1,r2,r3 + asm("bl TRealXAdd "); // add a1+a2, result in r1,r2,r3 + asm("bl TRealXGetTReal64 "); // convert result to TReal64 in r0,r1 error code in r12 + asm("cmp r12, #0 "); // check error code + __CPOPRET(eq,"r4-r8,"); + asm("stmfd sp!, {r0,r1} "); // save result + asm("mov r0, r12 "); // error code into r0 + asm("bl __math_exception "); // raise exception + __POPRET("r0,r1,r4-r8,"); + } + +__NAKED__ EXPORT_C TReal32 __subsf3(TReal32 /*a1*/, TReal32 /*a2*/) +// +// Subtract two floats +// + { + // a1 is in r0, a2 in r1 on entry; return with answer in r0 + asm("stmfd sp!, {r4-r8,lr} "); + asm("bl ConvertTReal32ToTRealX "); // convert a2 to TRealX in r1,r2,r3 + asm("mov r4, r1 "); // move into r4,r5,r6 + asm("mov r5, r2 "); + asm("mov r6, r3 "); + asm("mov r1, r0 "); // a1 into r1 + asm("bl ConvertTReal32ToTRealX "); // convert a1 to TRealX in r1,r2,r3 + asm("bl TRealXSubtract "); // subtract a1-a2, result in r1,r2,r3 + asm("bl TRealXGetTReal32 "); // convert result to TReal32 in r0, error code in r12 + asm("cmp r12, #0 "); // check error code + __CPOPRET(eq,"r4-r8,"); + asm("stmfd sp!, {r0} "); // save result + asm("mov r0, r12 "); // error code into r0 + asm("bl __math_exception "); // raise exception + __POPRET("r0,r4-r8,"); + } + +__NAKED__ EXPORT_C TReal64 __subdf3(TReal64 /*a1*/, TReal64 /*a2*/) +// +// Subtract two doubles +// + { + // a1 is in r0,r1 a2 in r2,r3 on entry; return with answer in r0,r1 + asm("stmfd sp!, {r4-r8,lr} "); + asm("mov r7, r0 "); // save a1 + asm("mov r8, r1 "); + asm("mov r1, r2 "); // a2 into r1,r2 + asm("mov r2, r3 "); + asm("bl ConvertTReal64ToTRealX "); // convert a2 to TRealX in r1,r2,r3 + asm("mov r4, r1 "); // move into r4,r5,r6 + asm("mov r5, r2 "); + asm("mov r6, r3 "); + asm("mov r1, r7 "); // a1 into r1,r2 + asm("mov r2, r8 "); + asm("bl ConvertTReal64ToTRealX "); // convert a1 to TRealX in r1,r2,r3 + asm("bl TRealXSubtract "); // subtract a1-a2, result in r1,r2,r3 + asm("bl TRealXGetTReal64 "); // convert result to TReal64 in r0,r1 error code in r12 + asm("cmp r12, #0 "); // check error code + __CPOPRET(eq,"r4-r8,"); + asm("stmfd sp!, {r0,r1} "); // save result + asm("mov r0, r12 "); // error code into r0 + asm("bl __math_exception "); // raise exception + __POPRET("r0,r1,r4-r8,"); + } + +__NAKED__ EXPORT_C TInt __cmpsf3(TReal32 /*a1*/, TReal32 /*a2*/) +// +// Compare two floats +// + { + // a1 in r0, a2 in r1 on entry + asm("stmfd sp!, {lr} "); + asm("bl CompareTReal32 "); // compare the two numbers + asm("mov r0, r0, lsl #28 "); + asm("msr cpsr_flg, r0 "); // N=unordered, Z=(a1>a2), C=(a1=a2), V=(a1a2 r0=+1 + __POPRET(""); + + // Compare two TReal32s in r0, r1. + // Return 1 if r0r1, 8 if unordered + // Registers r0,r1,r12 modified + asm("CompareTReal32: "); + asm("mov r12, r0, lsr #23 "); + asm("and r12, r12, #0xFF "); // r12=r0 exponent + asm("cmp r12, #0xFF "); // check if r0 is a NaN + asm("bne CompareTReal32a "); + asm("movs r12, r0, lsl #9 "); // exponent=FF, check mantissa + asm("movne r0, #8 "); // if not zero, r0 is a NaN so result is unordered + __JUMP(ne,lr); + asm("CompareTReal32a: "); + asm("mov r12, r1, lsr #23 "); + asm("and r12, r12, #0xFF "); // r12=r1 exponent + asm("cmp r12, #0xFF "); // check if r1 is a NaN + asm("bne CompareTReal32b "); + asm("movs r12, r1, lsl #9 "); // exponent=FF, check mantissa + asm("movne r0, #8 "); // if not zero, r1 is a NaN so result is unordered + __JUMP(ne,lr); + asm("CompareTReal32b: "); + asm("bics r12, r0, #0x80000000 "); // check if r0=0 (can be +0 or -0) + asm("moveq r0, #0 "); // if it is, make it +0 + asm("bics r12, r1, #0x80000000 "); // check if r1=0 (can be +0 or -0) + asm("moveq r1, #0 "); // if it is, make it +0 + asm("teq r0, r1 "); // test if signs different + asm("bmi CompareTReal32c "); // branch if different + asm("cmp r0, r1 "); // if same, check exponents + mantissas + asm("moveq r0, #2 "); // if equal, return 2 + __JUMP(eq,lr); + asm("movhi r0, #4 "); // if r0>r1, r0=4 + asm("movcc r0, #1 "); // if r0a2), C=(a1=a2), V=(a1a2 r0=+1 + __POPRET(""); + + // Compare two TReal64s in r0,r1 and r2,r3. + // Return 1 if r0,r1r2,r3 + // Return 8 if unordered + // Registers r0,r1,r12 modified + asm("CompareTReal64: "); +#ifndef __DOUBLE_WORDS_SWAPPED__ + asm("mov r12, r0 "); + asm("mov r0, r1 "); + asm("mov r1, r12 "); + asm("mov r12, r2 "); + asm("mov r2, r3 "); + asm("mov r3, r12 "); +#endif + asm("mov r12, r0, lsr #20 "); + asm("bic r12, r12, #0x800 "); // r12=first operand exponent + asm("add r12, r12, #1 "); // add 1 to get usable compare value + asm("cmp r12, #0x800 "); // check if first operand is a NaN + asm("bne CompareTReal64a "); + asm("movs r12, r0, lsl #12 "); // exponent=7FF, check mantissa + asm("cmpeq r1, #0 "); + asm("movne r0, #8 "); // if not zero, 1st op is a NaN so result is unordered + __JUMP(ne,lr); + asm("CompareTReal64a: "); + asm("mov r12, r2, lsr #20 "); + asm("bic r12, r12, #0x800 "); // r12=second operand exponent + asm("add r12, r12, #1 "); // add 1 to get usable compare value + asm("cmp r12, #0x800 "); // check if second operand is a NaN + asm("bne CompareTReal64b "); + asm("movs r12, r2, lsl #12 "); // exponent=7FF, check mantissa + asm("cmpeq r3, #0 "); + asm("movne r0, #8 "); // if not zero, 2nd op is a NaN so result is unordered + __JUMP(ne,lr); + asm("CompareTReal64b: "); + asm("bics r12, r0, #0x80000000 "); // check if first operand is zero (can be +0 or -0) + asm("cmpeq r1, #0 "); + asm("moveq r0, #0 "); // if it is, make it +0 + asm("bics r12, r2, #0x80000000 "); // check if second operand is zero (can be +0 or -0) + asm("cmpeq r3, #0 "); + asm("moveq r2, #0 "); // if it is, make it +0 + asm("teq r0, r2 "); // test if signs different + asm("bmi CompareTReal64c "); // branch if different + asm("cmp r0, r2 "); // if same, check exponents + mantissas + asm("cmpeq r1, r3 "); + asm("moveq r0, #2 "); // if equal, return 2 + __JUMP(eq,lr); + asm("movhi r0, #4 "); // if 1st operand > 2nd operand, r0=4 + asm("movcc r0, #1 "); // if 1st operand < 2nd operand, r0=1 + asm("cmp r2, #0 "); // check signs + asm("eormi r0, r0, #5 "); // if negative, switch 1 and 4 + __JUMP(,lr); + asm("CompareTReal64c: "); // come here if signs different + asm("cmp r0, #0 "); // check sign of r0 + asm("movpl r0, #4 "); // if first operand nonnegative, return 4 + asm("movmi r0, #1 "); // if first operand negative, return 1 + __JUMP(,lr); + } + +__NAKED__ EXPORT_C TInt __eqsf2(TReal32 /*a1*/, TReal32 /*a2*/) +// +// Compare if two floats are equal +// + { + // a1 in r0, a2 in r1 on entry + asm("stmfd sp!, {lr} "); + asm("bl CompareTReal32 "); // compare the two numbers + asm("tst r0, #2 "); + asm("movne r0, #0 "); // if ordered and equal return 0 + asm("moveq r0, #1 "); // else return 1 + __POPRET(""); + } + +__NAKED__ EXPORT_C TInt __eqdf2(TReal64 /*a1*/, TReal64 /*a2*/) +// +// Compare if two doubles are equal +// + { + // a1 in r0,r1, a2 in r2,r3 on entry + asm("stmfd sp!, {lr} "); + asm("bl CompareTReal64 "); // compare the two numbers + asm("tst r0, #2 "); + asm("movne r0, #0 "); // if ordered and equal return 0 + asm("moveq r0, #1 "); // else return 1 + __POPRET(""); + } + +__NAKED__ EXPORT_C TInt __nesf2(TReal32 /*a1*/, TReal32 /*a2*/) +// +// Compare if two floats are not equal +// + { + // a1 in r0, a2 in r1 on entry + asm("stmfd sp!, {lr} "); + asm("bl CompareTReal32 "); // compare the two numbers + asm("tst r0, #5 "); // test if ordered and unequal + asm("moveq r0, #0 "); // if equal or unordered return 0 + asm("movne r0, #1 "); // if ordered and unequal return 1 + __POPRET(""); + } + +__NAKED__ EXPORT_C TInt __nedf2(TReal64 /*a1*/, TReal64 /*a2*/) +// +// Compare if two doubles are not equal +// + { + // a1 in r0,r1, a2 in r2,r3 on entry + asm("stmfd sp!, {lr} "); + asm("bl CompareTReal64 "); // compare the two numbers + asm("tst r0, #5 "); // test if ordered and unequal + asm("moveq r0, #0 "); // if equal or unordered return 0 + asm("movne r0, #1 "); // if ordered and unequal return 1 + __POPRET(""); + } + +__NAKED__ EXPORT_C TInt __gtsf2(TReal32 /*a1*/, TReal32 /*a2*/) +// +// Compare if one float is greater than another +// + { + // a1 in r0, a2 in r1 on entry + asm("stmfd sp!, {lr} "); + asm("bl CompareTReal32 "); // compare the two numbers + asm("tst r0, #4 "); // test if ordered and a1>a2 + asm("movne r0, #1 "); // if ordered and a1>a2 return +1 + asm("mvneq r0, #0 "); // else return -1 + __POPRET(""); + } + +__NAKED__ EXPORT_C TInt __gtdf2(TReal64 /*a1*/, TReal64 /*a2*/) +// +// Compare if one double is greater than another +// + { + // a1 in r0,r1, a2 in r2,r3 on entry + asm("stmfd sp!, {lr} "); + asm("bl CompareTReal64 "); // compare the two numbers + asm("tst r0, #4 "); // test if ordered and a1>a2 + asm("movne r0, #1 "); // if ordered and a1>a2 return +1 + asm("mvneq r0, #0 "); // else return -1 + __POPRET(""); + } + +__NAKED__ EXPORT_C TInt __gesf2(TReal32 /*a1*/, TReal32 /*a2*/) +// +// Compare if one float is greater than or equal to another +// + { + // a1 in r0, a2 in r1 on entry + asm("stmfd sp!, {lr} "); + asm("bl CompareTReal32 "); // compare the two numbers + asm("tst r0, #6 "); // test if ordered and a1>=a2 + asm("movne r0, #1 "); // if ordered and a1>=a2 return +1 + asm("mvneq r0, #0 "); // else return -1 + __POPRET(""); + } + +__NAKED__ EXPORT_C TInt __gedf2(TReal64 /*a1*/, TReal64 /*a2*/) +// +// Compare if one double is greater than or equal to another +// + { + // a1 in r0,r1, a2 in r2,r3 on entry + asm("stmfd sp!, {lr} "); + asm("bl CompareTReal64 "); // compare the two numbers + asm("tst r0, #6 "); // test if ordered and a1>=a2 + asm("movne r0, #1 "); // if ordered and a1>=a2 return +1 + asm("mvneq r0, #0 "); // else return -1 + __POPRET(""); + } + +__NAKED__ EXPORT_C TInt __ltsf2(TReal32 /*a1*/, TReal32 /*a2*/) +// +// Compare if one float is less than another +// + { + // a1 in r0, a2 in r1 on entry + asm("stmfd sp!, {lr} "); + asm("bl CompareTReal32 "); // compare the two numbers + asm("tst r0, #1 "); // test if ordered and a1, round up + asm("tst lr, #1 "); // check rounded-down flag + asm("bne TReal64GetTReal32d "); // if rounded down, round up + asm("tst r2, #0x100 "); // else round to even - test LSB of result mantissa + asm("beq TReal64GetTReal32c "); // if zero, truncate, else round up + asm("TReal64GetTReal32d: "); // come here to round up + asm("adds r2, r2, #0x100 "); // increment the mantissa + asm("movcs r2, #0x80000000 "); // if carry, mantissa=800000 + asm("addcs r12, r12, #1 "); // and increment exponent + asm("cmpmi r12, #1 "); // if mantissa normalised, check exponent>0 + asm("movmi r12, #1 "); // if normalised and exponent=0, set exponent to 1 + asm("TReal64GetTReal32c: "); // come here to truncate + asm("and r0, r0, #0x80000000 "); // leave only sign bit in r0 + asm("orr r0, r0, r12, lsl #23 "); // exponent into r0 bits 23-30 + asm("bic r2, r2, #0x80000000 "); // remove integer bit from mantissa + asm("orr r0, r0, r2, lsr #8 "); // non-integer mantissa bits into r0 bits 0-22 + asm("cmp r12, #0xFF "); // check for overflow + asm("mvneq r12, #8 "); // if overflow, return KErrOverflow + asm("biceq pc, lr, #3 "); + asm("bics r1, r0, #0x80000000 "); // check for underflow + asm("mvneq r12, #9 "); // if underflow return KErrUnderflow + asm("movne r12, #0 "); // else return KErrNone + asm("bic pc, lr, #3 "); + asm("TReal64GetTReal32a: "); // come here if overflow, infinity or NaN + asm("add r3, r12, #1 "); + asm("cmp r3, #0x480 "); // check for infinity or NaN + asm("movne r1, #0 "); // if not, set mantissa to 0 for infinity result + asm("movne r0, r0, lsr #20 "); + asm("movne r0, r0, lsl #20 "); + asm("mov r1, r1, lsr #29 "); // assemble 23 bit mantissa in r1 + asm("orr r1, r1, r0, lsl #3 "); + asm("bic r1, r1, #0xFF000000 "); + asm("and r0, r0, #0x80000000 "); // leave only sign in r0 + asm("orr r0, r0, #0x7F000000 "); // r0 bits 23-30 = FF = exponent + asm("orr r0, r0, #0x00800000 "); + asm("orr r0, r0, r1 "); // r0 bits 0-22 = result mantissa + asm("movs r12, r0, lsl #9 "); // check if result is infinity or NaN + asm("mvneq r12, #8 "); // if infinity return KErrOverflow + asm("mvnne r12, #5 "); // else return KErrArgument + asm("bic pc, lr, #3 "); + } +} // end of extern "C" declaration +#endif +#endif +