1*34129Sbostic; 2*34129Sbostic; Copyright (c) 1985 Regents of the University of California. 3*34129Sbostic; All rights reserved. 4*34129Sbostic; 5*34129Sbostic; Redistribution and use in source and binary forms are permitted 6*34129Sbostic; provided that this notice is preserved and that due credit is given 7*34129Sbostic; to the University of California at Berkeley. The name of the University 8*34129Sbostic; may not be used to endorse or promote products derived from this 9*34129Sbostic; software without specific prior written permission. This software 10*34129Sbostic; is provided ``as is'' without express or implied warranty. 11*34129Sbostic; 12*34129Sbostic; All recipients should regard themselves as participants in an ongoing 13*34129Sbostic; research project and hence should feel obligated to report their 14*34129Sbostic; experiences (good or bad) with these elementary function codes, using 15*34129Sbostic; the sendbug(8) program, to the authors. 16*34129Sbostic; 17*34129Sbostic; @(#)support.s 5.2 (Berkeley) 04/29/88 18*34129Sbostic; 19*34129Sbostic 2026460Selefunt; IEEE recommended functions 2126460Selefunt; 2226460Selefunt; double copysign(x,y) 2326460Selefunt; double x,y; 2426460Selefunt; IEEE 754 recommended function, return x*sign(y) 2526460Selefunt; Coded by K.C. Ng in National 32k assembler, 11/9/85. 2626460Selefunt; 2726460Selefunt .vers 2 2826460Selefunt .text 2926460Selefunt .align 2 3026460Selefunt .globl _copysign 3126460Selefunt_copysign: 3226460Selefunt movl 4(sp),f0 3326460Selefunt movd 8(sp),r0 3426460Selefunt movd 16(sp),r1 3526460Selefunt xord r0,r1 3626907Selefunt andd 0x80000000,r1 3726460Selefunt cmpqd 0,r1 3826460Selefunt beq end 3926460Selefunt negl f0,f0 4026460Selefuntend: ret 0 4126460Selefunt 4226460Selefunt; 4326460Selefunt; double logb(x) 4426460Selefunt; double x; 4526460Selefunt; IEEE p854 recommended function, return the exponent of x (return float(N) 4626460Selefunt; such that 1 <= x*2**-N < 2, even for subnormal number. 4726460Selefunt; Coded by K.C. Ng in National 32k assembler, 11/9/85. 4826460Selefunt; Note: subnormal number (if implemented) will be taken care of. 4926460Selefunt; 5026460Selefunt .vers 2 5126460Selefunt .text 5226460Selefunt .align 2 5326460Selefunt .globl _logb 5426460Selefunt_logb: 5526460Selefunt; 5626460Selefunt; extract the exponent of x 5726460Selefunt; glossaries: r0 = high part of x 5826460Selefunt; r1 = unbias exponent of x 5926460Selefunt; r2 = 20 (first exponent bit position) 6026460Selefunt; 6126460Selefunt movd 8(sp),r0 6226460Selefunt movd 20,r2 6326460Selefunt extd r2,r0,r1,11 ; extract the exponent of x 6426460Selefunt cmpqd 0,r1 ; if exponent bits = 0, goto L3 6526460Selefunt beq L3 6626460Selefunt cmpd 0x7ff,r1 6726460Selefunt beq L2 ; if exponent bits = 0x7ff, goto L2 6826460SelefuntL1: subd 1023,r1 ; unbias the exponent 6926460Selefunt movdl r1,f0 ; convert the exponent to floating value 7026460Selefunt ret 0 7126460Selefunt; 7226460Selefunt; x is INF or NaN, simply return x 7326460Selefunt; 7426460SelefuntL2: 7526460Selefunt movl 4(sp),f0 ; logb(+inf)=+inf, logb(NaN)=NaN 7626460Selefunt ret 0 7726460Selefunt; 7826460Selefunt; x is 0 or subnormal 7926460Selefunt; 8026460SelefuntL3: 8126460Selefunt movl 4(sp),f0 8226460Selefunt cmpl 0f0,f0 8326460Selefunt beq L5 ; x is 0 , goto L5 (return -inf) 8426460Selefunt; 8526460Selefunt; Now x is subnormal 8626460Selefunt; 8726460Selefunt mull L64,f0 ; scale up f0 with 2**64 8826460Selefunt movl f0,tos 8926460Selefunt movd tos,r0 9026460Selefunt movd tos,r0 ; now r0 = new high part of x 9126460Selefunt extd r2,r0,r1,11 ; extract the exponent of x to r1 9226460Selefunt subd 1087,r1 ; unbias the exponent with correction 9326460Selefunt movdl r1,f0 ; convert the exponent to floating value 9426460Selefunt ret 0 9526460Selefunt; 9626460Selefunt; x is 0, return logb(0)= -INF 9726460Selefunt; 9826460SelefuntL5: 9926460Selefunt movl 0f1.0e300,f0 10026460Selefunt mull 0f-1.0e300,f0 ; multiply two big numbers to get -INF 10126460Selefunt ret 0 10226460Selefunt; 10326460Selefunt; double rint(x) 10426460Selefunt; double x; 10526460Selefunt; ... delivers integer nearest x in direction of prevailing rounding 10626460Selefunt; ... mode 10726460Selefunt; Coded by K.C. Ng in National 32k assembler, 11/9/85. 10826460Selefunt; Note: subnormal number (if implemented) will be taken care of. 10926460Selefunt; 11026460Selefunt .vers 2 11126460Selefunt .text 11226460Selefunt .align 2 11326460Selefunt .globl _rint 11426460Selefunt_rint: 11526460Selefunt; 11626460Selefunt movd 8(sp),r0 11726460Selefunt movd 20,r2 11826460Selefunt extd r2,r0,r1,11 ; extract the exponent of x 11926460Selefunt cmpd 0x433,r1 12026460Selefunt ble itself 12126460Selefunt movl L52,f2 ; f2 = L = 2**52 12226460Selefunt cmpqd 0,r0 12326460Selefunt ble L1 12426460Selefunt negl f2,f2 ; f2 = s = copysign(L,x) 12526460SelefuntL1: addl f2,f0 ; f0 = x + s 12626460Selefunt subl f2,f0 ; f0 = f0 - s 12726460Selefunt ret 0 12826460Selefuntitself: movl 4(sp),f0 12926460Selefunt ret 0 13026460SelefuntL52: .double 0x0,0x43300000 ; L52=2**52 13126460Selefunt; 13226460Selefunt; int finite(x) 13326460Selefunt; double x; 13426460Selefunt; IEEE 754 recommended function, return 0 if x is NaN or INF, else 0 13526460Selefunt; Coded by K.C. Ng in National 32k assembler, 11/9/85. 13626460Selefunt; 13726460Selefunt .vers 2 13826460Selefunt .text 13926460Selefunt .align 2 14026460Selefunt .globl _finite 14126460Selefunt_finite: 14226460Selefunt movd 4(sp),r1 14326460Selefunt andd 0x800fffff,r1 14426460Selefunt cmpd 0x7ff00000,r1 14526460Selefunt sned r0 ; r0=0 if exponent(x) = 0x7ff 14626460Selefunt ret 0 14726460Selefunt; 14826460Selefunt; double scalb(x,N) 14926460Selefunt; double x; int N; 15026460Selefunt; IEEE 754 recommended function, return x*2**N by adjusting 15126460Selefunt; exponent of x. 15226460Selefunt; Coded by K.C. Ng in National 32k assembler, 11/9/85. 15326460Selefunt; Note: subnormal number (if implemented) will be taken care of 15426460Selefunt; 15526460Selefunt .vers 2 15626460Selefunt .text 15726460Selefunt .align 2 15826460Selefunt .globl _scalb 15926460Selefunt_scalb: 16026460Selefunt; 16126460Selefunt; if x=0 return 0 16226460Selefunt; 16326460Selefunt movl 4(sp),f0 16426460Selefunt cmpl 0f0,f0 16526460Selefunt beq end ; scalb(0,N) is x itself 16626460Selefunt; 16726460Selefunt; extract the exponent of x 16826460Selefunt; glossaries: r0 = high part of x, 16926460Selefunt; r1 = unbias exponent of x, 17026460Selefunt; r2 = 20 (first exponent bit position). 17126460Selefunt; 17226460Selefunt movd 8(sp),r0 ; r0 = high part of x 17326460Selefunt movd 20,r2 ; r2 = 20 17426460Selefunt extd r2,r0,r1,11 ; extract the exponent of x in r1 17526460Selefunt cmpd 0x7ff,r1 17626460Selefunt; 17726460Selefunt; if exponent of x is 0x7ff, then x is NaN or INF; simply return x 17826460Selefunt; 17926460Selefunt beq end 18026460Selefunt cmpqd 0,r1 18126460Selefunt; 18226460Selefunt; if exponent of x is zero, then x is subnormal; goto L19 18326460Selefunt; 18426460Selefunt beq L19 18526460Selefunt addd 12(sp),r1 ; r1 = (exponent of x) + N 18626460Selefunt bfs inof ; if integer overflows, goto inof 18726460Selefunt cmpqd 0,r1 ; if new exponent <= 0, goto underflow 18826460Selefunt bge underflow 18926460Selefunt cmpd 2047,r1 ; if new exponent >= 2047 goto overflow 19026460Selefunt ble overflow 19126460Selefunt insd r2,r1,r0,11 ; insert the new exponent 19226460Selefunt movd r0,tos 19326460Selefunt movd 8(sp),tos 19426460Selefunt movl tos,f0 ; return x*2**N 19526460Selefuntend: ret 0 19626460Selefuntinof: bcs underflow ; negative int overflow if Carry bit is set 19726460Selefuntoverflow: 19826460Selefunt andd 0x80000000,r0 ; keep the sign of x 19926460Selefunt ord 0x7fe00000,r0 ; set x to a huge number 20026460Selefunt movd r0,tos 20126460Selefunt movqd 0,tos 20226460Selefunt movl tos,f0 20326460Selefunt mull 0f1.0e300,f0 ; multiply two huge number to get overflow 20426460Selefunt ret 0 20526460Selefuntunderflow: 20626460Selefunt addd 64,r1 ; add 64 to exonent to see if it is subnormal 20726460Selefunt cmpqd 0,r1 20826460Selefunt bge zero ; underflow to zero 20926460Selefunt insd r2,r1,r0,11 ; insert the new exponent 21026460Selefunt movd r0,tos 21126460Selefunt movd 8(sp),tos 21226460Selefunt movl tos,f0 21326460Selefunt mull L30,f0 ; readjust x by multiply it with 2**-64 21426460Selefunt ret 0 21526460Selefuntzero: andd 0x80000000,r0 ; keep the sign of x 21626460Selefunt ord 0x00100000,r0 ; set x to a tiny number 21726460Selefunt movd r0,tos 21826460Selefunt movqd 0,tos 21926460Selefunt movl tos,f0 22026460Selefunt mull 0f1.0e-300,f0 ; underflow to 0 by multipling two tiny nos. 22126460Selefunt ret 0 22226460SelefuntL19: ; subnormal number 22326460Selefunt mull L32,f0 ; scale up x by 2**64 22426460Selefunt movl f0,tos 22526460Selefunt movd tos,r0 22626460Selefunt movd tos,r0 ; get the high part of new x 22726460Selefunt extd r2,r0,r1,11 ; extract the exponent of x in r1 22826460Selefunt addd 12(sp),r1 ; exponent of x + N 22926460Selefunt subd 64,r1 ; adjust it by subtracting 64 23026460Selefunt cmpqd 0,r1 23126460Selefunt bge underflow 23226460Selefunt cmpd 2047,r1 23326460Selefunt ble overflow 23426460Selefunt insd r2,r1,r0,11 ; insert back the incremented exponent 23526460Selefunt movd r0,tos 23626460Selefunt movd 8(sp),tos 23726460Selefunt movl tos,f0 23826460Selefuntend: ret 0 23926460SelefuntL30: .double 0x0,0x3bf00000 ; floating point 2**-64 24026460SelefuntL32: .double 0x0,0x43f00000 ; floating point 2**64 24131848Szliu; 24231848Szliu; double drem(x,y) 24331848Szliu; double x,y; 24431848Szliu; IEEE double remainder function, return x-n*y, where n=x/y rounded to 24531848Szliu; nearest integer (half way case goes to even). Result exact. 24631848Szliu; Coded by K.C. Ng in National 32k assembly, 11/19/85. 24731848Szliu; 24831848Szliu .vers 2 24931848Szliu .text 25031848Szliu .align 2 25131848Szliu .globl _drem 25231848Szliu_drem: 25331848Szliu; 25431848Szliu; glossaries: 25531848Szliu; r2 = high part of x 25631848Szliu; r3 = exponent of x 25731848Szliu; r4 = high part of y 25831848Szliu; r5 = exponent of y 25931848Szliu; r6 = sign of x 26031848Szliu; r7 = constant 0x7ff00000 26131848Szliu; 26231848Szliu; 16(fp) : y 26331848Szliu; 8(fp) : x 26431848Szliu; -12(fp) : adjustment on y when y is subnormal 26531848Szliu; -16(fp) : fsr 26631848Szliu; -20(fp) : nx 26731848Szliu; -28(fp) : t 26831848Szliu; -36(fp) : t1 26931848Szliu; -40(fp) : nf 27031848Szliu; 27131848Szliu; 27231848Szliu enter [r3,r4,r5,r6,r7],40 27331848Szliu movl f6,tos 27431848Szliu movl f4,tos 27531848Szliu movl 0f0,-12(fp) 27631848Szliu movd 0,-20(fp) 27731848Szliu movd 0,-40(fp) 27831848Szliu movd 0x7ff00000,r7 ; initialize r7=0x7ff00000 27931848Szliu movd 12(fp),r2 ; r2 = high(x) 28031848Szliu movd r2,r3 28131848Szliu andd r7,r3 ; r3 = xexp 28231848Szliu cmpd r7,r3 28331848Szliu; if x is NaN or INF goto L1 28431848Szliu beq L1 28531848Szliu movd 20(fp),r4 28631848Szliu bicd [31],r4 ; r4 = high part of |y| 28731848Szliu movd r4,20(fp) ; y = |y| 28831848Szliu movd r4,r5 28931848Szliu andd r7,r5 ; r5 = yexp 29031848Szliu cmpd r7,r5 29131848Szliu beq L2 ; if y is NaN or INF goto L2 29231848Szliu cmpd 0x04000000,r5 ; 29331848Szliu bgt L3 ; if y is tiny goto L3 29431848Szliu; 29531848Szliu; now y != 0 , x is finite 29631848Szliu; 29731848SzliuL10: 29831848Szliu movd r2,r6 29931848Szliu andd 0x80000000,r6 ; r6 = sign(x) 30031848Szliu bicd [31],r2 ; x <- |x| 30131848Szliu sfsr r1 30231848Szliu movd r1,-16(fp) ; save fsr in -16(fp) 30331848Szliu bicd [5],r1 30431848Szliu lfsr r1 ; disable inexact interupt 30531848Szliu movd 16(fp),r0 ; r0 = low part of y 30631848Szliu movd r0,r1 ; r1 = r0 = low part of y 30731848Szliu andd 0xf8000000,r1 ; mask off the lsb 27 bits of y 30831848Szliu 30931848Szliu movd r2,12(fp) ; update x to |x| 31031848Szliu movd r0,-28(fp) ; 31131848Szliu movd r4,-24(fp) ; t = y 31231848Szliu movd r4,-32(fp) ; 31331848Szliu movd r1,-36(fp) ; t1 = y with trialing 27 zeros 31431848Szliu movd 0x01900000,r1 ; r1 = 25 in exponent field 31531848SzliuLOOP: 31631848Szliu movl 8(fp),f0 ; f0 = x 31731848Szliu movl 16(fp),f2 ; f2 = y 31831848Szliu cmpl f0,f2 31931848Szliu ble fnad ; goto fnad (final adjustment) if x <= y 32031848Szliu movd r4,-32(fp) 32131848Szliu movd r3,r0 32231848Szliu subd r5,r0 ; xexp - yexp 32331848Szliu subd r1,r0 ; r0 = xexp - yexp - m25 32431848Szliu cmpqd 0,r0 ; r0 > 0 ? 32531848Szliu bge 1f 32631848Szliu addd r4,r0 ; scale up (high) y 32731848Szliu movd r0,-24(fp) ; scale up t 32831848Szliu movl -28(fp),f2 ; t 32931848Szliu movd r0,-32(fp) ; scale up t1 33031848Szliu1: 33131848Szliu movl -36(fp),f4 ; t1 33231848Szliu movl f0,f6 33331848Szliu divl f2,f6 ; f6 = x/t 33431848Szliu floorld f6,r0 ; r0 = [x/t] 33531848Szliu movdl r0,f6 ; f6 = n 33631848Szliu subl f4,f2 ; t = t - t1 (tail of t1) 33731848Szliu mull f6,f4 ; f4 = n*t1 ...exact 33831848Szliu subl f4,f0 ; x = x - n*t1 33931848Szliu mull f6,f2 ; n*(t-t1) ...exact 34031848Szliu subl f2,f0 ; x = x - n*(t-t1) 34131848Szliu; update xexp 34231848Szliu movl f0,8(fp) 34331848Szliu movd 12(fp),r3 34431848Szliu andd r7,r3 34531848Szliu jump LOOP 34631848Szliufnad: 34731848Szliu cmpqd 0,-20(fp) ; 0 = nx? 34831848Szliu beq final 34931848Szliu mull -12(fp),8(fp) ; scale up x the same amount as y 35031848Szliu movd 0,-20(fp) 35131848Szliu movd 12(fp),r2 35231848Szliu movd r2,r3 35331848Szliu andd r7,r3 ; update exponent of x 35431848Szliu jump LOOP 35531848Szliu 35631848Szliufinal: 35731848Szliu movl 16(fp),f2 ; f2 = y (f0=x, r0=n) 35831848Szliu subd 0x100000,r4 ; high y /2 35931848Szliu movd r4,-24(fp) 36031848Szliu movl -28(fp),f4 ; f4 = y/2 36131848Szliu cmpl f0,f4 ; x > y/2 ? 36231848Szliu bgt 1f 36331848Szliu bne 2f 36431848Szliu andd 1,r0 ; n is odd or even 36531848Szliu cmpqd 0,r0 36631848Szliu beq 2f 36731848Szliu1: 36831848Szliu subl f2,f0 ; x = x - y 36931848Szliu2: 37031848Szliu cmpqd 0,-40(fp) 37131848Szliu beq 3f 37231848Szliu divl -12(fp),f0 ; scale down the answer 37331848Szliu3: 37431848Szliu movl f0,tos 37531848Szliu xord r6,tos 37631848Szliu movl tos,f0 37731848Szliu movd -16(fp),r0 37831848Szliu lfsr r0 ; restore the fsr 37931848Szliu 38031848Szliuend: movl tos,f4 38131848Szliu movl tos,f6 38231848Szliu exit [r3,r4,r5,r6,r7] 38331848Szliu ret 0 38431848Szliu; 38531848Szliu; y is NaN or INF 38631848Szliu; 38731848SzliuL2: 38831848Szliu movd 16(fp),r0 ; r0 = low part of y 38931848Szliu andd 0xfffff,r4 ; r4 = high part of y & 0x000fffff 39031848Szliu ord r4,r0 39131848Szliu cmpqd 0,r0 39231848Szliu beq L4 39331848Szliu movl 16(fp),f0 ; y is NaN, return y 39431848Szliu jump end 39531848SzliuL4: movl 8(fp),f0 ; y is inf, return x 39631848Szliu jump end 39731848Szliu; 39831848Szliu; exponent of y is less than 64, y may be zero or subnormal 39931848Szliu; 40031848SzliuL3: 40131848Szliu movl 16(fp),f0 40231848Szliu cmpl 0f0,f0 40331848Szliu bne L5 40431848Szliu divl f0,f0 ; y is 0, return NaN by doing 0/0 40531848Szliu jump end 40631848Szliu; 40731848Szliu; subnormal y or tiny y 40831848Szliu; 40931848SzliuL5: 41031848Szliu movd 0x04000000,-20(fp) ; nx = 64 in exponent field 41131848Szliu movl L64,f2 41231848Szliu movl f2,-12(fp) 41331848Szliu mull f2,f0 41431848Szliu cmpl f0,LTINY 41531848Szliu bgt L6 41631848Szliu mull f2,f0 41731848Szliu addd 0x04000000,-20(fp) ; nx = nx + 64 in exponent field 41831848Szliu mull f2,-12(fp) 41931848SzliuL6: 42031848Szliu movd -20(fp),-40(fp) 42131848Szliu movl f0,16(fp) 42231848Szliu movd 20(fp),r4 42331848Szliu movd r4,r5 42431848Szliu andd r7,r5 ; exponent of new y 42531848Szliu jump L10 42631848Szliu; 42731848Szliu; x is NaN or INF, return x-x 42831848Szliu; 42931848SzliuL1: 43031848Szliu movl 8(fp),f0 43131848Szliu subl f0,f0 ; if x is INF, then INF-INF is NaN 43231848Szliu ret 0 43331848SzliuL64: .double 0x0,0x43f00000 ; L64 = 2**64 43431848SzliuLTINY: .double 0x0,0x04000000 ; LTINY = 2**-959 435