kolibrios-gitea/programs/media/ac97snd/trunk/mp3dec/pow.asm
heavyiron 3eda462807 Kernel: Smoothing image code from Mario79, build scripts for skin and drivers/build.bat
Programs: fasm updated to 1.67.14, small fixes in desktop, stackcfg, calc, board, pipes, freecell, big cleanup of unused programs, added some applications from 0.6.3.0 distr...

git-svn-id: svn://kolibrios.org@205 a494cfbc-eb01-0410-851d-a64ba20cac60
2006-11-02 14:18:23 +00:00

356 lines
8.4 KiB
NASM

; ix87 specific implementation of pow function.
; Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
; This file is part of the GNU C Library.
; Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
; The GNU C Library is free software; you can redistribute it and/or
; modify it under the terms of the GNU Library General Public License as
; published by the Free Software Foundation; either version 2 of the
; License, or (at your option) any later version.
; The GNU C Library is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
; Library General Public License for more details.
; You should have received a copy of the GNU Library General Public
; License along with the GNU C Library; see the file COPYING.LIB. If not,
; write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
; Boston, MA 02111-1307, USA. */
format MS COFF
include 'proc32.inc'
section '.text' code readable executable
;public _pow_test@8
public _scalbn
align 4
proc _scalbn
fild dword [esp+12]
fld qword [esp+4]
fscale
fstp st1
ret
endp
proc _pow_test@8 stdcall x:dword, y:dword
fld [x]
fld [y]
jmp __CIpow
__CIpow:
; fldl 12(%esp) // y
fxam
fnstsw ax
mov dl,ah
and ah, 0x45
cmp ah, 0x40 ; is y == 0 ?
je .L_11
cmp ah, 0x05 ; is y == ±inf ?
je .L_12
cmp ah, 0x01 ; is y == NaN ?
je .L_30
fxch
sub esp, 8
fxam
fnstsw ax
mov dh, ah
and ah, 0x45
cmp ah, 0x40
je .L_20 ; x is ±0
cmp ah, 0x05
je .L_15 ; x is ±inf
fxch ; y : x
; First see whether `y' is a natural number. In this case we
; can use a more precise algorithm. */
fld st ; y : y : x
fistp qword [esp] ; y : x
fild qword [esp] ; int(y) : y : x
fucomp st1 ; y : x
fnstsw ax
sahf
jne .L_2
; OK, we have an integer value for y. */
pop eax
pop edx
or edx,0
fstp st0 ; x
jns .L_4 ; y >= 0, jump
fidiv dword [one] ; 1/x (now referred to as x)
neg eax
adc edx,0
neg edx
.L_4:
fld1 ; 1 : x
fxch
.L_6:
shrd edx, eax,1
jnc .L_5
fxch
fmul st1,st0 ; x : ST*x
fxch
.L_5:
fmul st0, st0 ; x*x : ST*x
shr edx,1
mov ecx, eax
or ecx, edx
jnz .L_6
fstp st0 ; ST*x
.L_30:
ret
align 4
; y is a real number. */
.L_2:
fxch ; x : y
fld1 ; 1.0 : x : y
fld st1 ; x : 1.0 : x : y
fsub st0,st1 ; x-1 : 1.0 : x : y
fabs ; |x-1| : 1.0 : x : y
fcomp qword [limit] ; 1.0 : x : y
fnstsw ax
fxch ; x : 1.0 : y
sahf
ja .L_7
fsub st0, st1 ; x-1 : 1.0 : y
fyl2xp1 ; log2(x) : y
jmp .L_8
.L_7:
fyl2x ; log2(x) : y
.L_8:
fmul st0,st1 ; y*log2(x) : y
fst st1 ; y*log2(x) : y*log2(x)
frndint ; int(y*log2(x)) : y*log2(x)
fsubr st1, st0 ; int(y*log2(x)) : fract(y*log2(x))
fxch ; fract(y*log2(x)) : int(y*log2(x))
f2xm1 ; 2^fract(y*log2(x))-1 : int(y*log2(x))
fld1
faddp ; 2^fract(y*log2(x)) : int(y*log2(x))
fscale ; 2^fract(y*log2(x))*2^int(y*log2(x)) : int(y*log2(x))
add esp,8
fstp st1 ; 2^fract(y*log2(x))*2^int(y*log2(x))
ret
align 4
; // pow(x,±0) = 1
.L_11:
fstp st0 ; pop y
fld1
ret
align 4
; y == ±inf
.L_12:
fstp st0 ; pop y
; fld 4(%esp) ; x
fabs
fcomp qword [one] ; < 1, == 1, or > 1
fnstsw ax
and ah,0x45
cmp ah,0x45
je .L_13 ; jump if x is NaN
cmp ah,0x40
je .L_14 ; jump if |x| == 1
shl ah, 1
xor ah, dl
and edx, 2
fld qword [inf_zero+edx+4]
ret
align 4
.L_14:
fld qword [infinity]
fmul qword [zero] ; raise invalid exception
ret
align 4
.L_13:
; //fld 4(%esp) // load x == NaN
ret
align 4
; // x is ±inf
.L_15:
fstp st0 ; y
test dh, 2
jz .L_16 ; jump if x == +inf
; We must find out whether y is an odd integer.
fld st ; y : y
fistp qword [esp] ; y
fild qword [esp] ; int(y) : y
fucompp ; <empty>
fnstsw ax
sahf
jne .L_17
; OK, the value is an integer, but is the number of bits small
; enough so that all are coming from the mantissa?
pop eax
pop edx
and al, 1
jz .L_18 ;// jump if not odd
mov eax, edx
or edx, eax
jns .L_155
neg eax
.L_155:
cmp eax, 0x00200000
ja .L_18 ;// does not fit in mantissa bits
; It's an odd integer.
shr edx, 31
fld qword [minf_mzero+edx+8]
ret
align 4
.L_16:
fcomp qword [zero]
add esp, 8
fnstsw ax
shr eax, 5
and eax, 8
fld qword [inf_zero+eax+1]
ret
align 4
.L_17:
shl edx, 30 ;// sign bit for y in right position
add esp ,8
.L_18:
shr edx, 31
fld qword [inf_zero+edx+8]
ret
align 4
; x is ±0
.L_20:
fstp st0 ; y
test dl,2
jz .L_21 ; y > 0
;x is ±0 and y is < 0. We must find out whether y is an odd integer.
test dh, 2
jz .L_25
fld st ; y : y
fistp qword [esp] ; y
fild qword [esp] ; int(y) : y
fucompp ; <empty>
fnstsw ax
sahf
jne .L_26
;OK, the value is an integer, but is the number of bits small
;enough so that all are coming from the mantissa?
pop eax
pop edx
and al, 1
jz .L_27 ; jump if not odd
cmp edx,0xffe00000
jbe .L_27 ; does not fit in mantissa bits
; It's an odd integer.
; Raise divide-by-zero exception and get minus infinity value.
fld1
fdiv qword [zero]
fchs
ret
.L_25:
fstp st0
.L_26:
add esp,8
.L_27:
;Raise divide-by-zero exception and get infinity value.
fld1
fdiv qword [zero]
ret
align 4
; x is ±0 and y is > 0. We must find out whether y is an odd integer.
.L_21:
test dh,2
jz .L_22
fld st ; y : y
fistp qword [esp] ; y
fild qword [esp] ; int(y) : y
fucompp ; <empty>
fnstsw ax
sahf
jne .L_23
; OK, the value is an integer, but is the number of bits small
; enough so that all are coming from the mantissa?
pop eax
pop edx
and al,1
jz .L_24 ; jump if not odd
cmp edx,0xffe00000
jae .L_24 ; does not fit in mantissa bits
; It's an odd integer.
fld qword [mzero]
ret
.L_22:
fstp st0
.L_23:
add esp,8 ; Don't use 2 x pop
.L_24:
fldz
ret
endp
align 4
inf_zero:
infinity:
db 0,0,0,0,0,0,0xf0,0x7f
zero: dq 0.0
minf_mzero:
minfinity:
db 0,0,0,0,0,0,0xf0,0xff
mzero:
db 0,0,0,0,0,0,0,0x80
one:
dq 1.0
limit:
dq 0.29