(* ***** BEGIN LICENSE BLOCK *****
*
* The function __lldiv is licensed under the CodeGear license terms.
*
* The initial developer of the original code is Fastcode
*
* Portions created by the initial developer are Copyright (C) 2002-2004
* the initial developer. All Rights Reserved.
*
* Contributor(s): AMD, John O'Harrow and Dennis Christensen
*
* ***** END LICENSE BLOCK ***** *)
// ------------------------------------------------------------------------------
// 64-bit signed division
// ------------------------------------------------------------------------------
//
// Dividend = Numerator, Divisor = Denominator
//
// Dividend(EDX:EAX), Divisor([ESP+8]:[ESP+4]) ; before reg pushing
//
//
procedure __lldiv; //JOH Version
asm //StackAlignSafe
{$IFDEF PC_MAPPED_EXCEPTIONS}
PUSH EBP
MOV EBP, ESP
{$ENDIF}
PUSH EBX
PUSH ESI
PUSH EDI
{$IFDEF PC_MAPPED_EXCEPTIONS}
MOV EBX, [ESP+20]
MOV ECX, [ESP+24]
{$ELSE !PC_MAPPED_EXCEPTIONS}
MOV EBX, [ESP+16]
MOV ECX, [ESP+20]
{$ENDIF !PC_MAPPED_EXCEPTIONS}
MOV ESI, EDX
MOV EDI, ECX
SAR ESI, 31
XOR EAX, ESI
XOR EDX, ESI
SUB EAX, ESI
SBB EDX, ESI // EDX:EAX := abs(Dividend)
SAR EDI, 31
XOR ESI, EDI // 0 if X and Y have same sign
XOR EBX, EDI
XOR ECX, EDI
SUB EBX, EDI
SBB ECX, EDI // ECX:EBX := abs(Divisor)
JNZ @@BigDivisor // divisor > 32^32-1
CMP EDX, EBX // only one division needed ? (ecx = 0)
JB @@OneDiv // yes, one division sufficient
MOV ECX, EAX // save dividend-lo in ecx
MOV EAX, EDX // get dividend-hi
XOR EDX, EDX // zero extend it into edx:eax
DIV EBX // quotient-hi in eax
XCHG EAX, ECX // ecx = quotient-hi, eax =dividend-lo
@@OneDiv:
DIV EBX // eax = quotient-lo
MOV EDX, ECX // edx = quotient-hi(quotient in edx:eax)
JMP @SetSign
@@BigDivisor:
SUB ESP, 12 // Create three local variables.
MOV [ESP ], EAX // dividend_lo
MOV [ESP+4], EBX // divisor_lo
MOV [ESP+8], EDX // dividend_hi
MOV EDI, ECX // edi:ebx and ecx:esi
SHR EDX, 1 // shift both
RCR EAX, 1 // divisor and
ROR EDI, 1 // and dividend
RCR EBX, 1 // right by 1 bit
BSR ECX, ECX // ecx = number of remaining shifts
SHRD EBX, EDI, CL // scale down divisor and
SHRD EAX, EDX, CL // dividend such that divisor
SHR EDX, CL // less than 2^32 (i.e. fits in ebx)
ROL EDI, 1 // restore original divisor (edi:esi)
DIV EBX // compute quotient
MOV EBX, [ESP] // dividend_lo
MOV ECX, EAX // save quotient
IMUL EDI, EAX // quotient * divisor hi-word (low only)
MUL DWORD PTR [ESP+4] // quotient * divisor low word
ADD EDX, EDI // edx:eax = quotient * divisor
SUB EBX, EAX // dividend-lo - (quot.*divisor)-lo
MOV EAX, ECX // get quotient
MOV ECX, [ESP+8] // dividend_hi
SBB ECX, EDX // subtract divisor * quot. from dividend
SBB EAX, 0 // Adjust quotient if remainder is negative.
XOR EDX, EDX // clear hi-word of quot (eax<=FFFFFFFFh)
ADD ESP, 12 // Remove local variables.
@SetSign:
XOR EAX, ESI // If (quotient < 0),
XOR EDX, ESI // compute 1's complement of result.
SUB EAX, ESI // If (quotient < 0),
SBB EDX, ESI // compute 2's complement of result.
@Done:
POP EDI
POP ESI
POP EBX
{$IFDEF PC_MAPPED_EXCEPTIONS}
POP EBP
{$ENDIF}
RET 8
end;