Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h)
Have multiple extension sections in the bld.inf, one for each version
of the compiler. The RVCT version building the tools will build the
runtime libraries for its version, but make sure we extract all the other
versions from zip archives. Also add the archive for RVCT4.
// 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 <e32cia.h>
#include <u32std.h>
#include <e32math.h>
#ifdef __USE_VFP_MATH
#include <arm_vfp.h>
#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, skip
asm("TRealXModulo5: ");
asm("subs r1, r1, r4 "); // 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=(a1<a2)
asm("mov r0, #0 ");
asm("mvnvs r0, #0 "); // if a1<a2 r0=-1
asm("moveq r0, #1 "); // if a1>a2 r0=+1
__POPRET("");
// Compare two TReal32s in r0, r1.
// Return 1 if r0<r1, 2 if r0=r1, 4 if r0>r1, 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 r0<r1, r0=1
asm("cmp r1, #0 "); // check signs
asm("eormi r0, r0, #5 "); // if negative, switch 1 and 4
__JUMP(,lr);
asm("CompareTReal32c: "); // come here if signs different
asm("cmp r0, #0 "); // check sign of r0
asm("movpl r0, #4 "); // if r0 nonnegative, then r0 is greater so return 4
asm("movmi r0, #1 "); // if r0 negative, return 1
__JUMP(,lr);
}
__NAKED__ EXPORT_C TInt __cmpdf3(TReal64 /*a1*/,TReal64 /*a2*/)
//
// Compare two doubles
//
{
// a1 in r0,r1, a2 in r2,r3 on entry
asm("stmfd sp!, {lr} ");
asm("bl CompareTReal64 "); // compare the two numbers
asm("mov r0, r0, lsl #28 ");
asm("msr cpsr_flg, r0 "); // N=unordered, Z=(a1>a2), C=(a1=a2), V=(a1<a2)
asm("mov r0, #0 ");
asm("mvnvs r0, #0 "); // if a1<a2 r0=-1
asm("moveq r0, #1 "); // if a1>a2 r0=+1
__POPRET("");
// Compare two TReal64s in r0,r1 and r2,r3.
// Return 1 if r0,r1<r2,r3
// Return 2 if r0,r1=r2,r3
// Return 4 if r0,r1>r2,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<a2
asm("mvnne r0, #0 "); // if ordered and a1<a2 return -1
asm("moveq r0, #1 "); // else return +1
__POPRET("");
}
__NAKED__ EXPORT_C TInt __ltdf2(TReal64 /*a1*/, TReal64 /*a2*/)
//
// Compare if one double is less 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, #1 "); // test if ordered and a1<a2
asm("mvnne r0, #0 "); // if ordered and a1<a2 return -1
asm("moveq r0, #1 "); // else return +1
__POPRET("");
}
__NAKED__ EXPORT_C TInt __lesf2(TReal32 /*a1*/, TReal32 /*a2*/)
//
// Compare if one float is less 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, #3 "); // test if ordered and a1<=a2
asm("mvnne r0, #0 "); // if ordered and a1<=a2 return -1
asm("moveq r0, #1 "); // else return +1
__POPRET("");
}
__NAKED__ EXPORT_C TInt __ledf2(TReal64 /*a1*/, TReal64 /*a2*/)
//
// Compare if one double is less 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, #3 "); // test if ordered and a1<=a2
asm("mvnne r0, #0 "); // if ordered and a1<=a2 return -1
asm("moveq r0, #1 "); // else return +1
__POPRET("");
}
__NAKED__ EXPORT_C TReal32 __mulsf3(TReal32 /*a1*/,TReal32 /*a2*/)
//
// Multiply two floats
//
{
// a1 is in r0, a2 in r1 on entry; return with answer in r0
asm("stmfd sp!, {r4-r7,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 TRealXMultiply "); // multiply 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-r7,");
asm("stmfd sp!, {r0} "); // save result
asm("mov r0, r12 "); // error code into r0
asm("bl __math_exception "); // raise exception
__POPRET("r0,r4-r7,");
}
__NAKED__ EXPORT_C TReal64 __muldf3(TReal64 /*a1*/, TReal64 /*a2*/)
//
// Multiply 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 TRealXMultiply "); // multiply 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 __divsf3(TReal32 /*a1*/, TReal32 /*a2*/)
//
// Divide two floats
//
{
// a1 is in r0, a2 in r1 on entry; return with answer in r0
asm("stmfd sp!, {r4-r9,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 TRealXDivide "); // divide a1/a2, result in r1,r2,r3 error code in r12
asm("mov r9, r12 "); // save error code in case it's division by zero
asm("bl TRealXGetTReal32 "); // convert result to TReal32 in r0, error code in r12
asm("cmn r9, #41 "); // check for KErrDivideByZero
asm("moveq r12, r9 ");
asm("cmp r12, #0 "); // check error code
__CPOPRET(eq,"r4-r9,");
asm("stmfd sp!, {r0} "); // save result
asm("mov r0, r12 "); // error code into r0
asm("bl __math_exception "); // raise exception
__POPRET("r0,r4-r9,");
}
__NAKED__ EXPORT_C TReal64 __divdf3(TReal64 /*a1*/, TReal64 /*a2*/)
//
// Divide two doubles
//
{
// a1 is in r0,r1 a2 in r2,r3 on entry; return with answer in r0,r1
asm("stmfd sp!, {r4-r9,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 TRealXDivide "); // divide a1/a2, result in r1,r2,r3
asm("mov r9, r12 "); // save error code in case it's division by zero
asm("bl TRealXGetTReal64 "); // convert result to TReal64 in r0,r1 error code in r12
asm("cmn r9, #41 "); // check for KErrDivideByZero
asm("moveq r12, r9 ");
asm("cmp r12, #0 "); // check error code
__CPOPRET(eq,"r4-r9,");
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-r9,");
}
__NAKED__ EXPORT_C TReal32 __negsf2(TReal32 /*a1*/)
//
// Negate a float
//
{
// a1 in r0 on entry, return value in r0
asm("eor r0, r0, #0x80000000 "); // change sign bit
__JUMP(,lr);
}
__NAKED__ EXPORT_C TReal64 __negdf2(TReal64 /*a1*/)
//
// Negate a double
//
{
// a1 in r0,r1 on entry, return value in r0,r1
asm("eor r0, r0, #0x80000000 "); // change sign bit
__JUMP(,lr);
}
__NAKED__ EXPORT_C TReal32 __floatsisf(TInt /*a1*/)
//
// Convert int to float
//
{
// a1 in r0 on entry, return value in r0
asm("cmp r0, #0 "); // test for zero or negative
__JUMP(eq,lr);
asm("and ip, r0, #0x80000000 "); // ip=bit 31 of r0 (sign bit)
asm("rsbmi r0, r0, #0 "); // if negative, negate it
asm("mov r2, #0x9E "); // r2=0x9E=exponent of 2^31
asm("cmp r0, #0x00010000 "); // normalise integer, adjusting exponent
asm("movcc r0, r0, lsl #16 ");
asm("subcc r2, r2, #16 ");
asm("cmp r0, #0x01000000 ");
asm("movcc r0, r0, lsl #8 ");
asm("subcc r2, r2, #8 ");
asm("cmp r0, #0x10000000 ");
asm("movcc r0, r0, lsl #4 ");
asm("subcc r2, r2, #4 ");
asm("cmp r0, #0x40000000 ");
asm("movcc r0, r0, lsl #2 ");
asm("subcc r2, r2, #2 ");
asm("cmp r0, #0x80000000 ");
asm("movcc r0, r0, lsl #1 ");
asm("subcc r2, r2, #1 ");
asm("and r1, r0, #0xFF "); // r1=bottom 8 bits=rounding bits
asm("cmp r1, #0x80 "); // check if we need to round up (carry=1 if we do)
asm("moveqs r1, r0, lsr #9 "); // if bottom 8 bits=0x80, set carry=LSB of mantissa
asm("addcss r0, r0, #0x100 "); // round up if necessary
asm("addcs r2, r2, #1 "); // if carry, increment exponent
asm("bic r0, r0, #0x80000000 "); // remove top bit (integer bit of mantissa implicit)
asm("mov r0, r0, lsr #8 "); // mantissa into r0 bits 0-22
asm("orr r0, r0, r2, lsl #23 "); // exponent into r0 bits 23-30
asm("orr r0, r0, ip "); // sign bit into r0 bit 31
__JUMP(,lr);
}
__NAKED__ EXPORT_C TReal64 __floatsidf(TInt /*a1*/)
//
// Convert int to double
//
{
// a1 in r0 on entry, return value in r0,r1
asm("cmp r0, #0 "); // test for zero or negative
asm("moveq r1, #0 "); // if zero, return 0
__JUMP(eq,lr);
asm("and ip, r0, #0x80000000 "); // ip=bit 31 of r0 (sign bit)
asm("rsbmi r0, r0, #0 "); // if negative, negate it
asm("mov r2, #0x400 "); // r2=0x41E=exponent of 2^31
asm("orr r2, r2, #0x1E ");
asm("cmp r0, #0x00010000 "); // normalise integer, adjusting exponent
asm("movcc r0, r0, lsl #16 ");
asm("subcc r2, r2, #16 ");
asm("cmp r0, #0x01000000 ");
asm("movcc r0, r0, lsl #8 ");
asm("subcc r2, r2, #8 ");
asm("cmp r0, #0x10000000 ");
asm("movcc r0, r0, lsl #4 ");
asm("subcc r2, r2, #4 ");
asm("cmp r0, #0x40000000 ");
asm("movcc r0, r0, lsl #2 ");
asm("subcc r2, r2, #2 ");
asm("cmp r0, #0x80000000 ");
asm("movcc r0, r0, lsl #1 ");
asm("subcc r2, r2, #1 ");
asm("bic r0, r0, #0x80000000 "); // remove top bit (integer bit of mantissa implicit)
asm("mov r1, r0, lsl #21 "); // low 11 bits of mantissa into r1
asm("mov r0, r0, lsr #11 "); // high 20 bits of mantissa into r0 bits 0-19
asm("orr r0, r0, r2, lsl #20 "); // exponent into r0 bits 20-30
asm("orr r0, r0, ip "); // sign bit into r0 bit 31
#ifndef __DOUBLE_WORDS_SWAPPED__
asm("mov ip, r0 ");
asm("mov r0, r1 ");
asm("mov r1, ip ");
#endif
__JUMP(,lr);
}
__NAKED__ EXPORT_C TInt __fixsfsi(TReal32 /*a1*/)
//
// Convert float to int
//
{
// a1 in r0 on entry, return value in r0
asm("mov r1, r0, lsr #23 ");
asm("and r1, r1, #0xFF "); // r1=exponent of a1
asm("cmp r1, #0xFF "); // check for NaN
asm("bne fixsfsi1 ");
asm("movs r2, r0, lsl #9 "); // exponent=FF, check mantissa
asm("movne r0, #0 "); // if non-zero, a1 is a NaN so return 0
__JUMP(ne,lr);
asm("fixsfsi1: ");
asm("rsbs r1, r1, #0x9E "); // r1=number of shifts to produce integer
asm("ble fixsfsi2 "); // if <=0, saturate result
asm("cmp r0, #0 "); // check sign bit
asm("orr r0, r0, #0x00800000 "); // set implicit integer bit
asm("mov r0, r0, lsl #8 "); // shift mantissa up so MSB is in MSB of r0
asm("mov r0, r0, lsr r1 "); // r0=absolute integer
asm("rsbmi r0, r0, #0 "); // if negative, negate
__JUMP(,lr);
asm("fixsfsi2: ");
asm("cmp r0, #0 "); // check sign
asm("mov r0, #0x80000000 ");
asm("subpl r0, r0, #1 "); // if -ve return 80000000, if +ve return 7FFFFFFF
__JUMP(,lr);
}
__NAKED__ EXPORT_C TInt __fixdfsi(TReal64 /*a1*/)
//
// Convert double to int
//
{
// a1 in r0,r1 on entry, return value in r0
#ifndef __DOUBLE_WORDS_SWAPPED__
asm("mov r2, r0 ");
asm("mov r0, r1 ");
asm("mov r1, r2 ");
#endif
asm("mov r2, r0, lsr #20 ");
asm("bic r2, r2, #0x800 "); // r1=exponent of a1
asm("add r3, r2, #1 ");
asm("cmp r3, #0x800 "); // check for NaN
asm("bne fixdfsi1 ");
asm("movs r3, r0, lsl #12 "); // exponent=FF, check mantissa
asm("cmpeq r1, #0 ");
asm("movne r0, #0 "); // if non-zero, a1 is a NaN so return 0
__JUMP(ne,lr);
asm("fixdfsi1: ");
asm("mov r3, #0x400 ");
asm("orr r3, r3, #0x1E "); // r3=0x41E (exponent of 2^31)
asm("subs r2, r3, r2 "); // r2=number of shifts to produce integer
asm("ble fixdfsi2 "); // 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("fixdfsi2: ");
asm("cmp r0, #0 "); // check sign
asm("mov r0, #0x80000000 ");
asm("subpl r0, r0, #1 "); // if -ve return 80000000, if +ve return 7FFFFFFF
__JUMP(,lr);
}
__NAKED__ EXPORT_C TReal64 __extendsfdf2(TReal32 /*a1*/)
//
// Convert a float to a double
//
{
// a1 in r0, return in r0,r1
asm("mov r3, r0, lsr #3 ");
asm("ands r3, r3, #0x0FF00000 "); // r3 bits 20-27 hold exponent, Z=1 if zero/denormal
asm("mov r1, r0, lsl #9 "); // r1 = TReal32 mantissa << 9
asm("and r0, r0, #0x80000000 "); // leave only sign bit in r0
asm("beq extendsfdf2a "); // branch if zero/denormal
asm("cmp r3, #0x0FF00000 "); // check for infinity or NaN
asm("orrcs r3, r3, #0x70000000 "); // if infinity or NaN, exponent = 7FF
asm("addcc r3, r3, #0x38000000 "); // else exponent = TReal32 exponent + 380
asm("orr r0, r0, r1, lsr #12 "); // top 20 mantissa bits into r0 bits 0-19
asm("mov r1, r1, lsl #20 "); // remaining mantissa bits in r1 bits 29-31
asm("orr r0, r0, r3 "); // exponent into r0 bits 20-30
asm("b 0f ");
asm("extendsfdf2a: "); // come here if zero or denormal
asm("cmp r1, #0 "); // check for zero
asm("beq 0f ");
asm("mov r3, #0x38000000 "); // else exponent = 380 (highest denormal exponent)
asm("cmp r1, #0x10000 "); // normalise mantissa, decrementing exponent as needed
asm("movcc r1, r1, lsl #16 ");
asm("subcc r3, r3, #0x01000000 ");
asm("cmp r1, #0x1000000 ");
asm("movcc r1, r1, lsl #8 ");
asm("subcc r3, r3, #0x00800000 ");
asm("cmp r1, #0x10000000 ");
asm("movcc r1, r1, lsl #4 ");
asm("subcc r3, r3, #0x00400000 ");
asm("cmp r1, #0x40000000 ");
asm("movcc r1, r1, lsl #2 ");
asm("subcc r3, r3, #0x00200000 ");
asm("cmp r1, #0x80000000 ");
asm("movcc r1, r1, lsl #1 ");
asm("subcc r3, r3, #0x00100000 ");
asm("add r1, r1, r1 "); // shift mantissa left one more to remove integer bit
asm("orr r0, r0, r1, lsr #12 "); // top 20 mantissa bits into r0 bits 0-19
asm("mov r1, r1, lsl #20 "); // remaining mantissa bits in r1 bits 29-31
asm("orr r0, r0, r3 "); // exponent into r0 bits 20-30
asm("0: ");
#ifndef __DOUBLE_WORDS_SWAPPED__
asm("mov r3, r0 ");
asm("mov r0, r1 ");
asm("mov r1, r3 ");
#endif
__JUMP(,lr);
}
__NAKED__ EXPORT_C TReal32 __truncdfsf2(TReal64 /*a1*/)
//
// Convert a double to a float
// Raises an exception if conversion results in an error
//
{
asm("stmfd sp!, {lr} ");
asm("bl TReal64GetTReal32 "); // do the conversion
asm("cmp r12, #0 "); // check error code
__CPOPRET(eq,"");
asm("stmfd sp!, {r0} "); // else save result
asm("mov r0, r12 "); // error code into r0
asm("bl __math_exception "); // raise exception
__POPRET("r0,");
// Convert TReal64 in r0,r1 to TReal32 in r0
// Return error code in r12
// r0-r3, r12 modified
// NB This function is purely internal to EUSER and therefore IS ONLY EVER CALLED IN ARM MODE.
asm("TReal64GetTReal32: ");
#ifndef __DOUBLE_WORDS_SWAPPED__
asm("mov r2, r0 ");
asm("mov r0, r1 ");
asm("mov r1, r2 ");
#endif
asm("mov r12, r0, lsr #20 ");
asm("bic r12, r12, #0x800 "); // r12=a1 exponent
asm("sub r12, r12, #0x380 "); // r12=exp in - 380 = result exponent if in range
asm("cmp r12, #0xFF "); // check if input exponent too big for TReal32
asm("bge TReal64GetTReal32a "); // branch if it is
asm("mov r2, r0, lsl #11 "); // left justify mantissa in r2:r1
asm("orr r2, r2, r1, lsr #21 ");
asm("mov r1, r1, lsl #11 ");
asm("orr r2, r2, #0x80000000 "); // set implied integer bit in mantissa
asm("cmp r12, #0 ");
asm("bgt TReal64GetTReal32b "); // branch if normalised result
asm("cmn r12, #23 "); // check for total underflow or zero
asm("bge TReal64GetTReal32e "); // skip if not
asm("bics r2, r0, #0x80000000 "); // check if input value zero
asm("cmpeq r1, #0 ");
asm("moveq r12, #0 "); // if zero return KErrNone
asm("mvnne r12, #9 "); // else return KErrUnderflow
asm("and r0, r0, #0x80000000 "); // return zero of appropriate sign
asm("mov r1, #0 ");
__JUMP(,lr);
asm("TReal64GetTReal32e: "); // result will be a denormal
asm("add r12, r12, #31 "); // r12=32-mantissa shift required = 32-(1-r12)
asm("movs r3, r1, lsl r12 "); // r3=lost bits when r2:r1 is shifted
asm("orrne lr, lr, #1 "); // if these are not zero, set rounded down flag
asm("rsb r3, r12, #32 ");
asm("mov r1, r1, lsr r3 ");
asm("orr r1, r1, r2, lsl r12 ");
asm("mov r2, r2, lsr r3 "); // r2 top 24 bits now give unrounded result mantissa
asm("mov r12, #0 "); // result exponent will be zero
asm("TReal64GetTReal32b: ");
asm("movs r3, r2, lsl #24 "); // top 8 truncated bits into top byte of r3
asm("bpl TReal64GetTReal32c "); // if top bit clear, truncate
asm("cmp r3, #0x80000000 ");
asm("cmpeq r1, #0 "); // compare rounding bits to 1000...
asm("bhi TReal64GetTReal32d "); // if >, 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