kolibrios/programs/develop/open watcom/trunk/clib/cgsupp/fdmth386.asm

485 lines
22 KiB
NASM
Raw Permalink Normal View History

;*****************************************************************************
;*
;* 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: REAL*8 math library.
;*
;*****************************************************************************
;
; inputs: EDX,EAX - operand 1 (high word, low word resp. ) (op1)
; ECX,EBX - operand 2 (op2)
;
; operations are performed as op1 (*) op2 where (*) is the selected
; operation
;
; output: EDX,EAX - result (high word, low word resp. )
;
;
include mdef.inc
include struct.inc
.8087
modstart fdmth386
xref __8087 ; indicate that NDP instructions are present
datasegment
extrn __real87 : byte ; 8087.asm
enddata
xref F8DivZero ; Fstatus
xref F8OverFlow ; Fstatus
xref F8UnderFlow ; Fstatus
xdefp __FDA ; add real*8 to real*8
xdefp __FDS ; subtract real*8 from real*8
xdefp __FDM ; 8-byte real multiply
defpe __FDS
xor ECX,80000000h ; flip the sign of op2 and add
defpe __FDA
or EBX,EBX ; if low word of op2 is 0
_if e ; then
_shl ECX,1 ; - place sign in carry
je ret_op1 ; - if op2 is 0 then return operand 1
rcr ECX,1 ; - put sign back
_endif ; endif
or EAX,EAX ; if op1 is 0
_if e ; then
_shl EDX,1 ; - place sign in carry
_if e ; - if op1 really is 0
mov EDX,ECX ; - - return operand 2
mov EAX,EBX ; - - . . .
ret_op1: ret ; - - return
_endif ; - endif
rcr EDX,1 ; - put sign back
_endif ; endif
cmp byte ptr __real87,0; if 8087 not to be used
je short __FDAemu ; then emulate
__FDA87:
push EDX ; push operand 1
push EAX ; . . .
fld qword ptr [ESP] ; load operand 1
push ECX ; push operand 2
push EBX ; . . .
fadd qword ptr [ESP] ; add operand 2 to operand 1
_ret87:
fstp qword ptr 8[ESP]; store result
add ESP,8 ; clean up stack
fwait ; wait
pop EAX ; load result into EDX:EAX
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
__FDAemu:
push EBP ; save EBP
push EDI ; save EDI
push ESI ; save EDI
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 ; ...
mov EBP,ECX ; assume op1 < op2
rol EDI,16 ; rotate signs to bottom
rol ECX,16 ; ...
add CX,DI ; 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
_endif ; endif
or CX,CX ; if op2 is not a denormal
_if ne ; then
or ESI,00100000h ; - turn on implied 1 bit
_endif ; endif
_shl EAX,1 ; shift left 1 to make room for guard bit
_rcl EDX,1 ; ...
_shl EBX,1 ; ...
_rcl ESI,1 ; ...
sub CX,DI ; calculate difference in exponents
_if ne ; if different
_if b ; - if op1 < op2
mov EBP,EDI ; - - get larger exponent for result
neg CX ; - - negate the shift count
xchg EAX,EBX ; - - flip operands
xchg EDX,ESI ; - - . . .
_endif ; - endif
cmp CX,53+1 ; - if shift count too big
_if a ; - then, return operand 1
mov EDX,ESI ; - - get value in correct registers
mov EAX,EBX ; - - . . .
_shl EBP,1 ; - - get sign
rcr EDX,1 ; - - rebuild operand 1
rcr EAX,1 ; - - ...
and EDX,800FFFFFh ; - - ...
ror EBP,13 ; - - rotate exponent into position
and EBP,7FF00000h ; - - ...
or EDX,EBP ; - - put in exponent
pop ESI ; - - restore ESI
pop EDI ; - - restore EDI
pop EBP ; - - restore EBP
ret ; - - return
_endif ; - endif
_endif ; endif
or ECX,ECX ; get bit 0 of sign word - value is 0 if
; both operands have same sign, 1 if not
_if s ; if signs are different
neg ESI ; - negate the fraction of op2
neg EBX ; - . . .
sbb ESI,0 ; - . . .
xor EBP,80000000h ; - flip sign
_endif ; endif
sub EDI,EDI ; get a zero for sticky bits
cmp CL,0 ; if shifting required
_if ne ; then
push EBX ; - save EBX
sub EBX,EBX ; - for zero fill
cmp CL,32 ; - if shift count >= 32
_if ae ; - then
or EAX,EAX ; - - check low order word for 1 bits
setne BL ; - - BL=1 if EAX non zero
mov EDI,EBX ; - - save sticky bits
sub EBX,EBX ; - - for zero fill
mov EAX,EDX ; - - shift right 32
sub EDX,EDX ; - - zero high word
;;; sub CL,32 ; - - adjust shift count
_endif ; - endif
shrd EBX,EAX,CL ; - get the extra sticky bits
or EDI,EBX ; - save them
sub EBX,EBX ; - for zero fill
shrd EAX,EDX,CL ; - align the fractions
shrd EDX,EBX,CL ; - ...
pop EBX ; - restore EBX
_endif ; endif
add EAX,EBX ; add the fractions
adc EDX,ESI ; . . .
_if s ; if answer is negative
cmp CL,53 ; - if shift count >= 53
_if ae ; - then
test EDI,7FFFFFFFh ; - - check the sticky bits
setne BL ; - - make single sticky bit
shr EBX,1 ; - - carry set if sticky=1
adc EAX,0 ; - - round up fraction if required
adc EDX,0 ; - - . . .
_endif ; - endif
neg EDX ; - negate the fraction
neg EAX ; - . . .
sbb EDX,0 ; - . . .
xor EBP,80000000h ; - flip the sign
_endif ; endif
mov EBX,EAX ; get result
or EBX,EDX ; if not zero
_if ne ; then
or BP,BP ; - if exponent is 0
je short denormal ; - denormal when exponent hits 0
_loop ; - loop (normalize)
test EDX,7FE00000h ; - - stop when bit slides into exponent field
_quif ne ; - - ...
dec BP ; - - decrement exponent
je short denormal; - - denormal when exponent hits 0
_shl EAX,1 ; - - shift fraction left one bit
_rcl EDX,1 ; - - ...
_endloop ; - endloop
test EDX,00400000h ; - if we got a carry
_if ne ; - then
shr EDX,1 ; - - shift fraction right 1
rcr EAX,1 ; - - ...
adc EDI,0 ; - - keep sticky bit
inc BP ; - - increment exponent
cmp BP,07FFh ; - - quit if overflow
je add_oflow ; - - . . .
_endif ; - endif
; normalize the fraction
shr EDX,1 ; - get guard bit
rcr EAX,1 ; - ...
_if c ; - if guard bit is on
or EDI,EDI ; - - check the sticky bits
setne BL ; - - make single sticky bit
or EBX,EAX ; - - or sticky bit with bottom bit
shr EBX,1 ; - - carry set if sticky=1 or bottom=1
adc EAX,0 ; - - round up fraction if required
adc EDX,0 ; - - . . .
test EDX,00200000h ; - - if we got a carry (02-nov-90)
_if ne ; - - then
shr EDX,1 ; - - - shift fraction right 1
rcr EAX,1 ; - - - ...
inc BP ; - - - increment exponent
cmp BP,07FFh ; - - - quit if overflow
je add_oflow ; - - - . . .
_endif ; - - endif
_endif ; - endif
and EDX,000FFFFFh ; - get rid of implied 1 bit
mov ECX,EBP ; - get sign
shl EBP,21 ; - shift exponent to top
_shl ECX,1 ; - get sign
rcr EBP,1 ; - put it in
or EDX,EBP ; - put exponent and sign into result
_endif ; endif
pop ESI ; restore ESI
pop EDI ; restore EDI
pop EBP ; restore EBP
ret ; return
denormal: ; handle denormal
_shl EBP,1 ; get sign
rcr EDX,1 ; put it in result
rcr EAX,1 ; ...
pop ESI ; restore ESI
pop EDI ; restore EDI
pop EBP ; restore EBP
ret ; return
add_oflow: ; handle overflow
mov EAX,EBP ; get proper sign for infinity
pop ESI ; restore ESI
pop EDI ; restore EDI
pop EBP ; restore EBP
jmp F8OverFlow ; handle overflow
endproc __FDA
endproc __FDS
;=====================================================================
;<> multiplies X by Y and places result in C.
;<> X2 and X1 represent the high and low words of X. Similarly for Y and C
;<> Special care is taken to use only six registers, so the code is a bit
;<> obscure
defpe __FDM
_guess ; guess: one of the operands is 0
or EAX,EAX ; - see if first arg is zero
_quif ne ; - quit if op1 is not 0
_shl EDX,1 ; - place sign in carry
_if e ; - if operand one is 0
ret ; - - return
_endif ; - endif
rcr EDX,1 ; - restore sign
_endguess ; endguess
_guess ; guess: op2 is 0
or EBX,EBX ; - quit if op2 is not 0
_quif ne ; - . . .
_shl ECX,1 ; - place sign in carry
_if e ; - if operand 2 is 0
sub EAX,EAX ; - - set result to 0
sub EDX,EDX ; - - . . .
ret ; - - return
_endif ; - endif
rcr ECX,1 ; - restore sign of op2
_endguess ; endguess
cmp byte ptr __real87,0; if 8087 not to be used
je short __FDMemu ; then emulate
__FDM87:
push EDX ; push operand 1
push EAX ; . . .
fld qword ptr [ESP] ; load operand 1
push ECX ; push operand 2
push EBX ; . . .
fmul qword ptr [ESP] ; multiply operand 1 by operand 2
jmp _ret87 ; goto common epilogue
__FDMemu:
push EBP ; save EBP
push EDI ; save EDI
push ESI ; save EDI
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 CX,DI ; 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 a denormal
_if e ; then
inc DI ; - adjust exponent by 1
_loop ; - loop (normalize it) 27-jul-90
dec DI ; - - decrement exponent
_shl EAX,1 ; - - shift left 1
_rcl EDX,1 ; - - ...
test EDX,00100000h ; - - check for implied 1 bit
_until ne ; - until normalized
_endif ; endif
or EDX,00100000h ; turn on implied 1 bit
or CX,CX ; if op2 is a denormal
_if e ; then
inc CX ; - adjust exponent by 1
_loop ; - loop (normalize it) 27-jul-90
dec CX ; - - decrement exponent
_shl EBX,1 ; - - shift left 1
_rcl ESI,1 ; - - ...
test ESI,00100000h ; - - check for implied 1 bit
_until ne ; - until normalized
_endif ; endif
or ESI,00100000h ; turn on implied 1 bit
_guess ; guess: overflow
add CX,DI ; - determine exponent of result
sub CX,03ffh ; - remove extra bias
_quif s ; - quit if exponent is negative
cmp CX,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 CX,-53 ; 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 ECX ; 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 ; ...
sub EBP,EBP ; zero EBP
push ESI ; save high part of op2
push EDX ; save high part of op1
push EAX ; save low part of op1
mul EBX ; low part of op1 * low part of op2
xchg EAX,ESI ; ESI becomes start of the sticky bits
mov ECX,EDX ; save high part of result
pop EDX ; restore low part of op1
mul EDX ; low part of op1 * high part of op2
mov EDI,EDX ; save high part of product
add ECX,EAX ; add partial product
adc EDI,EBP ; ...
adc EBP,EBP ; ...
pop EAX ; restore high part of op1
xchg EAX,EBX ; flip with low part of op2
mul EBX ; high part of op1 * low part of op2
add ECX,EAX ; add partial product
adc EDI,EDX ; ...
adc EBP,0 ; ...
mov EAX,EBX ; get high part of op1
pop EDX ; restore high part of op2
mul EDX ; high part of op1 * high part of op2
add EAX,EDI ; add partial product
adc EDX,EBP ; ...
sub EBX,EBX ; get zero for zero fill
mov CL,10 ; shift result over
shrd EBX,EAX,CL ; ... get sticky bits 18-feb-91
shrd EAX,EDX,CL ; ...
shrd EDX,EBX,CL ; ...
pop ECX ; restore sign and exponent
_loop ; loop
test EDX,00200000h ; - test to see if bit in exponent field
_quif e ; - quit if not
shr EDX,1 ; - shift result right
rcr EAX,1 ; - . . .
rcr EBX,1 ; - save carry
inc CX ; - inc exponent for every shift
cmp CX,07FFh ; - quit if overflow
je mul_oflow ; - . . .
_endloop ; endloop
_shl EBX,1 ; get guard bit
_if c ; if set
_if e ; - if rest of sticky bits are 0
or ESI,ESI ; - - check the bottom sticky bits
setne BL ; - - ...
shr EBX,1 ; - - if all sticky bits are zero
_if nc ; - - then
mov ESI,EAX ; - - - get bottom bit of result
shr ESI,1 ; - - - as rounding bit
_endif ; - - endif
_endif ; - endif
adc EAX,0 ; - round up
adc EDX,0 ; - ...
test EDX,00200000h ; - test to see if bit in exponent field
_if ne ; - if fraction overflowed
shr EDX,1 ; - - shift right
rcr EAX,1 ; - - ...
inc CX ; - - increment exponent
cmp CX,07FFh ; - - quit if overflow
je mul_oflow ; - - . . .
_endif ; - endif
_endif ; endif
or CX,CX ; if exponent <= 0
_if le ; then (denormal result)
_if e ; - if exponent = 0
mov CL,1 ; - - set shift count to 1
_else ; - else
neg CX ; - - negate to get shift count
dec CX ; - - adjust
_endif ; - endif
sub EBX,EBX ; - for zero fill
shrd EAX,EDX,CL ; - align the fraction
shrd EDX,EBX,CL ; - ...
sub CX,CX ; - set exponent to 0
_endif ; endif
and EDX,000FFFFFh ; isolate fraction
mov ESI,ECX ; get copy of sign
ror ECX,11 ; get exponent
_shl ESI,1 ; get sign
rcr ECX,1 ; put it in
and ECX,0FFF00000h ; isolate sign and exponent
or EDX,ECX ; place it in result
pop ESI ; restore ESI
pop EDI ; restore EDI
pop EBP ; restore EBP
ret ; return
mul_oflow: ; overflow
mov EAX,ECX ; get sign of infinity
pop ESI ; restore ESI
pop EDI ; restore EDI
pop EBP ; restore EBP
jmp F8OverFlow ; handle overflow
endproc __FDM
endmod
end