             AREA |C$$code|,CODE,READONLY

             GET "Hdr.Common"

; Tests the exponent in the log functions so that we can return
; log fraction early if the exponent is zero.

             MACRO
             zeroexp $rexp

             teq $rexp,#0
             IF FPE_POINTERS
             vmoveq.F64 r1,r0,d0
             stmdbeq r13!,{r0,r1}
             DCD 0x0CBD8102
             ELIF {TARGET_FPU_SOFTVFP_VFP}
             vmoveq.F64 r0,r1,d0
             ENDIF
             ldmdbeq fp,{fp,sp,pc}
             MEND

; Converts the exponent to another base, multiplying by 1/log_2 base
; enter with integer exponent in $rexp, convert to fp and multiply
; by $scale. Then add in log fraction in d0

             MACRO
             baseexp $rexp,$scale

             vmov s2,$rexp
             vcvt.F64.S32 d4,s2
             adr r2,$scale
             vldr.64 d7,[r2]
             vmla.F64 d0,d4,d7
             MEND

             EXPORT vfp_exp
vfp_exp      p1arg
             adr r2,log2e
             vldr.64 d7,[r2]
             vdiv.F64 d6,d0,d7
             vmov.F64 d4,#0.5
             vadd.F64 d6,d6,d4
             vcmp.F64 d6,#0
             vmrs apsr_nzcv,fpscr
             vmovmi.F64 d5,#1.0
             vsubmi.F64 d6,d6,d5
             vcvt.S32.F64 s2,d6
             vcvt.F64.S32 d4,s2
             vmls.F64 d0,d4,d7
             b expser

             EXPORT vfp_exp2
vfp_exp2     p1arg
             vmov.F64 d6,d0
             vcmp.F64 d6,#0
             vmrs apsr_nzcv,fpscr
             vmovmi.F64 d5,#1.0
             vsubmi.F64 d6,d6,d5
             vcvt.S32.F64 s2,d6
             vcvt.F64.S32 d4,s2
             vsub.F64 d0,d0,d4        ; leave the integer part in s2 and fraction in d0
             adr r2,log2e
             vldr.64 d5,[r2]
             vmul.F64 d0,d0,d5        ; Convert to a power of e
             b expser

expser       adr r2,expcoeff          ; calculate exp(y) from power series
             add r3,r2,#96
             vldr.64 d6,[r2],#8       ; d6=sum
10           vldr.64 d4,[r2],#8
             vmla.F64 d4,d6,d0        ; sum=sum*y + term
             vmov.F64 d6,d4
             cmp r2,r3
             blt %BT10
             vmov.F64 d4,#1.0
             vmla.F64 d4,d6,d0        ; add in the y term
             vmov.F64 d6,#1.0
             vmla.F64 d6,d4,d0        ; and the constant term
             vmov r1,s2
             add r1,r1,#1024
             sub r1,r1,#1
             mov r1,r1,lsl #20
             mov r2,#0
             vmov.F64 d4,r2,r1
             vmul.F64 d0,d6,d4
             pres
             mov pc,r14

expcoeff     DCFD 1.147074559772972289E-11
             DCFD 1.605904383682161593E-10
             DCFD 2.087675698786809605E-9
             DCFD 2.755731922398588828E-7
             DCFD 2.755731922398589251E-6
             DCFD 2.480158730158729818E-5
             DCFD 1.984126984126984126E-4
             DCFD 1.388888888888888725E-3
             DCFD 8.333333333333333333E-3
             DCFD 4.166666666666666435E-2 
             DCFD 1.666666666666666666E-1
             DCFD 5.000000000000000000E-1

             EXPORT vfp_pow
vfp_pow      mov ip,sp
             stmdb sp!,{fp,ip,lr,pc}
             sub fp,ip,#4
             p2arg                    ; get the exponent in d1
             bl vfp_ln                ; ln x is still in d0 after this call
             vmul.F64 d0,d0,d1        ; multiply the exponent by ln x
             pcall
             ldmdb fp,{fp,sp,lr}
             b vfp_exp                ; x^y=exp(y*ln x)

             EXPORT vfp_ln
vfp_ln       mov ip,sp
             stmdb sp!,{fp,ip,lr,pc}
             sub fp,ip,#4
             getmexp r1,d0
             bl ln_main
             zeroexp r1
             baseexp r1,log2e
             pres
             ldmdb fp,{fp,sp,pc}
log2e        DCFD 0.69314718055994530942

; Base 2 logarithm of x. The base 2 log of the exponent is simple
; so calculate ln fraction, convert to base 2 and add exponent

             EXPORT vfp_log2
vfp_log2     mov ip,sp
             stmdb sp!,{fp,ip,lr,pc}
             sub fp,ip,#4
             getmexp r1,d0
             bl ln_main
             vmov.F64 d4,d0
             vmov s2,r1               ; integer exponent in s2
             vcvt.F64.S32 d0,s2       ; integer to double
             adr r2,loge2
             vldr.64 d7,[r2]
             vmla.F64 d0,d4,d7
             pres
             ldmdb fp,{fp,sp,pc}
loge2        DCFD 1.44269504088896340735

             EXPORT vfp_log
vfp_log      mov ip,sp
             stmdb sp!,{fp,ip,lr,pc}
             sub fp,ip,#4
             getmexp r1,d0
             bl ln_main
             adr r2,loge10
             vldr.64 d7,[r2]
             vmul.F64 d0,d0,d7        ; convert logarithm to base 10
             zeroexp r1
             baseexp r1,log2ten
             pres
             ldmdb fp,{fp,sp,pc}
loge10       DCFD 0.43429448190325182765
log2ten      DCFD 0.30102999566398119521

; Calculates ln x using a rational approximation

ln_main      vmov.F64 d4,#1.0
             vsub.F64 d0,d0,d4
             vmul.F64 d5,d0,d0
             adr r2,logcoeff
             add r3,r2,#96
             vldr.64 d6,[r2],#8       ; d6=psum
             vldr.64 d7,[r2],#8       ; d7=qsum
10           vldr.64 d4,[r2],#8
             vmla.F64 d4,d6,d0        ; psum=psum*x + term
             vmov.F64 d6,d4
             vldr.64 d4,[r2],#8
             vmla.F64 d4,d7,d0        ; qsum=qsum*x + term
             vmov.F64 d7,d4
             cmp r2,r3
             blt %BT10
             vmul.F64 d6,d5,d6
             vdiv.F64 d6,d6,d7
             vmul.F64 d6,d6,d0        ; x^3 * psum/qsum
             vmov.F64 d4,#0.5
             vmls.F64 d6,d5,d4
             vadd.F64 d0,d6,d0        ; x - 0.5*z^2 + x^3 * psum/qsum
             mov pc,r14

logcoeff     DCFD  1.01875663804580931796E-4
             DCFD  1.0
             DCFD  4.97494994976747001425E-1
             DCFD  1.12873587189167450590E1
             DCFD  4.70579119878881725854E0
             DCFD  4.52279145837532221105E1
             DCFD  1.44989225341610930846E1
             DCFD  8.29875266912776603211E1
             DCFD  1.79368678507819816313E1
             DCFD  7.11544750618563894466E1
             DCFD  7.70838733755885391666E0
             DCFD  2.31251620126765340583E1
             END
