kolibrios-gitea/programs/develop/open watcom/trunk/clib/cgsupp/i8d.asm
Sergey Semyonov (Serge) 836c97f0ac Clib string & memory functions
git-svn-id: svn://kolibrios.org@553 a494cfbc-eb01-0410-851d-a64ba20cac60
2007-06-26 00:54:22 +00:00

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