kernel/eka/euser/epoc/arm/uc_i64.cia
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:29:07 +0100
changeset 30 8aab599e3476
parent 0 a41df078684a
permissions -rw-r--r--
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_i64.cia
// 
//

#include <u32std.h>
#include <e32math.h>

#if defined(__GCC32__)
extern "C" void __division_by_zero();
#define DIV_BY_ZERO " __division_by_zero "
#elif defined(__ARMCC__)
extern "C" void __rt_div0 (void);
#define DIV_BY_ZERO " __cpp(__rt_div0) "
#endif




EXPORT_C __NAKED__ void Math::Mul64(Int64 /*aX*/, Int64 /*aY*/, Int64& /*aOutH*/, Uint64& /*aOutL*/)
/**
Multiply aX by aY to generate a 128 bit result.

The high order 64 bits of this calculation are stored in aOutH,
and the low order 64 bits are stored in aOutL.

@param aX     The first 64-bit operand.
@param aY     The second 64-bit operand.
@param aOutH  The high order 64 bits of the result.
@param aOutL  The low order  64 bits of the result.
*/
	{
	// Enter with r1:r0=aX, r3:r2=aY, [sp]=&aOutH, [sp+4]=&aOutL
	asm("stmfd sp!, {r4-r5,lr} ");
	asm("umull r4, r5, r0, r2 ");	// r5:r4 = x0 * y0
	asm("mov r12, #0 ");			// clear r12 initially
	asm("umlal r5, r12, r0, r3 ");	// r12:r5:r4 = x0 * y
	asm("mov r14, #0 ");			// clear r14 initially
	asm("smlal r12, r14, r1, r3 ");	// r14:r12:r5:r4 = x0 * y + (x1*y1)<<64
	asm("and r3, r0, r3, asr #32 ");	// if aY<0, r3=x0 else r3=0
	asm("and r0, r2, r1, asr #32 ");	// if aX<0, r0=y0 else r0=0
	asm("subs r12, r12, r3 ");
	asm("sbcs r14, r14, #0 ");
	asm("subs r12, r12, r0 ");
	asm("sbcs r14, r14, #0 ");
	asm("umull r0, r3, r1, r2 ");	// r3:r0 = x1 * y0
	asm("ldr r1, [sp, #12] ");		// r1=&aOutH
	asm("ldr r2, [sp, #16] ");		// r1=&aOutL
	asm("adds r5, r5, r0 ");		// shift left by 32 and add to give final result
	asm("adcs r12, r12, r3 ");
	asm("adcs r14, r14, #0 ");		// final result now in r14:r12:r5:r4
	asm("stmia r2, {r4,r5} ");		// store low 64
	asm("stmia r1, {r12,r14} ");	// store high 64
	__POPRET("r4-r5,");
	}




EXPORT_C __NAKED__ void Math::UMul64(Uint64 /*aX*/, Uint64 /*aY*/, Uint64& /*aOutH*/, Uint64& /*aOutL*/)
/**
Multiply aX by aY to generate a 128 bit result.

The high order 64 bits of this calculation are stored in aOutH,
and the low order 64 bits are stored in aOutL.

@param aX     The first 64-bit operand.
@param aY     The second 64-bit operand.
@param aOutH  The high order 64 bits of the result.
@param aOutL  The low order  64 bits of the result.
*/
	{
	// Enter with r1:r0=aX, r3:r2=aY, [sp]=&aOutH, [sp+4]=&aOutL
	asm("stmfd sp!, {r4-r5,lr} ");
	asm("umull r4, r5, r0, r2 ");	// r5:r4 = x0 * y0
	asm("mov r12, #0 ");			// clear r12 initially
	asm("umlal r5, r12, r0, r3 ");	// r12:r5:r4 = x0 * y
	asm("mov r14, #0 ");			// clear r14 initially
	asm("umlal r12, r14, r1, r3 ");	// r14:r12:r5:r4 = x0 * y + (x1*y1)<<64
									// r0, r3 no longer required
	asm("umull r0, r3, r1, r2 ");	// r3:r0 = x1 * y0
	asm("ldr r1, [sp, #12] ");		// r1=&aOutH
	asm("ldr r2, [sp, #16] ");		// r1=&aOutL
	asm("adds r5, r5, r0 ");		// shift left by 32 and add to give final result
	asm("adcs r12, r12, r3 ");
	asm("adcs r14, r14, #0 ");		// final result now in r14:r12:r5:r4
	asm("stmia r2, {r4,r5} ");		// store low 64
	asm("stmia r1, {r12,r14} ");	// store high 64
	__POPRET("r4-r5,");
	}




