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