ifpsp060/src/fpsp.S [21671:22928]:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#########################################################################
# XDEF ****************************************************************	#
#	_denorm(): denormalize an intermediate result			#
#									#
# XREF ****************************************************************	#
#	None								#
#									#
# INPUT *************************************************************** #
#	a0 = points to the operand to be denormalized			#
#		(in the internal extended format)			#
#									#
#	d0 = rounding precision						#
#									#
# OUTPUT **************************************************************	#
#	a0 = pointer to the denormalized result				#
#		(in the internal extended format)			#
#									#
#	d0 = guard,round,sticky						#
#									#
# ALGORITHM ***********************************************************	#
#	According to the exponent underflow threshold for the given	#
# precision, shift the mantissa bits to the right in order raise the	#
# exponent of the operand to the threshold value. While shifting the	#
# mantissa bits right, maintain the value of the guard, round, and	#
# sticky bits.								#
# other notes:								#
#	(1) _denorm() is called by the underflow routines		#
#	(2) _denorm() does NOT affect the status register		#
#									#
#########################################################################

#
# table of exponent threshold values for each precision
#
tbl_thresh:
	short		0x0
	short		sgl_thresh
	short		dbl_thresh

	global		_denorm
_denorm:
#
# Load the exponent threshold for the precision selected and check
# to see if (threshold - exponent) is > 65 in which case we can
# simply calculate the sticky bit and zero the mantissa. otherwise
# we have to call the denormalization routine.
#
	lsr.b		&0x2, %d0		# shift prec to lo bits
	mov.w		(tbl_thresh.b,%pc,%d0.w*2), %d1 # load prec threshold
	mov.w		%d1, %d0		# copy d1 into d0
	sub.w		FTEMP_EX(%a0), %d0	# diff = threshold - exp
	cmpi.w		%d0, &66		# is diff > 65? (mant + g,r bits)
	bpl.b		denorm_set_stky		# yes; just calc sticky

	clr.l		%d0			# clear g,r,s
	btst		&inex2_bit, FPSR_EXCEPT(%a6) # yes; was INEX2 set?
	beq.b		denorm_call		# no; don't change anything
	bset		&29, %d0		# yes; set sticky bit

denorm_call:
	bsr.l		dnrm_lp			# denormalize the number
	rts

#
# all bit would have been shifted off during the denorm so simply
# calculate if the sticky should be set and clear the entire mantissa.
#
denorm_set_stky:
	mov.l		&0x20000000, %d0	# set sticky bit in return value
	mov.w		%d1, FTEMP_EX(%a0)	# load exp with threshold
	clr.l		FTEMP_HI(%a0)		# set d1 = 0 (ms mantissa)
	clr.l		FTEMP_LO(%a0)		# set d2 = 0 (ms mantissa)
	rts

#									#
# dnrm_lp(): normalize exponent/mantissa to specified threshold		#
#									#
# INPUT:								#
#	%a0	   : points to the operand to be denormalized		#
#	%d0{31:29} : initial guard,round,sticky				#
#	%d1{15:0}  : denormalization threshold				#
# OUTPUT:								#
#	%a0	   : points to the denormalized operand			#
#	%d0{31:29} : final guard,round,sticky				#
#									#

# *** Local Equates *** #
set	GRS,		L_SCR2			# g,r,s temp storage
set	FTEMP_LO2,	L_SCR1			# FTEMP_LO copy

	global		dnrm_lp
dnrm_lp:

#
# make a copy of FTEMP_LO and place the g,r,s bits directly after it
# in memory so as to make the bitfield extraction for denormalization easier.
#
	mov.l		FTEMP_LO(%a0), FTEMP_LO2(%a6) # make FTEMP_LO copy
	mov.l		%d0, GRS(%a6)		# place g,r,s after it

#
# check to see how much less than the underflow threshold the operand
# exponent is.
#
	mov.l		%d1, %d0		# copy the denorm threshold
	sub.w		FTEMP_EX(%a0), %d1	# d1 = threshold - uns exponent
	ble.b		dnrm_no_lp		# d1 <= 0
	cmpi.w		%d1, &0x20		# is ( 0 <= d1 < 32) ?
	blt.b		case_1			# yes
	cmpi.w		%d1, &0x40		# is (32 <= d1 < 64) ?
	blt.b		case_2			# yes
	bra.w		case_3			# (d1 >= 64)

#
# No normalization necessary
#
dnrm_no_lp:
	mov.l		GRS(%a6), %d0		# restore original g,r,s
	rts

#
# case (0<d1<32)
#
# %d0 = denorm threshold
# %d1 = "n" = amt to shift
#
#	---------------------------------------------------------
#	|     FTEMP_HI	  |	FTEMP_LO     |grs000.........000|
#	---------------------------------------------------------
#	<-(32 - n)-><-(n)-><-(32 - n)-><-(n)-><-(32 - n)-><-(n)->
#	\	   \		      \			 \
#	 \	    \		       \		  \
#	  \	     \			\		   \
#	   \	      \			 \		    \
#	    \	       \		  \		     \
#	     \		\		   \		      \
#	      \		 \		    \		       \
#	       \	  \		     \			\
#	<-(n)-><-(32 - n)-><------(32)-------><------(32)------->
#	---------------------------------------------------------
#	|0.....0| NEW_HI  |  NEW_FTEMP_LO     |grs		|
#	---------------------------------------------------------
#
case_1:
	mov.l		%d2, -(%sp)		# create temp storage

	mov.w		%d0, FTEMP_EX(%a0)	# exponent = denorm threshold
	mov.l		&32, %d0
	sub.w		%d1, %d0		# %d0 = 32 - %d1

	cmpi.w		%d1, &29		# is shft amt >= 29
	blt.b		case1_extract		# no; no fix needed
	mov.b		GRS(%a6), %d2
	or.b		%d2, 3+FTEMP_LO2(%a6)

case1_extract:
	bfextu		FTEMP_HI(%a0){&0:%d0}, %d2 # %d2 = new FTEMP_HI
	bfextu		FTEMP_HI(%a0){%d0:&32}, %d1 # %d1 = new FTEMP_LO
	bfextu		FTEMP_LO2(%a6){%d0:&32}, %d0 # %d0 = new G,R,S

	mov.l		%d2, FTEMP_HI(%a0)	# store new FTEMP_HI
	mov.l		%d1, FTEMP_LO(%a0)	# store new FTEMP_LO

	bftst		%d0{&2:&30}		# were bits shifted off?
	beq.b		case1_sticky_clear	# no; go finish
	bset		&rnd_stky_bit, %d0	# yes; set sticky bit

case1_sticky_clear:
	and.l		&0xe0000000, %d0	# clear all but G,R,S
	mov.l		(%sp)+, %d2		# restore temp register
	rts

#
# case (32<=d1<64)
#
# %d0 = denorm threshold
# %d1 = "n" = amt to shift
#
#	---------------------------------------------------------
#	|     FTEMP_HI	  |	FTEMP_LO     |grs000.........000|
#	---------------------------------------------------------
#	<-(32 - n)-><-(n)-><-(32 - n)-><-(n)-><-(32 - n)-><-(n)->
#	\	   \		      \
#	 \	    \		       \
#	  \	     \			-------------------
#	   \	      --------------------		   \
#	    -------------------		  \		    \
#			       \	   \		     \
#				\	    \		      \
#				 \	     \		       \
#	<-------(32)------><-(n)-><-(32 - n)-><------(32)------->
#	---------------------------------------------------------
#	|0...............0|0....0| NEW_LO     |grs		|
#	---------------------------------------------------------
#
case_2:
	mov.l		%d2, -(%sp)		# create temp storage

	mov.w		%d0, FTEMP_EX(%a0)	# exponent = denorm threshold
	subi.w		&0x20, %d1		# %d1 now between 0 and 32
	mov.l		&0x20, %d0
	sub.w		%d1, %d0		# %d0 = 32 - %d1

# subtle step here; or in the g,r,s at the bottom of FTEMP_LO to minimize
# the number of bits to check for the sticky detect.
# it only plays a role in shift amounts of 61-63.
	mov.b		GRS(%a6), %d2
	or.b		%d2, 3+FTEMP_LO2(%a6)

	bfextu		FTEMP_HI(%a0){&0:%d0}, %d2 # %d2 = new FTEMP_LO
	bfextu		FTEMP_HI(%a0){%d0:&32}, %d1 # %d1 = new G,R,S

	bftst		%d1{&2:&30}		# were any bits shifted off?
	bne.b		case2_set_sticky	# yes; set sticky bit
	bftst		FTEMP_LO2(%a6){%d0:&31}	# were any bits shifted off?
	bne.b		case2_set_sticky	# yes; set sticky bit

	mov.l		%d1, %d0		# move new G,R,S to %d0
	bra.b		case2_end

case2_set_sticky:
	mov.l		%d1, %d0		# move new G,R,S to %d0
	bset		&rnd_stky_bit, %d0	# set sticky bit

case2_end:
	clr.l		FTEMP_HI(%a0)		# store FTEMP_HI = 0
	mov.l		%d2, FTEMP_LO(%a0)	# store FTEMP_LO
	and.l		&0xe0000000, %d0	# clear all but G,R,S

	mov.l		(%sp)+,%d2		# restore temp register
	rts

#
# case (d1>=64)
#
# %d0 = denorm threshold
# %d1 = amt to shift
#
case_3:
	mov.w		%d0, FTEMP_EX(%a0)	# insert denorm threshold

	cmpi.w		%d1, &65		# is shift amt > 65?
	blt.b		case3_64		# no; it's == 64
	beq.b		case3_65		# no; it's == 65

#
# case (d1>65)
#
# Shift value is > 65 and out of range. All bits are shifted off.
# Return a zero mantissa with the sticky bit set
#
	clr.l		FTEMP_HI(%a0)		# clear hi(mantissa)
	clr.l		FTEMP_LO(%a0)		# clear lo(mantissa)
	mov.l		&0x20000000, %d0	# set sticky bit
	rts

#
# case (d1 == 64)
#
#	---------------------------------------------------------
#	|     FTEMP_HI	  |	FTEMP_LO     |grs000.........000|
#	---------------------------------------------------------
#	<-------(32)------>
#	\		   \
#	 \		    \
#	  \		     \
#	   \		      ------------------------------
#	    -------------------------------		    \
#					   \		     \
#					    \		      \
#					     \		       \
#					      <-------(32)------>
#	---------------------------------------------------------
#	|0...............0|0................0|grs		|
#	---------------------------------------------------------
#
case3_64:
	mov.l		FTEMP_HI(%a0), %d0	# fetch hi(mantissa)
	mov.l		%d0, %d1		# make a copy
	and.l		&0xc0000000, %d0	# extract G,R
	and.l		&0x3fffffff, %d1	# extract other bits

	bra.b		case3_complete

#
# case (d1 == 65)
#
#	---------------------------------------------------------
#	|     FTEMP_HI	  |	FTEMP_LO     |grs000.........000|
#	---------------------------------------------------------
#	<-------(32)------>
#	\		   \
#	 \		    \
#	  \		     \
#	   \		      ------------------------------
#	    --------------------------------		    \
#					    \		     \
#					     \		      \
#					      \		       \
#					       <-------(31)----->
#	---------------------------------------------------------
#	|0...............0|0................0|0rs		|
#	---------------------------------------------------------
#
case3_65:
	mov.l		FTEMP_HI(%a0), %d0	# fetch hi(mantissa)
	and.l		&0x80000000, %d0	# extract R bit
	lsr.l		&0x1, %d0		# shift high bit into R bit
	and.l		&0x7fffffff, %d1	# extract other bits