EXPORT_C __NAKED__ Int64 Math::DivMod64(Int64 /*aDividend*/, Int64 /*aDivisor*/, Int64& /*aRemainder*/)
/**
Divides aDividend by aDivisor.

The quotient is returned, and the remainder is stored in aRemainder.
The remainder has same sign as the dividend.

@param aDividend The 64-bit dividend.
@param aDivisor  The 64-bit divisor.
@param aRemainder The 64-bit remainder.

@return The 64-bit quotient.
*/
	{
	// Enter with: r1:r0=dividend, r3:r2=divisor, [sp]=&aRemainder
	// Return quotient in r1:r0
	asm("stmfd sp!, {r4-r8,lr} ");
	__EH_FRAME_PUSH2(r4-r8,lr)
	asm("mov r8, r1, asr #1 ");		// r8 bit 31 =  r8 bit 30 = dividend sign
	asm("eor r8, r8, r3, lsr #1 ");	// r8 bit 31 = dividend sign, r8 bit 30 = quotient sign
	asm("cmp r1, #0 ");
	asm("bpl 1f ");
	asm("rsbs r0, r0, #0 ");		// r1:r0=ABS(dividend)
	asm("rscs r1, r1, #0 ");
	asm("1: ");
	asm("cmp r3, #0 ");
	asm("bpl 2f ");
	asm("rsbs r2, r2, #0 ");		// r3:r2=ABS(divisor)
	asm("rscs r3, r3, #0 ");
	asm("2: ");
#ifndef __EABI__
	asm(".extern UDiv01 ");
	asm("bl UDiv01 ");				// do division, quotient->r5:r4, rem->r6:r3
	asm("mov r2, r3");				// move to make regs same as EABI function
	asm("mov r0, r4");
	asm("mov r1, r5");
	asm("mov r3, r6");
#else //__EABI__
	asm(".extern __aeabi_uldivmod ");
	asm("bl __aeabi_uldivmod ");	// do division, quotient->r1:r0, rem->r3:r2
#endif //__EABI__
	asm("add ip, r8, r8 ");			// ip bit 31 = quotient sign
	asm("ldr r6, [sp, #24] ");		// r6 = &aRemainder
	asm("eors r4, r0, ip, asr #32 ");	// quotient into r5:r4, inverted if quotient -ve
	asm("eors r5, r1, ip, asr #32 ");
	asm("adcs r0, r4, #0 ");		// if quotient -ve, add 1 whilst moving back to r1:r0
	asm("adcs r1, r5, #0 ");
	asm("cmp r8, #0 ");
	asm("bpl 3f ");
	asm("rsbs r2, r2, #0 ");		// if dividend -ve, negate remainder
	asm("rscs r3, r3, #0 ");
	asm("3: ");
	asm("stmia r6, {r2,r3} ");		// store remainder
	__POPRET("r4-r8,");
	}




EXPORT_C __NAKED__ Uint64 Math::UDivMod64(Uint64 /*aDividend*/, Uint64 /*aDivisor*/, Uint64& /*aRemainder*/)
/**
Divides aDividend by aDivisor.

The quotient is returned, and the remainder is stored in aRemainder.

@param aDividend The 64-bit dividend.
@param aDivisor  The 64-bit divisor.
@param aRemainder The 64-bit remainder.

@return The 64-bit quotient.
*/
	{
	// Enter with: r1:r0=dividend, r3:r2=divisor, [sp]=&aRemainder
	// Return quotient in r1:r0
#ifdef __EABI__
	// need to keep sp 8-byte aligned
	asm("stmfd sp!, {r4-r8,lr} ");
	__EH_FRAME_PUSH2(r4-r8,lr)
#else
	asm("stmfd sp!, {r4-r7,lr} ");
#endif

#ifndef __EABI__
	asm(".extern UDiv01 ");
	asm("bl UDiv01 ");				// do division, quotient->r5:r4, rem->r6:r3
	asm("mov r2, r3");				// move to make regs same as EABI function
	asm("mov r0, r4");
	asm("mov r1, r5");
	asm("mov r3, r6");
#else //__EABI__
	asm("bl __aeabi_uldivmod ");	// do division, quotient->r1:r0, rem->r3:r2
#endif //__EABI__

#ifdef __EABI__
	asm("ldr r6, [sp, #24] ");		// r6 = &aRemainder
#else 
	asm("ldr r6, [sp, #20] ");		// r6 = &aRemainder
#endif 

	asm("stmia r6, {r2,r3} ");		// store remainder

#ifdef __EABI__
	__POPRET("r4-r8,");
#else
	__POPRET("r4-r7,");
#endif
	}