kolibrios/programs/develop/open watcom/trunk/clib/cgsupp/div386.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

308 lines
15 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!
;*
;*****************************************************************************
;
include mdef.inc
include struct.inc
.8087
modstart div386
xref __8087 ; indicate that NDP instructions are present
datasegment
extrn __real87 : byte ; 8087.asm
extrn __chipbug: byte
enddata
xref F8DivZero ; Fstatus
xref F8OverFlow ; Fstatus
xref F8UnderFlow ; Fstatus
xref __fdiv_m64
xdefp __FDD
; double __FDD( double , double )
sign equ -12
den equ sign-8
quot equ den-12
lo equ 0
hi equ 4
defpe __FDD
or EBX,EBX ; if low word of divisor is 0
_if e ; then
_shl ECX,1 ; - shift sign of divisor into carry
_if e ; - if divisor is zero
jmp F8DivZero ; - - handle divide by zero
_endif ; - endif
rcr ECX,1 ; - restore sign of divisor
_endif ; endif
or EAX,EAX ; check dividend for zero
_if e ; if so then
_shl EDX,1 ; - save sign of dividend
_if e ; - if dividend is 0
ret ; - - return
_endif ; - endif
rcr EDX,1 ; - restore sign of dividend
_endif ; endif
cmp byte ptr __real87,0 ; if no 80x87 is present
je short __FDDemu ; then emulate
__FDD87:
push EDX ; push operand 1
push EAX ; . . .
fld qword ptr [ESP] ; load operand 1
push ECX ; push operand 2
push EBX ; . . .
test byte ptr __chipbug,1 ; have we got a bad divider?
_if ne ; then
call __fdiv_m64 ; - call support rtn for divide
_else ; else
fdiv qword ptr [ESP] ; - divide operand 1 by operand 2
add ESP,8 ; - clean up stack
_endif ; endif
fstp qword ptr [ESP] ; store result
fwait ; wait
pop EAX ; load result into DX:AX
pop EDX ; . . .
cmp EDX,80000000H ; is it a negative zero?
_if e ; if it is then
sub EDX,EDX ; - make it positive 0.0
mov EAX,EDX ; - ...
_endif ; endif
ret ; return
__FDDemu:
push EBP ; save EBP
mov EBP,ESP ; get access to stack
push EDI ; save EDI
push ESI ; and ESI
mov EDI,EDX ; get high part of op1
mov ESI,ECX ; get high part of op2
sar EDI,20 ; shift exponent to bottom, duplicating sign
sar ECX,20 ; shift exponent to bottom, duplicating sign
and EDI,0800007FFh ; isolate signs and exponent
and ECX,0800007FFh ; ...
rol EDI,16 ; rotate signs to bottom
rol ECX,16 ; ...
add DI,CX ; calc sign of result
rol EDI,16 ; rotate signs to top
rol ECX,16 ; ...
and EDX,000FFFFFh ; isolate fraction
and ESI,000FFFFFh ; isolate fraction
or DI,DI ; if op1 is not a denormal
_if ne ; then
or EDX,00100000h ; - turn on implied 1 bit
_else ; else (denormal)
_loop ; - loop (normalize it)
_shl EAX,1 ; - - shift fraction left
_rcl EDX,1 ; - - . . .
dec DI ; - - decrement exponent
test EDX,00100000h ; - - until implied 1 bit is on
_until ne ; - until implied 1 bit is on
_endif ; endif
or CX,CX ; if op2 is not a denormal
_if ne ; then
or ESI,00100000h ; - turn on implied 1 bit
_else ; else (denormal)
_loop ; - loop (normalize it)
_shl EBX,1 ; - - shift fraction left
_rcl ESI,1 ; - - . . .
dec CX ; - - decrement exponent
test ESI,00100000h ; - - until implied 1 bit is on
_until ne ; - until implied 1 bit is on
_endif ; endif
sub DI,CX ; calculate exponent of result
add DI,03ffh ; add in removed bias
_guess ; guess: overflow
_quif s ; - quit if exponent is negative
cmp DI,07FFh ; - quit if not overflow
_quif b ; - . . .
mov EAX,ECX ; - put sign into EAX
pop ESI ; - restore ESI
pop EDI ; - restore EDI
pop EBP ; - restore EBP
jmp F8OverFlow ; - handle overflow
_endguess ; endguess
cmp DI,-52 ; if exponent is too small
_if l ; then underflow
pop ESI ; - restore ESI
pop EDI ; - restore EDI
pop EBP ; - restore EBP
jmp F8UnderFlow ; - handle underflow
_endif ; endif
push EDI ; save sign and exponent
mov CL,11 ; shift fractions to top of registers
shld EDX,EAX,CL ; ...
shld EAX,EBP,CL ; ...
and EAX,0FFFFF800h ; ...
shld ESI,EBX,CL ; ...
shld EBX,EBP,CL ; ...
and EBX,0FFFFF800h ; ...
push ESI ; save divisor
push EBX ; ...
mov ECX,ESI ; get top part of divisor
mov EDI,EDX ; get dividend
mov ESI,EAX ; ...
sub EAX,EAX ; assume top bit is 0
cmp ECX,EDX ; check high parts
_if be ; if hi(divisor) <= hi(dividend)
sub EDX,ECX ; - subtract divisor from dividend
inc EAX ; - set quotient to 1
_endif ; endif
push EAX ; save high word of quotient
mov EAX,ESI ; get low part of dividend
div ECX ; estimate next word of quotient
push EAX ; save estimate of quotient (quot+4[EBP])
xchg EAX,EBX ; save quot., get low word of divisor
mul EBX ; calc. estimate * lo(divisor)
xchg EAX,ECX ; ...
xchg EBX,EDX ; save partial product
mul EDX ; calc. estimate * hi(divisor)
add EAX,EBX ; add to partial product
adc EDX,0 ; ...
mov EBX,den+lo[EBP] ; get low word of divisor
test byte ptr quot+8[EBP],1 ; if high word of quot is 1
_if ne ; then
add EAX,EBX ; - add in divisor
adc EDX,den+hi[EBP] ; - ...
_endif ; endif
; subtract estimate * divisor from dividend
neg ECX ; 0 - ECX
sbb ESI,EAX ; ...
sbb EDI,EDX ; ...
_if ne ; if high word not 0 (quotient too big)
_loop ; - loop (find correct quotient)
sub dword ptr quot+4[EBP],1; - - decrement quotient
sbb dword ptr quot+8[EBP],0; - - ...
add ECX,EBX ; - - add divisor back to dividend
adc ESI,den+hi[EBP] ; - - ...
adc EDI,0 ; - - ...
_until e ; - until done
_endif ; endif
mov EDI,ESI ; get new dividend
mov ESI,ECX ; ...
mov ECX,den+hi[EBP] ; get divisor
cmp ECX,EDI ; check high parts 13-aug-90
_if be ; if hi(divisor) <= hi(dividend)
sub EDI,ECX ; - subtract divisor from dividend
add dword ptr quot+4[EBP],1 ; - increment quotient
adc dword ptr quot+8[EBP],0 ; - ...
_endif ; endif
mov EDX,EDI ; get dividend into EDX:EAX
mov EAX,ESI ; ...
div ECX ; estimate next word of quotient
push EAX ; save estimate of quotient (-4[EBP])
or EAX,EAX ; if quotient non-zero
_if ne ; then
xchg EAX,EBX ; - save quot., get low word of divisor
mul EBX ; - calc. estimate * lo(divisor)
xchg EAX,ECX ; - ...
xchg EBX,EDX ; - save partial product
mul EDX ; - calc. estimate * hi(divisor)
add EAX,EBX ; - add to partial product
adc EDX,0 ; - ...
; - subtract estimate * divisor from dividend
neg ECX ; - 0 - ECX
sbb ESI,EAX ; - ...
sbb EDI,EDX ; - ...
_if ne ; - if high word not 0 (quotient too big)
_loop ; - - loop (find correct quotient)
sub dword ptr quot+0[EBP],1; - - - decrement quotient
sbb dword ptr quot+4[EBP],0; - - - ...
sbb dword ptr quot+8[EBP],0; - - - ...
add ECX,den+lo[EBP] ; - - - add divisor back to dividend
adc ESI,den+hi[EBP] ; - - - ...
adc EDI,0 ; - - - ...
_until e ; - - until done
_endif ; - endif
_endif ; endif
pop EAX ; get quotient
pop EDX ; ...
pop EBX ; get high bit
add ESP,8 ; remove divisor
pop EDI ; restore sign and exponent
dec DI ; decrement exponent
shr EBX,1 ; if non-zero
_if c ; then
rcr EDX,1 ; - shift answer right
rcr EAX,1 ; - ...
inc EDI ; - increment exponent
_endif ; endif
sub ESI,ESI ; get zero for zero fill
mov CL,11 ; shift result over
shrd EAX,EDX,CL ; ...
rcr ESI,1 ; save carry
shrd EDX,ESI,CL ; ...
or EDX,0FFF00000h ; turn top bits all on
_shl ESI,1 ; get guard bit
adc EAX,0 ; round up
adc EDX,0 ; ...
adc EDI,0 ; increment exponent if required
or DI,DI ; if exponent <= 0
_if le ; then (denormal result)
_if e ; - if exponent = 0
mov CL,1 ; - - set shift count to 1
_else ; - else
neg DI ; - - negate to get shift count
mov CX,DI ; - - ...
_endif ; - endif
and EDX,001FFFFFh ; - isolate fraction
sub EBX,EBX ; - for zero fill
shrd EAX,EDX,CL ; - align the fraction
shrd EDX,EBX,CL ; - ...
sub DI,DI ; - set exponent to 0
_endif ; endif
and EDX,000FFFFFh ; isolate fraction
mov ESI,EDI ; get copy of sign
ror EDI,11 ; get exponent
_shl ESI,1 ; get sign
rcr EDI,1 ; put it in
and EDI,0FFF00000h ; isolate sign and exponent
or EDX,EDI ; place it in result
pop ESI ; restore registers
pop EDI ; ...
pop EBP ; ...
ret ; return
endproc __FDD
endmod
end