case3_complete:
# last operation done was an "and" of the bits shifted off so the condition
# codes are already set so branch accordingly.
	bne.b		case3_set_sticky	# yes; go set new sticky
	tst.l		FTEMP_LO(%a0)		# were any bits shifted off?
	bne.b		case3_set_sticky	# yes; go set new sticky
	tst.b		GRS(%a6)		# were any bits shifted off?
	bne.b		case3_set_sticky	# yes; go set new sticky

#
# no bits were shifted off so don't set the sticky bit.
# the guard and
# the entire mantissa is zero.
#
	clr.l		FTEMP_HI(%a0)		# clear hi(mantissa)
	clr.l		FTEMP_LO(%a0)		# clear lo(mantissa)
	rts

#
# some bits were shifted off so set the sticky bit.
# the entire mantissa is zero.
#
case3_set_sticky:
	bset		&rnd_stky_bit,%d0	# set new sticky bit
	clr.l		FTEMP_HI(%a0)		# clear hi(mantissa)
	clr.l		FTEMP_LO(%a0)		# clear lo(mantissa)
	rts

#########################################################################
# XDEF ****************************************************************	#
#	_round(): round result according to precision/mode		#
#									#
# XREF ****************************************************************	#
#	None								#
#									#
# INPUT ***************************************************************	#
#	a0	  = ptr to input operand in internal extended format	#
#	d1(hi)    = contains rounding precision:			#
#			ext = $0000xxxx					#
#			sgl = $0004xxxx					#
#			dbl = $0008xxxx					#
#	d1(lo)	  = contains rounding mode:				#
#			RN  = $xxxx0000					#
#			RZ  = $xxxx0001					#
#			RM  = $xxxx0002					#
#			RP  = $xxxx0003					#
#	d0{31:29} = contains the g,r,s bits (extended)			#
#									#
# OUTPUT **************************************************************	#
#	a0 = pointer to rounded result					#
#									#
# ALGORITHM ***********************************************************	#
#	On return the value pointed to by a0 is correctly rounded,	#
#	a0 is preserved and the g-r-s bits in d0 are cleared.		#
#	The result is not typed - the tag field is invalid.  The	#
#	result is still in the internal extended format.		#
#									#
#	The INEX bit of USER_FPSR will be set if the rounded result was	#
#	inexact (i.e. if any of the g-r-s bits were set).		#
#									#
#########################################################################

	global		_round
_round:
#
# ext_grs() looks at the rounding precision and sets the appropriate
# G,R,S bits.
# If (G,R,S == 0) then result is exact and round is done, else set
# the inex flag in status reg and continue.
#
	bsr.l		ext_grs			# extract G,R,S

	tst.l		%d0			# are G,R,S zero?
	beq.w		truncate		# yes; round is complete

	or.w		&inx2a_mask, 2+USER_FPSR(%a6) # set inex2/ainex

#
# Use rounding mode as an index into a jump table for these modes.
# All of the following assumes grs != 0.
#
	mov.w		(tbl_mode.b,%pc,%d1.w*2), %a1 # load jump offset
	jmp		(tbl_mode.b,%pc,%a1)	# jmp to rnd mode handler

tbl_mode:
	short		rnd_near - tbl_mode
	short		truncate - tbl_mode	# RZ always truncates
	short		rnd_mnus - tbl_mode
	short		rnd_plus - tbl_mode

#################################################################
#	ROUND PLUS INFINITY					#
#								#
#	If sign of fp number = 0 (positive), then add 1 to l.	#
#################################################################
rnd_plus:
	tst.b		FTEMP_SGN(%a0)		# check for sign
	bmi.w		truncate		# if positive then truncate

	mov.l		&0xffffffff, %d0	# force g,r,s to be all f's
	swap		%d1			# set up d1 for round prec.

	cmpi.b		%d1, &s_mode		# is prec = sgl?
	beq.w		add_sgl			# yes
	bgt.w		add_dbl			# no; it's dbl
	bra.w		add_ext			# no; it's ext

#################################################################
#	ROUND MINUS INFINITY					#
#								#
#	If sign of fp number = 1 (negative), then add 1 to l.	#
#################################################################
rnd_mnus:
	tst.b		FTEMP_SGN(%a0)		# check for sign
	bpl.w		truncate		# if negative then truncate

	mov.l		&0xffffffff, %d0	# force g,r,s to be all f's
	swap		%d1			# set up d1 for round prec.

	cmpi.b		%d1, &s_mode		# is prec = sgl?
	beq.w		add_sgl			# yes
	bgt.w		add_dbl			# no; it's dbl
	bra.w		add_ext			# no; it's ext

#################################################################
#	ROUND NEAREST						#
#								#
#	If (g=1), then add 1 to l and if (r=s=0), then clear l	#
#	Note that this will round to even in case of a tie.	#
#################################################################
rnd_near:
	asl.l		&0x1, %d0		# shift g-bit to c-bit
	bcc.w		truncate		# if (g=1) then

	swap		%d1			# set up d1 for round prec.

	cmpi.b		%d1, &s_mode		# is prec = sgl?
	beq.w		add_sgl			# yes
	bgt.w		add_dbl			# no; it's dbl
	bra.w		add_ext			# no; it's ext

# *** LOCAL EQUATES ***
set	ad_1_sgl,	0x00000100	# constant to add 1 to l-bit in sgl prec
set	ad_1_dbl,	0x00000800	# constant to add 1 to l-bit in dbl prec

#########################
#	ADD SINGLE	#
#########################
add_sgl:
	add.l		&ad_1_sgl, FTEMP_HI(%a0)
	bcc.b		scc_clr			# no mantissa overflow
	roxr.w		FTEMP_HI(%a0)		# shift v-bit back in
	roxr.w		FTEMP_HI+2(%a0)		# shift v-bit back in
	add.w		&0x1, FTEMP_EX(%a0)	# and incr exponent
scc_clr:
	tst.l		%d0			# test for rs = 0
	bne.b		sgl_done
	and.w		&0xfe00, FTEMP_HI+2(%a0) # clear the l-bit
sgl_done:
	and.l		&0xffffff00, FTEMP_HI(%a0) # truncate bits beyond sgl limit
	clr.l		FTEMP_LO(%a0)		# clear d2
	rts

#########################
#	ADD EXTENDED	#
#########################
add_ext:
	addq.l		&1,FTEMP_LO(%a0)	# add 1 to l-bit
	bcc.b		xcc_clr			# test for carry out
	addq.l		&1,FTEMP_HI(%a0)	# propagate carry
	bcc.b		xcc_clr
	roxr.w		FTEMP_HI(%a0)		# mant is 0 so restore v-bit
	roxr.w		FTEMP_HI+2(%a0)		# mant is 0 so restore v-bit
	roxr.w		FTEMP_LO(%a0)
	roxr.w		FTEMP_LO+2(%a0)
	add.w		&0x1,FTEMP_EX(%a0)	# and inc exp
xcc_clr:
	tst.l		%d0			# test rs = 0
	bne.b		add_ext_done
	and.b		&0xfe,FTEMP_LO+3(%a0)	# clear the l bit
add_ext_done:
	rts

#########################
#	ADD DOUBLE	#
#########################
add_dbl:
	add.l		&ad_1_dbl, FTEMP_LO(%a0) # add 1 to lsb
	bcc.b		dcc_clr			# no carry
	addq.l		&0x1, FTEMP_HI(%a0)	# propagate carry
	bcc.b		dcc_clr			# no carry

	roxr.w		FTEMP_HI(%a0)		# mant is 0 so restore v-bit
	roxr.w		FTEMP_HI+2(%a0)		# mant is 0 so restore v-bit
	roxr.w		FTEMP_LO(%a0)
	roxr.w		FTEMP_LO+2(%a0)
	addq.w		&0x1, FTEMP_EX(%a0)	# incr exponent
dcc_clr:
	tst.l		%d0			# test for rs = 0
	bne.b		dbl_done
	and.w		&0xf000, FTEMP_LO+2(%a0) # clear the l-bit

dbl_done:
	and.l		&0xfffff800,FTEMP_LO(%a0) # truncate bits beyond dbl limit
	rts

###########################
# Truncate all other bits #
###########################
truncate:
	swap		%d1			# select rnd prec

	cmpi.b		%d1, &s_mode		# is prec sgl?
	beq.w		sgl_done		# yes
	bgt.b		dbl_done		# no; it's dbl
	rts					# no; it's ext


#
# ext_grs(): extract guard, round and sticky bits according to
#	     rounding precision.
#
# INPUT
#	d0	   = extended precision g,r,s (in d0{31:29})
#	d1	   = {PREC,ROUND}
# OUTPUT
#	d0{31:29}  = guard, round, sticky
#
# The ext_grs extract the guard/round/sticky bits according to the
# selected rounding precision. It is called by the round subroutine
# only.  All registers except d0 are kept intact. d0 becomes an
# updated guard,round,sticky in d0{31:29}
#
# Notes: the ext_grs uses the round PREC, and therefore has to swap d1
#	 prior to usage, and needs to restore d1 to original. this
#	 routine is tightly tied to the round routine and not meant to
#	 uphold standard subroutine calling practices.
#

ext_grs:
	swap		%d1			# have d1.w point to round precision
	tst.b		%d1			# is rnd prec = extended?
	bne.b		ext_grs_not_ext		# no; go handle sgl or dbl

#
# %d0 actually already hold g,r,s since _round() had it before calling
# this function. so, as long as we don't disturb it, we are "returning" it.
#
ext_grs_ext:
	swap		%d1			# yes; return to correct positions
	rts

ext_grs_not_ext:
	movm.l		&0x3000, -(%sp)		# make some temp registers {d2/d3}

	cmpi.b		%d1, &s_mode		# is rnd prec = sgl?
	bne.b		ext_grs_dbl		# no; go handle dbl

#
# sgl:
#	96		64	  40	32		0
#	-----------------------------------------------------
#	| EXP	|XXXXXXX|	  |xx	|		|grs|
#	-----------------------------------------------------
#			<--(24)--->nn\			   /
#				   ee ---------------------
#				   ww		|
#						v
#				   gr	   new sticky
#
ext_grs_sgl:
	bfextu		FTEMP_HI(%a0){&24:&2}, %d3 # sgl prec. g-r are 2 bits right
	mov.l		&30, %d2		# of the sgl prec. limits
	lsl.l		%d2, %d3		# shift g-r bits to MSB of d3
	mov.l		FTEMP_HI(%a0), %d2	# get word 2 for s-bit test
	and.l		&0x0000003f, %d2	# s bit is the or of all other
	bne.b		ext_grs_st_stky		# bits to the right of g-r
	tst.l		FTEMP_LO(%a0)		# test lower mantissa
	bne.b		ext_grs_st_stky		# if any are set, set sticky
	tst.l		%d0			# test original g,r,s
	bne.b		ext_grs_st_stky		# if any are set, set sticky
	bra.b		ext_grs_end_sd		# if words 3 and 4 are clr, exit

#
# dbl:
#	96		64		32	 11	0
#	-----------------------------------------------------
#	| EXP	|XXXXXXX|		|	 |xx	|grs|
#	-----------------------------------------------------
#						  nn\	    /
#						  ee -------
#						  ww	|
#							v
#						  gr	new sticky
#
ext_grs_dbl:
	bfextu		FTEMP_LO(%a0){&21:&2}, %d3 # dbl-prec. g-r are 2 bits right
	mov.l		&30, %d2		# of the dbl prec. limits
	lsl.l		%d2, %d3		# shift g-r bits to the MSB of d3
	mov.l		FTEMP_LO(%a0), %d2	# get lower mantissa  for s-bit test
	and.l		&0x000001ff, %d2	# s bit is the or-ing of all
	bne.b		ext_grs_st_stky		# other bits to the right of g-r
	tst.l		%d0			# test word original g,r,s
	bne.b		ext_grs_st_stky		# if any are set, set sticky
	bra.b		ext_grs_end_sd		# if clear, exit

