round.sa revision 1.2
11.1Smycroft*	MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP
21.1Smycroft*	M68000 Hi-Performance Microprocessor Division
31.1Smycroft*	M68040 Software Package 
41.1Smycroft*
51.1Smycroft*	M68040 Software Package Copyright (c) 1993, 1994 Motorola Inc.
61.1Smycroft*	All rights reserved.
71.1Smycroft*
81.1Smycroft*	THE SOFTWARE is provided on an "AS IS" basis and without warranty.
91.1Smycroft*	To the maximum extent permitted by applicable law,
101.1Smycroft*	MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED,
111.1Smycroft*	INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A
121.1Smycroft*	PARTICULAR PURPOSE and any warranty against infringement with
131.1Smycroft*	regard to the SOFTWARE (INCLUDING ANY MODIFIED VERSIONS THEREOF)
141.1Smycroft*	and any accompanying written materials. 
151.1Smycroft*
161.1Smycroft*	To the maximum extent permitted by applicable law,
171.1Smycroft*	IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER
181.1Smycroft*	(INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS
191.1Smycroft*	PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR
201.1Smycroft*	OTHER PECUNIARY LOSS) ARISING OF THE USE OR INABILITY TO USE THE
211.1Smycroft*	SOFTWARE.  Motorola assumes no responsibility for the maintenance
221.1Smycroft*	and support of the SOFTWARE.  
231.1Smycroft*
241.1Smycroft*	You are hereby granted a copyright license to use, modify, and
251.1Smycroft*	distribute the SOFTWARE so long as this entire notice is retained
261.1Smycroft*	without alteration in any modified and/or redistributed versions,
271.1Smycroft*	and that such modified versions are clearly identified as such.
281.1Smycroft*	No licenses are granted by implication, estoppel or otherwise
291.1Smycroft*	under any patents or trademarks of Motorola, Inc.
301.1Smycroft
311.1Smycroft*
321.1Smycroft*	round.sa 3.4 7/29/91
331.1Smycroft*
341.1Smycroft*	handle rounding and normalization tasks
351.1Smycroft*
361.1Smycroft
371.1SmycroftROUND	IDNT    2,1 Motorola 040 Floating Point Software Package
381.1Smycroft
391.1Smycroft	section	8
401.1Smycroft
411.1Smycroft	include	fpsp.h
421.1Smycroft
431.1Smycroft*
441.1Smycroft*	round --- round result according to precision/mode
451.1Smycroft*
461.1Smycroft*	a0 points to the input operand in the internal extended format 
471.1Smycroft*	d1(high word) contains rounding precision:
481.1Smycroft*		ext = $0000xxxx
491.1Smycroft*		sgl = $0001xxxx
501.1Smycroft*		dbl = $0002xxxx
511.1Smycroft*	d1(low word) contains rounding mode:
521.1Smycroft*		RN  = $xxxx0000
531.1Smycroft*		RZ  = $xxxx0001
541.1Smycroft*		RM  = $xxxx0010
551.1Smycroft*		RP  = $xxxx0011
561.1Smycroft*	d0{31:29} contains the g,r,s bits (extended)
571.1Smycroft*
581.1Smycroft*	On return the value pointed to by a0 is correctly rounded,
591.1Smycroft*	a0 is preserved and the g-r-s bits in d0 are cleared.
601.1Smycroft*	The result is not typed - the tag field is invalid.  The
611.1Smycroft*	result is still in the internal extended format.
621.1Smycroft*
631.1Smycroft*	The INEX bit of USER_FPSR will be set if the rounded result was
641.1Smycroft*	inexact (i.e. if any of the g-r-s bits were set).
651.1Smycroft*
661.1Smycroft
671.1Smycroft	xdef	round
681.1Smycroftround:
691.1Smycroft* If g=r=s=0 then result is exact and round is done, else set 
701.1Smycroft* the inex flag in status reg and continue.  
711.1Smycroft*
721.1Smycroft	bsr.b	ext_grs			;this subroutine looks at the 
731.1Smycroft*					:rounding precision and sets 
741.1Smycroft*					;the appropriate g-r-s bits.
751.1Smycroft	tst.l	d0			;if grs are zero, go force
761.1Smycroft	bne.w	rnd_cont		;lower bits to zero for size
771.1Smycroft	
781.1Smycroft	swap	d1			;set up d1.w for round prec.
791.1Smycroft	bra.w	truncate
801.1Smycroft
811.1Smycroftrnd_cont:
821.1Smycroft*
831.1Smycroft* Use rounding mode as an index into a jump table for these modes.
841.1Smycroft*
851.1Smycroft	or.l	#inx2a_mask,USER_FPSR(a6) ;set inex2/ainex
861.1Smycroft	lea	mode_tab,a1
871.1Smycroft	move.l	(a1,d1.w*4),a1
881.1Smycroft	jmp	(a1)
891.1Smycroft*
901.1Smycroft* Jump table indexed by rounding mode in d1.w.  All following assumes
911.1Smycroft* grs != 0.
921.1Smycroft*
931.1Smycroftmode_tab:
941.1Smycroft	dc.l	rnd_near
951.1Smycroft	dc.l	rnd_zero
961.1Smycroft	dc.l	rnd_mnus
971.1Smycroft	dc.l	rnd_plus
981.1Smycroft*
991.1Smycroft*	ROUND PLUS INFINITY
1001.1Smycroft*
1011.1Smycroft*	If sign of fp number = 0 (positive), then add 1 to l.
1021.1Smycroft*
1031.1Smycroftrnd_plus:
1041.1Smycroft	swap 	d1			;set up d1 for round prec.
1051.1Smycroft	tst.b	LOCAL_SGN(a0)		;check for sign
1061.1Smycroft	bmi.w	truncate		;if positive then truncate
1071.1Smycroft	move.l	#$ffffffff,d0		;force g,r,s to be all f's
1081.1Smycroft	lea	add_to_l,a1
1091.1Smycroft	move.l	(a1,d1.w*4),a1
1101.1Smycroft	jmp	(a1)
1111.1Smycroft*
1121.1Smycroft*	ROUND MINUS INFINITY
1131.1Smycroft*
1141.1Smycroft*	If sign of fp number = 1 (negative), then add 1 to l.
1151.1Smycroft*
1161.1Smycroftrnd_mnus:
1171.1Smycroft	swap 	d1			;set up d1 for round prec.
1181.1Smycroft	tst.b	LOCAL_SGN(a0)		;check for sign	
1191.1Smycroft	bpl.w	truncate		;if negative then truncate
1201.1Smycroft	move.l	#$ffffffff,d0		;force g,r,s to be all f's
1211.1Smycroft	lea	add_to_l,a1
1221.1Smycroft	move.l	(a1,d1.w*4),a1
1231.1Smycroft	jmp	(a1)
1241.1Smycroft*
1251.1Smycroft*	ROUND ZERO
1261.1Smycroft*
1271.1Smycroft*	Always truncate.
1281.1Smycroftrnd_zero:
1291.1Smycroft	swap 	d1			;set up d1 for round prec.
1301.1Smycroft	bra.w	truncate
1311.1Smycroft*
1321.1Smycroft*
1331.1Smycroft*	ROUND NEAREST
1341.1Smycroft*
1351.1Smycroft*	If (g=1), then add 1 to l and if (r=s=0), then clear l
1361.1Smycroft*	Note that this will round to even in case of a tie.
1371.1Smycroft*
1381.1Smycroftrnd_near:
1391.1Smycroft	swap 	d1			;set up d1 for round prec.
1401.2Smycroft	add.l	d0,d0			;shift g-bit to c-bit
1411.1Smycroft	bcc.w	truncate		;if (g=1) then
1421.1Smycroft	lea	add_to_l,a1
1431.1Smycroft	move.l	(a1,d1.w*4),a1
1441.1Smycroft	jmp	(a1)
1451.1Smycroft
1461.1Smycroft*
1471.1Smycroft*	ext_grs --- extract guard, round and sticky bits
1481.1Smycroft*
1491.1Smycroft* Input:	d1 =		PREC:ROUND
1501.1Smycroft* Output:  	d0{31:29}=	guard, round, sticky
1511.1Smycroft*
1521.1Smycroft* The ext_grs extract the guard/round/sticky bits according to the
1531.1Smycroft* selected rounding precision. It is called by the round subroutine
1541.1Smycroft* only.  All registers except d0 are kept intact. d0 becomes an 
1551.1Smycroft* updated guard,round,sticky in d0{31:29}
1561.1Smycroft*
1571.1Smycroft* Notes: the ext_grs uses the round PREC, and therefore has to swap d1
1581.1Smycroft*	 prior to usage, and needs to restore d1 to original.
1591.1Smycroft*
1601.1Smycroftext_grs:
1611.1Smycroft	swap	d1			;have d1.w point to round precision
1621.2Smycroft	tst.w	d1
1631.1Smycroft	bne.b	sgl_or_dbl
1641.1Smycroft	bra.b	end_ext_grs
1651.1Smycroft 
1661.1Smycroftsgl_or_dbl:
1671.1Smycroft	movem.l	d2/d3,-(a7)		;make some temp registers
1681.1Smycroft	cmpi.w	#1,d1
1691.1Smycroft	bne.b	grs_dbl
1701.1Smycroftgrs_sgl:
1711.1Smycroft	bfextu	LOCAL_HI(a0){24:2},d3	;sgl prec. g-r are 2 bits right
1721.1Smycroft	move.l	#30,d2			;of the sgl prec. limits
1731.1Smycroft	lsl.l	d2,d3			;shift g-r bits to MSB of d3
1741.1Smycroft	move.l	LOCAL_HI(a0),d2		;get word 2 for s-bit test
1751.1Smycroft	andi.l	#$0000003f,d2		;s bit is the or of all other 
1761.1Smycroft	bne.b	st_stky			;bits to the right of g-r
1771.1Smycroft	tst.l	LOCAL_LO(a0)		;test lower mantissa
1781.1Smycroft	bne.b	st_stky			;if any are set, set sticky
1791.1Smycroft	tst.l	d0			;test original g,r,s
1801.1Smycroft	bne.b	st_stky			;if any are set, set sticky
1811.1Smycroft	bra.b	end_sd			;if words 3 and 4 are clr, exit
1821.1Smycroftgrs_dbl:    
1831.1Smycroft	bfextu	LOCAL_LO(a0){21:2},d3	;dbl-prec. g-r are 2 bits right
1841.1Smycroft	move.l	#30,d2			;of the dbl prec. limits
1851.1Smycroft	lsl.l	d2,d3			;shift g-r bits to the MSB of d3
1861.1Smycroft	move.l	LOCAL_LO(a0),d2		;get lower mantissa  for s-bit test
1871.1Smycroft	andi.l	#$000001ff,d2		;s bit is the or-ing of all 
1881.1Smycroft	bne.b	st_stky			;other bits to the right of g-r
1891.1Smycroft	tst.l	d0			;test word original g,r,s
1901.1Smycroft	bne.b	st_stky			;if any are set, set sticky
1911.1Smycroft	bra.b	end_sd			;if clear, exit
1921.1Smycroftst_stky:
1931.1Smycroft	bset	#rnd_stky_bit,d3
1941.1Smycroftend_sd:
1951.1Smycroft	move.l	d3,d0			;return grs to d0
1961.1Smycroft	movem.l	(a7)+,d2/d3		;restore scratch registers
1971.1Smycroftend_ext_grs:
1981.1Smycroft	swap	d1			;restore d1 to original
1991.1Smycroft	rts
2001.1Smycroft
2011.1Smycroft********************  Local Equates
2021.1Smycroftad_1_sgl equ	$00000100	constant to add 1 to l-bit in sgl prec
2031.1Smycroftad_1_dbl equ	$00000800	constant to add 1 to l-bit in dbl prec
2041.1Smycroft
2051.1Smycroft
2061.1Smycroft*Jump table for adding 1 to the l-bit indexed by rnd prec
2071.1Smycroft
2081.1Smycroftadd_to_l:
2091.1Smycroft	dc.l	add_ext
2101.1Smycroft	dc.l	add_sgl
2111.1Smycroft	dc.l	add_dbl
2121.1Smycroft	dc.l	add_dbl
2131.1Smycroft*
2141.1Smycroft*	ADD SINGLE
2151.1Smycroft*
2161.1Smycroftadd_sgl:
2171.1Smycroft	add.l	#ad_1_sgl,LOCAL_HI(a0)
2181.1Smycroft	bcc.b	scc_clr			;no mantissa overflow
2191.1Smycroft	roxr.w  LOCAL_HI(a0)		;shift v-bit back in
2201.1Smycroft	roxr.w  LOCAL_HI+2(a0)		;shift v-bit back in
2211.1Smycroft	add.w	#$1,LOCAL_EX(a0)	;and incr exponent
2221.1Smycroftscc_clr:
2231.1Smycroft	tst.l	d0			;test for rs = 0
2241.1Smycroft	bne.b	sgl_done
2251.1Smycroft	andi.w  #$fe00,LOCAL_HI+2(a0)	;clear the l-bit
2261.1Smycroftsgl_done:
2271.1Smycroft	andi.l	#$ffffff00,LOCAL_HI(a0) ;truncate bits beyond sgl limit
2281.1Smycroft	clr.l	LOCAL_LO(a0)		;clear d2
2291.1Smycroft	rts
2301.1Smycroft
2311.1Smycroft*
2321.1Smycroft*	ADD EXTENDED
2331.1Smycroft*
2341.1Smycroftadd_ext:
2351.1Smycroft	addq.l  #1,LOCAL_LO(a0)		;add 1 to l-bit
2361.1Smycroft	bcc.b	xcc_clr			;test for carry out
2371.1Smycroft	addq.l  #1,LOCAL_HI(a0)		;propogate carry
2381.1Smycroft	bcc.b	xcc_clr
2391.1Smycroft	roxr.w  LOCAL_HI(a0)		;mant is 0 so restore v-bit
2401.1Smycroft	roxr.w  LOCAL_HI+2(a0)		;mant is 0 so restore v-bit
2411.1Smycroft	roxr.w	LOCAL_LO(a0)
2421.1Smycroft	roxr.w	LOCAL_LO+2(a0)
2431.1Smycroft	add.w	#$1,LOCAL_EX(a0)	;and inc exp
2441.1Smycroftxcc_clr:
2451.1Smycroft	tst.l	d0			;test rs = 0
2461.1Smycroft	bne.b	add_ext_done
2471.1Smycroft	andi.b	#$fe,LOCAL_LO+3(a0)	;clear the l bit
2481.1Smycroftadd_ext_done:
2491.1Smycroft	rts
2501.1Smycroft*
2511.1Smycroft*	ADD DOUBLE
2521.1Smycroft*
2531.1Smycroftadd_dbl:
2541.1Smycroft	add.l	#ad_1_dbl,LOCAL_LO(a0)
2551.1Smycroft	bcc.b	dcc_clr
2561.1Smycroft	addq.l	#1,LOCAL_HI(a0)		;propogate carry
2571.1Smycroft	bcc.b	dcc_clr
2581.1Smycroft	roxr.w	LOCAL_HI(a0)		;mant is 0 so restore v-bit
2591.1Smycroft	roxr.w	LOCAL_HI+2(a0)		;mant is 0 so restore v-bit
2601.1Smycroft	roxr.w	LOCAL_LO(a0)
2611.1Smycroft	roxr.w	LOCAL_LO+2(a0)
2621.1Smycroft	add.w	#$1,LOCAL_EX(a0)	;incr exponent
2631.1Smycroftdcc_clr:
2641.1Smycroft	tst.l	d0			;test for rs = 0
2651.1Smycroft	bne.b	dbl_done
2661.1Smycroft	andi.w	#$f000,LOCAL_LO+2(a0)	;clear the l-bit
2671.1Smycroft
2681.1Smycroftdbl_done:
2691.1Smycroft	andi.l	#$fffff800,LOCAL_LO(a0) ;truncate bits beyond dbl limit
2701.1Smycroft	rts
2711.1Smycroft
2721.1Smycrofterror:
2731.1Smycroft	rts
2741.1Smycroft*
2751.1Smycroft* Truncate all other bits
2761.1Smycroft*
2771.1Smycrofttrunct:
2781.1Smycroft	dc.l	end_rnd
2791.1Smycroft	dc.l	sgl_done
2801.1Smycroft	dc.l	dbl_done
2811.1Smycroft	dc.l	dbl_done
2821.1Smycroft
2831.1Smycrofttruncate:
2841.1Smycroft	lea	trunct,a1
2851.1Smycroft	move.l	(a1,d1.w*4),a1
2861.1Smycroft	jmp	(a1)
2871.1Smycroft
2881.1Smycroftend_rnd:
2891.1Smycroft	rts
2901.1Smycroft
2911.1Smycroft*
2921.1Smycroft*	NORMALIZE
2931.1Smycroft*
2941.1Smycroft* These routines (nrm_zero & nrm_set) normalize the unnorm.  This 
2951.1Smycroft* is done by shifting the mantissa left while decrementing the 
2961.1Smycroft* exponent.
2971.1Smycroft*
2981.1Smycroft* NRM_SET shifts and decrements until there is a 1 set in the integer 
2991.1Smycroft* bit of the mantissa (msb in d1).
3001.1Smycroft*
3011.1Smycroft* NRM_ZERO shifts and decrements until there is a 1 set in the integer 
3021.1Smycroft* bit of the mantissa (msb in d1) unless this would mean the exponent 
3031.1Smycroft* would go less than 0.  In that case the number becomes a denorm - the 
3041.1Smycroft* exponent (d0) is set to 0 and the mantissa (d1 & d2) is not 
3051.1Smycroft* normalized.
3061.1Smycroft*
3071.1Smycroft* Note that both routines have been optimized (for the worst case) and 
3081.1Smycroft* therefore do not have the easy to follow decrement/shift loop.
3091.1Smycroft*
3101.1Smycroft*	NRM_ZERO
3111.1Smycroft*
3121.1Smycroft*	Distance to first 1 bit in mantissa = X
3131.1Smycroft*	Distance to 0 from exponent = Y
3141.1Smycroft*	If X < Y
3151.1Smycroft*	Then
3161.1Smycroft*	  nrm_set
3171.1Smycroft*	Else
3181.1Smycroft*	  shift mantissa by Y
3191.1Smycroft*	  set exponent = 0
3201.1Smycroft*
3211.1Smycroft*input:
3221.1Smycroft*	FP_SCR1 = exponent, ms mantissa part, ls mantissa part
3231.1Smycroft*output:
3241.1Smycroft*	L_SCR1{4} = fpte15 or ete15 bit
3251.1Smycroft*
3261.1Smycroft	xdef	nrm_zero
3271.1Smycroftnrm_zero:
3281.1Smycroft	move.w	LOCAL_EX(a0),d0
3291.1Smycroft	cmp.w   #64,d0          ;see if exp > 64 
3301.1Smycroft	bmi.b	d0_less
3311.1Smycroft	bsr	nrm_set		;exp > 64 so exp won't exceed 0 
3321.1Smycroft	rts
3331.1Smycroftd0_less:
3341.1Smycroft	movem.l	d2/d3/d5/d6,-(a7)
3351.1Smycroft	move.l	LOCAL_HI(a0),d1
3361.1Smycroft	move.l	LOCAL_LO(a0),d2
3371.1Smycroft
3381.1Smycroft	bfffo	d1{0:32},d3	;get the distance to the first 1 
3391.1Smycroft*				;in ms mant
3401.1Smycroft	beq.b	ms_clr		;branch if no bits were set
3411.1Smycroft	cmp.w	d3,d0		;of X>Y
3421.1Smycroft	bmi.b	greater		;then exp will go past 0 (neg) if 
3431.1Smycroft*				;it is just shifted
3441.1Smycroft	bsr	nrm_set		;else exp won't go past 0
3451.1Smycroft	movem.l	(a7)+,d2/d3/d5/d6
3461.1Smycroft	rts	
3471.1Smycroftgreater:
3481.1Smycroft	move.l	d2,d6		;save ls mant in d6
3491.1Smycroft	lsl.l	d0,d2		;shift ls mant by count
3501.1Smycroft	lsl.l	d0,d1		;shift ms mant by count
3511.1Smycroft	move.l	#32,d5
3521.1Smycroft	sub.l	d0,d5		;make op a denorm by shifting bits 
3531.1Smycroft	lsr.l	d5,d6		;by the number in the exp, then 
3541.1Smycroft*				;set exp = 0.
3551.1Smycroft	or.l	d6,d1		;shift the ls mant bits into the ms mant
3561.2Smycroft	clr.l	d0		;same as if decremented exp to 0 
3571.1Smycroft*				;while shifting
3581.1Smycroft	move.w	d0,LOCAL_EX(a0)
3591.1Smycroft	move.l	d1,LOCAL_HI(a0)
3601.1Smycroft	move.l	d2,LOCAL_LO(a0)
3611.1Smycroft	movem.l	(a7)+,d2/d3/d5/d6
3621.1Smycroft	rts
3631.1Smycroftms_clr:
3641.1Smycroft	bfffo	d2{0:32},d3	;check if any bits set in ls mant
3651.1Smycroft	beq.b	all_clr		;branch if none set
3661.1Smycroft	add.w	#32,d3
3671.1Smycroft	cmp.w	d3,d0		;if X>Y
3681.1Smycroft	bmi.b	greater		;then branch
3691.1Smycroft	bsr	nrm_set		;else exp won't go past 0
3701.1Smycroft	movem.l	(a7)+,d2/d3/d5/d6
3711.1Smycroft	rts
3721.1Smycroftall_clr:
3731.2Smycroft	clr.w	LOCAL_EX(a0)	;no mantissa bits set. Set exp = 0.
3741.1Smycroft	movem.l	(a7)+,d2/d3/d5/d6
3751.1Smycroft	rts
3761.1Smycroft*
3771.1Smycroft*	NRM_SET
3781.1Smycroft*
3791.1Smycroft	xdef	nrm_set
3801.1Smycroftnrm_set:
3811.1Smycroft	move.l	d7,-(a7)
3821.1Smycroft	bfffo	LOCAL_HI(a0){0:32},d7 ;find first 1 in ms mant to d7)
3831.1Smycroft	beq.b	lower		;branch if ms mant is all 0's
3841.1Smycroft
3851.1Smycroft	move.l	d6,-(a7)
3861.1Smycroft
3871.1Smycroft	sub.w	d7,LOCAL_EX(a0)	;sub exponent by count
3881.1Smycroft	move.l	LOCAL_HI(a0),d0	;d0 has ms mant
3891.1Smycroft	move.l	LOCAL_LO(a0),d1 ;d1 has ls mant
3901.1Smycroft
3911.1Smycroft	lsl.l	d7,d0		;shift first 1 to j bit position
3921.1Smycroft	move.l	d1,d6		;copy ls mant into d6
3931.1Smycroft	lsl.l	d7,d6		;shift ls mant by count
3941.1Smycroft	move.l	d6,LOCAL_LO(a0)	;store ls mant into memory
3951.1Smycroft	moveq.l	#32,d6
3961.1Smycroft	sub.l	d7,d6		;continue shift
3971.1Smycroft	lsr.l	d6,d1		;shift off all bits but those that will
3981.1Smycroft*				;be shifted into ms mant
3991.1Smycroft	or.l	d1,d0		;shift the ls mant bits into the ms mant
4001.1Smycroft	move.l	d0,LOCAL_HI(a0)	;store ms mant into memory
4011.1Smycroft	movem.l	(a7)+,d7/d6	;restore registers
4021.1Smycroft	rts
4031.1Smycroft
4041.1Smycroft*
4051.1Smycroft* We get here if ms mant was = 0, and we assume ls mant has bits 
4061.1Smycroft* set (otherwise this would have been tagged a zero not a denorm).
4071.1Smycroft*
4081.1Smycroftlower:
4091.1Smycroft	move.w	LOCAL_EX(a0),d0	;d0 has exponent
4101.1Smycroft	move.l	LOCAL_LO(a0),d1	;d1 has ls mant
4111.1Smycroft	sub.w	#32,d0		;account for ms mant being all zeros
4121.1Smycroft	bfffo	d1{0:32},d7	;find first 1 in ls mant to d7)
4131.1Smycroft	sub.w	d7,d0		;subtract shift count from exp
4141.1Smycroft	lsl.l	d7,d1		;shift first 1 to integer bit in ms mant
4151.1Smycroft	move.w	d0,LOCAL_EX(a0)	;store ms mant
4161.1Smycroft	move.l	d1,LOCAL_HI(a0)	;store exp
4171.1Smycroft	clr.l	LOCAL_LO(a0)	;clear ls mant
4181.1Smycroft	move.l	(a7)+,d7
4191.1Smycroft	rts
4201.1Smycroft*
4211.1Smycroft*	denorm --- denormalize an intermediate result
4221.1Smycroft*
4231.1Smycroft*	Used by underflow.
4241.1Smycroft*
4251.1Smycroft* Input: 
4261.1Smycroft*	a0	 points to the operand to be denormalized
4271.1Smycroft*		 (in the internal extended format)
4281.1Smycroft*		 
4291.1Smycroft*	d0: 	 rounding precision
4301.1Smycroft* Output:
4311.1Smycroft*	a0	 points to the denormalized result
4321.1Smycroft*		 (in the internal extended format)
4331.1Smycroft*
4341.1Smycroft*	d0 	is guard,round,sticky
4351.1Smycroft*
4361.1Smycroft* d0 comes into this routine with the rounding precision. It 
4371.1Smycroft* is then loaded with the denormalized exponent threshold for the 
4381.1Smycroft* rounding precision.
4391.1Smycroft*
4401.1Smycroft
4411.1Smycroft	xdef	denorm
4421.1Smycroftdenorm:
4431.1Smycroft	btst.b	#6,LOCAL_EX(a0)	;check for exponents between $7fff-$4000
4441.1Smycroft	beq.b	no_sgn_ext	
4451.1Smycroft	bset.b	#7,LOCAL_EX(a0)	;sign extend if it is so
4461.1Smycroftno_sgn_ext:
4471.1Smycroft
4481.2Smycroft	tst.b	d0		;if 0 then extended precision
4491.1Smycroft	bne.b	not_ext		;else branch
4501.1Smycroft
4511.1Smycroft	clr.l	d1		;load d1 with ext threshold
4521.1Smycroft	clr.l	d0		;clear the sticky flag
4531.1Smycroft	bsr	dnrm_lp		;denormalize the number
4541.1Smycroft	tst.b	d1		;check for inex
4551.1Smycroft	beq.w	no_inex		;if clr, no inex
4561.1Smycroft	bra.b	dnrm_inex	;if set, set inex
4571.1Smycroft
4581.1Smycroftnot_ext:
4591.1Smycroft	cmpi.l	#1,d0		;if 1 then single precision
4601.1Smycroft	beq.b	load_sgl	;else must be 2, double prec
4611.1Smycroft
4621.1Smycroftload_dbl:
4631.1Smycroft	move.w	#dbl_thresh,d1	;put copy of threshold in d1
4641.1Smycroft	move.l	d1,d0		;copy d1 into d0
4651.1Smycroft	sub.w	LOCAL_EX(a0),d0	;diff = threshold - exp
4661.1Smycroft	cmp.w	#67,d0		;if diff > 67 (mant + grs bits)
4671.1Smycroft	bpl.b	chk_stky	;then branch (all bits would be 
4681.1Smycroft*				; shifted off in denorm routine)
4691.1Smycroft	clr.l	d0		;else clear the sticky flag
4701.1Smycroft	bsr	dnrm_lp		;denormalize the number
4711.1Smycroft	tst.b	d1		;check flag
4721.1Smycroft	beq.b	no_inex		;if clr, no inex
4731.1Smycroft	bra.b	dnrm_inex	;if set, set inex
4741.1Smycroft
4751.1Smycroftload_sgl:
4761.1Smycroft	move.w	#sgl_thresh,d1	;put copy of threshold in d1
4771.1Smycroft	move.l	d1,d0		;copy d1 into d0
4781.1Smycroft	sub.w	LOCAL_EX(a0),d0	;diff = threshold - exp
4791.1Smycroft	cmp.w	#67,d0		;if diff > 67 (mant + grs bits)
4801.1Smycroft	bpl.b	chk_stky	;then branch (all bits would be 
4811.1Smycroft*				; shifted off in denorm routine)
4821.1Smycroft	clr.l	d0		;else clear the sticky flag
4831.1Smycroft	bsr	dnrm_lp		;denormalize the number
4841.1Smycroft	tst.b	d1		;check flag
4851.1Smycroft	beq.b	no_inex		;if clr, no inex
4861.1Smycroft	bra.b	dnrm_inex	;if set, set inex
4871.1Smycroft
4881.1Smycroftchk_stky:
4891.1Smycroft	tst.l	LOCAL_HI(a0)	;check for any bits set
4901.1Smycroft	bne.b	set_stky
4911.1Smycroft	tst.l	LOCAL_LO(a0)	;check for any bits set
4921.1Smycroft	bne.b	set_stky
4931.1Smycroft	bra.b	clr_mant
4941.1Smycroftset_stky:
4951.1Smycroft	or.l	#inx2a_mask,USER_FPSR(a6) ;set inex2/ainex
4961.1Smycroft	move.l	#$20000000,d0	;set sticky bit in return value
4971.1Smycroftclr_mant:
4981.1Smycroft	move.w	d1,LOCAL_EX(a0)		;load exp with threshold
4991.2Smycroft	clr.l	LOCAL_HI(a0) 	;set d1 = 0 (ms mantissa)
5001.2Smycroft	clr.l	LOCAL_LO(a0)		;set d2 = 0 (ms mantissa)
5011.1Smycroft	rts
5021.1Smycroftdnrm_inex:
5031.1Smycroft	or.l	#inx2a_mask,USER_FPSR(a6) ;set inex2/ainex
5041.1Smycroftno_inex:
5051.1Smycroft	rts
5061.1Smycroft
5071.1Smycroft*
5081.1Smycroft*	dnrm_lp --- normalize exponent/mantissa to specified threshhold
5091.1Smycroft*
5101.1Smycroft* Input:
5111.1Smycroft*	a0		points to the operand to be denormalized
5121.1Smycroft*	d0{31:29} 	initial guard,round,sticky
5131.1Smycroft*	d1{15:0}	denormalization threshold
5141.1Smycroft* Output:
5151.1Smycroft*	a0		points to the denormalized operand
5161.1Smycroft*	d0{31:29}	final guard,round,sticky
5171.1Smycroft*	d1.b		inexact flag:  all ones means inexact result
5181.1Smycroft*
5191.1Smycroft* The LOCAL_LO and LOCAL_GRS parts of the value are copied to FP_SCR2
5201.1Smycroft* so that bfext can be used to extract the new low part of the mantissa.
5211.1Smycroft* Dnrm_lp can be called with a0 pointing to ETEMP or WBTEMP and there 
5221.1Smycroft* is no LOCAL_GRS scratch word following it on the fsave frame.
5231.1Smycroft*
5241.1Smycroft	xdef	dnrm_lp
5251.1Smycroftdnrm_lp:
5261.1Smycroft	move.l	d2,-(sp)		;save d2 for temp use
5271.1Smycroft	btst.b	#E3,E_BYTE(a6)		;test for type E3 exception
5281.1Smycroft	beq.b	not_E3			;not type E3 exception
5291.1Smycroft	bfextu	WBTEMP_GRS(a6){6:3},d2	;extract guard,round, sticky  bit
5301.1Smycroft	move.l	#29,d0
5311.1Smycroft	lsl.l	d0,d2			;shift g,r,s to their postions
5321.1Smycroft	move.l	d2,d0
5331.1Smycroftnot_E3:
5341.1Smycroft	move.l	(sp)+,d2		;restore d2
5351.1Smycroft	move.l	LOCAL_LO(a0),FP_SCR2+LOCAL_LO(a6)
5361.1Smycroft	move.l	d0,FP_SCR2+LOCAL_GRS(a6)
5371.1Smycroft	move.l	d1,d0			;copy the denorm threshold
5381.1Smycroft	sub.w	LOCAL_EX(a0),d1		;d1 = threshold - uns exponent
5391.1Smycroft	ble.b	no_lp			;d1 <= 0
5401.1Smycroft	cmp.w	#32,d1			
5411.1Smycroft	blt.b	case_1			;0 = d1 < 32 
5421.1Smycroft	cmp.w	#64,d1
5431.1Smycroft	blt.b	case_2			;32 <= d1 < 64
5441.1Smycroft	bra.w	case_3			;d1 >= 64
5451.1Smycroft*
5461.1Smycroft* No normalization necessary
5471.1Smycroft*
5481.1Smycroftno_lp:
5491.1Smycroft	clr.b	d1			;set no inex2 reported
5501.1Smycroft	move.l	FP_SCR2+LOCAL_GRS(a6),d0	;restore original g,r,s
5511.1Smycroft	rts
5521.1Smycroft*
5531.1Smycroft* case (0<d1<32)
5541.1Smycroft*
5551.1Smycroftcase_1:
5561.1Smycroft	move.l	d2,-(sp)
5571.1Smycroft	move.w	d0,LOCAL_EX(a0)		;exponent = denorm threshold
5581.1Smycroft	move.l	#32,d0
5591.1Smycroft	sub.w	d1,d0			;d0 = 32 - d1
5601.1Smycroft	bfextu	LOCAL_EX(a0){d0:32},d2
5611.1Smycroft	bfextu	d2{d1:d0},d2		;d2 = new LOCAL_HI
5621.1Smycroft	bfextu	LOCAL_HI(a0){d0:32},d1	;d1 = new LOCAL_LO
5631.1Smycroft	bfextu	FP_SCR2+LOCAL_LO(a6){d0:32},d0	;d0 = new G,R,S
5641.1Smycroft	move.l	d2,LOCAL_HI(a0)		;store new LOCAL_HI
5651.1Smycroft	move.l	d1,LOCAL_LO(a0)		;store new LOCAL_LO
5661.1Smycroft	clr.b	d1
5671.1Smycroft	bftst	d0{2:30}	
5681.1Smycroft	beq.b	c1nstky
5691.1Smycroft	bset.l	#rnd_stky_bit,d0
5701.1Smycroft	st.b	d1
5711.1Smycroftc1nstky:
5721.1Smycroft	move.l	FP_SCR2+LOCAL_GRS(a6),d2	;restore original g,r,s
5731.1Smycroft	andi.l	#$e0000000,d2		;clear all but G,R,S
5741.1Smycroft	tst.l	d2			;test if original G,R,S are clear
5751.1Smycroft	beq.b	grs_clear
5761.1Smycroft	or.l	#$20000000,d0		;set sticky bit in d0
5771.1Smycroftgrs_clear:
5781.1Smycroft	andi.l	#$e0000000,d0		;clear all but G,R,S
5791.1Smycroft	move.l	(sp)+,d2
5801.1Smycroft	rts
5811.1Smycroft*
5821.1Smycroft* case (32<=d1<64)
5831.1Smycroft*
5841.1Smycroftcase_2:
5851.1Smycroft	move.l	d2,-(sp)
5861.1Smycroft	move.w	d0,LOCAL_EX(a0)		;unsigned exponent = threshold
5871.1Smycroft	sub.w	#32,d1			;d1 now between 0 and 32
5881.1Smycroft	move.l	#32,d0
5891.1Smycroft	sub.w	d1,d0			;d0 = 32 - d1
5901.1Smycroft	bfextu	LOCAL_EX(a0){d0:32},d2
5911.1Smycroft	bfextu	d2{d1:d0},d2		;d2 = new LOCAL_LO
5921.1Smycroft	bfextu	LOCAL_HI(a0){d0:32},d1	;d1 = new G,R,S
5931.1Smycroft	bftst	d1{2:30}
5941.1Smycroft	bne.b	c2_sstky		;bra if sticky bit to be set
5951.1Smycroft	bftst	FP_SCR2+LOCAL_LO(a6){d0:32}
5961.1Smycroft	bne.b	c2_sstky		;bra if sticky bit to be set
5971.1Smycroft	move.l	d1,d0
5981.1Smycroft	clr.b	d1
5991.1Smycroft	bra.b	end_c2
6001.1Smycroftc2_sstky:
6011.1Smycroft	move.l	d1,d0
6021.1Smycroft	bset.l	#rnd_stky_bit,d0
6031.1Smycroft	st.b	d1
6041.1Smycroftend_c2:
6051.1Smycroft	clr.l	LOCAL_HI(a0)		;store LOCAL_HI = 0
6061.1Smycroft	move.l	d2,LOCAL_LO(a0)		;store LOCAL_LO
6071.1Smycroft	move.l	FP_SCR2+LOCAL_GRS(a6),d2	;restore original g,r,s
6081.1Smycroft	andi.l	#$e0000000,d2		;clear all but G,R,S
6091.1Smycroft	tst.l	d2			;test if original G,R,S are clear
6101.1Smycroft	beq.b	clear_grs		
6111.1Smycroft	or.l	#$20000000,d0		;set sticky bit in d0
6121.1Smycroftclear_grs:
6131.1Smycroft	andi.l	#$e0000000,d0		;get rid of all but G,R,S
6141.1Smycroft	move.l	(sp)+,d2
6151.1Smycroft	rts
6161.1Smycroft*
6171.1Smycroft* d1 >= 64 Force the exponent to be the denorm threshold with the
6181.1Smycroft* correct sign.
6191.1Smycroft*
6201.1Smycroftcase_3:
6211.1Smycroft	move.w	d0,LOCAL_EX(a0)
6221.1Smycroft	tst.w	LOCAL_SGN(a0)
6231.1Smycroft	bge.b	c3con
6241.1Smycroftc3neg:
6251.1Smycroft	or.l	#$80000000,LOCAL_EX(a0)
6261.1Smycroftc3con:
6271.1Smycroft	cmp.w	#64,d1
6281.1Smycroft	beq.b	sixty_four
6291.1Smycroft	cmp.w	#65,d1
6301.1Smycroft	beq.b	sixty_five
6311.1Smycroft*
6321.1Smycroft* Shift value is out of range.  Set d1 for inex2 flag and
6331.1Smycroft* return a zero with the given threshold.
6341.1Smycroft*
6351.1Smycroft	clr.l	LOCAL_HI(a0)
6361.1Smycroft	clr.l	LOCAL_LO(a0)
6371.1Smycroft	move.l	#$20000000,d0
6381.1Smycroft	st.b	d1
6391.1Smycroft	rts
6401.1Smycroft
6411.1Smycroftsixty_four:
6421.1Smycroft	move.l	LOCAL_HI(a0),d0
6431.1Smycroft	bfextu	d0{2:30},d1
6441.1Smycroft	andi.l	#$c0000000,d0
6451.1Smycroft	bra.b	c3com
6461.1Smycroft	
6471.1Smycroftsixty_five:
6481.1Smycroft	move.l	LOCAL_HI(a0),d0
6491.1Smycroft	bfextu	d0{1:31},d1
6501.1Smycroft	andi.l	#$80000000,d0
6511.1Smycroft	lsr.l	#1,d0			;shift high bit into R bit
6521.1Smycroft
6531.1Smycroftc3com:
6541.1Smycroft	tst.l	d1
6551.1Smycroft	bne.b	c3ssticky
6561.1Smycroft	tst.l	LOCAL_LO(a0)
6571.1Smycroft	bne.b	c3ssticky
6581.1Smycroft	tst.b	FP_SCR2+LOCAL_GRS(a6)
6591.1Smycroft	bne.b	c3ssticky
6601.1Smycroft	clr.b	d1
6611.1Smycroft	bra.b	c3end
6621.1Smycroft
6631.1Smycroftc3ssticky:
6641.1Smycroft	bset.l	#rnd_stky_bit,d0
6651.1Smycroft	st.b	d1
6661.1Smycroftc3end:
6671.1Smycroft	clr.l	LOCAL_HI(a0)
6681.1Smycroft	clr.l	LOCAL_LO(a0)
6691.1Smycroft	rts
6701.1Smycroft
6711.1Smycroft	end
672