1*31848Szliu; @(#)support.s 1.3 (ucb.elefunt) 07/13/87 226460Selefunt; 326460Selefunt; IEEE recommended functions 426460Selefunt; 526460Selefunt; double copysign(x,y) 626460Selefunt; double x,y; 726460Selefunt; IEEE 754 recommended function, return x*sign(y) 826460Selefunt; Coded by K.C. Ng in National 32k assembler, 11/9/85. 926460Selefunt; 1026460Selefunt .vers 2 1126460Selefunt .text 1226460Selefunt .align 2 1326460Selefunt .globl _copysign 1426460Selefunt_copysign: 1526460Selefunt movl 4(sp),f0 1626460Selefunt movd 8(sp),r0 1726460Selefunt movd 16(sp),r1 1826460Selefunt xord r0,r1 1926907Selefunt andd 0x80000000,r1 2026460Selefunt cmpqd 0,r1 2126460Selefunt beq end 2226460Selefunt negl f0,f0 2326460Selefuntend: ret 0 2426460Selefunt 2526460Selefunt; 2626460Selefunt; double logb(x) 2726460Selefunt; double x; 2826460Selefunt; IEEE p854 recommended function, return the exponent of x (return float(N) 2926460Selefunt; such that 1 <= x*2**-N < 2, even for subnormal number. 3026460Selefunt; Coded by K.C. Ng in National 32k assembler, 11/9/85. 3126460Selefunt; Note: subnormal number (if implemented) will be taken care of. 3226460Selefunt; 3326460Selefunt .vers 2 3426460Selefunt .text 3526460Selefunt .align 2 3626460Selefunt .globl _logb 3726460Selefunt_logb: 3826460Selefunt; 3926460Selefunt; extract the exponent of x 4026460Selefunt; glossaries: r0 = high part of x 4126460Selefunt; r1 = unbias exponent of x 4226460Selefunt; r2 = 20 (first exponent bit position) 4326460Selefunt; 4426460Selefunt movd 8(sp),r0 4526460Selefunt movd 20,r2 4626460Selefunt extd r2,r0,r1,11 ; extract the exponent of x 4726460Selefunt cmpqd 0,r1 ; if exponent bits = 0, goto L3 4826460Selefunt beq L3 4926460Selefunt cmpd 0x7ff,r1 5026460Selefunt beq L2 ; if exponent bits = 0x7ff, goto L2 5126460SelefuntL1: subd 1023,r1 ; unbias the exponent 5226460Selefunt movdl r1,f0 ; convert the exponent to floating value 5326460Selefunt ret 0 5426460Selefunt; 5526460Selefunt; x is INF or NaN, simply return x 5626460Selefunt; 5726460SelefuntL2: 5826460Selefunt movl 4(sp),f0 ; logb(+inf)=+inf, logb(NaN)=NaN 5926460Selefunt ret 0 6026460Selefunt; 6126460Selefunt; x is 0 or subnormal 6226460Selefunt; 6326460SelefuntL3: 6426460Selefunt movl 4(sp),f0 6526460Selefunt cmpl 0f0,f0 6626460Selefunt beq L5 ; x is 0 , goto L5 (return -inf) 6726460Selefunt; 6826460Selefunt; Now x is subnormal 6926460Selefunt; 7026460Selefunt mull L64,f0 ; scale up f0 with 2**64 7126460Selefunt movl f0,tos 7226460Selefunt movd tos,r0 7326460Selefunt movd tos,r0 ; now r0 = new high part of x 7426460Selefunt extd r2,r0,r1,11 ; extract the exponent of x to r1 7526460Selefunt subd 1087,r1 ; unbias the exponent with correction 7626460Selefunt movdl r1,f0 ; convert the exponent to floating value 7726460Selefunt ret 0 7826460Selefunt; 7926460Selefunt; x is 0, return logb(0)= -INF 8026460Selefunt; 8126460SelefuntL5: 8226460Selefunt movl 0f1.0e300,f0 8326460Selefunt mull 0f-1.0e300,f0 ; multiply two big numbers to get -INF 8426460Selefunt ret 0 8526460Selefunt; 8626460Selefunt; double rint(x) 8726460Selefunt; double x; 8826460Selefunt; ... delivers integer nearest x in direction of prevailing rounding 8926460Selefunt; ... mode 9026460Selefunt; Coded by K.C. Ng in National 32k assembler, 11/9/85. 9126460Selefunt; Note: subnormal number (if implemented) will be taken care of. 9226460Selefunt; 9326460Selefunt .vers 2 9426460Selefunt .text 9526460Selefunt .align 2 9626460Selefunt .globl _rint 9726460Selefunt_rint: 9826460Selefunt; 9926460Selefunt movd 8(sp),r0 10026460Selefunt movd 20,r2 10126460Selefunt extd r2,r0,r1,11 ; extract the exponent of x 10226460Selefunt cmpd 0x433,r1 10326460Selefunt ble itself 10426460Selefunt movl L52,f2 ; f2 = L = 2**52 10526460Selefunt cmpqd 0,r0 10626460Selefunt ble L1 10726460Selefunt negl f2,f2 ; f2 = s = copysign(L,x) 10826460SelefuntL1: addl f2,f0 ; f0 = x + s 10926460Selefunt subl f2,f0 ; f0 = f0 - s 11026460Selefunt ret 0 11126460Selefuntitself: movl 4(sp),f0 11226460Selefunt ret 0 11326460SelefuntL52: .double 0x0,0x43300000 ; L52=2**52 11426460Selefunt; 11526460Selefunt; int finite(x) 11626460Selefunt; double x; 11726460Selefunt; IEEE 754 recommended function, return 0 if x is NaN or INF, else 0 11826460Selefunt; Coded by K.C. Ng in National 32k assembler, 11/9/85. 11926460Selefunt; 12026460Selefunt .vers 2 12126460Selefunt .text 12226460Selefunt .align 2 12326460Selefunt .globl _finite 12426460Selefunt_finite: 12526460Selefunt movd 4(sp),r1 12626460Selefunt andd 0x800fffff,r1 12726460Selefunt cmpd 0x7ff00000,r1 12826460Selefunt sned r0 ; r0=0 if exponent(x) = 0x7ff 12926460Selefunt ret 0 13026460Selefunt; 13126460Selefunt; double scalb(x,N) 13226460Selefunt; double x; int N; 13326460Selefunt; IEEE 754 recommended function, return x*2**N by adjusting 13426460Selefunt; exponent of x. 13526460Selefunt; Coded by K.C. Ng in National 32k assembler, 11/9/85. 13626460Selefunt; Note: subnormal number (if implemented) will be taken care of 13726460Selefunt; 13826460Selefunt .vers 2 13926460Selefunt .text 14026460Selefunt .align 2 14126460Selefunt .globl _scalb 14226460Selefunt_scalb: 14326460Selefunt; 14426460Selefunt; if x=0 return 0 14526460Selefunt; 14626460Selefunt movl 4(sp),f0 14726460Selefunt cmpl 0f0,f0 14826460Selefunt beq end ; scalb(0,N) is x itself 14926460Selefunt; 15026460Selefunt; extract the exponent of x 15126460Selefunt; glossaries: r0 = high part of x, 15226460Selefunt; r1 = unbias exponent of x, 15326460Selefunt; r2 = 20 (first exponent bit position). 15426460Selefunt; 15526460Selefunt movd 8(sp),r0 ; r0 = high part of x 15626460Selefunt movd 20,r2 ; r2 = 20 15726460Selefunt extd r2,r0,r1,11 ; extract the exponent of x in r1 15826460Selefunt cmpd 0x7ff,r1 15926460Selefunt; 16026460Selefunt; if exponent of x is 0x7ff, then x is NaN or INF; simply return x 16126460Selefunt; 16226460Selefunt beq end 16326460Selefunt cmpqd 0,r1 16426460Selefunt; 16526460Selefunt; if exponent of x is zero, then x is subnormal; goto L19 16626460Selefunt; 16726460Selefunt beq L19 16826460Selefunt addd 12(sp),r1 ; r1 = (exponent of x) + N 16926460Selefunt bfs inof ; if integer overflows, goto inof 17026460Selefunt cmpqd 0,r1 ; if new exponent <= 0, goto underflow 17126460Selefunt bge underflow 17226460Selefunt cmpd 2047,r1 ; if new exponent >= 2047 goto overflow 17326460Selefunt ble overflow 17426460Selefunt insd r2,r1,r0,11 ; insert the new exponent 17526460Selefunt movd r0,tos 17626460Selefunt movd 8(sp),tos 17726460Selefunt movl tos,f0 ; return x*2**N 17826460Selefuntend: ret 0 17926460Selefuntinof: bcs underflow ; negative int overflow if Carry bit is set 18026460Selefuntoverflow: 18126460Selefunt andd 0x80000000,r0 ; keep the sign of x 18226460Selefunt ord 0x7fe00000,r0 ; set x to a huge number 18326460Selefunt movd r0,tos 18426460Selefunt movqd 0,tos 18526460Selefunt movl tos,f0 18626460Selefunt mull 0f1.0e300,f0 ; multiply two huge number to get overflow 18726460Selefunt ret 0 18826460Selefuntunderflow: 18926460Selefunt addd 64,r1 ; add 64 to exonent to see if it is subnormal 19026460Selefunt cmpqd 0,r1 19126460Selefunt bge zero ; underflow to zero 19226460Selefunt insd r2,r1,r0,11 ; insert the new exponent 19326460Selefunt movd r0,tos 19426460Selefunt movd 8(sp),tos 19526460Selefunt movl tos,f0 19626460Selefunt mull L30,f0 ; readjust x by multiply it with 2**-64 19726460Selefunt ret 0 19826460Selefuntzero: andd 0x80000000,r0 ; keep the sign of x 19926460Selefunt ord 0x00100000,r0 ; set x to a tiny number 20026460Selefunt movd r0,tos 20126460Selefunt movqd 0,tos 20226460Selefunt movl tos,f0 20326460Selefunt mull 0f1.0e-300,f0 ; underflow to 0 by multipling two tiny nos. 20426460Selefunt ret 0 20526460SelefuntL19: ; subnormal number 20626460Selefunt mull L32,f0 ; scale up x by 2**64 20726460Selefunt movl f0,tos 20826460Selefunt movd tos,r0 20926460Selefunt movd tos,r0 ; get the high part of new x 21026460Selefunt extd r2,r0,r1,11 ; extract the exponent of x in r1 21126460Selefunt addd 12(sp),r1 ; exponent of x + N 21226460Selefunt subd 64,r1 ; adjust it by subtracting 64 21326460Selefunt cmpqd 0,r1 21426460Selefunt bge underflow 21526460Selefunt cmpd 2047,r1 21626460Selefunt ble overflow 21726460Selefunt insd r2,r1,r0,11 ; insert back the incremented exponent 21826460Selefunt movd r0,tos 21926460Selefunt movd 8(sp),tos 22026460Selefunt movl tos,f0 22126460Selefuntend: ret 0 22226460SelefuntL30: .double 0x0,0x3bf00000 ; floating point 2**-64 22326460SelefuntL32: .double 0x0,0x43f00000 ; floating point 2**64 224*31848Szliu; 225*31848Szliu; double drem(x,y) 226*31848Szliu; double x,y; 227*31848Szliu; IEEE double remainder function, return x-n*y, where n=x/y rounded to 228*31848Szliu; nearest integer (half way case goes to even). Result exact. 229*31848Szliu; Coded by K.C. Ng in National 32k assembly, 11/19/85. 230*31848Szliu; 231*31848Szliu .vers 2 232*31848Szliu .text 233*31848Szliu .align 2 234*31848Szliu .globl _drem 235*31848Szliu_drem: 236*31848Szliu; 237*31848Szliu; glossaries: 238*31848Szliu; r2 = high part of x 239*31848Szliu; r3 = exponent of x 240*31848Szliu; r4 = high part of y 241*31848Szliu; r5 = exponent of y 242*31848Szliu; r6 = sign of x 243*31848Szliu; r7 = constant 0x7ff00000 244*31848Szliu; 245*31848Szliu; 16(fp) : y 246*31848Szliu; 8(fp) : x 247*31848Szliu; -12(fp) : adjustment on y when y is subnormal 248*31848Szliu; -16(fp) : fsr 249*31848Szliu; -20(fp) : nx 250*31848Szliu; -28(fp) : t 251*31848Szliu; -36(fp) : t1 252*31848Szliu; -40(fp) : nf 253*31848Szliu; 254*31848Szliu; 255*31848Szliu enter [r3,r4,r5,r6,r7],40 256*31848Szliu movl f6,tos 257*31848Szliu movl f4,tos 258*31848Szliu movl 0f0,-12(fp) 259*31848Szliu movd 0,-20(fp) 260*31848Szliu movd 0,-40(fp) 261*31848Szliu movd 0x7ff00000,r7 ; initialize r7=0x7ff00000 262*31848Szliu movd 12(fp),r2 ; r2 = high(x) 263*31848Szliu movd r2,r3 264*31848Szliu andd r7,r3 ; r3 = xexp 265*31848Szliu cmpd r7,r3 266*31848Szliu; if x is NaN or INF goto L1 267*31848Szliu beq L1 268*31848Szliu movd 20(fp),r4 269*31848Szliu bicd [31],r4 ; r4 = high part of |y| 270*31848Szliu movd r4,20(fp) ; y = |y| 271*31848Szliu movd r4,r5 272*31848Szliu andd r7,r5 ; r5 = yexp 273*31848Szliu cmpd r7,r5 274*31848Szliu beq L2 ; if y is NaN or INF goto L2 275*31848Szliu cmpd 0x04000000,r5 ; 276*31848Szliu bgt L3 ; if y is tiny goto L3 277*31848Szliu; 278*31848Szliu; now y != 0 , x is finite 279*31848Szliu; 280*31848SzliuL10: 281*31848Szliu movd r2,r6 282*31848Szliu andd 0x80000000,r6 ; r6 = sign(x) 283*31848Szliu bicd [31],r2 ; x <- |x| 284*31848Szliu sfsr r1 285*31848Szliu movd r1,-16(fp) ; save fsr in -16(fp) 286*31848Szliu bicd [5],r1 287*31848Szliu lfsr r1 ; disable inexact interupt 288*31848Szliu movd 16(fp),r0 ; r0 = low part of y 289*31848Szliu movd r0,r1 ; r1 = r0 = low part of y 290*31848Szliu andd 0xf8000000,r1 ; mask off the lsb 27 bits of y 291*31848Szliu 292*31848Szliu movd r2,12(fp) ; update x to |x| 293*31848Szliu movd r0,-28(fp) ; 294*31848Szliu movd r4,-24(fp) ; t = y 295*31848Szliu movd r4,-32(fp) ; 296*31848Szliu movd r1,-36(fp) ; t1 = y with trialing 27 zeros 297*31848Szliu movd 0x01900000,r1 ; r1 = 25 in exponent field 298*31848SzliuLOOP: 299*31848Szliu movl 8(fp),f0 ; f0 = x 300*31848Szliu movl 16(fp),f2 ; f2 = y 301*31848Szliu cmpl f0,f2 302*31848Szliu ble fnad ; goto fnad (final adjustment) if x <= y 303*31848Szliu movd r4,-32(fp) 304*31848Szliu movd r3,r0 305*31848Szliu subd r5,r0 ; xexp - yexp 306*31848Szliu subd r1,r0 ; r0 = xexp - yexp - m25 307*31848Szliu cmpqd 0,r0 ; r0 > 0 ? 308*31848Szliu bge 1f 309*31848Szliu addd r4,r0 ; scale up (high) y 310*31848Szliu movd r0,-24(fp) ; scale up t 311*31848Szliu movl -28(fp),f2 ; t 312*31848Szliu movd r0,-32(fp) ; scale up t1 313*31848Szliu1: 314*31848Szliu movl -36(fp),f4 ; t1 315*31848Szliu movl f0,f6 316*31848Szliu divl f2,f6 ; f6 = x/t 317*31848Szliu floorld f6,r0 ; r0 = [x/t] 318*31848Szliu movdl r0,f6 ; f6 = n 319*31848Szliu subl f4,f2 ; t = t - t1 (tail of t1) 320*31848Szliu mull f6,f4 ; f4 = n*t1 ...exact 321*31848Szliu subl f4,f0 ; x = x - n*t1 322*31848Szliu mull f6,f2 ; n*(t-t1) ...exact 323*31848Szliu subl f2,f0 ; x = x - n*(t-t1) 324*31848Szliu; update xexp 325*31848Szliu movl f0,8(fp) 326*31848Szliu movd 12(fp),r3 327*31848Szliu andd r7,r3 328*31848Szliu jump LOOP 329*31848Szliufnad: 330*31848Szliu cmpqd 0,-20(fp) ; 0 = nx? 331*31848Szliu beq final 332*31848Szliu mull -12(fp),8(fp) ; scale up x the same amount as y 333*31848Szliu movd 0,-20(fp) 334*31848Szliu movd 12(fp),r2 335*31848Szliu movd r2,r3 336*31848Szliu andd r7,r3 ; update exponent of x 337*31848Szliu jump LOOP 338*31848Szliu 339*31848Szliufinal: 340*31848Szliu movl 16(fp),f2 ; f2 = y (f0=x, r0=n) 341*31848Szliu subd 0x100000,r4 ; high y /2 342*31848Szliu movd r4,-24(fp) 343*31848Szliu movl -28(fp),f4 ; f4 = y/2 344*31848Szliu cmpl f0,f4 ; x > y/2 ? 345*31848Szliu bgt 1f 346*31848Szliu bne 2f 347*31848Szliu andd 1,r0 ; n is odd or even 348*31848Szliu cmpqd 0,r0 349*31848Szliu beq 2f 350*31848Szliu1: 351*31848Szliu subl f2,f0 ; x = x - y 352*31848Szliu2: 353*31848Szliu cmpqd 0,-40(fp) 354*31848Szliu beq 3f 355*31848Szliu divl -12(fp),f0 ; scale down the answer 356*31848Szliu3: 357*31848Szliu movl f0,tos 358*31848Szliu xord r6,tos 359*31848Szliu movl tos,f0 360*31848Szliu movd -16(fp),r0 361*31848Szliu lfsr r0 ; restore the fsr 362*31848Szliu 363*31848Szliuend: movl tos,f4 364*31848Szliu movl tos,f6 365*31848Szliu exit [r3,r4,r5,r6,r7] 366*31848Szliu ret 0 367*31848Szliu; 368*31848Szliu; y is NaN or INF 369*31848Szliu; 370*31848SzliuL2: 371*31848Szliu movd 16(fp),r0 ; r0 = low part of y 372*31848Szliu andd 0xfffff,r4 ; r4 = high part of y & 0x000fffff 373*31848Szliu ord r4,r0 374*31848Szliu cmpqd 0,r0 375*31848Szliu beq L4 376*31848Szliu movl 16(fp),f0 ; y is NaN, return y 377*31848Szliu jump end 378*31848SzliuL4: movl 8(fp),f0 ; y is inf, return x 379*31848Szliu jump end 380*31848Szliu; 381*31848Szliu; exponent of y is less than 64, y may be zero or subnormal 382*31848Szliu; 383*31848SzliuL3: 384*31848Szliu movl 16(fp),f0 385*31848Szliu cmpl 0f0,f0 386*31848Szliu bne L5 387*31848Szliu divl f0,f0 ; y is 0, return NaN by doing 0/0 388*31848Szliu jump end 389*31848Szliu; 390*31848Szliu; subnormal y or tiny y 391*31848Szliu; 392*31848SzliuL5: 393*31848Szliu movd 0x04000000,-20(fp) ; nx = 64 in exponent field 394*31848Szliu movl L64,f2 395*31848Szliu movl f2,-12(fp) 396*31848Szliu mull f2,f0 397*31848Szliu cmpl f0,LTINY 398*31848Szliu bgt L6 399*31848Szliu mull f2,f0 400*31848Szliu addd 0x04000000,-20(fp) ; nx = nx + 64 in exponent field 401*31848Szliu mull f2,-12(fp) 402*31848SzliuL6: 403*31848Szliu movd -20(fp),-40(fp) 404*31848Szliu movl f0,16(fp) 405*31848Szliu movd 20(fp),r4 406*31848Szliu movd r4,r5 407*31848Szliu andd r7,r5 ; exponent of new y 408*31848Szliu jump L10 409*31848Szliu; 410*31848Szliu; x is NaN or INF, return x-x 411*31848Szliu; 412*31848SzliuL1: 413*31848Szliu movl 8(fp),f0 414*31848Szliu subl f0,f0 ; if x is INF, then INF-INF is NaN 415*31848Szliu ret 0 416*31848SzliuL64: .double 0x0,0x43f00000 ; L64 = 2**64 417*31848SzliuLTINY: .double 0x0,0x04000000 ; LTINY = 2**-959 418