ext_grs_st_stky:
	bset		&rnd_stky_bit, %d3	# set sticky bit
ext_grs_end_sd:
	mov.l		%d3, %d0		# return grs to d0

	movm.l		(%sp)+, &0xc		# restore scratch registers {d2/d3}

	swap		%d1			# restore d1 to original
	rts

#########################################################################
# norm(): normalize the mantissa of an extended precision input. the	#
#	  input operand should not be normalized already.		#
#									#
# XDEF ****************************************************************	#
#	norm()								#
#									#
# XREF **************************************************************** #
#	none								#
#									#
# INPUT *************************************************************** #
#	a0 = pointer fp extended precision operand to normalize		#
#									#
# OUTPUT ************************************************************** #
#	d0 = number of bit positions the mantissa was shifted		#
#	a0 = the input operand's mantissa is normalized; the exponent	#
#	     is unchanged.						#
#									#
#########################################################################
	global		norm
norm:
	mov.l		%d2, -(%sp)		# create some temp regs
	mov.l		%d3, -(%sp)

	mov.l		FTEMP_HI(%a0), %d0	# load hi(mantissa)
	mov.l		FTEMP_LO(%a0), %d1	# load lo(mantissa)

	bfffo		%d0{&0:&32}, %d2	# how many places to shift?
	beq.b		norm_lo			# hi(man) is all zeroes!

norm_hi:
	lsl.l		%d2, %d0		# left shift hi(man)
	bfextu		%d1{&0:%d2}, %d3	# extract lo bits

	or.l		%d3, %d0		# create hi(man)
	lsl.l		%d2, %d1		# create lo(man)

	mov.l		%d0, FTEMP_HI(%a0)	# store new hi(man)
	mov.l		%d1, FTEMP_LO(%a0)	# store new lo(man)

	mov.l		%d2, %d0		# return shift amount

	mov.l		(%sp)+, %d3		# restore temp regs
	mov.l		(%sp)+, %d2

	rts

norm_lo:
	bfffo		%d1{&0:&32}, %d2	# how many places to shift?
	lsl.l		%d2, %d1		# shift lo(man)
	add.l		&32, %d2		# add 32 to shft amount

	mov.l		%d1, FTEMP_HI(%a0)	# store hi(man)
	clr.l		FTEMP_LO(%a0)		# lo(man) is now zero

	mov.l		%d2, %d0		# return shift amount

	mov.l		(%sp)+, %d3		# restore temp regs
	mov.l		(%sp)+, %d2

	rts

#########################################################################
# unnorm_fix(): - changes an UNNORM to one of NORM, DENORM, or ZERO	#
#		- returns corresponding optype tag			#
#									#
# XDEF ****************************************************************	#
#	unnorm_fix()							#
#									#
# XREF **************************************************************** #
#	norm() - normalize the mantissa					#
#									#
# INPUT *************************************************************** #
#	a0 = pointer to unnormalized extended precision number		#
#									#
# OUTPUT ************************************************************** #
#	d0 = optype tag - is corrected to one of NORM, DENORM, or ZERO	#
#	a0 = input operand has been converted to a norm, denorm, or	#
#	     zero; both the exponent and mantissa are changed.		#
#									#
#########################################################################

	global		unnorm_fix
unnorm_fix:
	bfffo		FTEMP_HI(%a0){&0:&32}, %d0 # how many shifts are needed?
	bne.b		unnorm_shift		# hi(man) is not all zeroes

#
# hi(man) is all zeroes so see if any bits in lo(man) are set
#
unnorm_chk_lo:
	bfffo		FTEMP_LO(%a0){&0:&32}, %d0 # is operand really a zero?
	beq.w		unnorm_zero		# yes

	add.w		&32, %d0		# no; fix shift distance

#
# d0 = # shifts needed for complete normalization
#
unnorm_shift:
	clr.l		%d1			# clear top word
	mov.w		FTEMP_EX(%a0), %d1	# extract exponent
	and.w		&0x7fff, %d1		# strip off sgn

	cmp.w		%d0, %d1		# will denorm push exp < 0?
	bgt.b		unnorm_nrm_zero		# yes; denorm only until exp = 0

#
# exponent would not go < 0. Therefore, number stays normalized
#
	sub.w		%d0, %d1		# shift exponent value
	mov.w		FTEMP_EX(%a0), %d0	# load old exponent
	and.w		&0x8000, %d0		# save old sign
	or.w		%d0, %d1		# {sgn,new exp}
	mov.w		%d1, FTEMP_EX(%a0)	# insert new exponent

	bsr.l		norm			# normalize UNNORM

	mov.b		&NORM, %d0		# return new optype tag
	rts

#
# exponent would go < 0, so only denormalize until exp = 0
#
unnorm_nrm_zero:
	cmp.b		%d1, &32		# is exp <= 32?
	bgt.b		unnorm_nrm_zero_lrg	# no; go handle large exponent

	bfextu		FTEMP_HI(%a0){%d1:&32}, %d0 # extract new hi(man)
	mov.l		%d0, FTEMP_HI(%a0)	# save new hi(man)

	mov.l		FTEMP_LO(%a0), %d0	# fetch old lo(man)
	lsl.l		%d1, %d0		# extract new lo(man)
	mov.l		%d0, FTEMP_LO(%a0)	# save new lo(man)

	and.w		&0x8000, FTEMP_EX(%a0)	# set exp = 0

	mov.b		&DENORM, %d0		# return new optype tag
	rts

#
# only mantissa bits set are in lo(man)
#
unnorm_nrm_zero_lrg:
	sub.w		&32, %d1		# adjust shft amt by 32

	mov.l		FTEMP_LO(%a0), %d0	# fetch old lo(man)
	lsl.l		%d1, %d0		# left shift lo(man)

	mov.l		%d0, FTEMP_HI(%a0)	# store new hi(man)
	clr.l		FTEMP_LO(%a0)		# lo(man) = 0

	and.w		&0x8000, FTEMP_EX(%a0)	# set exp = 0

	mov.b		&DENORM, %d0		# return new optype tag
	rts

#
# whole mantissa is zero so this UNNORM is actually a zero
#
unnorm_zero:
	and.w		&0x8000, FTEMP_EX(%a0)	# force exponent to zero

	mov.b		&ZERO, %d0		# fix optype tag
	rts

#########################################################################
# XDEF ****************************************************************	#
#	set_tag_x(): return the optype of the input ext fp number	#
#									#
# XREF ****************************************************************	#
#	None								#
#									#
# INPUT ***************************************************************	#
#	a0 = pointer to extended precision operand			#
#									#
# OUTPUT **************************************************************	#
#	d0 = value of type tag						#
#		one of: NORM, INF, QNAN, SNAN, DENORM, UNNORM, ZERO	#
#									#
# ALGORITHM ***********************************************************	#
#	Simply test the exponent, j-bit, and mantissa values to		#
# determine the type of operand.					#
#	If it's an unnormalized zero, alter the operand and force it	#
# to be a normal zero.							#
#									#
#########################################################################

	global		set_tag_x
set_tag_x:
	mov.w		FTEMP_EX(%a0), %d0	# extract exponent
	andi.w		&0x7fff, %d0		# strip off sign
	cmpi.w		%d0, &0x7fff		# is (EXP == MAX)?
	beq.b		inf_or_nan_x
not_inf_or_nan_x:
	btst		&0x7,FTEMP_HI(%a0)
	beq.b		not_norm_x
is_norm_x:
	mov.b		&NORM, %d0
	rts
not_norm_x:
	tst.w		%d0			# is exponent = 0?
	bne.b		is_unnorm_x
not_unnorm_x:
	tst.l		FTEMP_HI(%a0)
	bne.b		is_denorm_x
	tst.l		FTEMP_LO(%a0)
	bne.b		is_denorm_x
is_zero_x:
	mov.b		&ZERO, %d0
	rts
is_denorm_x:
	mov.b		&DENORM, %d0
	rts
# must distinguish now "Unnormalized zeroes" which we
# must convert to zero.
is_unnorm_x:
	tst.l		FTEMP_HI(%a0)
	bne.b		is_unnorm_reg_x
	tst.l		FTEMP_LO(%a0)
	bne.b		is_unnorm_reg_x
# it's an "unnormalized zero". let's convert it to an actual zero...
	andi.w		&0x8000,FTEMP_EX(%a0)	# clear exponent
	mov.b		&ZERO, %d0
	rts
is_unnorm_reg_x:
	mov.b		&UNNORM, %d0
	rts
inf_or_nan_x:
	tst.l		FTEMP_LO(%a0)
	bne.b		is_nan_x
	mov.l		FTEMP_HI(%a0), %d0
	and.l		&0x7fffffff, %d0	# msb is a don't care!
	bne.b		is_nan_x
is_inf_x:
	mov.b		&INF, %d0
	rts
is_nan_x:
	btst		&0x6, FTEMP_HI(%a0)
	beq.b		is_snan_x
	mov.b		&QNAN, %d0
	rts
is_snan_x:
	mov.b		&SNAN, %d0
	rts

#########################################################################
# XDEF ****************************************************************	#
#	set_tag_d(): return the optype of the input dbl fp number	#
#									#
# XREF ****************************************************************	#
#	None								#
#									#
# INPUT ***************************************************************	#
#	a0 = points to double precision operand				#
#									#
# OUTPUT **************************************************************	#
#	d0 = value of type tag						#
#		one of: NORM, INF, QNAN, SNAN, DENORM, ZERO		#
#									#
# ALGORITHM ***********************************************************	#
#	Simply test the exponent, j-bit, and mantissa values to		#
# determine the type of operand.					#
#									#
#########################################################################

	global		set_tag_d
set_tag_d:
	mov.l		FTEMP(%a0), %d0
	mov.l		%d0, %d1

	andi.l		&0x7ff00000, %d0
	beq.b		zero_or_denorm_d

	cmpi.l		%d0, &0x7ff00000
	beq.b		inf_or_nan_d

is_norm_d:
	mov.b		&NORM, %d0
	rts
zero_or_denorm_d:
	and.l		&0x000fffff, %d1
	bne		is_denorm_d
	tst.l		4+FTEMP(%a0)
	bne		is_denorm_d
is_zero_d:
	mov.b		&ZERO, %d0
	rts
is_denorm_d:
	mov.b		&DENORM, %d0
	rts
inf_or_nan_d:
	and.l		&0x000fffff, %d1
	bne		is_nan_d
	tst.l		4+FTEMP(%a0)
	bne		is_nan_d
is_inf_d:
	mov.b		&INF, %d0
	rts
is_nan_d:
	btst		&19, %d1
	bne		is_qnan_d
is_snan_d:
	mov.b		&SNAN, %d0
	rts
is_qnan_d:
	mov.b		&QNAN, %d0
	rts

#########################################################################
# XDEF ****************************************************************	#
#	set_tag_s(): return the optype of the input sgl fp number	#
#									#
# XREF ****************************************************************	#
#	None								#
#									#
# INPUT ***************************************************************	#
#	a0 = pointer to single precision operand			#
#									#
# OUTPUT **************************************************************	#
#	d0 = value of type tag						#
#		one of: NORM, INF, QNAN, SNAN, DENORM, ZERO		#
#									#
# ALGORITHM ***********************************************************	#
#	Simply test the exponent, j-bit, and mantissa values to		#
# determine the type of operand.					#
#									#
#########################################################################

	global		set_tag_s
set_tag_s:
	mov.l		FTEMP(%a0), %d0
	mov.l		%d0, %d1

	andi.l		&0x7f800000, %d0
	beq.b		zero_or_denorm_s

	cmpi.l		%d0, &0x7f800000
	beq.b		inf_or_nan_s

