1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
|
;_ulldiv divides two unsigned 64-bit integers, and returns
; the quotient.
;
;INPUT: [ESP+8]:[ESP+4] dividend
; [ESP+16]:[ESP+12] divisor
;
;OUTPUT: EDX:EAX quotient of division
;
;DESTROYS: EAX,ECX,EDX,EFlags
_ulldiv PROC
PUSH EBX ;save EBX as per calling convention
MOV ECX, [ESP+20] ;divisor_hi
MOV EBX, [ESP+16] ;divisor_lo
MOV EDX, [ESP+12] ;dividend_hi
MOV EAX, [ESP+8] ;dividend_lo
TEST ECX, ECX ;divisor > 2^321?
JNZ $big_divisor ;yes, divisor > 32^321
CMP EDX, EBX ;only one division needed? (ECX = 0)
JAE $two_divs ;need two divisions
DIV EBX ;EAX = quotient_lo
MOV EDX, ECX ;EDX = quotient_hi = 0 (quotient in ; EDX:EAX)
POP EBX ;restore EBX as per calling convention
RET ;done, return to caller
$two_divs:
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
DIV EBX ;EAX = quotient_lo
MOV EDX, ECX ;EDX = quotient_hi (quotient in EDX:EAX)
POP EBX ;restore EBX as per calling convention
RET ;done, return to caller
$big_divisor:
PUSH EDI ;save EDI as per calling convention
MOV EDI, ECX ;save divisor_hi
SHR EDX, 1 ;shift both divisor and dividend right
RCR EAX, 1 ; by 1 bit
ROR EDI, 1
RCR EBX, 1
BSR ECX, ECX ;ECX = number of remaining shifts
SHRD EBX, EDI, CL ;scale down divisor and dividend
SHRD EAX, EDX, CL ; such that divisor is
SHR EDX, CL ; less than 2^32 (i.e. fits in EBX)
ROL EDI, 1 ;restore original divisor_hi
DIV EBX ;compute quotient
MOV EBX, [ESP+12] ;dividend_lo
MOV ECX, EAX ;save quotient
IMUL EDI, EAX ;quotient * divisor hi-word
; (low only)
MUL DWORD PTR [ESP+20] ;quotient * divisor lo-word
ADD EDX, EDI ;EDX:EAX = quotient * divisor
SUB EBX, EAX ;dividend_lo (quot.*divisor)_lo
MOV EAX, ECX ;get quotient
MOV ECX, [ESP+16] ;dividend_hi
SBB ECX, EDX ;subtract divisor * quot. from dividend
SBB EAX, 0 ;adjust quotient if remainder negative
XOR EDX, EDX ;clear hi-word of quot(EAX<=FFFFFFFFh)
POP EDI ;restore EDI as per calling convention
POP EBX ;restore EBX as per calling convention
RET ;done, return to caller
_ulldiv ENDP |
Partager