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

238 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!
;*
;*****************************************************************************
; double modf( double value, double *iptr );
;
; Description:
; The modf function breaks the argument value into integral and
; fractional parts, each of which has the same sign as the argument.
; It stores the integral part as a double in the object pointed to
; by iptr.
;
; Returns:
; The modf function returns the signed fractional part of value.
;
; 18-oct-86 ... Fraction in Modf not computed right
; significant digits
;
include mdef.inc
include struct.inc
modstart amodf386
xdefp __ModF
xdefp __ZBuf2F
;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
;[]
;[] __ModF
;[]
;[] void __ModF( double near *AX, double near *DX );
;[] Input: EAX - pointer to double precision float
;[] EDX - place to store integral part
;[] Output: [EAX] - fractional part of value.
;[] [EDX] - integral part of value
;[]
;[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
defpe __ModF
push EBP ; save BP
push ESI ; save SI
push EDI ; save DI
push ECX ; save CX
push EBX ; save BX
mov ESI,EDX ; get address for ipart
mov EBP,EAX ; get address of float
mov EAX,0[EBP] ; get float
mov EDX,4[EBP] ; . . .
xchg ESI,EBP ; flip pointers
mov 0[EBP],EAX ; store integral part of value
mov 4[EBP],EDX ; . . .
_guess ; guess: fraction is zero
mov ECX,EDX ; - get exponent
and ECX,7FF00000h ; - get exponent part of R into DI
je short done ; - set integer part to 0 if exponent = 0
cmp ECX,(3FFh+52) shl 20; - check for exponent > 52
_quif b ; - quit if fraction not zero
xchg EBP,ESI ; - get address of fractional part
done: sub EAX,EAX ; - set fraction(or integer) to 0
mov 4[EBP],EAX ; - . . .
mov 0[EBP],EAX ; - . . .
pop EBX ; - restore BX
pop ECX ; - restore CX
pop EDI ; - restore DI
pop ESI ; - restore SI
pop EBP ; - restore BP
ret ; - return
_endguess ; endguess
mov EDI,ECX ; save exponent
shr ECX,20 ; move exponent to bottom
sub CX,03FFh ; remove bias
jb done ; quit if number < 1.0
push EDX ; save sign
sub EAX,EAX ; initialize mask to 0
mov EDX,0FFF00000h ; ...
cmp CL,20 ; if exponent > 20
_if a ; then
sar EDX,21 ; - set ESI to all ones
rcr EAX,1 ; - set high bit of EBX
sub CL,21 ; - get shift count for second part
sar EAX,CL ; - create rest of mask
_else ; else
sar EDX,CL ; - create mask in high part only
_endif ; endif
and 4[EBP],EDX ; mask off the remaining fraction bits
and 0[EBP],EAX ; . . .
not EDX ; complement the mask to get fractional part
not EAX ; . . .
mov EBP,ESI ; get address of fractional part
and EDX,4[EBP] ; get fraction bits
and EAX,0[EBP] ; . . .
call Norm ; normalize the fraction
pop ESI ; restore sign
or EDX,EDX ; if fraction is not 0
_if ne ; then
and ESI,80000000h ; - isolate sign
or EDX,ESI ; - set sign in fractional part
_endif ; endif
mov 4[EBP],EDX ; store fractional part
mov 0[EBP],EAX ; . . .
pop EBX ; restore BX
pop ECX ; restore CX
pop EDI ; restore DI
pop ESI ; restore SI
pop EBP ; restore BP
ret ; return
endproc __ModF
;<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
;<> <>
;<> __ZBuf2F - convert buffer of significant digits into floating <>
;<> void __ZBuf2F( char near *buf, double near *value ) <>
;<> <>
;<> input: EAX - address of buffer of significant digits <>
;<> EDX - place to store value <>
;<> output: [EDX] - floating point number <>
;<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
defpe __ZBuf2F
push EBP ; save BP
push ESI ; save SI
push EDI ; save DI
push ECX ; save CX
push EBX ; save BX
push EDX ; save pointer to result
mov ESI,EAX ; get address of buffer
sub EDX,EDX ; set 54-bit integer to 0
sub ECX,ECX ; . . .
sub EAX,EAX ; zero out EAX
_loop ; loop (convert digits into 54-bit int)
mov AL,[ESI] ; - get next digit
cmp AL,0 ; - quit if at end of buffer
_quif e ; - . . .
;[] multiply current value in EDX:ECX by 10
mov EDI,EDX ; - save current value
mov EBX,ECX ; - ...
_shl ECX,1 ; - multiply number by 4
_rcl EDX,1 ; - by shifting left 2 places
_shl ECX,1 ; - . . .
_rcl EDX,1 ; - . . .
add ECX,EBX ; - add original value
adc EDX,EDI ; - (this will make it times 5)
_shl ECX,1 ; - shift left to make it times 10
_rcl EDX,1 ; - . . .
and AL,0Fh ; - isolate binary digit
add ECX,EAX ; - add in current digit
adc EDX,0 ; - . . .
inc ESI ; - point to next digit in buffer
_endloop ; endloop
mov EAX,ECX ; get low order word into EAX
;[] Turn the integer in EDX:EAX into a real number
mov EDI,(3FFh+52) shl 20; set exponent
call Norm ; convert the 52 bit integer to a float
pop EBP ; restore pointer to result
mov 4[EBP],EDX ; store result
mov 0[EBP],EAX ; . . .
pop EBX ; restore BX
pop ECX ; restore CX
pop EDI ; restore DI
pop ESI ; restore SI
pop EBP ; restore BP
ret ; return to caller
endproc __ZBuf2F
;[] Norm normalizes an unsigned real in EDX:EAX
;[] expects the exponent to be in EDI. The real returned is in 'packed'
;[] format
;[] ESI is destroyed
Norm proc near ; normalize floating point number
sub ESI,ESI ; clear out SI
or ESI,EAX ; see if the integer is zero
or ESI,EDX ; . . .
je short Z_52ret ; if integer is zero, return to caller
test EDX,0FFF00000h ; see if we have to shift forward or backward
_if e ; if (we haven't shifted msb into bit 53)
_loop ; - loop
sub EDI,00100000h ; - - exp <-- exp - 1
_shl EAX,1 ; - - shift integer left by 1 bit
_rcl EDX,1 ; - - . . .
test EDX,0FFF00000h;
_until ne ; - until( msb is shifted into bit 53 )
_else ; else (we must shift to the right)
test EDX,0FFE00000h ; -
je short done1 ; - if msb is bit 53, we are done
_loop ; - loop
add EDI,00100000h ; - - exp <-- exp + 1
shr EDX,1 ; - - shift integer right by 1 bit
rcr EAX,1 ; - - . . .
rcr ESI,1 ; - - save lsb
test EDX,0FFE00000h; -
_until e ; - until( msb is bit 53 )
_rcl ESI,1 ; - get lsb
adc EAX,0 ; - and use it to round off the number
adc EDX,0 ; - . . .
_endif ; endif
done1: and EDX,000FFFFFh ; clear out implied bit
or EDX,EDI ; put in exponent
Z_52ret:ret ; return
endproc Norm
endmod
end