// 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");
}