2004-07-25 11:55:58 +02:00
|
|
|
; this one adapted from elks, http://elks.sourceforge.net
|
|
|
|
; multiply cx:bx * dx:ax, result in dx:ax
|
|
|
|
; optimized by Arkady Belousov:
|
|
|
|
; dx:ax * cx:bx
|
|
|
|
; = xh:xl * yh:yl
|
|
|
|
; = xh:xl*yh*w + xh:xl*yl
|
|
|
|
; = [xh*yh*w*w +] (xl*yh + xh*yl)*w + xl*yl
|
2002-01-23 23:29:41 +01:00
|
|
|
|
|
|
|
%macro LMULU 0
|
|
|
|
|
2004-07-25 11:55:58 +02:00
|
|
|
push cx
|
|
|
|
push si
|
|
|
|
xchg si,ax ; si=xl (XCHG instead MOV)
|
|
|
|
xchg ax,dx ; ax=xh (XCHG instead MOV)
|
|
|
|
mul bx ; dx:ax=xh*yl (forget dx)
|
|
|
|
xchg cx,ax ; cx=low(xh*yl), ax=yh
|
|
|
|
mul si ; dx:ax=xl*yh (forget dx)
|
|
|
|
add cx,ax ; cx=low(xl*yh+xh*yl)
|
|
|
|
xchg ax,si ; ax=xl (XCHG instead MOV)
|
|
|
|
mul bx ; dx:ax=xl*yl
|
|
|
|
add dx,cx
|
|
|
|
pop si
|
|
|
|
pop cx
|
2002-01-23 23:29:41 +01:00
|
|
|
ret
|
|
|
|
|
|
|
|
%endmacro
|
|
|
|
|
|
|
|
; divide dx:ax / cx:bx, quotient in dx:ax, remainder in cx:bx
|
|
|
|
|
|
|
|
%macro LDIVMODU 0
|
2002-01-27 02:13:07 +01:00
|
|
|
; this one is adapted from an assembly gem:
|
|
|
|
; gem writer: Norbert Juffa, norbert.juffa@amd.com
|
|
|
|
; Dividing 64-bit unsigned integers Assembler / 80386
|
|
|
|
; (adapted back to 32-bit by Bart Oldeman ;-))
|
2004-07-25 11:55:58 +02:00
|
|
|
; ...bugfixed and optimized by Arkady Belousov.
|
|
|
|
|
|
|
|
; This macro divides two unsigned long numbers, the dividend and the divisor
|
2002-01-27 02:13:07 +01:00
|
|
|
; resulting in a quotient and a remainder.
|
|
|
|
;
|
|
|
|
; input:
|
2004-07-25 11:55:58 +02:00
|
|
|
; dx:ax = dividend (x=xh:xl)
|
|
|
|
; cx:bx = divisor (y=yh:yl)
|
2002-01-27 02:13:07 +01:00
|
|
|
; output:
|
2004-07-25 11:55:58 +02:00
|
|
|
; dx:ax = quotient of division of dividend by divisor (q=x/y)
|
|
|
|
; cx:bx = remainder of division of dividend by divisor (r=x%y)
|
2002-01-27 02:13:07 +01:00
|
|
|
; destroys:
|
|
|
|
; flags
|
|
|
|
;
|
2004-07-25 11:55:58 +02:00
|
|
|
%if XCPU < 386
|
|
|
|
|
|
|
|
jcxz %%div3216 ; cx=0 -> divisor < 2^16
|
|
|
|
|
|
|
|
push si ; save temp
|
|
|
|
push di ; variables
|
|
|
|
|
|
|
|
push dx ; save
|
|
|
|
push ax ; dividend x
|
|
|
|
mov si,bx ; si=yl
|
|
|
|
mov di,cx ; di:si=cx:bx=y
|
|
|
|
|
|
|
|
%%shift_loop:
|
|
|
|
shr dx,1 ; shift both
|
|
|
|
rcr ax,1 ; divisor and
|
|
|
|
shr cx,1 ; and dividend
|
|
|
|
rcr bx,1 ; right by 1 bit (rcr preserves ZF)
|
|
|
|
jnz %%shift_loop ; until zero in cx (divisor < 2^16)
|
|
|
|
div bx ; ax=quotient q, di:si=y
|
2002-01-27 02:13:07 +01:00
|
|
|
|
2004-07-25 11:55:58 +02:00
|
|
|
mov cx,ax ; cx=q
|
|
|
|
mul di ; dx:ax=q*yh (forget dx)
|
|
|
|
xchg bx,ax ; bx=low(q*yh) (XCHG instead MOV)
|
|
|
|
mov ax,cx ; ax=q
|
|
|
|
mul si ; dx:ax=q*yl
|
|
|
|
add dx,bx ; dx:ax=q*y, cx=q
|
2002-01-27 02:13:07 +01:00
|
|
|
|
2004-07-25 11:55:58 +02:00
|
|
|
pop bx ; bx=xl
|
|
|
|
sub bx,ax ; bx=xl-low(q*y)
|
|
|
|
xchg ax,cx ; ax=q (XCHG instead MOV)
|
|
|
|
pop cx ; cx=xh
|
|
|
|
sbb cx,dx ; cx:bx=x-q*y=remainder r, ax=q
|
2002-01-27 02:13:07 +01:00
|
|
|
|
2004-07-25 11:55:58 +02:00
|
|
|
jae %%div_done ; if remainder < 0
|
|
|
|
add bx,si
|
|
|
|
adc cx,di ; correct remainder (r+=y)
|
|
|
|
dec ax ; and quotient (q-=1)
|
|
|
|
%%div_done:
|
|
|
|
xor dx,dx ; dx:ax=0:q=q
|
2002-01-27 02:13:07 +01:00
|
|
|
|
2004-07-25 11:55:58 +02:00
|
|
|
pop di ; restore temp
|
|
|
|
pop si ; variables
|
2002-01-27 02:13:07 +01:00
|
|
|
ret
|
2002-01-23 23:29:41 +01:00
|
|
|
|
2004-07-25 11:55:58 +02:00
|
|
|
; dx:ax=x, bx=y, cx=0
|
|
|
|
; x=xh:xl=xh*w+xl=[xh/y]*y*w+xh%y*w+xl=[xh/y]*y*w+xt
|
|
|
|
; w=2^16, xh=x/w, xl=x%w, xt=xh%y*w+xl
|
|
|
|
; remainder = x%y = xt%y
|
|
|
|
; quotient = [x/y] = [xh/y]*w+xt/y
|
|
|
|
|
|
|
|
%%div3216:
|
|
|
|
cmp dx,bx ; xh < y ?
|
|
|
|
jb %%one_div ; yes, one division sufficient
|
|
|
|
|
|
|
|
xchg cx,ax ; ax=0, cx=xl
|
|
|
|
xchg ax,dx ; dx:ax=0:xh, cx=xl
|
|
|
|
div bx ; ax=xh/y, dx=xh%y, cx=xl
|
|
|
|
xchg ax,cx ; dx:ax=xh%y*w+xl=xt, cx=xh/y
|
|
|
|
|
|
|
|
%%one_div:
|
|
|
|
div bx ; ax=xt/y, dx=xt%d=x%d, cx=xh/y
|
|
|
|
mov bx,dx ; bx=x%d
|
|
|
|
mov dx,cx ; dx:ax=xh/y*w+xt/y=x/y
|
|
|
|
xor cx,cx ; cx:bx=x%d
|
2002-01-23 23:29:41 +01:00
|
|
|
ret
|
|
|
|
|
2004-07-25 11:55:58 +02:00
|
|
|
%else ; XCPU >= 386 (Svilen Stoianov and Luchezar Georgiev, Varna, Bulgaria)
|
|
|
|
|
|
|
|
push eax ; save eax.high
|
|
|
|
pop ax
|
|
|
|
push edx ; save edx.high
|
|
|
|
push ax
|
|
|
|
pop eax ; eax=x
|
|
|
|
push ecx ; save ecx.high
|
|
|
|
push bx
|
|
|
|
pop ecx ; ecx=y
|
|
|
|
|
|
|
|
xor edx,edx
|
|
|
|
div ecx ; eax=q, edx=r
|
|
|
|
|
|
|
|
push edx
|
|
|
|
pop bx
|
|
|
|
pop ecx ; restore ecx.high, cx:bx=r
|
|
|
|
push eax
|
|
|
|
pop ax
|
|
|
|
pop edx ; restore edx.high, dx:ax=q
|
|
|
|
push ax
|
|
|
|
pop eax ; restore eax.high
|
|
|
|
ret
|
|
|
|
|
|
|
|
%endif
|
|
|
|
%endmacro
|