162306a36Sopenharmony_ci|
262306a36Sopenharmony_ci|	round.sa 3.4 7/29/91
362306a36Sopenharmony_ci|
462306a36Sopenharmony_ci|	handle rounding and normalization tasks
562306a36Sopenharmony_ci|
662306a36Sopenharmony_ci|
762306a36Sopenharmony_ci|
862306a36Sopenharmony_ci|		Copyright (C) Motorola, Inc. 1990
962306a36Sopenharmony_ci|			All Rights Reserved
1062306a36Sopenharmony_ci|
1162306a36Sopenharmony_ci|       For details on the license for this file, please see the
1262306a36Sopenharmony_ci|       file, README, in this same directory.
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci|ROUND	idnt    2,1 | Motorola 040 Floating Point Software Package
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci	|section	8
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include "fpsp.h"
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci|
2162306a36Sopenharmony_ci|	round --- round result according to precision/mode
2262306a36Sopenharmony_ci|
2362306a36Sopenharmony_ci|	a0 points to the input operand in the internal extended format
2462306a36Sopenharmony_ci|	d1(high word) contains rounding precision:
2562306a36Sopenharmony_ci|		ext = $0000xxxx
2662306a36Sopenharmony_ci|		sgl = $0001xxxx
2762306a36Sopenharmony_ci|		dbl = $0002xxxx
2862306a36Sopenharmony_ci|	d1(low word) contains rounding mode:
2962306a36Sopenharmony_ci|		RN  = $xxxx0000
3062306a36Sopenharmony_ci|		RZ  = $xxxx0001
3162306a36Sopenharmony_ci|		RM  = $xxxx0010
3262306a36Sopenharmony_ci|		RP  = $xxxx0011
3362306a36Sopenharmony_ci|	d0{31:29} contains the g,r,s bits (extended)
3462306a36Sopenharmony_ci|
3562306a36Sopenharmony_ci|	On return the value pointed to by a0 is correctly rounded,
3662306a36Sopenharmony_ci|	a0 is preserved and the g-r-s bits in d0 are cleared.
3762306a36Sopenharmony_ci|	The result is not typed - the tag field is invalid.  The
3862306a36Sopenharmony_ci|	result is still in the internal extended format.
3962306a36Sopenharmony_ci|
4062306a36Sopenharmony_ci|	The INEX bit of USER_FPSR will be set if the rounded result was
4162306a36Sopenharmony_ci|	inexact (i.e. if any of the g-r-s bits were set).
4262306a36Sopenharmony_ci|
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	.global	round
4562306a36Sopenharmony_ciround:
4662306a36Sopenharmony_ci| If g=r=s=0 then result is exact and round is done, else set
4762306a36Sopenharmony_ci| the inex flag in status reg and continue.
4862306a36Sopenharmony_ci|
4962306a36Sopenharmony_ci	bsrs	ext_grs			|this subroutine looks at the
5062306a36Sopenharmony_ci|					:rounding precision and sets
5162306a36Sopenharmony_ci|					;the appropriate g-r-s bits.
5262306a36Sopenharmony_ci	tstl	%d0			|if grs are zero, go force
5362306a36Sopenharmony_ci	bne	rnd_cont		|lower bits to zero for size
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	swap	%d1			|set up d1.w for round prec.
5662306a36Sopenharmony_ci	bra	truncate
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cirnd_cont:
5962306a36Sopenharmony_ci|
6062306a36Sopenharmony_ci| Use rounding mode as an index into a jump table for these modes.
6162306a36Sopenharmony_ci|
6262306a36Sopenharmony_ci	orl	#inx2a_mask,USER_FPSR(%a6) |set inex2/ainex
6362306a36Sopenharmony_ci	lea	mode_tab,%a1
6462306a36Sopenharmony_ci	movel	(%a1,%d1.w*4),%a1
6562306a36Sopenharmony_ci	jmp	(%a1)
6662306a36Sopenharmony_ci|
6762306a36Sopenharmony_ci| Jump table indexed by rounding mode in d1.w.  All following assumes
6862306a36Sopenharmony_ci| grs != 0.
6962306a36Sopenharmony_ci|
7062306a36Sopenharmony_cimode_tab:
7162306a36Sopenharmony_ci	.long	rnd_near
7262306a36Sopenharmony_ci	.long	rnd_zero
7362306a36Sopenharmony_ci	.long	rnd_mnus
7462306a36Sopenharmony_ci	.long	rnd_plus
7562306a36Sopenharmony_ci|
7662306a36Sopenharmony_ci|	ROUND PLUS INFINITY
7762306a36Sopenharmony_ci|
7862306a36Sopenharmony_ci|	If sign of fp number = 0 (positive), then add 1 to l.
7962306a36Sopenharmony_ci|
8062306a36Sopenharmony_cirnd_plus:
8162306a36Sopenharmony_ci	swap	%d1			|set up d1 for round prec.
8262306a36Sopenharmony_ci	tstb	LOCAL_SGN(%a0)		|check for sign
8362306a36Sopenharmony_ci	bmi	truncate		|if positive then truncate
8462306a36Sopenharmony_ci	movel	#0xffffffff,%d0		|force g,r,s to be all f's
8562306a36Sopenharmony_ci	lea	add_to_l,%a1
8662306a36Sopenharmony_ci	movel	(%a1,%d1.w*4),%a1
8762306a36Sopenharmony_ci	jmp	(%a1)
8862306a36Sopenharmony_ci|
8962306a36Sopenharmony_ci|	ROUND MINUS INFINITY
9062306a36Sopenharmony_ci|
9162306a36Sopenharmony_ci|	If sign of fp number = 1 (negative), then add 1 to l.
9262306a36Sopenharmony_ci|
9362306a36Sopenharmony_cirnd_mnus:
9462306a36Sopenharmony_ci	swap	%d1			|set up d1 for round prec.
9562306a36Sopenharmony_ci	tstb	LOCAL_SGN(%a0)		|check for sign
9662306a36Sopenharmony_ci	bpl	truncate		|if negative then truncate
9762306a36Sopenharmony_ci	movel	#0xffffffff,%d0		|force g,r,s to be all f's
9862306a36Sopenharmony_ci	lea	add_to_l,%a1
9962306a36Sopenharmony_ci	movel	(%a1,%d1.w*4),%a1
10062306a36Sopenharmony_ci	jmp	(%a1)
10162306a36Sopenharmony_ci|
10262306a36Sopenharmony_ci|	ROUND ZERO
10362306a36Sopenharmony_ci|
10462306a36Sopenharmony_ci|	Always truncate.
10562306a36Sopenharmony_cirnd_zero:
10662306a36Sopenharmony_ci	swap	%d1			|set up d1 for round prec.
10762306a36Sopenharmony_ci	bra	truncate
10862306a36Sopenharmony_ci|
10962306a36Sopenharmony_ci|
11062306a36Sopenharmony_ci|	ROUND NEAREST
11162306a36Sopenharmony_ci|
11262306a36Sopenharmony_ci|	If (g=1), then add 1 to l and if (r=s=0), then clear l
11362306a36Sopenharmony_ci|	Note that this will round to even in case of a tie.
11462306a36Sopenharmony_ci|
11562306a36Sopenharmony_cirnd_near:
11662306a36Sopenharmony_ci	swap	%d1			|set up d1 for round prec.
11762306a36Sopenharmony_ci	asll	#1,%d0			|shift g-bit to c-bit
11862306a36Sopenharmony_ci	bcc	truncate		|if (g=1) then
11962306a36Sopenharmony_ci	lea	add_to_l,%a1
12062306a36Sopenharmony_ci	movel	(%a1,%d1.w*4),%a1
12162306a36Sopenharmony_ci	jmp	(%a1)
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci|
12462306a36Sopenharmony_ci|	ext_grs --- extract guard, round and sticky bits
12562306a36Sopenharmony_ci|
12662306a36Sopenharmony_ci| Input:	d1 =		PREC:ROUND
12762306a36Sopenharmony_ci| Output:	d0{31:29}=	guard, round, sticky
12862306a36Sopenharmony_ci|
12962306a36Sopenharmony_ci| The ext_grs extract the guard/round/sticky bits according to the
13062306a36Sopenharmony_ci| selected rounding precision. It is called by the round subroutine
13162306a36Sopenharmony_ci| only.  All registers except d0 are kept intact. d0 becomes an
13262306a36Sopenharmony_ci| updated guard,round,sticky in d0{31:29}
13362306a36Sopenharmony_ci|
13462306a36Sopenharmony_ci| Notes: the ext_grs uses the round PREC, and therefore has to swap d1
13562306a36Sopenharmony_ci|	 prior to usage, and needs to restore d1 to original.
13662306a36Sopenharmony_ci|
13762306a36Sopenharmony_ciext_grs:
13862306a36Sopenharmony_ci	swap	%d1			|have d1.w point to round precision
13962306a36Sopenharmony_ci	cmpiw	#0,%d1
14062306a36Sopenharmony_ci	bnes	sgl_or_dbl
14162306a36Sopenharmony_ci	bras	end_ext_grs
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_cisgl_or_dbl:
14462306a36Sopenharmony_ci	moveml	%d2/%d3,-(%a7)		|make some temp registers
14562306a36Sopenharmony_ci	cmpiw	#1,%d1
14662306a36Sopenharmony_ci	bnes	grs_dbl
14762306a36Sopenharmony_cigrs_sgl:
14862306a36Sopenharmony_ci	bfextu	LOCAL_HI(%a0){#24:#2},%d3	|sgl prec. g-r are 2 bits right
14962306a36Sopenharmony_ci	movel	#30,%d2			|of the sgl prec. limits
15062306a36Sopenharmony_ci	lsll	%d2,%d3			|shift g-r bits to MSB of d3
15162306a36Sopenharmony_ci	movel	LOCAL_HI(%a0),%d2		|get word 2 for s-bit test
15262306a36Sopenharmony_ci	andil	#0x0000003f,%d2		|s bit is the or of all other
15362306a36Sopenharmony_ci	bnes	st_stky			|bits to the right of g-r
15462306a36Sopenharmony_ci	tstl	LOCAL_LO(%a0)		|test lower mantissa
15562306a36Sopenharmony_ci	bnes	st_stky			|if any are set, set sticky
15662306a36Sopenharmony_ci	tstl	%d0			|test original g,r,s
15762306a36Sopenharmony_ci	bnes	st_stky			|if any are set, set sticky
15862306a36Sopenharmony_ci	bras	end_sd			|if words 3 and 4 are clr, exit
15962306a36Sopenharmony_cigrs_dbl:
16062306a36Sopenharmony_ci	bfextu	LOCAL_LO(%a0){#21:#2},%d3	|dbl-prec. g-r are 2 bits right
16162306a36Sopenharmony_ci	movel	#30,%d2			|of the dbl prec. limits
16262306a36Sopenharmony_ci	lsll	%d2,%d3			|shift g-r bits to the MSB of d3
16362306a36Sopenharmony_ci	movel	LOCAL_LO(%a0),%d2		|get lower mantissa  for s-bit test
16462306a36Sopenharmony_ci	andil	#0x000001ff,%d2		|s bit is the or-ing of all
16562306a36Sopenharmony_ci	bnes	st_stky			|other bits to the right of g-r
16662306a36Sopenharmony_ci	tstl	%d0			|test word original g,r,s
16762306a36Sopenharmony_ci	bnes	st_stky			|if any are set, set sticky
16862306a36Sopenharmony_ci	bras	end_sd			|if clear, exit
16962306a36Sopenharmony_cist_stky:
17062306a36Sopenharmony_ci	bset	#rnd_stky_bit,%d3
17162306a36Sopenharmony_ciend_sd:
17262306a36Sopenharmony_ci	movel	%d3,%d0			|return grs to d0
17362306a36Sopenharmony_ci	moveml	(%a7)+,%d2/%d3		|restore scratch registers
17462306a36Sopenharmony_ciend_ext_grs:
17562306a36Sopenharmony_ci	swap	%d1			|restore d1 to original
17662306a36Sopenharmony_ci	rts
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci|*******************  Local Equates
17962306a36Sopenharmony_ci	.set	ad_1_sgl,0x00000100	|  constant to add 1 to l-bit in sgl prec
18062306a36Sopenharmony_ci	.set	ad_1_dbl,0x00000800	|  constant to add 1 to l-bit in dbl prec
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci|Jump table for adding 1 to the l-bit indexed by rnd prec
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ciadd_to_l:
18662306a36Sopenharmony_ci	.long	add_ext
18762306a36Sopenharmony_ci	.long	add_sgl
18862306a36Sopenharmony_ci	.long	add_dbl
18962306a36Sopenharmony_ci	.long	add_dbl
19062306a36Sopenharmony_ci|
19162306a36Sopenharmony_ci|	ADD SINGLE
19262306a36Sopenharmony_ci|
19362306a36Sopenharmony_ciadd_sgl:
19462306a36Sopenharmony_ci	addl	#ad_1_sgl,LOCAL_HI(%a0)
19562306a36Sopenharmony_ci	bccs	scc_clr			|no mantissa overflow
19662306a36Sopenharmony_ci	roxrw  LOCAL_HI(%a0)		|shift v-bit back in
19762306a36Sopenharmony_ci	roxrw  LOCAL_HI+2(%a0)		|shift v-bit back in
19862306a36Sopenharmony_ci	addw	#0x1,LOCAL_EX(%a0)	|and incr exponent
19962306a36Sopenharmony_ciscc_clr:
20062306a36Sopenharmony_ci	tstl	%d0			|test for rs = 0
20162306a36Sopenharmony_ci	bnes	sgl_done
20262306a36Sopenharmony_ci	andiw  #0xfe00,LOCAL_HI+2(%a0)	|clear the l-bit
20362306a36Sopenharmony_cisgl_done:
20462306a36Sopenharmony_ci	andil	#0xffffff00,LOCAL_HI(%a0) |truncate bits beyond sgl limit
20562306a36Sopenharmony_ci	clrl	LOCAL_LO(%a0)		|clear d2
20662306a36Sopenharmony_ci	rts
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci|
20962306a36Sopenharmony_ci|	ADD EXTENDED
21062306a36Sopenharmony_ci|
21162306a36Sopenharmony_ciadd_ext:
21262306a36Sopenharmony_ci	addql  #1,LOCAL_LO(%a0)		|add 1 to l-bit
21362306a36Sopenharmony_ci	bccs	xcc_clr			|test for carry out
21462306a36Sopenharmony_ci	addql  #1,LOCAL_HI(%a0)		|propagate carry
21562306a36Sopenharmony_ci	bccs	xcc_clr
21662306a36Sopenharmony_ci	roxrw  LOCAL_HI(%a0)		|mant is 0 so restore v-bit
21762306a36Sopenharmony_ci	roxrw  LOCAL_HI+2(%a0)		|mant is 0 so restore v-bit
21862306a36Sopenharmony_ci	roxrw	LOCAL_LO(%a0)
21962306a36Sopenharmony_ci	roxrw	LOCAL_LO+2(%a0)
22062306a36Sopenharmony_ci	addw	#0x1,LOCAL_EX(%a0)	|and inc exp
22162306a36Sopenharmony_cixcc_clr:
22262306a36Sopenharmony_ci	tstl	%d0			|test rs = 0
22362306a36Sopenharmony_ci	bnes	add_ext_done
22462306a36Sopenharmony_ci	andib	#0xfe,LOCAL_LO+3(%a0)	|clear the l bit
22562306a36Sopenharmony_ciadd_ext_done:
22662306a36Sopenharmony_ci	rts
22762306a36Sopenharmony_ci|
22862306a36Sopenharmony_ci|	ADD DOUBLE
22962306a36Sopenharmony_ci|
23062306a36Sopenharmony_ciadd_dbl:
23162306a36Sopenharmony_ci	addl	#ad_1_dbl,LOCAL_LO(%a0)
23262306a36Sopenharmony_ci	bccs	dcc_clr
23362306a36Sopenharmony_ci	addql	#1,LOCAL_HI(%a0)		|propagate carry
23462306a36Sopenharmony_ci	bccs	dcc_clr
23562306a36Sopenharmony_ci	roxrw	LOCAL_HI(%a0)		|mant is 0 so restore v-bit
23662306a36Sopenharmony_ci	roxrw	LOCAL_HI+2(%a0)		|mant is 0 so restore v-bit
23762306a36Sopenharmony_ci	roxrw	LOCAL_LO(%a0)
23862306a36Sopenharmony_ci	roxrw	LOCAL_LO+2(%a0)
23962306a36Sopenharmony_ci	addw	#0x1,LOCAL_EX(%a0)	|incr exponent
24062306a36Sopenharmony_cidcc_clr:
24162306a36Sopenharmony_ci	tstl	%d0			|test for rs = 0
24262306a36Sopenharmony_ci	bnes	dbl_done
24362306a36Sopenharmony_ci	andiw	#0xf000,LOCAL_LO+2(%a0)	|clear the l-bit
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_cidbl_done:
24662306a36Sopenharmony_ci	andil	#0xfffff800,LOCAL_LO(%a0) |truncate bits beyond dbl limit
24762306a36Sopenharmony_ci	rts
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_cierror:
25062306a36Sopenharmony_ci	rts
25162306a36Sopenharmony_ci|
25262306a36Sopenharmony_ci| Truncate all other bits
25362306a36Sopenharmony_ci|
25462306a36Sopenharmony_citrunct:
25562306a36Sopenharmony_ci	.long	end_rnd
25662306a36Sopenharmony_ci	.long	sgl_done
25762306a36Sopenharmony_ci	.long	dbl_done
25862306a36Sopenharmony_ci	.long	dbl_done
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_citruncate:
26162306a36Sopenharmony_ci	lea	trunct,%a1
26262306a36Sopenharmony_ci	movel	(%a1,%d1.w*4),%a1
26362306a36Sopenharmony_ci	jmp	(%a1)
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ciend_rnd:
26662306a36Sopenharmony_ci	rts
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci|
26962306a36Sopenharmony_ci|	NORMALIZE
27062306a36Sopenharmony_ci|
27162306a36Sopenharmony_ci| These routines (nrm_zero & nrm_set) normalize the unnorm.  This
27262306a36Sopenharmony_ci| is done by shifting the mantissa left while decrementing the
27362306a36Sopenharmony_ci| exponent.
27462306a36Sopenharmony_ci|
27562306a36Sopenharmony_ci| NRM_SET shifts and decrements until there is a 1 set in the integer
27662306a36Sopenharmony_ci| bit of the mantissa (msb in d1).
27762306a36Sopenharmony_ci|
27862306a36Sopenharmony_ci| NRM_ZERO shifts and decrements until there is a 1 set in the integer
27962306a36Sopenharmony_ci| bit of the mantissa (msb in d1) unless this would mean the exponent
28062306a36Sopenharmony_ci| would go less than 0.  In that case the number becomes a denorm - the
28162306a36Sopenharmony_ci| exponent (d0) is set to 0 and the mantissa (d1 & d2) is not
28262306a36Sopenharmony_ci| normalized.
28362306a36Sopenharmony_ci|
28462306a36Sopenharmony_ci| Note that both routines have been optimized (for the worst case) and
28562306a36Sopenharmony_ci| therefore do not have the easy to follow decrement/shift loop.
28662306a36Sopenharmony_ci|
28762306a36Sopenharmony_ci|	NRM_ZERO
28862306a36Sopenharmony_ci|
28962306a36Sopenharmony_ci|	Distance to first 1 bit in mantissa = X
29062306a36Sopenharmony_ci|	Distance to 0 from exponent = Y
29162306a36Sopenharmony_ci|	If X < Y
29262306a36Sopenharmony_ci|	Then
29362306a36Sopenharmony_ci|	  nrm_set
29462306a36Sopenharmony_ci|	Else
29562306a36Sopenharmony_ci|	  shift mantissa by Y
29662306a36Sopenharmony_ci|	  set exponent = 0
29762306a36Sopenharmony_ci|
29862306a36Sopenharmony_ci|input:
29962306a36Sopenharmony_ci|	FP_SCR1 = exponent, ms mantissa part, ls mantissa part
30062306a36Sopenharmony_ci|output:
30162306a36Sopenharmony_ci|	L_SCR1{4} = fpte15 or ete15 bit
30262306a36Sopenharmony_ci|
30362306a36Sopenharmony_ci	.global	nrm_zero
30462306a36Sopenharmony_cinrm_zero:
30562306a36Sopenharmony_ci	movew	LOCAL_EX(%a0),%d0
30662306a36Sopenharmony_ci	cmpw   #64,%d0          |see if exp > 64
30762306a36Sopenharmony_ci	bmis	d0_less
30862306a36Sopenharmony_ci	bsr	nrm_set		|exp > 64 so exp won't exceed 0
30962306a36Sopenharmony_ci	rts
31062306a36Sopenharmony_cid0_less:
31162306a36Sopenharmony_ci	moveml	%d2/%d3/%d5/%d6,-(%a7)
31262306a36Sopenharmony_ci	movel	LOCAL_HI(%a0),%d1
31362306a36Sopenharmony_ci	movel	LOCAL_LO(%a0),%d2
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	bfffo	%d1{#0:#32},%d3	|get the distance to the first 1
31662306a36Sopenharmony_ci|				;in ms mant
31762306a36Sopenharmony_ci	beqs	ms_clr		|branch if no bits were set
31862306a36Sopenharmony_ci	cmpw	%d3,%d0		|of X>Y
31962306a36Sopenharmony_ci	bmis	greater		|then exp will go past 0 (neg) if
32062306a36Sopenharmony_ci|				;it is just shifted
32162306a36Sopenharmony_ci	bsr	nrm_set		|else exp won't go past 0
32262306a36Sopenharmony_ci	moveml	(%a7)+,%d2/%d3/%d5/%d6
32362306a36Sopenharmony_ci	rts
32462306a36Sopenharmony_cigreater:
32562306a36Sopenharmony_ci	movel	%d2,%d6		|save ls mant in d6
32662306a36Sopenharmony_ci	lsll	%d0,%d2		|shift ls mant by count
32762306a36Sopenharmony_ci	lsll	%d0,%d1		|shift ms mant by count
32862306a36Sopenharmony_ci	movel	#32,%d5
32962306a36Sopenharmony_ci	subl	%d0,%d5		|make op a denorm by shifting bits
33062306a36Sopenharmony_ci	lsrl	%d5,%d6		|by the number in the exp, then
33162306a36Sopenharmony_ci|				;set exp = 0.
33262306a36Sopenharmony_ci	orl	%d6,%d1		|shift the ls mant bits into the ms mant
33362306a36Sopenharmony_ci	movel	#0,%d0		|same as if decremented exp to 0
33462306a36Sopenharmony_ci|				;while shifting
33562306a36Sopenharmony_ci	movew	%d0,LOCAL_EX(%a0)
33662306a36Sopenharmony_ci	movel	%d1,LOCAL_HI(%a0)
33762306a36Sopenharmony_ci	movel	%d2,LOCAL_LO(%a0)
33862306a36Sopenharmony_ci	moveml	(%a7)+,%d2/%d3/%d5/%d6
33962306a36Sopenharmony_ci	rts
34062306a36Sopenharmony_cims_clr:
34162306a36Sopenharmony_ci	bfffo	%d2{#0:#32},%d3	|check if any bits set in ls mant
34262306a36Sopenharmony_ci	beqs	all_clr		|branch if none set
34362306a36Sopenharmony_ci	addw	#32,%d3
34462306a36Sopenharmony_ci	cmpw	%d3,%d0		|if X>Y
34562306a36Sopenharmony_ci	bmis	greater		|then branch
34662306a36Sopenharmony_ci	bsr	nrm_set		|else exp won't go past 0
34762306a36Sopenharmony_ci	moveml	(%a7)+,%d2/%d3/%d5/%d6
34862306a36Sopenharmony_ci	rts
34962306a36Sopenharmony_ciall_clr:
35062306a36Sopenharmony_ci	movew	#0,LOCAL_EX(%a0)	|no mantissa bits set. Set exp = 0.
35162306a36Sopenharmony_ci	moveml	(%a7)+,%d2/%d3/%d5/%d6
35262306a36Sopenharmony_ci	rts
35362306a36Sopenharmony_ci|
35462306a36Sopenharmony_ci|	NRM_SET
35562306a36Sopenharmony_ci|
35662306a36Sopenharmony_ci	.global	nrm_set
35762306a36Sopenharmony_cinrm_set:
35862306a36Sopenharmony_ci	movel	%d7,-(%a7)
35962306a36Sopenharmony_ci	bfffo	LOCAL_HI(%a0){#0:#32},%d7 |find first 1 in ms mant to d7)
36062306a36Sopenharmony_ci	beqs	lower		|branch if ms mant is all 0's
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	movel	%d6,-(%a7)
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	subw	%d7,LOCAL_EX(%a0)	|sub exponent by count
36562306a36Sopenharmony_ci	movel	LOCAL_HI(%a0),%d0	|d0 has ms mant
36662306a36Sopenharmony_ci	movel	LOCAL_LO(%a0),%d1 |d1 has ls mant
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	lsll	%d7,%d0		|shift first 1 to j bit position
36962306a36Sopenharmony_ci	movel	%d1,%d6		|copy ls mant into d6
37062306a36Sopenharmony_ci	lsll	%d7,%d6		|shift ls mant by count
37162306a36Sopenharmony_ci	movel	%d6,LOCAL_LO(%a0)	|store ls mant into memory
37262306a36Sopenharmony_ci	moveql	#32,%d6
37362306a36Sopenharmony_ci	subl	%d7,%d6		|continue shift
37462306a36Sopenharmony_ci	lsrl	%d6,%d1		|shift off all bits but those that will
37562306a36Sopenharmony_ci|				;be shifted into ms mant
37662306a36Sopenharmony_ci	orl	%d1,%d0		|shift the ls mant bits into the ms mant
37762306a36Sopenharmony_ci	movel	%d0,LOCAL_HI(%a0)	|store ms mant into memory
37862306a36Sopenharmony_ci	moveml	(%a7)+,%d7/%d6	|restore registers
37962306a36Sopenharmony_ci	rts
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci|
38262306a36Sopenharmony_ci| We get here if ms mant was = 0, and we assume ls mant has bits
38362306a36Sopenharmony_ci| set (otherwise this would have been tagged a zero not a denorm).
38462306a36Sopenharmony_ci|
38562306a36Sopenharmony_cilower:
38662306a36Sopenharmony_ci	movew	LOCAL_EX(%a0),%d0	|d0 has exponent
38762306a36Sopenharmony_ci	movel	LOCAL_LO(%a0),%d1	|d1 has ls mant
38862306a36Sopenharmony_ci	subw	#32,%d0		|account for ms mant being all zeros
38962306a36Sopenharmony_ci	bfffo	%d1{#0:#32},%d7	|find first 1 in ls mant to d7)
39062306a36Sopenharmony_ci	subw	%d7,%d0		|subtract shift count from exp
39162306a36Sopenharmony_ci	lsll	%d7,%d1		|shift first 1 to integer bit in ms mant
39262306a36Sopenharmony_ci	movew	%d0,LOCAL_EX(%a0)	|store ms mant
39362306a36Sopenharmony_ci	movel	%d1,LOCAL_HI(%a0)	|store exp
39462306a36Sopenharmony_ci	clrl	LOCAL_LO(%a0)	|clear ls mant
39562306a36Sopenharmony_ci	movel	(%a7)+,%d7
39662306a36Sopenharmony_ci	rts
39762306a36Sopenharmony_ci|
39862306a36Sopenharmony_ci|	denorm --- denormalize an intermediate result
39962306a36Sopenharmony_ci|
40062306a36Sopenharmony_ci|	Used by underflow.
40162306a36Sopenharmony_ci|
40262306a36Sopenharmony_ci| Input:
40362306a36Sopenharmony_ci|	a0	 points to the operand to be denormalized
40462306a36Sopenharmony_ci|		 (in the internal extended format)
40562306a36Sopenharmony_ci|
40662306a36Sopenharmony_ci|	d0:	 rounding precision
40762306a36Sopenharmony_ci| Output:
40862306a36Sopenharmony_ci|	a0	 points to the denormalized result
40962306a36Sopenharmony_ci|		 (in the internal extended format)
41062306a36Sopenharmony_ci|
41162306a36Sopenharmony_ci|	d0	is guard,round,sticky
41262306a36Sopenharmony_ci|
41362306a36Sopenharmony_ci| d0 comes into this routine with the rounding precision. It
41462306a36Sopenharmony_ci| is then loaded with the denormalized exponent threshold for the
41562306a36Sopenharmony_ci| rounding precision.
41662306a36Sopenharmony_ci|
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	.global	denorm
41962306a36Sopenharmony_cidenorm:
42062306a36Sopenharmony_ci	btstb	#6,LOCAL_EX(%a0)	|check for exponents between $7fff-$4000
42162306a36Sopenharmony_ci	beqs	no_sgn_ext
42262306a36Sopenharmony_ci	bsetb	#7,LOCAL_EX(%a0)	|sign extend if it is so
42362306a36Sopenharmony_cino_sgn_ext:
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	cmpib	#0,%d0		|if 0 then extended precision
42662306a36Sopenharmony_ci	bnes	not_ext		|else branch
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	clrl	%d1		|load d1 with ext threshold
42962306a36Sopenharmony_ci	clrl	%d0		|clear the sticky flag
43062306a36Sopenharmony_ci	bsr	dnrm_lp		|denormalize the number
43162306a36Sopenharmony_ci	tstb	%d1		|check for inex
43262306a36Sopenharmony_ci	beq	no_inex		|if clr, no inex
43362306a36Sopenharmony_ci	bras	dnrm_inex	|if set, set inex
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_cinot_ext:
43662306a36Sopenharmony_ci	cmpil	#1,%d0		|if 1 then single precision
43762306a36Sopenharmony_ci	beqs	load_sgl	|else must be 2, double prec
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ciload_dbl:
44062306a36Sopenharmony_ci	movew	#dbl_thresh,%d1	|put copy of threshold in d1
44162306a36Sopenharmony_ci	movel	%d1,%d0		|copy d1 into d0
44262306a36Sopenharmony_ci	subw	LOCAL_EX(%a0),%d0	|diff = threshold - exp
44362306a36Sopenharmony_ci	cmpw	#67,%d0		|if diff > 67 (mant + grs bits)
44462306a36Sopenharmony_ci	bpls	chk_stky	|then branch (all bits would be
44562306a36Sopenharmony_ci|				; shifted off in denorm routine)
44662306a36Sopenharmony_ci	clrl	%d0		|else clear the sticky flag
44762306a36Sopenharmony_ci	bsr	dnrm_lp		|denormalize the number
44862306a36Sopenharmony_ci	tstb	%d1		|check flag
44962306a36Sopenharmony_ci	beqs	no_inex		|if clr, no inex
45062306a36Sopenharmony_ci	bras	dnrm_inex	|if set, set inex
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ciload_sgl:
45362306a36Sopenharmony_ci	movew	#sgl_thresh,%d1	|put copy of threshold in d1
45462306a36Sopenharmony_ci	movel	%d1,%d0		|copy d1 into d0
45562306a36Sopenharmony_ci	subw	LOCAL_EX(%a0),%d0	|diff = threshold - exp
45662306a36Sopenharmony_ci	cmpw	#67,%d0		|if diff > 67 (mant + grs bits)
45762306a36Sopenharmony_ci	bpls	chk_stky	|then branch (all bits would be
45862306a36Sopenharmony_ci|				; shifted off in denorm routine)
45962306a36Sopenharmony_ci	clrl	%d0		|else clear the sticky flag
46062306a36Sopenharmony_ci	bsr	dnrm_lp		|denormalize the number
46162306a36Sopenharmony_ci	tstb	%d1		|check flag
46262306a36Sopenharmony_ci	beqs	no_inex		|if clr, no inex
46362306a36Sopenharmony_ci	bras	dnrm_inex	|if set, set inex
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_cichk_stky:
46662306a36Sopenharmony_ci	tstl	LOCAL_HI(%a0)	|check for any bits set
46762306a36Sopenharmony_ci	bnes	set_stky
46862306a36Sopenharmony_ci	tstl	LOCAL_LO(%a0)	|check for any bits set
46962306a36Sopenharmony_ci	bnes	set_stky
47062306a36Sopenharmony_ci	bras	clr_mant
47162306a36Sopenharmony_ciset_stky:
47262306a36Sopenharmony_ci	orl	#inx2a_mask,USER_FPSR(%a6) |set inex2/ainex
47362306a36Sopenharmony_ci	movel	#0x20000000,%d0	|set sticky bit in return value
47462306a36Sopenharmony_ciclr_mant:
47562306a36Sopenharmony_ci	movew	%d1,LOCAL_EX(%a0)		|load exp with threshold
47662306a36Sopenharmony_ci	movel	#0,LOCAL_HI(%a0)	|set d1 = 0 (ms mantissa)
47762306a36Sopenharmony_ci	movel	#0,LOCAL_LO(%a0)		|set d2 = 0 (ms mantissa)
47862306a36Sopenharmony_ci	rts
47962306a36Sopenharmony_cidnrm_inex:
48062306a36Sopenharmony_ci	orl	#inx2a_mask,USER_FPSR(%a6) |set inex2/ainex
48162306a36Sopenharmony_cino_inex:
48262306a36Sopenharmony_ci	rts
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci|
48562306a36Sopenharmony_ci|	dnrm_lp --- normalize exponent/mantissa to specified threshold
48662306a36Sopenharmony_ci|
48762306a36Sopenharmony_ci| Input:
48862306a36Sopenharmony_ci|	a0		points to the operand to be denormalized
48962306a36Sopenharmony_ci|	d0{31:29}	initial guard,round,sticky
49062306a36Sopenharmony_ci|	d1{15:0}	denormalization threshold
49162306a36Sopenharmony_ci| Output:
49262306a36Sopenharmony_ci|	a0		points to the denormalized operand
49362306a36Sopenharmony_ci|	d0{31:29}	final guard,round,sticky
49462306a36Sopenharmony_ci|	d1.b		inexact flag:  all ones means inexact result
49562306a36Sopenharmony_ci|
49662306a36Sopenharmony_ci| The LOCAL_LO and LOCAL_GRS parts of the value are copied to FP_SCR2
49762306a36Sopenharmony_ci| so that bfext can be used to extract the new low part of the mantissa.
49862306a36Sopenharmony_ci| Dnrm_lp can be called with a0 pointing to ETEMP or WBTEMP and there
49962306a36Sopenharmony_ci| is no LOCAL_GRS scratch word following it on the fsave frame.
50062306a36Sopenharmony_ci|
50162306a36Sopenharmony_ci	.global	dnrm_lp
50262306a36Sopenharmony_cidnrm_lp:
50362306a36Sopenharmony_ci	movel	%d2,-(%sp)		|save d2 for temp use
50462306a36Sopenharmony_ci	btstb	#E3,E_BYTE(%a6)		|test for type E3 exception
50562306a36Sopenharmony_ci	beqs	not_E3			|not type E3 exception
50662306a36Sopenharmony_ci	bfextu	WBTEMP_GRS(%a6){#6:#3},%d2	|extract guard,round, sticky  bit
50762306a36Sopenharmony_ci	movel	#29,%d0
50862306a36Sopenharmony_ci	lsll	%d0,%d2			|shift g,r,s to their positions
50962306a36Sopenharmony_ci	movel	%d2,%d0
51062306a36Sopenharmony_cinot_E3:
51162306a36Sopenharmony_ci	movel	(%sp)+,%d2		|restore d2
51262306a36Sopenharmony_ci	movel	LOCAL_LO(%a0),FP_SCR2+LOCAL_LO(%a6)
51362306a36Sopenharmony_ci	movel	%d0,FP_SCR2+LOCAL_GRS(%a6)
51462306a36Sopenharmony_ci	movel	%d1,%d0			|copy the denorm threshold
51562306a36Sopenharmony_ci	subw	LOCAL_EX(%a0),%d1		|d1 = threshold - uns exponent
51662306a36Sopenharmony_ci	bles	no_lp			|d1 <= 0
51762306a36Sopenharmony_ci	cmpw	#32,%d1
51862306a36Sopenharmony_ci	blts	case_1			|0 = d1 < 32
51962306a36Sopenharmony_ci	cmpw	#64,%d1
52062306a36Sopenharmony_ci	blts	case_2			|32 <= d1 < 64
52162306a36Sopenharmony_ci	bra	case_3			|d1 >= 64
52262306a36Sopenharmony_ci|
52362306a36Sopenharmony_ci| No normalization necessary
52462306a36Sopenharmony_ci|
52562306a36Sopenharmony_cino_lp:
52662306a36Sopenharmony_ci	clrb	%d1			|set no inex2 reported
52762306a36Sopenharmony_ci	movel	FP_SCR2+LOCAL_GRS(%a6),%d0	|restore original g,r,s
52862306a36Sopenharmony_ci	rts
52962306a36Sopenharmony_ci|
53062306a36Sopenharmony_ci| case (0<d1<32)
53162306a36Sopenharmony_ci|
53262306a36Sopenharmony_cicase_1:
53362306a36Sopenharmony_ci	movel	%d2,-(%sp)
53462306a36Sopenharmony_ci	movew	%d0,LOCAL_EX(%a0)		|exponent = denorm threshold
53562306a36Sopenharmony_ci	movel	#32,%d0
53662306a36Sopenharmony_ci	subw	%d1,%d0			|d0 = 32 - d1
53762306a36Sopenharmony_ci	bfextu	LOCAL_EX(%a0){%d0:#32},%d2
53862306a36Sopenharmony_ci	bfextu	%d2{%d1:%d0},%d2		|d2 = new LOCAL_HI
53962306a36Sopenharmony_ci	bfextu	LOCAL_HI(%a0){%d0:#32},%d1	|d1 = new LOCAL_LO
54062306a36Sopenharmony_ci	bfextu	FP_SCR2+LOCAL_LO(%a6){%d0:#32},%d0	|d0 = new G,R,S
54162306a36Sopenharmony_ci	movel	%d2,LOCAL_HI(%a0)		|store new LOCAL_HI
54262306a36Sopenharmony_ci	movel	%d1,LOCAL_LO(%a0)		|store new LOCAL_LO
54362306a36Sopenharmony_ci	clrb	%d1
54462306a36Sopenharmony_ci	bftst	%d0{#2:#30}
54562306a36Sopenharmony_ci	beqs	c1nstky
54662306a36Sopenharmony_ci	bsetl	#rnd_stky_bit,%d0
54762306a36Sopenharmony_ci	st	%d1
54862306a36Sopenharmony_cic1nstky:
54962306a36Sopenharmony_ci	movel	FP_SCR2+LOCAL_GRS(%a6),%d2	|restore original g,r,s
55062306a36Sopenharmony_ci	andil	#0xe0000000,%d2		|clear all but G,R,S
55162306a36Sopenharmony_ci	tstl	%d2			|test if original G,R,S are clear
55262306a36Sopenharmony_ci	beqs	grs_clear
55362306a36Sopenharmony_ci	orl	#0x20000000,%d0		|set sticky bit in d0
55462306a36Sopenharmony_cigrs_clear:
55562306a36Sopenharmony_ci	andil	#0xe0000000,%d0		|clear all but G,R,S
55662306a36Sopenharmony_ci	movel	(%sp)+,%d2
55762306a36Sopenharmony_ci	rts
55862306a36Sopenharmony_ci|
55962306a36Sopenharmony_ci| case (32<=d1<64)
56062306a36Sopenharmony_ci|
56162306a36Sopenharmony_cicase_2:
56262306a36Sopenharmony_ci	movel	%d2,-(%sp)
56362306a36Sopenharmony_ci	movew	%d0,LOCAL_EX(%a0)		|unsigned exponent = threshold
56462306a36Sopenharmony_ci	subw	#32,%d1			|d1 now between 0 and 32
56562306a36Sopenharmony_ci	movel	#32,%d0
56662306a36Sopenharmony_ci	subw	%d1,%d0			|d0 = 32 - d1
56762306a36Sopenharmony_ci	bfextu	LOCAL_EX(%a0){%d0:#32},%d2
56862306a36Sopenharmony_ci	bfextu	%d2{%d1:%d0},%d2		|d2 = new LOCAL_LO
56962306a36Sopenharmony_ci	bfextu	LOCAL_HI(%a0){%d0:#32},%d1	|d1 = new G,R,S
57062306a36Sopenharmony_ci	bftst	%d1{#2:#30}
57162306a36Sopenharmony_ci	bnes	c2_sstky		|bra if sticky bit to be set
57262306a36Sopenharmony_ci	bftst	FP_SCR2+LOCAL_LO(%a6){%d0:#32}
57362306a36Sopenharmony_ci	bnes	c2_sstky		|bra if sticky bit to be set
57462306a36Sopenharmony_ci	movel	%d1,%d0
57562306a36Sopenharmony_ci	clrb	%d1
57662306a36Sopenharmony_ci	bras	end_c2
57762306a36Sopenharmony_cic2_sstky:
57862306a36Sopenharmony_ci	movel	%d1,%d0
57962306a36Sopenharmony_ci	bsetl	#rnd_stky_bit,%d0
58062306a36Sopenharmony_ci	st	%d1
58162306a36Sopenharmony_ciend_c2:
58262306a36Sopenharmony_ci	clrl	LOCAL_HI(%a0)		|store LOCAL_HI = 0
58362306a36Sopenharmony_ci	movel	%d2,LOCAL_LO(%a0)		|store LOCAL_LO
58462306a36Sopenharmony_ci	movel	FP_SCR2+LOCAL_GRS(%a6),%d2	|restore original g,r,s
58562306a36Sopenharmony_ci	andil	#0xe0000000,%d2		|clear all but G,R,S
58662306a36Sopenharmony_ci	tstl	%d2			|test if original G,R,S are clear
58762306a36Sopenharmony_ci	beqs	clear_grs
58862306a36Sopenharmony_ci	orl	#0x20000000,%d0		|set sticky bit in d0
58962306a36Sopenharmony_ciclear_grs:
59062306a36Sopenharmony_ci	andil	#0xe0000000,%d0		|get rid of all but G,R,S
59162306a36Sopenharmony_ci	movel	(%sp)+,%d2
59262306a36Sopenharmony_ci	rts
59362306a36Sopenharmony_ci|
59462306a36Sopenharmony_ci| d1 >= 64 Force the exponent to be the denorm threshold with the
59562306a36Sopenharmony_ci| correct sign.
59662306a36Sopenharmony_ci|
59762306a36Sopenharmony_cicase_3:
59862306a36Sopenharmony_ci	movew	%d0,LOCAL_EX(%a0)
59962306a36Sopenharmony_ci	tstw	LOCAL_SGN(%a0)
60062306a36Sopenharmony_ci	bges	c3con
60162306a36Sopenharmony_cic3neg:
60262306a36Sopenharmony_ci	orl	#0x80000000,LOCAL_EX(%a0)
60362306a36Sopenharmony_cic3con:
60462306a36Sopenharmony_ci	cmpw	#64,%d1
60562306a36Sopenharmony_ci	beqs	sixty_four
60662306a36Sopenharmony_ci	cmpw	#65,%d1
60762306a36Sopenharmony_ci	beqs	sixty_five
60862306a36Sopenharmony_ci|
60962306a36Sopenharmony_ci| Shift value is out of range.  Set d1 for inex2 flag and
61062306a36Sopenharmony_ci| return a zero with the given threshold.
61162306a36Sopenharmony_ci|
61262306a36Sopenharmony_ci	clrl	LOCAL_HI(%a0)
61362306a36Sopenharmony_ci	clrl	LOCAL_LO(%a0)
61462306a36Sopenharmony_ci	movel	#0x20000000,%d0
61562306a36Sopenharmony_ci	st	%d1
61662306a36Sopenharmony_ci	rts
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_cisixty_four:
61962306a36Sopenharmony_ci	movel	LOCAL_HI(%a0),%d0
62062306a36Sopenharmony_ci	bfextu	%d0{#2:#30},%d1
62162306a36Sopenharmony_ci	andil	#0xc0000000,%d0
62262306a36Sopenharmony_ci	bras	c3com
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_cisixty_five:
62562306a36Sopenharmony_ci	movel	LOCAL_HI(%a0),%d0
62662306a36Sopenharmony_ci	bfextu	%d0{#1:#31},%d1
62762306a36Sopenharmony_ci	andil	#0x80000000,%d0
62862306a36Sopenharmony_ci	lsrl	#1,%d0			|shift high bit into R bit
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_cic3com:
63162306a36Sopenharmony_ci	tstl	%d1
63262306a36Sopenharmony_ci	bnes	c3ssticky
63362306a36Sopenharmony_ci	tstl	LOCAL_LO(%a0)
63462306a36Sopenharmony_ci	bnes	c3ssticky
63562306a36Sopenharmony_ci	tstb	FP_SCR2+LOCAL_GRS(%a6)
63662306a36Sopenharmony_ci	bnes	c3ssticky
63762306a36Sopenharmony_ci	clrb	%d1
63862306a36Sopenharmony_ci	bras	c3end
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_cic3ssticky:
64162306a36Sopenharmony_ci	bsetl	#rnd_stky_bit,%d0
64262306a36Sopenharmony_ci	st	%d1
64362306a36Sopenharmony_cic3end:
64462306a36Sopenharmony_ci	clrl	LOCAL_HI(%a0)
64562306a36Sopenharmony_ci	clrl	LOCAL_LO(%a0)
64662306a36Sopenharmony_ci	rts
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	|end
649