is_norm_s:
	mov.b		&NORM, %d0
	rts
zero_or_denorm_s:
	and.l		&0x007fffff, %d1
	bne		is_denorm_s
is_zero_s:
	mov.b		&ZERO, %d0
	rts
is_denorm_s:
	mov.b		&DENORM, %d0
	rts
inf_or_nan_s:
	and.l		&0x007fffff, %d1
	bne		is_nan_s
is_inf_s:
	mov.b		&INF, %d0
	rts
is_nan_s:
	btst		&22, %d1
	bne		is_qnan_s
is_snan_s:
	mov.b		&SNAN, %d0
	rts
is_qnan_s:
	mov.b		&QNAN, %d0
	rts

#########################################################################
# XDEF ****************************************************************	#
#	unf_res(): routine to produce default underflow result of a	#
#		   scaled extended precision number; this is used by	#
#		   fadd/fdiv/fmul/etc. emulation routines.		#
#	unf_res4(): same as above but for fsglmul/fsgldiv which use	#
#		    single round prec and extended prec mode.		#
#									#
# XREF ****************************************************************	#
#	_denorm() - denormalize according to scale factor		#
#	_round() - round denormalized number according to rnd prec	#
#									#
# INPUT ***************************************************************	#
#	a0 = pointer to extended precison operand			#
#	d0 = scale factor						#
#	d1 = rounding precision/mode					#
#									#
# OUTPUT **************************************************************	#
#	a0 = pointer to default underflow result in extended precision	#
#	d0.b = result FPSR_cc which caller may or may not want to save	#
#									#
# ALGORITHM ***********************************************************	#
#	Convert the input operand to "internal format" which means the	#
# exponent is extended to 16 bits and the sign is stored in the unused	#
# portion of the extended precison operand. Denormalize the number	#
# according to the scale factor passed in d0. Then, round the		#
# denormalized result.							#
#	Set the FPSR_exc bits as appropriate but return the cc bits in	#
# d0 in case the caller doesn't want to save them (as is the case for	#
# fmove out).								#
#	unf_res4() for fsglmul/fsgldiv forces the denorm to extended	#
# precision and the rounding mode to single.				#
#									#
#########################################################################
	global		unf_res
unf_res:
	mov.l		%d1, -(%sp)		# save rnd prec,mode on stack

	btst		&0x7, FTEMP_EX(%a0)	# make "internal" format
	sne		FTEMP_SGN(%a0)

	mov.w		FTEMP_EX(%a0), %d1	# extract exponent
	and.w		&0x7fff, %d1
	sub.w		%d0, %d1
	mov.w		%d1, FTEMP_EX(%a0)	# insert 16 bit exponent

	mov.l		%a0, -(%sp)		# save operand ptr during calls

	mov.l		0x4(%sp),%d0		# pass rnd prec.
	andi.w		&0x00c0,%d0
	lsr.w		&0x4,%d0
	bsr.l		_denorm			# denorm result

	mov.l		(%sp),%a0
	mov.w		0x6(%sp),%d1		# load prec:mode into %d1
	andi.w		&0xc0,%d1		# extract rnd prec
	lsr.w		&0x4,%d1
	swap		%d1
	mov.w		0x6(%sp),%d1
	andi.w		&0x30,%d1
	lsr.w		&0x4,%d1
	bsr.l		_round			# round the denorm

	mov.l		(%sp)+, %a0

# result is now rounded properly. convert back to normal format
	bclr		&0x7, FTEMP_EX(%a0)	# clear sgn first; may have residue
	tst.b		FTEMP_SGN(%a0)		# is "internal result" sign set?
	beq.b		unf_res_chkifzero	# no; result is positive
	bset		&0x7, FTEMP_EX(%a0)	# set result sgn
	clr.b		FTEMP_SGN(%a0)		# clear temp sign

# the number may have become zero after rounding. set ccodes accordingly.
unf_res_chkifzero:
	clr.l		%d0
	tst.l		FTEMP_HI(%a0)		# is value now a zero?
	bne.b		unf_res_cont		# no
	tst.l		FTEMP_LO(%a0)
	bne.b		unf_res_cont		# no
#	bset		&z_bit, FPSR_CC(%a6)	# yes; set zero ccode bit
	bset		&z_bit, %d0		# yes; set zero ccode bit

unf_res_cont:

#
# can inex1 also be set along with unfl and inex2???
#
# we know that underflow has occurred. aunfl should be set if INEX2 is also set.
#
	btst		&inex2_bit, FPSR_EXCEPT(%a6) # is INEX2 set?
	beq.b		unf_res_end		# no
	bset		&aunfl_bit, FPSR_AEXCEPT(%a6) # yes; set aunfl

unf_res_end:
	add.l		&0x4, %sp		# clear stack
	rts

# unf_res() for fsglmul() and fsgldiv().
	global		unf_res4
unf_res4:
	mov.l		%d1,-(%sp)		# save rnd prec,mode on stack

	btst		&0x7,FTEMP_EX(%a0)	# make "internal" format
	sne		FTEMP_SGN(%a0)

	mov.w		FTEMP_EX(%a0),%d1	# extract exponent
	and.w		&0x7fff,%d1
	sub.w		%d0,%d1
	mov.w		%d1,FTEMP_EX(%a0)	# insert 16 bit exponent

	mov.l		%a0,-(%sp)		# save operand ptr during calls

	clr.l		%d0			# force rnd prec = ext
	bsr.l		_denorm			# denorm result

	mov.l		(%sp),%a0
	mov.w		&s_mode,%d1		# force rnd prec = sgl
	swap		%d1
	mov.w		0x6(%sp),%d1		# load rnd mode
	andi.w		&0x30,%d1		# extract rnd prec
	lsr.w		&0x4,%d1
	bsr.l		_round			# round the denorm

	mov.l		(%sp)+,%a0

# result is now rounded properly. convert back to normal format
	bclr		&0x7,FTEMP_EX(%a0)	# clear sgn first; may have residue
	tst.b		FTEMP_SGN(%a0)		# is "internal result" sign set?
	beq.b		unf_res4_chkifzero	# no; result is positive
	bset		&0x7,FTEMP_EX(%a0)	# set result sgn
	clr.b		FTEMP_SGN(%a0)		# clear temp sign

# the number may have become zero after rounding. set ccodes accordingly.
unf_res4_chkifzero:
	clr.l		%d0
	tst.l		FTEMP_HI(%a0)		# is value now a zero?
	bne.b		unf_res4_cont		# no
	tst.l		FTEMP_LO(%a0)
	bne.b		unf_res4_cont		# no
#	bset		&z_bit,FPSR_CC(%a6)	# yes; set zero ccode bit
	bset		&z_bit,%d0		# yes; set zero ccode bit

unf_res4_cont:

#
# can inex1 also be set along with unfl and inex2???
#
# we know that underflow has occurred. aunfl should be set if INEX2 is also set.
#
	btst		&inex2_bit,FPSR_EXCEPT(%a6) # is INEX2 set?
	beq.b		unf_res4_end		# no
	bset		&aunfl_bit,FPSR_AEXCEPT(%a6) # yes; set aunfl

unf_res4_end:
	add.l		&0x4,%sp		# clear stack
	rts

#########################################################################
# XDEF ****************************************************************	#
#	ovf_res(): routine to produce the default overflow result of	#
#		   an overflowing number.				#
#	ovf_res2(): same as above but the rnd mode/prec are passed	#
#		    differently.					#
#									#
# XREF ****************************************************************	#
#	none								#
#									#
# INPUT ***************************************************************	#
#	d1.b	= '-1' => (-); '0' => (+)				#
#   ovf_res():								#
#	d0	= rnd mode/prec						#
#   ovf_res2():								#
#	hi(d0)	= rnd prec						#
#	lo(d0)	= rnd mode						#
#									#
# OUTPUT **************************************************************	#
#	a0	= points to extended precision result			#
#	d0.b	= condition code bits					#
#									#
# ALGORITHM ***********************************************************	#
#	The default overflow result can be determined by the sign of	#
# the result and the rounding mode/prec in effect. These bits are	#
# concatenated together to create an index into the default result	#
# table. A pointer to the correct result is returned in a0. The		#
# resulting condition codes are returned in d0 in case the caller	#
# doesn't want FPSR_cc altered (as is the case for fmove out).		#
#									#
#########################################################################

	global		ovf_res
ovf_res:
	andi.w		&0x10,%d1		# keep result sign
	lsr.b		&0x4,%d0		# shift prec/mode
	or.b		%d0,%d1			# concat the two
	mov.w		%d1,%d0			# make a copy
	lsl.b		&0x1,%d1		# multiply d1 by 2
	bra.b		ovf_res_load

	global		ovf_res2
ovf_res2:
	and.w		&0x10, %d1		# keep result sign
	or.b		%d0, %d1		# insert rnd mode
	swap		%d0
	or.b		%d0, %d1		# insert rnd prec
	mov.w		%d1, %d0		# make a copy
	lsl.b		&0x1, %d1		# shift left by 1

#
# use the rounding mode, precision, and result sign as in index into the
# two tables below to fetch the default result and the result ccodes.
#
ovf_res_load:
	mov.b		(tbl_ovfl_cc.b,%pc,%d0.w*1), %d0 # fetch result ccodes
	lea		(tbl_ovfl_result.b,%pc,%d1.w*8), %a0 # return result ptr

	rts

tbl_ovfl_cc:
	byte		0x2, 0x0, 0x0, 0x2
	byte		0x2, 0x0, 0x0, 0x2
	byte		0x2, 0x0, 0x0, 0x2
	byte		0x0, 0x0, 0x0, 0x0
	byte		0x2+0x8, 0x8, 0x2+0x8, 0x8
	byte		0x2+0x8, 0x8, 0x2+0x8, 0x8
	byte		0x2+0x8, 0x8, 0x2+0x8, 0x8

tbl_ovfl_result:
	long		0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RN
	long		0x7ffe0000,0xffffffff,0xffffffff,0x00000000 # +EXT; RZ
	long		0x7ffe0000,0xffffffff,0xffffffff,0x00000000 # +EXT; RM
	long		0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RP

	long		0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RN
	long		0x407e0000,0xffffff00,0x00000000,0x00000000 # +SGL; RZ
	long		0x407e0000,0xffffff00,0x00000000,0x00000000 # +SGL; RM
	long		0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RP

	long		0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RN
	long		0x43fe0000,0xffffffff,0xfffff800,0x00000000 # +DBL; RZ
	long		0x43fe0000,0xffffffff,0xfffff800,0x00000000 # +DBL; RM
	long		0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RP

	long		0x00000000,0x00000000,0x00000000,0x00000000
	long		0x00000000,0x00000000,0x00000000,0x00000000
	long		0x00000000,0x00000000,0x00000000,0x00000000
	long		0x00000000,0x00000000,0x00000000,0x00000000

	long		0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RN
	long		0xfffe0000,0xffffffff,0xffffffff,0x00000000 # -EXT; RZ
	long		0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RM
	long		0xfffe0000,0xffffffff,0xffffffff,0x00000000 # -EXT; RP

	long		0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RN
	long		0xc07e0000,0xffffff00,0x00000000,0x00000000 # -SGL; RZ
	long		0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RM
	long		0xc07e0000,0xffffff00,0x00000000,0x00000000 # -SGL; RP

	long		0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RN
	long		0xc3fe0000,0xffffffff,0xfffff800,0x00000000 # -DBL; RZ
	long		0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RM
	long		0xc3fe0000,0xffffffff,0xfffff800,0x00000000 # -DBL; RP

#########################################################################
# XDEF ****************************************************************	#
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -



