sl@0: /* sl@0: * Copyright (c) 1995-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\nklib\x86\vchelp.cpp sl@0: * sl@0: */ sl@0: sl@0: sl@0: #ifndef __NAKED__ sl@0: #define __NAKED__ __declspec(naked) sl@0: #endif sl@0: sl@0: #include sl@0: sl@0: #pragma warning ( disable : 4414 ) // short jump to function converted to near sl@0: sl@0: extern "C" { sl@0: __NAKED__ void _allmul() sl@0: // sl@0: // Multiply two 64 bit integers returning a 64 bit result sl@0: // On entry: sl@0: // [esp+4], [esp+8] = arg 1 sl@0: // [esp+12], [esp+16] = arg 1 sl@0: // Return result in edx:eax sl@0: // Remove arguments from stack sl@0: // sl@0: { sl@0: _asm mov eax, [esp+4] // eax = low1 sl@0: _asm mul dword ptr [esp+16] // edx:eax = low1*high2 sl@0: _asm mov ecx, eax // keep low 32 bits of product sl@0: _asm mov eax, [esp+8] // eax = high1 sl@0: _asm mul dword ptr [esp+12] // edx:eax = high1*low2 sl@0: _asm add ecx, eax // accumulate low 32 bits of product sl@0: _asm mov eax, [esp+4] // eax = low1 sl@0: _asm mul dword ptr [esp+12] // edx:eax = low1*low2 sl@0: _asm add edx, ecx // add cross terms to high 32 bits sl@0: _asm ret 16 sl@0: } sl@0: sl@0: void udiv64_divby0() sl@0: { sl@0: _asm int 0 // division by zero exception sl@0: _asm ret sl@0: } sl@0: sl@0: __NAKED__ void UDiv64() sl@0: { sl@0: // unsigned divide edx:eax by edi:esi sl@0: // quotient in ebx:eax, remainder in edi:edx sl@0: // ecx, ebp, esi also modified sl@0: _asm test edi, edi sl@0: _asm jnz short UDiv64a // branch if divisor >= 2^32 sl@0: _asm test esi, esi sl@0: // _ASM_j(z,DivisionByZero) // if divisor=0, branch to error routine sl@0: _asm jz udiv64_divby0 sl@0: _asm mov ebx, eax // ebx=dividend low sl@0: _asm mov eax, edx // eax=dividend high sl@0: _asm xor edx, edx // edx=0 sl@0: _asm div esi // quotient high now in eax sl@0: _asm xchg eax, ebx // quotient high in ebx, dividend low in eax sl@0: _asm div esi // quotient now in ebx:eax, remainder in edi:edx sl@0: _asm ret sl@0: UDiv64e: sl@0: _asm xor eax, eax // set result to 0xFFFFFFFF sl@0: _asm dec eax sl@0: _asm jmp short UDiv64f sl@0: UDiv64a: sl@0: _asm js short UDiv64b // skip if divisor msb set sl@0: _asm bsr ecx, edi // ecx=bit number of divisor msb - 32 sl@0: _asm inc cl sl@0: _asm push edi // save divisor high sl@0: _asm push esi // save divisor low sl@0: _asm shrd esi, edi, cl // shift divisor right so that msb is bit 31 sl@0: _asm mov ebx, edx // dividend into ebx:ebp sl@0: _asm mov ebp, eax sl@0: _asm shrd eax, edx, cl // shift dividend right same number of bits sl@0: _asm shr edx, cl sl@0: _asm cmp edx, esi // check if approx quotient will be 2^32 sl@0: _asm jae short UDiv64e // if so, true result must be 0xFFFFFFFF sl@0: _asm div esi // approximate quotient now in eax sl@0: UDiv64f: sl@0: _asm mov ecx, eax // into ecx sl@0: _asm mul edi // multiply approx. quotient by divisor high sl@0: _asm mov esi, eax // ls dword into esi, ms into edi sl@0: _asm mov edi, edx sl@0: _asm mov eax, ecx // approx. quotient into eax sl@0: _asm mul dword ptr [esp] // multiply approx. quotient by divisor low sl@0: _asm add edx, esi // edi:edx:eax now equals approx. quotient * divisor sl@0: _asm adc edi, 0 sl@0: _asm xor esi, esi sl@0: _asm sub ebp, eax // subtract dividend - approx. quotient *divisor sl@0: _asm sbb ebx, edx sl@0: _asm sbb esi, edi sl@0: _asm jnc short UDiv64c // if no borrow, result OK sl@0: _asm dec ecx // else result is one too big sl@0: _asm add ebp, [esp] // and add divisor to get correct remainder sl@0: _asm adc ebx, [esp+4] sl@0: UDiv64c: sl@0: _asm mov eax, ecx // result into ebx:eax, remainder into edi:edx sl@0: _asm mov edi, ebx sl@0: _asm mov edx, ebp sl@0: _asm xor ebx, ebx sl@0: _asm add esp, 8 // remove temporary values from stack sl@0: _asm ret sl@0: UDiv64b: sl@0: _asm mov ebx, 1 sl@0: _asm sub eax, esi // subtract divisor from dividend sl@0: _asm sbb edx, edi sl@0: _asm jnc short UDiv64d // if no borrow, result=1, remainder in edx:eax sl@0: _asm add eax, esi // else add back sl@0: _asm adc edx, edi sl@0: _asm dec ebx // and decrement quotient sl@0: UDiv64d: sl@0: _asm mov edi, edx // remainder into edi:edx sl@0: _asm mov edx, eax sl@0: _asm mov eax, ebx // result in ebx:eax sl@0: _asm xor ebx, ebx sl@0: _asm ret sl@0: } sl@0: sl@0: __NAKED__ void _aulldiv() sl@0: // sl@0: // Divide two 64 bit unsigned integers returning a 64 bit result sl@0: // On entry: sl@0: // [esp+4], [esp+8] = dividend sl@0: // [esp+12], [esp+16] = divisor sl@0: // Return result in edx:eax sl@0: // Remove arguments from stack sl@0: // sl@0: { sl@0: _asm push ebp sl@0: _asm push edi sl@0: _asm push esi sl@0: _asm push ebx sl@0: _asm mov eax, [esp+20] sl@0: _asm mov edx, [esp+24] sl@0: _asm mov esi, [esp+28] sl@0: _asm mov edi, [esp+32] sl@0: _asm call UDiv64 sl@0: _asm mov edx, ebx sl@0: _asm pop ebx sl@0: _asm pop esi sl@0: _asm pop edi sl@0: _asm pop ebp sl@0: _asm ret 16 sl@0: } sl@0: sl@0: __NAKED__ void _alldiv() sl@0: // sl@0: // Divide two 64 bit signed integers returning a 64 bit result sl@0: // On entry: sl@0: // [esp+4], [esp+8] = dividend sl@0: // [esp+12], [esp+16] = divisor sl@0: // Return result in edx:eax sl@0: // Remove arguments from stack sl@0: // sl@0: { sl@0: _asm push ebp sl@0: _asm push edi sl@0: _asm push esi sl@0: _asm push ebx sl@0: _asm mov eax, [esp+20] sl@0: _asm mov edx, [esp+24] sl@0: _asm mov esi, [esp+28] sl@0: _asm mov edi, [esp+32] sl@0: _asm test edx, edx sl@0: _asm jns dividend_nonnegative sl@0: _asm neg edx sl@0: _asm neg eax sl@0: _asm sbb edx, 0 sl@0: dividend_nonnegative: sl@0: _asm test edi, edi sl@0: _asm jns divisor_nonnegative sl@0: _asm neg edi sl@0: _asm neg esi sl@0: _asm sbb edi, 0 sl@0: divisor_nonnegative: sl@0: _asm call UDiv64 sl@0: _asm mov ecx, [esp+24] sl@0: _asm mov edx, ebx sl@0: _asm xor ecx, [esp+32] sl@0: _asm jns quotient_nonnegative sl@0: _asm neg edx sl@0: _asm neg eax sl@0: _asm sbb edx, 0 sl@0: quotient_nonnegative: sl@0: _asm pop ebx sl@0: _asm pop esi sl@0: _asm pop edi sl@0: _asm pop ebp sl@0: _asm ret 16 sl@0: } sl@0: sl@0: __NAKED__ void _aullrem() sl@0: // sl@0: // Divide two 64 bit unsigned integers and return 64 bit remainder sl@0: // On entry: sl@0: // [esp+4], [esp+8] = dividend sl@0: // [esp+12], [esp+16] = divisor sl@0: // Return result in edx:eax sl@0: // Remove arguments from stack sl@0: // sl@0: { sl@0: _asm push ebp sl@0: _asm push edi sl@0: _asm push esi sl@0: _asm push ebx sl@0: _asm mov eax, [esp+20] sl@0: _asm mov edx, [esp+24] sl@0: _asm mov esi, [esp+28] sl@0: _asm mov edi, [esp+32] sl@0: _asm call UDiv64 sl@0: _asm mov eax, edx sl@0: _asm mov edx, edi sl@0: _asm pop ebx sl@0: _asm pop esi sl@0: _asm pop edi sl@0: _asm pop ebp sl@0: _asm ret 16 sl@0: } sl@0: sl@0: __NAKED__ void _allrem() sl@0: // sl@0: // Divide two 64 bit signed integers and return 64 bit remainder sl@0: // On entry: sl@0: // [esp+4], [esp+8] = dividend sl@0: // [esp+12], [esp+16] = divisor sl@0: // Return result in edx:eax sl@0: // Remove arguments from stack sl@0: // sl@0: { sl@0: _asm push ebp sl@0: _asm push edi sl@0: _asm push esi sl@0: _asm push ebx sl@0: _asm mov eax, [esp+20] sl@0: _asm mov edx, [esp+24] sl@0: _asm mov esi, [esp+28] sl@0: _asm mov edi, [esp+32] sl@0: _asm test edx, edx sl@0: _asm jns dividend_nonnegative sl@0: _asm neg edx sl@0: _asm neg eax sl@0: _asm sbb edx, 0 sl@0: dividend_nonnegative: sl@0: _asm test edi, edi sl@0: _asm jns divisor_nonnegative sl@0: _asm neg edi sl@0: _asm neg esi sl@0: _asm sbb edi, 0 sl@0: divisor_nonnegative: sl@0: _asm call UDiv64 sl@0: _asm mov eax, edx sl@0: _asm mov edx, edi sl@0: _asm cmp dword ptr [esp+24], 0 sl@0: _asm jns rem_nonnegative sl@0: _asm neg edx sl@0: _asm neg eax sl@0: _asm sbb edx, 0 sl@0: rem_nonnegative: sl@0: _asm pop ebx sl@0: _asm pop esi sl@0: _asm pop edi sl@0: _asm pop ebp sl@0: _asm ret 16 sl@0: } sl@0: sl@0: __NAKED__ void _allshr() sl@0: // sl@0: // Arithmetic shift right EDX:EAX by ECX sl@0: // sl@0: { sl@0: _asm cmp ecx, 64 sl@0: _asm jae asr_count_ge_64 sl@0: _asm cmp cl, 32 sl@0: _asm jae asr_count_ge_32 sl@0: _asm shrd eax, edx, cl sl@0: _asm sar edx, cl sl@0: _asm ret sl@0: asr_count_ge_32: sl@0: _asm sub cl, 32 sl@0: _asm mov eax, edx sl@0: _asm cdq sl@0: _asm sar eax, cl sl@0: _asm ret sl@0: asr_count_ge_64: sl@0: _asm sar edx, 32 sl@0: _asm mov eax, edx sl@0: _asm ret sl@0: } sl@0: sl@0: __NAKED__ void _allshl() sl@0: // sl@0: // shift left EDX:EAX by ECX sl@0: // sl@0: { sl@0: _asm cmp ecx, 64 sl@0: _asm jae lsl_count_ge_64 sl@0: _asm cmp cl, 32 sl@0: _asm jae lsl_count_ge_32 sl@0: _asm shld edx, eax, cl sl@0: _asm shl eax, cl sl@0: _asm ret sl@0: lsl_count_ge_32: sl@0: _asm sub cl, 32 sl@0: _asm mov edx, eax sl@0: _asm xor eax, eax sl@0: _asm shl edx, cl sl@0: _asm ret sl@0: lsl_count_ge_64: sl@0: _asm xor edx, edx sl@0: _asm xor eax, eax sl@0: _asm ret sl@0: } sl@0: sl@0: __NAKED__ void _aullshr() sl@0: // sl@0: // Logical shift right EDX:EAX by ECX sl@0: // sl@0: { sl@0: _asm cmp ecx, 64 sl@0: _asm jae lsr_count_ge_64 sl@0: _asm cmp cl, 32 sl@0: _asm jae lsr_count_ge_32 sl@0: _asm shrd eax, edx, cl sl@0: _asm shr edx, cl sl@0: _asm ret sl@0: lsr_count_ge_32: sl@0: _asm sub cl, 32 sl@0: _asm mov eax, edx sl@0: _asm xor edx, edx sl@0: _asm shr eax, cl sl@0: _asm ret sl@0: lsr_count_ge_64: sl@0: _asm xor edx, edx sl@0: _asm xor eax, eax sl@0: _asm ret sl@0: } sl@0: } sl@0: