836c97f0ac
git-svn-id: svn://kolibrios.org@553 a494cfbc-eb01-0410-851d-a64ba20cac60
225 lines
10 KiB
NASM
225 lines
10 KiB
NASM
;*****************************************************************************
|
|
;*
|
|
;* Open Watcom Project
|
|
;*
|
|
;* Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
|
|
;*
|
|
;* ========================================================================
|
|
;*
|
|
;* This file contains Original Code and/or Modifications of Original
|
|
;* Code as defined in and that are subject to the Sybase Open Watcom
|
|
;* Public License version 1.0 (the 'License'). You may not use this file
|
|
;* except in compliance with the License. BY USING THIS FILE YOU AGREE TO
|
|
;* ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
|
|
;* provided with the Original Code and Modifications, and is also
|
|
;* available at www.sybase.com/developer/opensource.
|
|
;*
|
|
;* The Original Code and all software distributed under the License are
|
|
;* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
|
;* EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
|
|
;* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
|
|
;* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
|
|
;* NON-INFRINGEMENT. Please see the License for the specific language
|
|
;* governing rights and limitations under the License.
|
|
;*
|
|
;* ========================================================================
|
|
;*
|
|
;* Description: WHEN YOU FIGURE OUT WHAT THIS FILE DOES, PLEASE
|
|
;* DESCRIBE IT HERE!
|
|
;*
|
|
;*****************************************************************************
|
|
|
|
|
|
;========================================================================
|
|
;== Name: I8D ==
|
|
;== Operation: Signed 8 byte divide ==
|
|
;== Inputs: EDX;EAX Dividend ==
|
|
;== ECX;EBX Divisor ==
|
|
;== Outputs: EDX;EAX Quotient ==
|
|
;== ECX;EBX Remainder (same sign as dividend) ==
|
|
;== Volatile: none ==
|
|
;== same sign as dividend for ==
|
|
;== consistency with 8086 idiv ==
|
|
;== and so (a/b)*b + a%b == a ==
|
|
;== to get a 64-bit version for 386==
|
|
;========================================================================
|
|
include mdef.inc
|
|
include struct.inc
|
|
|
|
modstart i8d
|
|
|
|
xdefp __I8D
|
|
|
|
defpe __I8D
|
|
or edx,edx ; check sign of dividend
|
|
js divneg ; handle case where dividend < 0
|
|
or ecx,ecx ; check sign of divisor
|
|
js notU8D ; easy case if it is also positive
|
|
|
|
; dividend >= 0, divisor >= 0
|
|
docall __U8D ; - ...
|
|
ret ; - ...
|
|
|
|
; dividend >= 0, divisor < 0
|
|
notU8D: neg ecx ; take positive value of divisor
|
|
neg ebx ; ...
|
|
sbb ecx,0 ; ...
|
|
docall __U8D ; do unsigned division
|
|
neg edx ; negate quotient
|
|
neg eax ; ...
|
|
sbb edx,0 ; ...
|
|
ret ; and return
|
|
|
|
divneg: ; dividend is negative
|
|
neg edx ; take absolute value of dividend
|
|
neg eax ; ...
|
|
sbb edx,0 ; ...
|
|
or ecx,ecx ; check sign of divisor
|
|
jns negres ; negative result if divisor > 0
|
|
|
|
; dividend < 0, divisor < 0
|
|
neg ecx ; negate divisor too
|
|
neg ebx ; ...
|
|
sbb ecx,0 ; ...
|
|
docall __U8D ; and do unsigned division
|
|
neg ecx ; negate remainder
|
|
neg ebx ; ...
|
|
sbb ecx,0 ; ...
|
|
ret ; and return
|
|
|
|
; dividend < 0, divisor >= 0
|
|
negres: docall __U8D ; do unsigned division
|
|
neg ecx ; negate remainder
|
|
neg ebx ; ...
|
|
sbb ecx,0 ; ...
|
|
neg edx ; negate quotient
|
|
neg eax ; ...
|
|
sbb edx,0 ; ...
|
|
ret ; and return
|
|
|
|
endproc __I8D
|
|
|
|
;========================================================================
|
|
;== Name: U8D ==
|
|
;== Operation: Unsigned 8 byte divide ==
|
|
;== Inputs: EDX;EAX Dividend ==
|
|
;== ECX;EBX Divisor ==
|
|
;== Outputs: EDX;EAX Quotient ==
|
|
;== ECX;EBX Remainder ==
|
|
;== Volatile: none ==
|
|
;========================================================================
|
|
|
|
xdefp __U8D
|
|
|
|
defpe __U8D
|
|
or ecx,ecx ; check for easy case
|
|
jne noteasy ; easy if divisor is 16 bit
|
|
dec ebx ; decrement divisor
|
|
_if ne ; if not dividing by 1
|
|
inc ebx ; - put divisor back
|
|
cmp ebx,edx ; - if quotient will be >= 64K
|
|
_if be ; - then
|
|
;
|
|
; 12-aug-88, added thanks to Eric Christensen from Fox Software
|
|
; divisor < 64K, dividend >= 64K, quotient will be >= 64K
|
|
;
|
|
; *note* this sequence is used in ltoa's #pragmas; any bug fixes
|
|
; should be reflected in ltoa's code bursts
|
|
;
|
|
mov ecx,eax ; - - save low word of dividend
|
|
mov eax,edx ; - - get high word of dividend
|
|
sub edx,edx ; - - zero high part
|
|
div ebx ; - - divide bx into high part of dividend
|
|
xchg eax,ecx ; - - swap high part of quot,low word of dvdnd
|
|
_endif ; - endif
|
|
div ebx ; - calculate low part
|
|
mov ebx,edx ; - get remainder
|
|
mov edx,ecx ; - get high part of quotient
|
|
sub ecx,ecx ; - zero high part of remainder
|
|
_endif ; endif
|
|
ret ; return
|
|
|
|
|
|
noteasy: ; have to work to do division
|
|
;
|
|
; check for divisor > dividend
|
|
;
|
|
_guess ; guess: divisor > dividend
|
|
cmp ecx,edx ; - quit if divisor <= dividend
|
|
_quif b ; - . . .
|
|
_if e ; - if high parts are the same
|
|
cmp ebx,eax ; - - compare the lower order words
|
|
_if be ; - - if divisor <= dividend
|
|
sub eax,ebx ; - - - calulate remainder
|
|
mov ebx,eax ; - - - ...
|
|
sub ecx,ecx ; - - - ...
|
|
sub edx,edx ; - - - quotient = 1
|
|
mov eax,1 ; - - - ...
|
|
ret ; - - - return
|
|
_endif ; - - endif
|
|
_endif ; - endif
|
|
sub ecx,ecx ; - set divisor = 0 (this will be quotient)
|
|
sub ebx,ebx ; - ...
|
|
xchg eax,ebx ; - return remainder = dividend
|
|
xchg edx,ecx ; - and quotient = 0
|
|
ret ; - return
|
|
_endguess ; endguess
|
|
push ebp ; save work registers
|
|
push esi ; ...
|
|
push edi ; ...
|
|
sub esi,esi ; zero quotient
|
|
mov edi,esi ; ...
|
|
mov ebp,esi ; and shift count
|
|
moveup: ; loop until divisor > dividend
|
|
_shl ebx,1 ; - divisor *= 2
|
|
_rcl ecx,1 ; - ...
|
|
jc backup ; - know its bigger if carry out
|
|
inc ebp ; - increment shift count
|
|
cmp ecx,edx ; - check if its bigger yet
|
|
jb moveup ; - no, keep going
|
|
ja divlup ; - if below, know we're done
|
|
cmp ebx,eax ; - check low parts (high parts equal)
|
|
jbe moveup ; until divisor > dividend
|
|
divlup: ; division loop
|
|
clc ; clear carry for rotate below
|
|
_loop ; loop
|
|
_loop ; - loop
|
|
_rcl esi,1 ; - - shift bit into quotient
|
|
_rcl edi,1 ; - - . . .
|
|
dec ebp ; - - quif( -- shift < 0 ) NB carry not changed
|
|
js donediv ; - - ...
|
|
backup: ; - - entry to remove last shift
|
|
rcr ecx,1 ; - - divisor /= 2 (NB also used by 'backup')
|
|
rcr ebx,1 ; - - ...
|
|
sub eax,ebx ; - - dividend -= divisor
|
|
sbb edx,ecx ; - - c=1 iff it won't go
|
|
cmc ; - - c=1 iff it will go
|
|
_until nc ; - until it won't go
|
|
_loop ; - loop
|
|
_shl esi,1 ; - - shift 0 into quotient
|
|
_rcl edi,1 ; - - . . .
|
|
dec ebp ; - - going to add, check if done
|
|
js toomuch ; - - if done, we subtracted to much
|
|
shr ecx,1 ; - - divisor /= 2
|
|
rcr ebx,1 ; - - ...
|
|
add eax,ebx ; - - dividend += divisor
|
|
adc edx,ecx ; - - c = 1 iff bit of quotient should be 1
|
|
_until c ; - until divisor will go into dividend
|
|
_endloop ; endloop
|
|
toomuch: ; we subtracted too much
|
|
add eax,ebx ; dividend += divisor
|
|
adc edx,ecx ; ...
|
|
donediv: ; now quotient in di;si, remainder in dx;ax
|
|
mov ebx,eax ; move remainder to cx;bx
|
|
mov ecx,edx ; ...
|
|
mov eax,esi ; move quotient to dx;ax
|
|
mov edx,edi ; ...
|
|
pop edi ; restore registers
|
|
pop esi ; ...
|
|
pop ebp ; ...
|
|
ret ; and return
|
|
endproc __U8D
|
|
|
|
endmod
|
|
end
|