kernel/eka/euser/epoc/x86/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) 2007-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\x86\uc_i64.cia
// 
//

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

extern "C" void UDiv64();

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.
*/
	{
	asm("mov eax, [esp+4]");
	asm("mul dword ptr [esp+12]");	// edx:eax = x0*y0
	asm("push edi");
	asm("push esi");
	asm("push ebx");				// [esp+16]=&aX, [esp+24]=&aY, [esp+32]=&aOutH, [esp+36]=&aOutL
	asm("mov ecx, eax");
	asm("mov ebx, edx");			// ebx:ecx = x0*y0
	asm("mov eax, [esp+16]");
	asm("mul dword ptr [esp+28]");	// edx:eax = x0*y1
	asm("xor esi, esi");
	asm("add ebx, eax");
	asm("adc esi, edx");			// esi:ebx:ecx = x0*y
	asm("mov eax, [esp+20]");		// eax=x1
	asm("imul dword ptr [esp+28]");	// edx:eax = x1*y1
	asm("mov edi, edx");
	asm("add esi, eax");
	asm("adc edi, 0");				// partial result in edi:esi:ebx:ecx
	asm("cmp dword ptr [esp+28],0");// y<0 ?
	asm("jns mul64_ypos");
	asm("sub esi, [esp+16]");		// if so, subtract x0<<64
	asm("sbb edi, 0");
	asm("mul64_ypos:");
	asm("mov eax, [esp+20]");		// eax=x1
	asm("cmp eax, 0");				// x<0 ?
	asm("jns mul64_xpos");
	asm("sub esi, [esp+24]");		// if so, subtract y0<<64
	asm("sbb edi, 0");
	asm("mul64_xpos:");
	asm("mul dword ptr [esp+24]");	// edx:eax = x1*y0
	asm("add ebx, eax");
	asm("mov eax, [esp+32]");		// eax=&aOutH
	asm("adc esi, edx");
	asm("mov edx, [esp+36]");		// edx=&aOutL
	asm("adc edi, 0");				// full result now in edi:esi:ebx:ecx
	asm("mov [eax], esi");
	asm("mov [eax+4], edi");		// store high 64
	asm("mov [edx], ecx");
	asm("mov [edx+4], ebx");		// store low 64
	asm("pop ebx");
	asm("pop esi");
	asm("pop edi");
	asm("ret");
	}




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.
*/
	{
	asm("mov eax, [esp+4]");
	asm("mul dword ptr [esp+12]");	// edx:eax = x0*y0
	asm("push edi");
	asm("push esi");
	asm("push ebx");				// [esp+16]=&aX, [esp+24]=&aY, [esp+32]=&aOutH, [esp+36]=&aOutL
	asm("mov ecx, eax");
	asm("mov ebx, edx");			// ebx:ecx = x0*y0
	asm("mov eax, [esp+16]");
	asm("mul dword ptr [esp+28]");	// edx:eax = x0*y1
	asm("xor esi, esi");
	asm("add ebx, eax");
	asm("adc esi, edx");			// esi:ebx:ecx = x0*y
	asm("mov eax, [esp+20]");		// eax=x1
	asm("mul dword ptr [esp+28]");	// edx:eax = x1*y1
	asm("mov edi, edx");
	asm("add esi, eax");
	asm("adc edi, 0");				// partial result in edi:esi:ebx:ecx
	asm("mov eax, [esp+20]");
	asm("mul dword ptr [esp+24]");	// edx:eax = x1*y0
	asm("add ebx, eax");
	asm("mov eax, [esp+32]");		// eax=&aOutH
	asm("adc esi, edx");
	asm("mov edx, [esp+36]");		// edx=&aOutL
	asm("adc edi, 0");				// full result now in edi:esi:ebx:ecx
	asm("mov [eax], esi");
	asm("mov [eax+4], edi");		// store high 64
	asm("mov [edx], ecx");
	asm("mov [edx+4], ebx");		// store low 64
	asm("pop ebx");
	asm("pop esi");
	asm("pop edi");
	asm("ret");
	}




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.
*/
	{
	asm("mov eax, [esp+4]");
	asm("mov edx, [esp+8]");		// edx:eax = dividend
	asm("cmp edx, 0");
	asm("jns divmod64_0");
	asm("neg edx");
	asm("neg eax");
	asm("sbb edx, 0");
	asm("divmod64_0:");				// edx:eax = ABS{dividend}
	asm("push edi");
	asm("push esi");
	asm("push ebx");
	asm("push ebp");
	asm("mov esi, [esp+28]");
	asm("mov edi, [esp+32]");		// edi:esi = dividend
	asm("cmp edi, 0");
	asm("jns divmod64_1");
	asm("neg edi");
	asm("neg esi");
	asm("sbb edi, 0");				// edi:esi = ABS{dividend}
	asm("divmod64_1:");	
	asm("call %a0": : "i"(&UDiv64));	// do division, quotient in ebx:eax remainder in edi:edx
	asm("xchg ebx, edx");			// quotient in edx:eax, remainder in edi:ebx
	asm("mov ecx, [esp+24]");		// ecx=dividend high
	asm("xor ecx, [esp+32]");		// ecx=dividend high ^ divisor high
	asm("jns divmod64_2");
	asm("neg edx");
	asm("neg eax");
	asm("sbb edx, 0");
	asm("divmod64_2:");				// edx:eax = quotient with correct sign
	asm("cmp dword ptr [esp+24], 0");
	asm("jns divmod64_3");
	asm("neg edi");
	asm("neg ebx");
	asm("sbb edi, 0");
	asm("divmod64_3:");				// edi:ebx = remainder with correct sign
	asm("mov ecx, [esp+36]");		// ecx=&aRemainder
	asm("mov [ecx], ebx");
	asm("mov [ecx+4], edi");
	asm("pop ebp");
	asm("pop ebx");
	asm("pop esi");
	asm("pop edi");
	asm("ret");
	}




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.
*/
	{
	asm("mov eax, [esp+4]");
	asm("mov edx, [esp+8]");		// edx:eax = dividend
	asm("push edi");
	asm("push esi");
	asm("push ebx");
	asm("push ebp");
	asm("mov esi, [esp+28]");
	asm("mov edi, [esp+32]");		// edi:esi = dividend
	asm("call %a0": : "i"(&UDiv64));	// do division, quotient in ebx:eax remainder in edi:edx
	asm("xchg ebx, edx");			// quotient in edx:eax, remainder in edi:ebx
	asm("mov ecx, [esp+36]");		// ecx=&aRemainder
	asm("mov [ecx], ebx");
	asm("mov [ecx+4], edi");
	asm("pop ebp");
	asm("pop ebx");
	asm("pop esi");
	asm("pop edi");
	asm("ret");
	}