I don't understand that substractions. What are they for? What do you mean by the high part (maybe high 64bits, or high 32)?
The high 64 bits. When you did the unsigned multiplication, an operand that was negative was regarded as larger than it really should be by 2^64, so you need to subtract 2^64 times the other operand.
Here is a quick and dirty way to divide (signed) 64 bit integers on x86:
Code: Select all
div64:
mov ecx,Denominator
or ecx,Denominator+4
jz dividedbyzero
fild Numerator
fild Denominator
fld st
fdivr st,st(2)
frndint
fld st
fistp Quotient
fmulp st(1),st
fsubp st(1),st
fistp Remainder
ret
The way I actually do it in my OS is slightly more involved, as it only uses integer instructions. This is unsigned, but a signed version can be made by doing what Brendan said, saving the signs and negating the result afterwards if different.
Code: Select all
public __aulldiv
__aulldiv:
mov eax,[esp+8]
mov ecx,[esp+16]
jecxz divu64_32
cmp eax,ecx
jb divu_0
push esi
mov edx,ecx
bsr ecx,edx
mov esi,[esp+16]
shrd esi,edx,cl
xchg edx,eax
mov eax,[esp+8]
cmp edx,esi
jb divu_ok
shrd eax,edx,1
shr edx,1
dec ecx
divu_ok:
div esi
add ecx,edi
shrd eax,edx,cl
mov esi,eax
mov ecx,eax
mul dword ptr [esp+16]
imul ecx,[esp+20]
add edx,ecx
sub eax,[esp+8]
sbb edx,[esp+12]
js divu_nofix
dec esi
divu_nofix:
mov eax,esi
xor edx,edx
pop esi
ret 16
divu64_32:
xor edx,edx
div dword ptr [esp+12]
push eax
mov eax,[esp+8]
div dword ptr [esp+16]
pop edx
ret 16
divu_0:
xor eax,eax
cdq
ret 16
public __aullrem
__aullrem:
mov eax,[esp+8]
mov ecx,[esp+16]
jecxz remu64_32
cmp eax,ecx
jb remu_0
push esi
mov edx,ecx
bsr ecx,edx
mov esi,[esp+16]
shrd esi,edx,cl
xchg edx,eax
mov eax,[esp+8]
cmp edx,esi
jb remu_ok
shrd eax,edx,1
shr edx,1
dec ecx
remu_ok:
div esi
add ecx,edi
shrd eax,edx,cl
mov ecx,eax
mul dword ptr [esp+16]
imul ecx,[esp+20]
add edx,ecx
sub eax,[esp+8]
sbb edx,[esp+12]
js remu_nofix
sub eax,[esp+16]
sbb edx,[esp+20]
remu_nofix:
neg eax
adc edx,0
neg edx
pop esi
ret 16
remu64_32:
xor edx,edx
div dword ptr [esp+12]
mov eax,[esp+4]
div dword ptr [esp+16]
xchg edx,eax
xor edx,edx
ret 16
remu_0:
xchg edx,eax
mov eax,[esp+4]
ret 16