/*
* Copyright (c) 1995-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\nklib\x86\vchelp.cpp
*
*/


#ifndef __NAKED__
#define __NAKED__	__declspec(naked)
#endif

#include <e32def.h>

#pragma warning ( disable : 4414 )  // short jump to function converted to near

extern "C" {
__NAKED__ void _allmul()
//
// Multiply two 64 bit integers returning a 64 bit result
// On entry:
//		[esp+4], [esp+8] = arg 1
//		[esp+12], [esp+16] = arg 1
// Return result in edx:eax
// Remove arguments from stack
//
	{
	_asm mov eax, [esp+4]			// eax = low1
	_asm mul dword ptr [esp+16]		// edx:eax = low1*high2
	_asm mov ecx, eax				// keep low 32 bits of product
	_asm mov eax, [esp+8]			// eax = high1
	_asm mul dword ptr [esp+12]		// edx:eax = high1*low2
	_asm add ecx, eax				// accumulate low 32 bits of product
	_asm mov eax, [esp+4]			// eax = low1
	_asm mul dword ptr [esp+12]		// edx:eax = low1*low2
	_asm add edx, ecx				// add cross terms to high 32 bits
	_asm ret 16
	}

void udiv64_divby0()
	{
	_asm int 0						// division by zero exception
	_asm ret
	}

__NAKED__ void UDiv64()
	{
	// unsigned divide edx:eax by edi:esi
	// quotient in ebx:eax, remainder in edi:edx
	// ecx, ebp, esi also modified
	_asm test edi, edi
	_asm jnz short UDiv64a				// branch if divisor >= 2^32
	_asm test esi, esi
//	_ASM_j(z,DivisionByZero)			// if divisor=0, branch to error routine
	_asm jz udiv64_divby0
	_asm mov ebx, eax					// ebx=dividend low
	_asm mov eax, edx					// eax=dividend high
	_asm xor edx, edx					// edx=0
	_asm div esi						// quotient high now in eax
	_asm xchg eax, ebx					// quotient high in ebx, dividend low in eax
	_asm div esi						// quotient now in ebx:eax, remainder in edi:edx
	_asm ret
	UDiv64e:
	_asm xor eax, eax					// set result to 0xFFFFFFFF
	_asm dec eax
	_asm jmp short UDiv64f
	UDiv64a:
	_asm js short UDiv64b				// skip if divisor msb set
	_asm bsr ecx, edi					// ecx=bit number of divisor msb - 32
	_asm inc cl
	_asm push edi						// save divisor high
	_asm push esi						// save divisor low
	_asm shrd esi, edi, cl				// shift divisor right so that msb is bit 31
	_asm mov ebx, edx					// dividend into ebx:ebp
	_asm mov ebp, eax
	_asm shrd eax, edx, cl				// shift dividend right same number of bits
	_asm shr edx, cl
	_asm cmp edx, esi					// check if approx quotient will be 2^32
	_asm jae short UDiv64e				// if so, true result must be 0xFFFFFFFF
	_asm div esi						// approximate quotient now in eax
	UDiv64f:
	_asm mov ecx, eax					// into ecx
	_asm mul edi						// multiply approx. quotient by divisor high
	_asm mov esi, eax					// ls dword into esi, ms into edi
	_asm mov edi, edx
	_asm mov eax, ecx					// approx. quotient into eax
	_asm mul dword ptr [esp]			// multiply approx. quotient by divisor low
	_asm add edx, esi					// edi:edx:eax now equals approx. quotient * divisor
	_asm adc edi, 0
	_asm xor esi, esi
	_asm sub ebp, eax					// subtract dividend - approx. quotient *divisor
	_asm sbb ebx, edx
	_asm sbb esi, edi
	_asm jnc short UDiv64c				// if no borrow, result OK
	_asm dec ecx						// else result is one too big
	_asm add ebp, [esp]					// and add divisor to get correct remainder
	_asm adc ebx, [esp+4]
	UDiv64c:
	_asm mov eax, ecx					// result into ebx:eax, remainder into edi:edx
	_asm mov edi, ebx
	_asm mov edx, ebp
	_asm xor ebx, ebx
	_asm add esp, 8						// remove temporary values from stack
	_asm ret
	UDiv64b:
	_asm mov ebx, 1
	_asm sub eax, esi					// subtract divisor from dividend
	_asm sbb edx, edi
	_asm jnc short UDiv64d				// if no borrow, result=1, remainder in edx:eax
	_asm add eax, esi					// else add back
	_asm adc edx, edi
	_asm dec ebx						// and decrement quotient
	UDiv64d:
	_asm mov edi, edx					// remainder into edi:edx
	_asm mov edx, eax
	_asm mov eax, ebx					// result in ebx:eax
	_asm xor ebx, ebx
	_asm ret
	}

__NAKED__ void _aulldiv()
//
// Divide two 64 bit unsigned integers returning a 64 bit result
// On entry:
//		[esp+4], [esp+8] = dividend
//		[esp+12], [esp+16] = divisor
// Return result in edx:eax
// Remove arguments from stack
//
	{
	_asm push ebp
	_asm push edi
	_asm push esi
	_asm push ebx
	_asm mov eax, [esp+20]
	_asm mov edx, [esp+24]
	_asm mov esi, [esp+28]
	_asm mov edi, [esp+32]
	_asm call UDiv64
	_asm mov edx, ebx
	_asm pop ebx
	_asm pop esi
	_asm pop edi
	_asm pop ebp
	_asm ret 16
	}

__NAKED__ void _alldiv()
//
// Divide two 64 bit signed integers returning a 64 bit result
// On entry:
//		[esp+4], [esp+8] = dividend
//		[esp+12], [esp+16] = divisor
// Return result in edx:eax
// Remove arguments from stack
//
	{
	_asm push ebp
	_asm push edi
	_asm push esi
	_asm push ebx
	_asm mov eax, [esp+20]
	_asm mov edx, [esp+24]
	_asm mov esi, [esp+28]
	_asm mov edi, [esp+32]
	_asm test edx, edx
	_asm jns dividend_nonnegative
	_asm neg edx
	_asm neg eax
	_asm sbb edx, 0
	dividend_nonnegative:
	_asm test edi, edi
	_asm jns divisor_nonnegative
	_asm neg edi
	_asm neg esi
	_asm sbb edi, 0
	divisor_nonnegative:
	_asm call UDiv64
	_asm mov ecx, [esp+24]
	_asm mov edx, ebx
	_asm xor ecx, [esp+32]
	_asm jns quotient_nonnegative
	_asm neg edx
	_asm neg eax
	_asm sbb edx, 0
	quotient_nonnegative:
	_asm pop ebx
	_asm pop esi
	_asm pop edi
	_asm pop ebp
	_asm ret 16
	}

__NAKED__ void _aullrem()
//
// Divide two 64 bit unsigned integers and return 64 bit remainder
// On entry:
//		[esp+4], [esp+8] = dividend
//		[esp+12], [esp+16] = divisor
// Return result in edx:eax
// Remove arguments from stack
//
	{
	_asm push ebp
	_asm push edi
	_asm push esi
	_asm push ebx
	_asm mov eax, [esp+20]
	_asm mov edx, [esp+24]
	_asm mov esi, [esp+28]
	_asm mov edi, [esp+32]
	_asm call UDiv64
	_asm mov eax, edx
	_asm mov edx, edi
	_asm pop ebx
	_asm pop esi
	_asm pop edi
	_asm pop ebp
	_asm ret 16
	}

__NAKED__ void _allrem()
//
// Divide two 64 bit signed integers and return 64 bit remainder
// On entry:
//		[esp+4], [esp+8] = dividend
//		[esp+12], [esp+16] = divisor
// Return result in edx:eax
// Remove arguments from stack
//
	{
	_asm push ebp
	_asm push edi
	_asm push esi
	_asm push ebx
	_asm mov eax, [esp+20]
	_asm mov edx, [esp+24]
	_asm mov esi, [esp+28]
	_asm mov edi, [esp+32]
	_asm test edx, edx
	_asm jns dividend_nonnegative
	_asm neg edx
	_asm neg eax
	_asm sbb edx, 0
	dividend_nonnegative:
	_asm test edi, edi
	_asm jns divisor_nonnegative
	_asm neg edi
	_asm neg esi
	_asm sbb edi, 0
	divisor_nonnegative:
	_asm call UDiv64
	_asm mov eax, edx
	_asm mov edx, edi
	_asm cmp dword ptr [esp+24], 0
	_asm jns rem_nonnegative
	_asm neg edx
	_asm neg eax
	_asm sbb edx, 0
	rem_nonnegative:
	_asm pop ebx
	_asm pop esi
	_asm pop edi
	_asm pop ebp
	_asm ret 16
	}

__NAKED__ void _allshr()
//
// Arithmetic shift right EDX:EAX by ECX
//
	{
	_asm cmp ecx, 64
	_asm jae asr_count_ge_64
	_asm cmp cl, 32
	_asm jae asr_count_ge_32
	_asm shrd eax, edx, cl
	_asm sar edx, cl
	_asm ret
	asr_count_ge_32:
	_asm sub cl, 32
	_asm mov eax, edx
	_asm cdq
	_asm sar eax, cl
	_asm ret
	asr_count_ge_64:
	_asm sar edx, 32
	_asm mov eax, edx
	_asm ret
	}

__NAKED__ void _allshl()
//
// shift left EDX:EAX by ECX
//
	{
	_asm cmp ecx, 64
	_asm jae lsl_count_ge_64
	_asm cmp cl, 32
	_asm jae lsl_count_ge_32
	_asm shld edx, eax, cl
	_asm shl eax, cl
	_asm ret
	lsl_count_ge_32:
	_asm sub cl, 32
	_asm mov edx, eax
	_asm xor eax, eax
	_asm shl edx, cl
	_asm ret
	lsl_count_ge_64:
	_asm xor edx, edx
	_asm xor eax, eax
	_asm ret
	}

__NAKED__ void _aullshr()
//
// Logical shift right EDX:EAX by ECX
//
	{
	_asm cmp ecx, 64
	_asm jae lsr_count_ge_64
	_asm cmp cl, 32
	_asm jae lsr_count_ge_32
	_asm shrd eax, edx, cl
	_asm shr edx, cl
	_asm ret
	lsr_count_ge_32:
	_asm sub cl, 32
	_asm mov eax, edx
	_asm xor edx, edx
	_asm shr eax, cl
	_asm ret
	lsr_count_ge_64:
	_asm xor edx, edx
	_asm xor eax, eax
	_asm ret
	}
}