ifpsp060/src/pfpsp.S [5793:7050]:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#########################################################################
# XDEF ****************************************************************	#
#	_denorm(): denormalize an intermediate result			#
#									#
# XREF ****************************************************************	#
#	None								#
#									#
# INPUT *************************************************************** #
#	a0 = points to the operand to be denormalized			#
#		(in the internal extended format)			#
#									#
#	d0 = rounding precision						#
#									#
# OUTPUT **************************************************************	#
#	a0 = pointer to the denormalized result				#
#		(in the internal extended format)			#
#									#
#	d0 = guard,round,sticky						#
#									#
# ALGORITHM ***********************************************************	#
#	According to the exponent underflow threshold for the given	#
# precision, shift the mantissa bits to the right in order raise the	#
# exponent of the operand to the threshold value. While shifting the	#
# mantissa bits right, maintain the value of the guard, round, and	#
# sticky bits.								#
# other notes:								#
#	(1) _denorm() is called by the underflow routines		#
#	(2) _denorm() does NOT affect the status register		#
#									#
#########################################################################

#
# table of exponent threshold values for each precision
#
tbl_thresh:
	short		0x0
	short		sgl_thresh
	short		dbl_thresh

	global		_denorm
_denorm:
#
# Load the exponent threshold for the precision selected and check
# to see if (threshold - exponent) is > 65 in which case we can
# simply calculate the sticky bit and zero the mantissa. otherwise
# we have to call the denormalization routine.
#
	lsr.b		&0x2, %d0		# shift prec to lo bits
	mov.w		(tbl_thresh.b,%pc,%d0.w*2), %d1 # load prec threshold
	mov.w		%d1, %d0		# copy d1 into d0
	sub.w		FTEMP_EX(%a0), %d0	# diff = threshold - exp
	cmpi.w		%d0, &66		# is diff > 65? (mant + g,r bits)
	bpl.b		denorm_set_stky		# yes; just calc sticky

	clr.l		%d0			# clear g,r,s
	btst		&inex2_bit, FPSR_EXCEPT(%a6) # yes; was INEX2 set?
	beq.b		denorm_call		# no; don't change anything
	bset		&29, %d0		# yes; set sticky bit

denorm_call:
	bsr.l		dnrm_lp			# denormalize the number
	rts

#
# all bit would have been shifted off during the denorm so simply
# calculate if the sticky should be set and clear the entire mantissa.
#
denorm_set_stky:
	mov.l		&0x20000000, %d0	# set sticky bit in return value
	mov.w		%d1, FTEMP_EX(%a0)	# load exp with threshold
	clr.l		FTEMP_HI(%a0)		# set d1 = 0 (ms mantissa)
	clr.l		FTEMP_LO(%a0)		# set d2 = 0 (ms mantissa)
	rts

#									#
# dnrm_lp(): normalize exponent/mantissa to specified threshold		#
#									#
# INPUT:								#
#	%a0	   : points to the operand to be denormalized		#
#	%d0{31:29} : initial guard,round,sticky				#
#	%d1{15:0}  : denormalization threshold				#
# OUTPUT:								#
#	%a0	   : points to the denormalized operand			#
#	%d0{31:29} : final guard,round,sticky				#
#									#

# *** Local Equates *** #
set	GRS,		L_SCR2			# g,r,s temp storage
set	FTEMP_LO2,	L_SCR1			# FTEMP_LO copy

	global		dnrm_lp
dnrm_lp:

#
# make a copy of FTEMP_LO and place the g,r,s bits directly after it
# in memory so as to make the bitfield extraction for denormalization easier.
#
	mov.l		FTEMP_LO(%a0), FTEMP_LO2(%a6) # make FTEMP_LO copy
	mov.l		%d0, GRS(%a6)		# place g,r,s after it

#
# check to see how much less than the underflow threshold the operand
# exponent is.
#
	mov.l		%d1, %d0		# copy the denorm threshold
	sub.w		FTEMP_EX(%a0), %d1	# d1 = threshold - uns exponent
	ble.b		dnrm_no_lp		# d1 <= 0
	cmpi.w		%d1, &0x20		# is ( 0 <= d1 < 32) ?
	blt.b		case_1			# yes
	cmpi.w		%d1, &0x40		# is (32 <= d1 < 64) ?
	blt.b		case_2			# yes
	bra.w		case_3			# (d1 >= 64)

#
# No normalization necessary
#
dnrm_no_lp:
	mov.l		GRS(%a6), %d0		# restore original g,r,s
	rts

#
# case (0<d1<32)
#
# %d0 = denorm threshold
# %d1 = "n" = amt to shift
#
#	---------------------------------------------------------
#	|     FTEMP_HI	  |	FTEMP_LO     |grs000.........000|
#	---------------------------------------------------------
#	<-(32 - n)-><-(n)-><-(32 - n)-><-(n)-><-(32 - n)-><-(n)->
#	\	   \		      \			 \
#	 \	    \		       \		  \
#	  \	     \			\		   \
#	   \	      \			 \		    \
#	    \	       \		  \		     \
#	     \		\		   \		      \
#	      \		 \		    \		       \
#	       \	  \		     \			\
#	<-(n)-><-(32 - n)-><------(32)-------><------(32)------->
#	---------------------------------------------------------
#	|0.....0| NEW_HI  |  NEW_FTEMP_LO     |grs		|
#	---------------------------------------------------------
#
case_1:
	mov.l		%d2, -(%sp)		# create temp storage

	mov.w		%d0, FTEMP_EX(%a0)	# exponent = denorm threshold
	mov.l		&32, %d0
	sub.w		%d1, %d0		# %d0 = 32 - %d1

	cmpi.w		%d1, &29		# is shft amt >= 29
	blt.b		case1_extract		# no; no fix needed
	mov.b		GRS(%a6), %d2
	or.b		%d2, 3+FTEMP_LO2(%a6)

case1_extract:
	bfextu		FTEMP_HI(%a0){&0:%d0}, %d2 # %d2 = new FTEMP_HI
	bfextu		FTEMP_HI(%a0){%d0:&32}, %d1 # %d1 = new FTEMP_LO
	bfextu		FTEMP_LO2(%a6){%d0:&32}, %d0 # %d0 = new G,R,S

	mov.l		%d2, FTEMP_HI(%a0)	# store new FTEMP_HI
	mov.l		%d1, FTEMP_LO(%a0)	# store new FTEMP_LO

	bftst		%d0{&2:&30}		# were bits shifted off?
	beq.b		case1_sticky_clear	# no; go finish
	bset		&rnd_stky_bit, %d0	# yes; set sticky bit

case1_sticky_clear:
	and.l		&0xe0000000, %d0	# clear all but G,R,S
	mov.l		(%sp)+, %d2		# restore temp register
	rts

#
# case (32<=d1<64)
#
# %d0 = denorm threshold
# %d1 = "n" = amt to shift
#
#	---------------------------------------------------------
#	|     FTEMP_HI	  |	FTEMP_LO     |grs000.........000|
#	---------------------------------------------------------
#	<-(32 - n)-><-(n)-><-(32 - n)-><-(n)-><-(32 - n)-><-(n)->
#	\	   \		      \
#	 \	    \		       \
#	  \	     \			-------------------
#	   \	      --------------------		   \
#	    -------------------		  \		    \
#			       \	   \		     \
#				\	    \		      \
#				 \	     \		       \
#	<-------(32)------><-(n)-><-(32 - n)-><------(32)------->
#	---------------------------------------------------------
#	|0...............0|0....0| NEW_LO     |grs		|
#	---------------------------------------------------------
#
case_2:
	mov.l		%d2, -(%sp)		# create temp storage

	mov.w		%d0, FTEMP_EX(%a0)	# exponent = denorm threshold
	subi.w		&0x20, %d1		# %d1 now between 0 and 32
	mov.l		&0x20, %d0
	sub.w		%d1, %d0		# %d0 = 32 - %d1

# subtle step here; or in the g,r,s at the bottom of FTEMP_LO to minimize
# the number of bits to check for the sticky detect.
# it only plays a role in shift amounts of 61-63.
	mov.b		GRS(%a6), %d2
	or.b		%d2, 3+FTEMP_LO2(%a6)

	bfextu		FTEMP_HI(%a0){&0:%d0}, %d2 # %d2 = new FTEMP_LO
	bfextu		FTEMP_HI(%a0){%d0:&32}, %d1 # %d1 = new G,R,S

	bftst		%d1{&2:&30}		# were any bits shifted off?
	bne.b		case2_set_sticky	# yes; set sticky bit
	bftst		FTEMP_LO2(%a6){%d0:&31}	# were any bits shifted off?
	bne.b		case2_set_sticky	# yes; set sticky bit

	mov.l		%d1, %d0		# move new G,R,S to %d0
	bra.b		case2_end

case2_set_sticky:
	mov.l		%d1, %d0		# move new G,R,S to %d0
	bset		&rnd_stky_bit, %d0	# set sticky bit

case2_end:
	clr.l		FTEMP_HI(%a0)		# store FTEMP_HI = 0
	mov.l		%d2, FTEMP_LO(%a0)	# store FTEMP_LO
	and.l		&0xe0000000, %d0	# clear all but G,R,S

	mov.l		(%sp)+,%d2		# restore temp register
	rts

#
# case (d1>=64)
#
# %d0 = denorm threshold
# %d1 = amt to shift
#
case_3:
	mov.w		%d0, FTEMP_EX(%a0)	# insert denorm threshold

	cmpi.w		%d1, &65		# is shift amt > 65?
	blt.b		case3_64		# no; it's == 64
	beq.b		case3_65		# no; it's == 65

#
# case (d1>65)
#
# Shift value is > 65 and out of range. All bits are shifted off.
# Return a zero mantissa with the sticky bit set
#
	clr.l		FTEMP_HI(%a0)		# clear hi(mantissa)
	clr.l		FTEMP_LO(%a0)		# clear lo(mantissa)
	mov.l		&0x20000000, %d0	# set sticky bit
	rts

#
# case (d1 == 64)
#
#	---------------------------------------------------------
#	|     FTEMP_HI	  |	FTEMP_LO     |grs000.........000|
#	---------------------------------------------------------
#	<-------(32)------>
#	\		   \
#	 \		    \
#	  \		     \
#	   \		      ------------------------------
#	    -------------------------------		    \
#					   \		     \
#					    \		      \
#					     \		       \
#					      <-------(32)------>
#	---------------------------------------------------------
#	|0...............0|0................0|grs		|
#	---------------------------------------------------------
#
case3_64:
	mov.l		FTEMP_HI(%a0), %d0	# fetch hi(mantissa)
	mov.l		%d0, %d1		# make a copy
	and.l		&0xc0000000, %d0	# extract G,R
	and.l		&0x3fffffff, %d1	# extract other bits

	bra.b		case3_complete

#
# case (d1 == 65)
#
#	---------------------------------------------------------
#	|     FTEMP_HI	  |	FTEMP_LO     |grs000.........000|
#	---------------------------------------------------------
#	<-------(32)------>
#	\		   \
#	 \		    \
#	  \		     \
#	   \		      ------------------------------
#	    --------------------------------		    \
#					    \		     \
#					     \		      \
#					      \		       \
#					       <-------(31)----->
#	---------------------------------------------------------
#	|0...............0|0................0|0rs		|
#	---------------------------------------------------------
#
case3_65:
	mov.l		FTEMP_HI(%a0), %d0	# fetch hi(mantissa)
	and.l		&0x80000000, %d0	# extract R bit
	lsr.l		&0x1, %d0		# shift high bit into R bit
	and.l		&0x7fffffff, %d1	# extract other bits

