xref: /csrg-svn/lib/libm/national/support.s (revision 31848)
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