forked from KolibriOS/kolibrios
836c97f0ac
git-svn-id: svn://kolibrios.org@553 a494cfbc-eb01-0410-851d-a64ba20cac60
308 lines
15 KiB
NASM
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
|