case3_complete:
# last operation done was an "and" of the bits shifted off so the condition
# codes are already set so branch accordingly.
	bne.b		case3_set_sticky	# yes; go set new sticky
	tst.l		FTEMP_LO(%a0)		# were any bits shifted off?
	bne.b		case3_set_sticky	# yes; go set new sticky
	tst.b		GRS(%a6)		# were any bits shifted off?
	bne.b		case3_set_sticky	# yes; go set new sticky

#
# no bits were shifted off so don't set the sticky bit.
# the guard and
# the entire mantissa is zero.
#
	clr.l		FTEMP_HI(%a0)		# clear hi(mantissa)
	clr.l		FTEMP_LO(%a0)		# clear lo(mantissa)
	rts

#
# some bits were shifted off so set the sticky bit.
# the entire mantissa is zero.
#
case3_set_sticky:
	bset		&rnd_stky_bit,%d0	# set new sticky bit
	clr.l		FTEMP_HI(%a0)		# clear hi(mantissa)
	clr.l		FTEMP_LO(%a0)		# clear lo(mantissa)
	rts

#########################################################################
# XDEF ****************************************************************	#
#	_round(): round result according to precision/mode		#
#									#
# XREF ****************************************************************	#
#	None								#
#									#
# INPUT ***************************************************************	#
#	a0	  = ptr to input operand in internal extended format	#
#	d1(hi)    = contains rounding precision:			#
#			ext = $0000xxxx					#
#			sgl = $0004xxxx					#
#			dbl = $0008xxxx					#
#	d1(lo)	  = contains rounding mode:				#
#			RN  = $xxxx0000					#
#			RZ  = $xxxx0001					#
#			RM  = $xxxx0002					#
#			RP  = $xxxx0003					#
#	d0{31:29} = contains the g,r,s bits (extended)			#
#									#
# OUTPUT **************************************************************	#
#	a0 = pointer to rounded result					#
#									#
# ALGORITHM ***********************************************************	#
#	On return the value pointed to by a0 is correctly rounded,	#
#	a0 is preserved and the g-r-s bits in d0 are cleared.		#
#	The result is not typed - the tag field is invalid.  The	#
#	result is still in the internal extended format.		#
#									#
#	The INEX bit of USER_FPSR will be set if the rounded result was	#
#	inexact (i.e. if any of the g-r-s bits were set).		#
#									#
#########################################################################

	global		_round
_round:
#
# ext_grs() looks at the rounding precision and sets the appropriate
# G,R,S bits.
# If (G,R,S == 0) then result is exact and round is done, else set
# the inex flag in status reg and continue.
#
	bsr.l		ext_grs			# extract G,R,S

	tst.l		%d0			# are G,R,S zero?
	beq.w		truncate		# yes; round is complete

	or.w		&inx2a_mask, 2+USER_FPSR(%a6) # set inex2/ainex

#
# Use rounding mode as an index into a jump table for these modes.
# All of the following assumes grs != 0.
#
	mov.w		(tbl_mode.b,%pc,%d1.w*2), %a1 # load jump offset
	jmp		(tbl_mode.b,%pc,%a1)	# jmp to rnd mode handler

tbl_mode:
	short		rnd_near - tbl_mode
	short		truncate - tbl_mode	# RZ always truncates
	short		rnd_mnus - tbl_mode
	short		rnd_plus - tbl_mode

#################################################################
#	ROUND PLUS INFINITY					#
#								#
#	If sign of fp number = 0 (positive), then add 1 to l.	#
#################################################################
rnd_plus:
	tst.b		FTEMP_SGN(%a0)		# check for sign
	bmi.w		truncate		# if positive then truncate

	mov.l		&0xffffffff, %d0	# force g,r,s to be all f's
	swap		%d1			# set up d1 for round prec.

	cmpi.b		%d1, &s_mode		# is prec = sgl?
	beq.w		add_sgl			# yes
	bgt.w		add_dbl			# no; it's dbl
	bra.w		add_ext			# no; it's ext

#################################################################
#	ROUND MINUS INFINITY					#
#								#
#	If sign of fp number = 1 (negative), then add 1 to l.	#
#################################################################
rnd_mnus:
	tst.b		FTEMP_SGN(%a0)		# check for sign
	bpl.w		truncate		# if negative then truncate

	mov.l		&0xffffffff, %d0	# force g,r,s to be all f's
	swap		%d1			# set up d1 for round prec.

	cmpi.b		%d1, &s_mode		# is prec = sgl?
	beq.w		add_sgl			# yes
	bgt.w		add_dbl			# no; it's dbl
	bra.w		add_ext			# no; it's ext

#################################################################
#	ROUND NEAREST						#
#								#
#	If (g=1), then add 1 to l and if (r=s=0), then clear l	#
#	Note that this will round to even in case of a tie.	#
#################################################################
rnd_near:
	asl.l		&0x1, %d0		# shift g-bit to c-bit
	bcc.w		truncate		# if (g=1) then

	swap		%d1			# set up d1 for round prec.

	cmpi.b		%d1, &s_mode		# is prec = sgl?
	beq.w		add_sgl			# yes
	bgt.w		add_dbl			# no; it's dbl
	bra.w		add_ext			# no; it's ext

# *** LOCAL EQUATES ***
set	ad_1_sgl,	0x00000100	# constant to add 1 to l-bit in sgl prec
set	ad_1_dbl,	0x00000800	# constant to add 1 to l-bit in dbl prec

#########################
#	ADD SINGLE	#
#########################
add_sgl:
	add.l		&ad_1_sgl, FTEMP_HI(%a0)
	bcc.b		scc_clr			# no mantissa overflow
	roxr.w		FTEMP_HI(%a0)		# shift v-bit back in
	roxr.w		FTEMP_HI+2(%a0)		# shift v-bit back in
	add.w		&0x1, FTEMP_EX(%a0)	# and incr exponent
scc_clr:
	tst.l		%d0			# test for rs = 0
	bne.b		sgl_done
	and.w		&0xfe00, FTEMP_HI+2(%a0) # clear the l-bit
sgl_done:
	and.l		&0xffffff00, FTEMP_HI(%a0) # truncate bits beyond sgl limit
	clr.l		FTEMP_LO(%a0)		# clear d2
	rts

#########################
#	ADD EXTENDED	#
#########################
add_ext:
	addq.l		&1,FTEMP_LO(%a0)	# add 1 to l-bit
	bcc.b		xcc_clr			# test for carry out
	addq.l		&1,FTEMP_HI(%a0)	# propagate carry
	bcc.b		xcc_clr
	roxr.w		FTEMP_HI(%a0)		# mant is 0 so restore v-bit
	roxr.w		FTEMP_HI+2(%a0)		# mant is 0 so restore v-bit
	roxr.w		FTEMP_LO(%a0)
	roxr.w		FTEMP_LO+2(%a0)
	add.w		&0x1,FTEMP_EX(%a0)	# and inc exp
xcc_clr:
	tst.l		%d0			# test rs = 0
	bne.b		add_ext_done
	and.b		&0xfe,FTEMP_LO+3(%a0)	# clear the l bit
add_ext_done:
	rts

#########################
#	ADD DOUBLE	#
#########################
add_dbl:
	add.l		&ad_1_dbl, FTEMP_LO(%a0) # add 1 to lsb
	bcc.b		dcc_clr			# no carry
	addq.l		&0x1, FTEMP_HI(%a0)	# propagate carry
	bcc.b		dcc_clr			# no carry

	roxr.w		FTEMP_HI(%a0)		# mant is 0 so restore v-bit
	roxr.w		FTEMP_HI+2(%a0)		# mant is 0 so restore v-bit
	roxr.w		FTEMP_LO(%a0)
	roxr.w		FTEMP_LO+2(%a0)
	addq.w		&0x1, FTEMP_EX(%a0)	# incr exponent
dcc_clr:
	tst.l		%d0			# test for rs = 0
	bne.b		dbl_done
	and.w		&0xf000, FTEMP_LO+2(%a0) # clear the l-bit

dbl_done:
	and.l		&0xfffff800,FTEMP_LO(%a0) # truncate bits beyond dbl limit
	rts

###########################
# Truncate all other bits #
###########################
truncate:
	swap		%d1			# select rnd prec

	cmpi.b		%d1, &s_mode		# is prec sgl?
	beq.w		sgl_done		# yes
	bgt.b		dbl_done		# no; it's dbl
	rts					# no; it's ext


#
# ext_grs(): extract guard, round and sticky bits according to
#	     rounding precision.
#
# INPUT
#	d0	   = extended precision g,r,s (in d0{31:29})
#	d1	   = {PREC,ROUND}
# OUTPUT
#	d0{31:29}  = guard, round, sticky
#
# The ext_grs extract the guard/round/sticky bits according to the
# selected rounding precision. It is called by the round subroutine
# only.  All registers except d0 are kept intact. d0 becomes an
# updated guard,round,sticky in d0{31:29}
#
# Notes: the ext_grs uses the round PREC, and therefore has to swap d1
#	 prior to usage, and needs to restore d1 to original. this
#	 routine is tightly tied to the round routine and not meant to
#	 uphold standard subroutine calling practices.
#

ext_grs:
	swap		%d1			# have d1.w point to round precision
	tst.b		%d1			# is rnd prec = extended?
	bne.b		ext_grs_not_ext		# no; go handle sgl or dbl

#
# %d0 actually already hold g,r,s since _round() had it before calling
# this function. so, as long as we don't disturb it, we are "returning" it.
#
ext_grs_ext:
	swap		%d1			# yes; return to correct positions
	rts

ext_grs_not_ext:
	movm.l		&0x3000, -(%sp)		# make some temp registers {d2/d3}

	cmpi.b		%d1, &s_mode		# is rnd prec = sgl?
	bne.b		ext_grs_dbl		# no; go handle dbl

#
# sgl:
#	96		64	  40	32		0
#	-----------------------------------------------------
#	| EXP	|XXXXXXX|	  |xx	|		|grs|
#	-----------------------------------------------------
#			<--(24)--->nn\			   /
#				   ee ---------------------
#				   ww		|
#						v
#				   gr	   new sticky
#
ext_grs_sgl:
	bfextu		FTEMP_HI(%a0){&24:&2}, %d3 # sgl prec. g-r are 2 bits right
	mov.l		&30, %d2		# of the sgl prec. limits
	lsl.l		%d2, %d3		# shift g-r bits to MSB of d3
	mov.l		FTEMP_HI(%a0), %d2	# get word 2 for s-bit test
	and.l		&0x0000003f, %d2	# s bit is the or of all other
	bne.b		ext_grs_st_stky		# bits to the right of g-r
	tst.l		FTEMP_LO(%a0)		# test lower mantissa
	bne.b		ext_grs_st_stky		# if any are set, set sticky
	tst.l		%d0			# test original g,r,s
	bne.b		ext_grs_st_stky		# if any are set, set sticky
	bra.b		ext_grs_end_sd		# if words 3 and 4 are clr, exit

#
# dbl:
#	96		64		32	 11	0
#	-----------------------------------------------------
#	| EXP	|XXXXXXX|		|	 |xx	|grs|
#	-----------------------------------------------------
#						  nn\	    /
#						  ee -------
#						  ww	|
#							v
#						  gr	new sticky
#
ext_grs_dbl:
	bfextu		FTEMP_LO(%a0){&21:&2}, %d3 # dbl-prec. g-r are 2 bits right
	mov.l		&30, %d2		# of the dbl prec. limits
	lsl.l		%d2, %d3		# shift g-r bits to the MSB of d3
	mov.l		FTEMP_LO(%a0), %d2	# get lower mantissa  for s-bit test
	and.l		&0x000001ff, %d2	# s bit is the or-ing of all
	bne.b		ext_grs_st_stky		# other bits to the right of g-r
	tst.l		%d0			# test word original g,r,s
	bne.b		ext_grs_st_stky		# if any are set, set sticky
	bra.b		ext_grs_end_sd		# if clear, exit

ext_grs_st_stky:
	bset		&rnd_stky_bit, %d3	# set sticky bit
ext_grs_end_sd:
	mov.l		%d3, %d0		# return grs to d0

	movm.l		(%sp)+, &0xc		# restore scratch registers {d2/d3}

	swap		%d1			# restore d1 to original
	rts

#########################################################################
# norm(): normalize the mantissa of an extended precision input. the	#
#	  input operand should not be normalized already.		#
#									#
# XDEF ****************************************************************	#
#	norm()								#
#									#
# XREF **************************************************************** #
#	none								#
#									#
# INPUT *************************************************************** #
#	a0 = pointer fp extended precision operand to normalize		#
#									#
# OUTPUT ************************************************************** #
#	d0 = number of bit positions the mantissa was shifted		#
#	a0 = the input operand's mantissa is normalized; the exponent	#
#	     is unchanged.						#
#									#
#########################################################################
	global		norm
norm:
	mov.l		%d2, -(%sp)		# create some temp regs
	mov.l		%d3, -(%sp)

	mov.l		FTEMP_HI(%a0), %d0	# load hi(mantissa)
	mov.l		FTEMP_LO(%a0), %d1	# load lo(mantissa)

	bfffo		%d0{&0:&32}, %d2	# how many places to shift?
	beq.b		norm_lo			# hi(man) is all zeroes!

norm_hi:
	lsl.l		%d2, %d0		# left shift hi(man)
	bfextu		%d1{&0:%d2}, %d3	# extract lo bits

	or.l		%d3, %d0		# create hi(man)
	lsl.l		%d2, %d1		# create lo(man)

	mov.l		%d0, FTEMP_HI(%a0)	# store new hi(man)
	mov.l		%d1, FTEMP_LO(%a0)	# store new lo(man)

	mov.l		%d2, %d0		# return shift amount

	mov.l		(%sp)+, %d3		# restore temp regs
	mov.l		(%sp)+, %d2

	rts

norm_lo:
	bfffo		%d1{&0:&32}, %d2	# how many places to shift?
	lsl.l		%d2, %d1		# shift lo(man)
	add.l		&32, %d2		# add 32 to shft amount

	mov.l		%d1, FTEMP_HI(%a0)	# store hi(man)
	clr.l		FTEMP_LO(%a0)		# lo(man) is now zero

	mov.l		%d2, %d0		# return shift amount

	mov.l		(%sp)+, %d3		# restore temp regs
	mov.l		(%sp)+, %d2

	rts

#########################################################################
# unnorm_fix(): - changes an UNNORM to one of NORM, DENORM, or ZERO	#
#		- returns corresponding optype tag			#
#									#
# XDEF ****************************************************************	#
#	unnorm_fix()							#
#									#
# XREF **************************************************************** #
#	norm() - normalize the mantissa					#
#									#
# INPUT *************************************************************** #
#	a0 = pointer to unnormalized extended precision number		#
#									#
# OUTPUT ************************************************************** #
#	d0 = optype tag - is corrected to one of NORM, DENORM, or ZERO	#
#	a0 = input operand has been converted to a norm, denorm, or	#
#	     zero; both the exponent and mantissa are changed.		#
#									#
#########################################################################

	global		unnorm_fix
unnorm_fix:
	bfffo		FTEMP_HI(%a0){&0:&32}, %d0 # how many shifts are needed?
	bne.b		unnorm_shift		# hi(man) is not all zeroes

#
# hi(man) is all zeroes so see if any bits in lo(man) are set
#
unnorm_chk_lo:
	bfffo		FTEMP_LO(%a0){&0:&32}, %d0 # is operand really a zero?
	beq.w		unnorm_zero		# yes

	add.w		&32, %d0		# no; fix shift distance

#
# d0 = # shifts needed for complete normalization
#
unnorm_shift:
	clr.l		%d1			# clear top word
	mov.w		FTEMP_EX(%a0), %d1	# extract exponent
	and.w		&0x7fff, %d1		# strip off sgn

	cmp.w		%d0, %d1		# will denorm push exp < 0?
	bgt.b		unnorm_nrm_zero		# yes; denorm only until exp = 0

#
# exponent would not go < 0. Therefore, number stays normalized
#
	sub.w		%d0, %d1		# shift exponent value
	mov.w		FTEMP_EX(%a0), %d0	# load old exponent
	and.w		&0x8000, %d0		# save old sign
	or.w		%d0, %d1		# {sgn,new exp}
	mov.w		%d1, FTEMP_EX(%a0)	# insert new exponent

	bsr.l		norm			# normalize UNNORM

	mov.b		&NORM, %d0		# return new optype tag
	rts

#
# exponent would go < 0, so only denormalize until exp = 0
#
unnorm_nrm_zero:
	cmp.b		%d1, &32		# is exp <= 32?
	bgt.b		unnorm_nrm_zero_lrg	# no; go handle large exponent

	bfextu		FTEMP_HI(%a0){%d1:&32}, %d0 # extract new hi(man)
	mov.l		%d0, FTEMP_HI(%a0)	# save new hi(man)

	mov.l		FTEMP_LO(%a0), %d0	# fetch old lo(man)
	lsl.l		%d1, %d0		# extract new lo(man)
	mov.l		%d0, FTEMP_LO(%a0)	# save new lo(man)

	and.w		&0x8000, FTEMP_EX(%a0)	# set exp = 0

	mov.b		&DENORM, %d0		# return new optype tag
	rts

#
# only mantissa bits set are in lo(man)
#
unnorm_nrm_zero_lrg:
	sub.w		&32, %d1		# adjust shft amt by 32

	mov.l		FTEMP_LO(%a0), %d0	# fetch old lo(man)
	lsl.l		%d1, %d0		# left shift lo(man)

	mov.l		%d0, FTEMP_HI(%a0)	# store new hi(man)
	clr.l		FTEMP_LO(%a0)		# lo(man) = 0

	and.w		&0x8000, FTEMP_EX(%a0)	# set exp = 0

	mov.b		&DENORM, %d0		# return new optype tag
	rts

#
# whole mantissa is zero so this UNNORM is actually a zero
#
unnorm_zero:
	and.w		&0x8000, FTEMP_EX(%a0)	# force exponent to zero

	mov.b		&ZERO, %d0		# fix optype tag
	rts

#########################################################################
# XDEF ****************************************************************	#
#	set_tag_x(): return the optype of the input ext fp number	#
#									#
# XREF ****************************************************************	#
#	None								#
#									#
# INPUT ***************************************************************	#
#	a0 = pointer to extended precision operand			#
#									#
# OUTPUT **************************************************************	#
#	d0 = value of type tag						#
#		one of: NORM, INF, QNAN, SNAN, DENORM, UNNORM, ZERO	#
#									#
# ALGORITHM ***********************************************************	#
#	Simply test the exponent, j-bit, and mantissa values to		#
# determine the type of operand.					#
#	If it's an unnormalized zero, alter the operand and force it	#
# to be a normal zero.							#
#									#
#########################################################################

	global		set_tag_x
set_tag_x:
	mov.w		FTEMP_EX(%a0), %d0	# extract exponent
	andi.w		&0x7fff, %d0		# strip off sign
	cmpi.w		%d0, &0x7fff		# is (EXP == MAX)?
	beq.b		inf_or_nan_x
not_inf_or_nan_x:
	btst		&0x7,FTEMP_HI(%a0)
	beq.b		not_norm_x
is_norm_x:
	mov.b		&NORM, %d0
	rts
not_norm_x:
	tst.w		%d0			# is exponent = 0?
	bne.b		is_unnorm_x
not_unnorm_x:
	tst.l		FTEMP_HI(%a0)
	bne.b		is_denorm_x
	tst.l		FTEMP_LO(%a0)
	bne.b		is_denorm_x
is_zero_x:
	mov.b		&ZERO, %d0
	rts
is_denorm_x:
	mov.b		&DENORM, %d0
	rts
# must distinguish now "Unnormalized zeroes" which we
# must convert to zero.
is_unnorm_x:
	tst.l		FTEMP_HI(%a0)
	bne.b		is_unnorm_reg_x
	tst.l		FTEMP_LO(%a0)
	bne.b		is_unnorm_reg_x
# it's an "unnormalized zero". let's convert it to an actual zero...
	andi.w		&0x8000,FTEMP_EX(%a0)	# clear exponent
	mov.b		&ZERO, %d0
	rts
is_unnorm_reg_x:
	mov.b		&UNNORM, %d0
	rts
inf_or_nan_x:
	tst.l		FTEMP_LO(%a0)
	bne.b		is_nan_x
	mov.l		FTEMP_HI(%a0), %d0
	and.l		&0x7fffffff, %d0	# msb is a don't care!
	bne.b		is_nan_x
is_inf_x:
	mov.b		&INF, %d0
	rts
is_nan_x:
	btst		&0x6, FTEMP_HI(%a0)
	beq.b		is_snan_x
	mov.b		&QNAN, %d0
	rts
is_snan_x:
	mov.b		&SNAN, %d0
	rts

#########################################################################
# XDEF ****************************************************************	#
#	set_tag_d(): return the optype of the input dbl fp number	#
#									#
# XREF ****************************************************************	#
#	None								#
#									#
# INPUT ***************************************************************	#
#	a0 = points to double precision operand				#
#									#
# OUTPUT **************************************************************	#
#	d0 = value of type tag						#
#		one of: NORM, INF, QNAN, SNAN, DENORM, ZERO		#
#									#
# ALGORITHM ***********************************************************	#
#	Simply test the exponent, j-bit, and mantissa values to		#
# determine the type of operand.					#
#									#
#########################################################################

	global		set_tag_d
set_tag_d:
	mov.l		FTEMP(%a0), %d0
	mov.l		%d0, %d1

	andi.l		&0x7ff00000, %d0
	beq.b		zero_or_denorm_d

	cmpi.l		%d0, &0x7ff00000
	beq.b		inf_or_nan_d

is_norm_d:
	mov.b		&NORM, %d0
	rts
zero_or_denorm_d:
	and.l		&0x000fffff, %d1
	bne		is_denorm_d
	tst.l		4+FTEMP(%a0)
	bne		is_denorm_d
is_zero_d:
	mov.b		&ZERO, %d0
	rts
is_denorm_d:
	mov.b		&DENORM, %d0
	rts
inf_or_nan_d:
	and.l		&0x000fffff, %d1
	bne		is_nan_d
	tst.l		4+FTEMP(%a0)
	bne		is_nan_d
is_inf_d:
	mov.b		&INF, %d0
	rts
is_nan_d:
	btst		&19, %d1
	bne		is_qnan_d
is_snan_d:
	mov.b		&SNAN, %d0
	rts
is_qnan_d:
	mov.b		&QNAN, %d0
	rts

#########################################################################
# XDEF ****************************************************************	#
#	set_tag_s(): return the optype of the input sgl fp number	#
#									#
# XREF ****************************************************************	#
#	None								#
#									#
# INPUT ***************************************************************	#
#	a0 = pointer to single precision operand			#
#									#
# OUTPUT **************************************************************	#
#	d0 = value of type tag						#
#		one of: NORM, INF, QNAN, SNAN, DENORM, ZERO		#
#									#
# ALGORITHM ***********************************************************	#
#	Simply test the exponent, j-bit, and mantissa values to		#
# determine the type of operand.					#
#									#
#########################################################################

	global		set_tag_s
set_tag_s:
	mov.l		FTEMP(%a0), %d0
	mov.l		%d0, %d1

	andi.l		&0x7f800000, %d0
	beq.b		zero_or_denorm_s

	cmpi.l		%d0, &0x7f800000
	beq.b		inf_or_nan_s

is_norm_s:
	mov.b		&NORM, %d0
	rts
zero_or_denorm_s:
	and.l		&0x007fffff, %d1
	bne		is_denorm_s
is_zero_s:
	mov.b		&ZERO, %d0
	rts
is_denorm_s:
	mov.b		&DENORM, %d0
	rts
inf_or_nan_s:
	and.l		&0x007fffff, %d1
	bne		is_nan_s
is_inf_s:
	mov.b		&INF, %d0
	rts
is_nan_s:
	btst		&22, %d1
	bne		is_qnan_s
is_snan_s:
	mov.b		&SNAN, %d0
	rts
is_qnan_s:
	mov.b		&QNAN, %d0
	rts

#########################################################################
# XDEF ****************************************************************	#
#	unf_res(): routine to produce default underflow result of a	#
#		   scaled extended precision number; this is used by	#
#		   fadd/fdiv/fmul/etc. emulation routines.		#
#	unf_res4(): same as above but for fsglmul/fsgldiv which use	#
#		    single round prec and extended prec mode.		#
#									#
# XREF ****************************************************************	#
#	_denorm() - denormalize according to scale factor		#
#	_round() - round denormalized number according to rnd prec	#
#									#
# INPUT ***************************************************************	#
#	a0 = pointer to extended precison operand			#
#	d0 = scale factor						#
#	d1 = rounding precision/mode					#
#									#
# OUTPUT **************************************************************	#
#	a0 = pointer to default underflow result in extended precision	#
#	d0.b = result FPSR_cc which caller may or may not want to save	#
#									#
# ALGORITHM ***********************************************************	#
#	Convert the input operand to "internal format" which means the	#
# exponent is extended to 16 bits and the sign is stored in the unused	#
# portion of the extended precison operand. Denormalize the number	#
# according to the scale factor passed in d0. Then, round the		#
# denormalized result.							#
#	Set the FPSR_exc bits as appropriate but return the cc bits in	#
# d0 in case the caller doesn't want to save them (as is the case for	#
# fmove out).								#
#	unf_res4() for fsglmul/fsgldiv forces the denorm to extended	#
# precision and the rounding mode to single.				#
#									#
#########################################################################
	global		unf_res
unf_res:
	mov.l		%d1, -(%sp)		# save rnd prec,mode on stack

	btst		&0x7, FTEMP_EX(%a0)	# make "internal" format
	sne		FTEMP_SGN(%a0)

	mov.w		FTEMP_EX(%a0), %d1	# extract exponent
	and.w		&0x7fff, %d1
	sub.w		%d0, %d1
	mov.w		%d1, FTEMP_EX(%a0)	# insert 16 bit exponent

	mov.l		%a0, -(%sp)		# save operand ptr during calls

	mov.l		0x4(%sp),%d0		# pass rnd prec.
	andi.w		&0x00c0,%d0
	lsr.w		&0x4,%d0
	bsr.l		_denorm			# denorm result

	mov.l		(%sp),%a0
	mov.w		0x6(%sp),%d1		# load prec:mode into %d1
	andi.w		&0xc0,%d1		# extract rnd prec
	lsr.w		&0x4,%d1
	swap		%d1
	mov.w		0x6(%sp),%d1
	andi.w		&0x30,%d1
	lsr.w		&0x4,%d1
	bsr.l		_round			# round the denorm

	mov.l		(%sp)+, %a0

# result is now rounded properly. convert back to normal format
	bclr		&0x7, FTEMP_EX(%a0)	# clear sgn first; may have residue
	tst.b		FTEMP_SGN(%a0)		# is "internal result" sign set?
	beq.b		unf_res_chkifzero	# no; result is positive
	bset		&0x7, FTEMP_EX(%a0)	# set result sgn
	clr.b		FTEMP_SGN(%a0)		# clear temp sign

# the number may have become zero after rounding. set ccodes accordingly.
unf_res_chkifzero:
	clr.l		%d0
	tst.l		FTEMP_HI(%a0)		# is value now a zero?
	bne.b		unf_res_cont		# no
	tst.l		FTEMP_LO(%a0)
	bne.b		unf_res_cont		# no
#	bset		&z_bit, FPSR_CC(%a6)	# yes; set zero ccode bit
	bset		&z_bit, %d0		# yes; set zero ccode bit

unf_res_cont:

#
# can inex1 also be set along with unfl and inex2???
#
# we know that underflow has occurred. aunfl should be set if INEX2 is also set.
#
	btst		&inex2_bit, FPSR_EXCEPT(%a6) # is INEX2 set?
	beq.b		unf_res_end		# no
	bset		&aunfl_bit, FPSR_AEXCEPT(%a6) # yes; set aunfl

unf_res_end:
	add.l		&0x4, %sp		# clear stack
	rts

# unf_res() for fsglmul() and fsgldiv().
	global		unf_res4
unf_res4:
	mov.l		%d1,-(%sp)		# save rnd prec,mode on stack

	btst		&0x7,FTEMP_EX(%a0)	# make "internal" format
	sne		FTEMP_SGN(%a0)

	mov.w		FTEMP_EX(%a0),%d1	# extract exponent
	and.w		&0x7fff,%d1
	sub.w		%d0,%d1
	mov.w		%d1,FTEMP_EX(%a0)	# insert 16 bit exponent

	mov.l		%a0,-(%sp)		# save operand ptr during calls

	clr.l		%d0			# force rnd prec = ext
	bsr.l		_denorm			# denorm result

	mov.l		(%sp),%a0
	mov.w		&s_mode,%d1		# force rnd prec = sgl
	swap		%d1
	mov.w		0x6(%sp),%d1		# load rnd mode
	andi.w		&0x30,%d1		# extract rnd prec
	lsr.w		&0x4,%d1
	bsr.l		_round			# round the denorm

	mov.l		(%sp)+,%a0

# result is now rounded properly. convert back to normal format
	bclr		&0x7,FTEMP_EX(%a0)	# clear sgn first; may have residue
	tst.b		FTEMP_SGN(%a0)		# is "internal result" sign set?
	beq.b		unf_res4_chkifzero	# no; result is positive
	bset		&0x7,FTEMP_EX(%a0)	# set result sgn
	clr.b		FTEMP_SGN(%a0)		# clear temp sign

# the number may have become zero after rounding. set ccodes accordingly.
unf_res4_chkifzero:
	clr.l		%d0
	tst.l		FTEMP_HI(%a0)		# is value now a zero?
	bne.b		unf_res4_cont		# no
	tst.l		FTEMP_LO(%a0)
	bne.b		unf_res4_cont		# no
#	bset		&z_bit,FPSR_CC(%a6)	# yes; set zero ccode bit
	bset		&z_bit,%d0		# yes; set zero ccode bit

unf_res4_cont:

#
# can inex1 also be set along with unfl and inex2???
#
# we know that underflow has occurred. aunfl should be set if INEX2 is also set.
#
	btst		&inex2_bit,FPSR_EXCEPT(%a6) # is INEX2 set?
	beq.b		unf_res4_end		# no
	bset		&aunfl_bit,FPSR_AEXCEPT(%a6) # yes; set aunfl

unf_res4_end:
	add.l		&0x4,%sp		# clear stack
	rts

#########################################################################
# XDEF ****************************************************************	#
#	ovf_res(): routine to produce the default overflow result of	#
#		   an overflowing number.				#
#	ovf_res2(): same as above but the rnd mode/prec are passed	#
#		    differently.					#
#									#
# XREF ****************************************************************	#
#	none								#
#									#
# INPUT ***************************************************************	#
#	d1.b	= '-1' => (-); '0' => (+)				#
#   ovf_res():								#
#	d0	= rnd mode/prec						#
#   ovf_res2():								#
#	hi(d0)	= rnd prec						#
#	lo(d0)	= rnd mode						#
#									#
# OUTPUT **************************************************************	#
#	a0	= points to extended precision result			#
#	d0.b	= condition code bits					#
#									#
# ALGORITHM ***********************************************************	#
#	The default overflow result can be determined by the sign of	#
# the result and the rounding mode/prec in effect. These bits are	#
# concatenated together to create an index into the default result	#
# table. A pointer to the correct result is returned in a0. The		#
# resulting condition codes are returned in d0 in case the caller	#
# doesn't want FPSR_cc altered (as is the case for fmove out).		#
#									#
#########################################################################

	global		ovf_res
ovf_res:
	andi.w		&0x10,%d1		# keep result sign
	lsr.b		&0x4,%d0		# shift prec/mode
	or.b		%d0,%d1			# concat the two
	mov.w		%d1,%d0			# make a copy
	lsl.b		&0x1,%d1		# multiply d1 by 2
	bra.b		ovf_res_load

	global		ovf_res2
ovf_res2:
	and.w		&0x10, %d1		# keep result sign
	or.b		%d0, %d1		# insert rnd mode
	swap		%d0
	or.b		%d0, %d1		# insert rnd prec
	mov.w		%d1, %d0		# make a copy
	lsl.b		&0x1, %d1		# shift left by 1

#
# use the rounding mode, precision, and result sign as in index into the
# two tables below to fetch the default result and the result ccodes.
#
ovf_res_load:
	mov.b		(tbl_ovfl_cc.b,%pc,%d0.w*1), %d0 # fetch result ccodes
	lea		(tbl_ovfl_result.b,%pc,%d1.w*8), %a0 # return result ptr

	rts

tbl_ovfl_cc:
	byte		0x2, 0x0, 0x0, 0x2
	byte		0x2, 0x0, 0x0, 0x2
	byte		0x2, 0x0, 0x0, 0x2
	byte		0x0, 0x0, 0x0, 0x0
	byte		0x2+0x8, 0x8, 0x2+0x8, 0x8
	byte		0x2+0x8, 0x8, 0x2+0x8, 0x8
	byte		0x2+0x8, 0x8, 0x2+0x8, 0x8

tbl_ovfl_result:
	long		0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RN
	long		0x7ffe0000,0xffffffff,0xffffffff,0x00000000 # +EXT; RZ
	long		0x7ffe0000,0xffffffff,0xffffffff,0x00000000 # +EXT; RM
	long		0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RP

	long		0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RN
	long		0x407e0000,0xffffff00,0x00000000,0x00000000 # +SGL; RZ
	long		0x407e0000,0xffffff00,0x00000000,0x00000000 # +SGL; RM
	long		0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RP

	long		0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RN
	long		0x43fe0000,0xffffffff,0xfffff800,0x00000000 # +DBL; RZ
	long		0x43fe0000,0xffffffff,0xfffff800,0x00000000 # +DBL; RM
	long		0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RP

	long		0x00000000,0x00000000,0x00000000,0x00000000
	long		0x00000000,0x00000000,0x00000000,0x00000000
	long		0x00000000,0x00000000,0x00000000,0x00000000
	long		0x00000000,0x00000000,0x00000000,0x00000000

	long		0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RN
	long		0xfffe0000,0xffffffff,0xffffffff,0x00000000 # -EXT; RZ
	long		0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RM
	long		0xfffe0000,0xffffffff,0xffffffff,0x00000000 # -EXT; RP

	long		0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RN
	long		0xc07e0000,0xffffff00,0x00000000,0x00000000 # -SGL; RZ
	long		0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RM
	long		0xc07e0000,0xffffff00,0x00000000,0x00000000 # -SGL; RP

	long		0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RN
	long		0xc3fe0000,0xffffffff,0xfffff800,0x00000000 # -DBL; RZ
	long		0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RM
	long		0xc3fe0000,0xffffffff,0xfffff800,0x00000000 # -DBL; RP

#########################################################################
# XDEF ****************************************************************	#
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -



