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

145 lines
5.7 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
modstart fdi4386
xdefp __FDI4
xdefp __RDI4
xdefp __FDU4
xdefp __RDU4
;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
;[]
;[] __FDU4 convert double float EDX:EAX into 32-bit integer EAX
;[] Input: EDX:EAX - double precision floating point number
;[] Output: EAX - 32-bit integer
;[]
;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
; convert floating double to 4-byte integer with rounding
defpe __RDU4
mov AL,80h+20h ; indicate we are rounding
jmp short DtoI ; do it
defpe __RDI4
mov AL,80h+1Fh ; indicate we are rounding
jmp short DtoI ; do it
defpe __FDI4
mov AL,1Fh ; indicate we are truncating
jmp short DtoI ; do it
; convert floating double to 4-byte integer with truncation
defpe __FDU4
mov AL,20h ; indicate we are truncating
DtoI: _shl EDX,1 ; get sign
rcr AH,1 ; AH <-- sign
shr AH,1 ; shift sign bit over 1
or AH,AL ; get rounding bit
shr EDX,1 ; restore exponent to its place
; high bit of AH is rounding bit
; next bit is the sign bit
;<~> Shift real right four places so that exponent occupies an entire
;<~> word and the mantissa occupies the remaining words. We do not need
;<~> AX because we only need 32 sig digits
push ECX ; save ECX
mov ECX,EDX ; get high part
sar ECX,20 ; get exponent to the bottom
and CX,07FFh ; isolate exponent
sub CX,03FEh ; remove bias from exponent
jl short DIzero ; if |real| < .5 goto DIzero
cmp CX,20h ; if exponent > 32
jg short DIo_f ; goto DIo_flow
and AL,3Fh ; isolate # of significant bits
cmp CL,AL ; quit if number too big
jg short DIo_f ; goto DIo_flow
mov CH,AH ; save rounding/truncation bit
and EDX,000FFFFFh ; isolate top 20 bits of fraction
and EAX,0FFF00000h ; isolate next 12 bits of fraction
or EDX,EAX ; glue them together
rol EDX,12 ; and rotate into position
stc ; set carry and
rcr EDX,1 ; restore implied 1/2 bit
rcr CH,1 ; save rounding bit
cmp CL,32 ; if want 32 bits
_if e ; then
mov EAX,EDX ; - get them
_shl CH,1 ; - get rounding bit
_else ; else
sub EAX,EAX ; - zero result register
shld EAX,EDX,CL ; - shift answer into EAX
shl EDX,CL ; - shift rounding bit into position
_shl CH,1 ; - get rid of rounding bit from CH
_shl EDX,1 ; - get proper rounding bit
_endif ; endif
mov CL,0FFh ; get mask
rcr CL,1 ; get rounding bit
and CH,CL ; mask it with rounding control bit
_shl CH,1 ; get rounding bit
adc EAX,0 ; add it to the integer to round it up
_shl CH,1 ; get sign
_if c ; if negative
neg EAX ; - negate integer
_endif ; endif
pop ECX ; restore ECX
ret ; return
DIo_f:
mov EAX,80000000h ; set answer to largest negative number
pop ECX ; restore ECX
ret ; return
; jmp I4OverFlow ; report overflow
DIzero: sub EAX,EAX ; set result to zero
pop ECX ; restore ECX
ret
endproc __FDU4
endproc __FDI4
endproc __RDI4
endproc __RDU4
endmod
end