sl@0: // Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // e32\euser\epoc\x86\uc_i64.cia sl@0: // sl@0: // sl@0: sl@0: #include "u32std.h" sl@0: #include sl@0: sl@0: extern "C" void UDiv64(); sl@0: sl@0: EXPORT_C __NAKED__ void Math::Mul64(Int64 /*aX*/, Int64 /*aY*/, Int64& /*aOutH*/, Uint64& /*aOutL*/) sl@0: /** sl@0: Multiply aX by aY to generate a 128 bit result. sl@0: sl@0: The high order 64 bits of this calculation are stored in aOutH, sl@0: and the low order 64 bits are stored in aOutL. sl@0: sl@0: @param aX The first 64-bit operand. sl@0: @param aY The second 64-bit operand. sl@0: @param aOutH The high order 64 bits of the result. sl@0: @param aOutL The low order 64 bits of the result. sl@0: */ sl@0: { sl@0: asm("mov eax, [esp+4]"); sl@0: asm("mul dword ptr [esp+12]"); // edx:eax = x0*y0 sl@0: asm("push edi"); sl@0: asm("push esi"); sl@0: asm("push ebx"); // [esp+16]=&aX, [esp+24]=&aY, [esp+32]=&aOutH, [esp+36]=&aOutL sl@0: asm("mov ecx, eax"); sl@0: asm("mov ebx, edx"); // ebx:ecx = x0*y0 sl@0: asm("mov eax, [esp+16]"); sl@0: asm("mul dword ptr [esp+28]"); // edx:eax = x0*y1 sl@0: asm("xor esi, esi"); sl@0: asm("add ebx, eax"); sl@0: asm("adc esi, edx"); // esi:ebx:ecx = x0*y sl@0: asm("mov eax, [esp+20]"); // eax=x1 sl@0: asm("imul dword ptr [esp+28]"); // edx:eax = x1*y1 sl@0: asm("mov edi, edx"); sl@0: asm("add esi, eax"); sl@0: asm("adc edi, 0"); // partial result in edi:esi:ebx:ecx sl@0: asm("cmp dword ptr [esp+28],0");// y<0 ? sl@0: asm("jns mul64_ypos"); sl@0: asm("sub esi, [esp+16]"); // if so, subtract x0<<64 sl@0: asm("sbb edi, 0"); sl@0: asm("mul64_ypos:"); sl@0: asm("mov eax, [esp+20]"); // eax=x1 sl@0: asm("cmp eax, 0"); // x<0 ? sl@0: asm("jns mul64_xpos"); sl@0: asm("sub esi, [esp+24]"); // if so, subtract y0<<64 sl@0: asm("sbb edi, 0"); sl@0: asm("mul64_xpos:"); sl@0: asm("mul dword ptr [esp+24]"); // edx:eax = x1*y0 sl@0: asm("add ebx, eax"); sl@0: asm("mov eax, [esp+32]"); // eax=&aOutH sl@0: asm("adc esi, edx"); sl@0: asm("mov edx, [esp+36]"); // edx=&aOutL sl@0: asm("adc edi, 0"); // full result now in edi:esi:ebx:ecx sl@0: asm("mov [eax], esi"); sl@0: asm("mov [eax+4], edi"); // store high 64 sl@0: asm("mov [edx], ecx"); sl@0: asm("mov [edx+4], ebx"); // store low 64 sl@0: asm("pop ebx"); sl@0: asm("pop esi"); sl@0: asm("pop edi"); sl@0: asm("ret"); sl@0: } sl@0: sl@0: sl@0: sl@0: sl@0: EXPORT_C __NAKED__ void Math::UMul64(Uint64 /*aX*/, Uint64 /*aY*/, Uint64& /*aOutH*/, Uint64& /*aOutL*/) sl@0: /** sl@0: Multiply aX by aY to generate a 128 bit result. sl@0: sl@0: The high order 64 bits of this calculation are stored in aOutH, sl@0: and the low order 64 bits are stored in aOutL. sl@0: sl@0: @param aX The first 64-bit operand. sl@0: @param aY The second 64-bit operand. sl@0: @param aOutH The high order 64 bits of the result. sl@0: @param aOutL The low order 64 bits of the result. sl@0: */ sl@0: { sl@0: asm("mov eax, [esp+4]"); sl@0: asm("mul dword ptr [esp+12]"); // edx:eax = x0*y0 sl@0: asm("push edi"); sl@0: asm("push esi"); sl@0: asm("push ebx"); // [esp+16]=&aX, [esp+24]=&aY, [esp+32]=&aOutH, [esp+36]=&aOutL sl@0: asm("mov ecx, eax"); sl@0: asm("mov ebx, edx"); // ebx:ecx = x0*y0 sl@0: asm("mov eax, [esp+16]"); sl@0: asm("mul dword ptr [esp+28]"); // edx:eax = x0*y1 sl@0: asm("xor esi, esi"); sl@0: asm("add ebx, eax"); sl@0: asm("adc esi, edx"); // esi:ebx:ecx = x0*y sl@0: asm("mov eax, [esp+20]"); // eax=x1 sl@0: asm("mul dword ptr [esp+28]"); // edx:eax = x1*y1 sl@0: asm("mov edi, edx"); sl@0: asm("add esi, eax"); sl@0: asm("adc edi, 0"); // partial result in edi:esi:ebx:ecx sl@0: asm("mov eax, [esp+20]"); sl@0: asm("mul dword ptr [esp+24]"); // edx:eax = x1*y0 sl@0: asm("add ebx, eax"); sl@0: asm("mov eax, [esp+32]"); // eax=&aOutH sl@0: asm("adc esi, edx"); sl@0: asm("mov edx, [esp+36]"); // edx=&aOutL sl@0: asm("adc edi, 0"); // full result now in edi:esi:ebx:ecx sl@0: asm("mov [eax], esi"); sl@0: asm("mov [eax+4], edi"); // store high 64 sl@0: asm("mov [edx], ecx"); sl@0: asm("mov [edx+4], ebx"); // store low 64 sl@0: asm("pop ebx"); sl@0: asm("pop esi"); sl@0: asm("pop edi"); sl@0: asm("ret"); sl@0: } sl@0: sl@0: sl@0: sl@0: sl@0: EXPORT_C __NAKED__ Int64 Math::DivMod64(Int64 /*aDividend*/, Int64 /*aDivisor*/, Int64& /*aRemainder*/) sl@0: /** sl@0: Divides aDividend by aDivisor. sl@0: sl@0: The quotient is returned, and the remainder is stored in aRemainder. sl@0: The remainder has same sign as the dividend. sl@0: sl@0: @param aDividend The 64-bit dividend. sl@0: @param aDivisor The 64-bit divisor. sl@0: @param aRemainder The 64-bit remainder. sl@0: sl@0: @return The 64-bit quotient. sl@0: */ sl@0: { sl@0: asm("mov eax, [esp+4]"); sl@0: asm("mov edx, [esp+8]"); // edx:eax = dividend sl@0: asm("cmp edx, 0"); sl@0: asm("jns divmod64_0"); sl@0: asm("neg edx"); sl@0: asm("neg eax"); sl@0: asm("sbb edx, 0"); sl@0: asm("divmod64_0:"); // edx:eax = ABS{dividend} sl@0: asm("push edi"); sl@0: asm("push esi"); sl@0: asm("push ebx"); sl@0: asm("push ebp"); sl@0: asm("mov esi, [esp+28]"); sl@0: asm("mov edi, [esp+32]"); // edi:esi = dividend sl@0: asm("cmp edi, 0"); sl@0: asm("jns divmod64_1"); sl@0: asm("neg edi"); sl@0: asm("neg esi"); sl@0: asm("sbb edi, 0"); // edi:esi = ABS{dividend} sl@0: asm("divmod64_1:"); sl@0: asm("call %a0": : "i"(&UDiv64)); // do division, quotient in ebx:eax remainder in edi:edx sl@0: asm("xchg ebx, edx"); // quotient in edx:eax, remainder in edi:ebx sl@0: asm("mov ecx, [esp+24]"); // ecx=dividend high sl@0: asm("xor ecx, [esp+32]"); // ecx=dividend high ^ divisor high sl@0: asm("jns divmod64_2"); sl@0: asm("neg edx"); sl@0: asm("neg eax"); sl@0: asm("sbb edx, 0"); sl@0: asm("divmod64_2:"); // edx:eax = quotient with correct sign sl@0: asm("cmp dword ptr [esp+24], 0"); sl@0: asm("jns divmod64_3"); sl@0: asm("neg edi"); sl@0: asm("neg ebx"); sl@0: asm("sbb edi, 0"); sl@0: asm("divmod64_3:"); // edi:ebx = remainder with correct sign sl@0: asm("mov ecx, [esp+36]"); // ecx=&aRemainder sl@0: asm("mov [ecx], ebx"); sl@0: asm("mov [ecx+4], edi"); sl@0: asm("pop ebp"); sl@0: asm("pop ebx"); sl@0: asm("pop esi"); sl@0: asm("pop edi"); sl@0: asm("ret"); sl@0: } sl@0: sl@0: sl@0: sl@0: sl@0: EXPORT_C __NAKED__ Uint64 Math::UDivMod64(Uint64 /*aDividend*/, Uint64 /*aDivisor*/, Uint64& /*aRemainder*/) sl@0: /** sl@0: Divides aDividend by aDivisor. sl@0: sl@0: The quotient is returned, and the remainder is stored in aRemainder. sl@0: sl@0: @param aDividend The 64-bit dividend. sl@0: @param aDivisor The 64-bit divisor. sl@0: @param aRemainder The 64-bit remainder. sl@0: sl@0: @return The 64-bit quotient. sl@0: */ sl@0: { sl@0: asm("mov eax, [esp+4]"); sl@0: asm("mov edx, [esp+8]"); // edx:eax = dividend sl@0: asm("push edi"); sl@0: asm("push esi"); sl@0: asm("push ebx"); sl@0: asm("push ebp"); sl@0: asm("mov esi, [esp+28]"); sl@0: asm("mov edi, [esp+32]"); // edi:esi = dividend sl@0: asm("call %a0": : "i"(&UDiv64)); // do division, quotient in ebx:eax remainder in edi:edx sl@0: asm("xchg ebx, edx"); // quotient in edx:eax, remainder in edi:ebx sl@0: asm("mov ecx, [esp+36]"); // ecx=&aRemainder sl@0: asm("mov [ecx], ebx"); sl@0: asm("mov [ecx+4], edi"); sl@0: asm("pop ebp"); sl@0: asm("pop ebx"); sl@0: asm("pop esi"); sl@0: asm("pop edi"); sl@0: asm("ret"); sl@0: } sl@0: sl@0: sl@0: