18c2ecf20Sopenharmony_ci|
28c2ecf20Sopenharmony_ci|	x_unfl.sa 3.4 7/1/91
38c2ecf20Sopenharmony_ci|
48c2ecf20Sopenharmony_ci|	fpsp_unfl --- FPSP handler for underflow exception
58c2ecf20Sopenharmony_ci|
68c2ecf20Sopenharmony_ci| Trap disabled results
78c2ecf20Sopenharmony_ci|	For 881/2 compatibility, sw must denormalize the intermediate
88c2ecf20Sopenharmony_ci| result, then store the result.  Denormalization is accomplished
98c2ecf20Sopenharmony_ci| by taking the intermediate result (which is always normalized) and
108c2ecf20Sopenharmony_ci| shifting the mantissa right while incrementing the exponent until
118c2ecf20Sopenharmony_ci| it is equal to the denormalized exponent for the destination
128c2ecf20Sopenharmony_ci| format.  After denormalization, the result is rounded to the
138c2ecf20Sopenharmony_ci| destination format.
148c2ecf20Sopenharmony_ci|
158c2ecf20Sopenharmony_ci| Trap enabled results
168c2ecf20Sopenharmony_ci|	All trap disabled code applies.	In addition the exceptional
178c2ecf20Sopenharmony_ci| operand needs to made available to the user with a bias of $6000
188c2ecf20Sopenharmony_ci| added to the exponent.
198c2ecf20Sopenharmony_ci|
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci|		Copyright (C) Motorola, Inc. 1990
228c2ecf20Sopenharmony_ci|			All Rights Reserved
238c2ecf20Sopenharmony_ci|
248c2ecf20Sopenharmony_ci|       For details on the license for this file, please see the
258c2ecf20Sopenharmony_ci|       file, README, in this same directory.
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ciX_UNFL:	|idnt    2,1 | Motorola 040 Floating Point Software Package
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci	|section	8
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#include "fpsp.h"
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	|xref	denorm
348c2ecf20Sopenharmony_ci	|xref	round
358c2ecf20Sopenharmony_ci	|xref	store
368c2ecf20Sopenharmony_ci	|xref	g_rndpr
378c2ecf20Sopenharmony_ci	|xref	g_opcls
388c2ecf20Sopenharmony_ci	|xref	g_dfmtou
398c2ecf20Sopenharmony_ci	|xref	real_unfl
408c2ecf20Sopenharmony_ci	|xref	real_inex
418c2ecf20Sopenharmony_ci	|xref	fpsp_done
428c2ecf20Sopenharmony_ci	|xref	b1238_fix
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	.global	fpsp_unfl
458c2ecf20Sopenharmony_cifpsp_unfl:
468c2ecf20Sopenharmony_ci	link		%a6,#-LOCAL_SIZE
478c2ecf20Sopenharmony_ci	fsave		-(%a7)
488c2ecf20Sopenharmony_ci	moveml		%d0-%d1/%a0-%a1,USER_DA(%a6)
498c2ecf20Sopenharmony_ci	fmovemx	%fp0-%fp3,USER_FP0(%a6)
508c2ecf20Sopenharmony_ci	fmoveml	%fpcr/%fpsr/%fpiar,USER_FPCR(%a6)
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci|
538c2ecf20Sopenharmony_ci	bsrl		unf_res	|denormalize, round & store interm op
548c2ecf20Sopenharmony_ci|
558c2ecf20Sopenharmony_ci| If underflow exceptions are not enabled, check for inexact
568c2ecf20Sopenharmony_ci| exception
578c2ecf20Sopenharmony_ci|
588c2ecf20Sopenharmony_ci	btstb		#unfl_bit,FPCR_ENABLE(%a6)
598c2ecf20Sopenharmony_ci	beqs		ck_inex
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	btstb		#E3,E_BYTE(%a6)
628c2ecf20Sopenharmony_ci	beqs		no_e3_1
638c2ecf20Sopenharmony_ci|
648c2ecf20Sopenharmony_ci| Clear dirty bit on dest resister in the frame before branching
658c2ecf20Sopenharmony_ci| to b1238_fix.
668c2ecf20Sopenharmony_ci|
678c2ecf20Sopenharmony_ci	bfextu		CMDREG3B(%a6){#6:#3},%d0	|get dest reg no
688c2ecf20Sopenharmony_ci	bclrb		%d0,FPR_DIRTY_BITS(%a6)	|clr dest dirty bit
698c2ecf20Sopenharmony_ci	bsrl		b1238_fix		|test for bug1238 case
708c2ecf20Sopenharmony_ci	movel		USER_FPSR(%a6),FPSR_SHADOW(%a6)
718c2ecf20Sopenharmony_ci	orl		#sx_mask,E_BYTE(%a6)
728c2ecf20Sopenharmony_cino_e3_1:
738c2ecf20Sopenharmony_ci	moveml		USER_DA(%a6),%d0-%d1/%a0-%a1
748c2ecf20Sopenharmony_ci	fmovemx	USER_FP0(%a6),%fp0-%fp3
758c2ecf20Sopenharmony_ci	fmoveml	USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
768c2ecf20Sopenharmony_ci	frestore	(%a7)+
778c2ecf20Sopenharmony_ci	unlk		%a6
788c2ecf20Sopenharmony_ci	bral		real_unfl
798c2ecf20Sopenharmony_ci|
808c2ecf20Sopenharmony_ci| It is possible to have either inex2 or inex1 exceptions with the
818c2ecf20Sopenharmony_ci| unfl.  If the inex enable bit is set in the FPCR, and either
828c2ecf20Sopenharmony_ci| inex2 or inex1 occurred, we must clean up and branch to the
838c2ecf20Sopenharmony_ci| real inex handler.
848c2ecf20Sopenharmony_ci|
858c2ecf20Sopenharmony_cick_inex:
868c2ecf20Sopenharmony_ci	moveb		FPCR_ENABLE(%a6),%d0
878c2ecf20Sopenharmony_ci	andb		FPSR_EXCEPT(%a6),%d0
888c2ecf20Sopenharmony_ci	andib		#0x3,%d0
898c2ecf20Sopenharmony_ci	beqs		unfl_done
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci|
928c2ecf20Sopenharmony_ci| Inexact enabled and reported, and we must take an inexact exception
938c2ecf20Sopenharmony_ci|
948c2ecf20Sopenharmony_citake_inex:
958c2ecf20Sopenharmony_ci	btstb		#E3,E_BYTE(%a6)
968c2ecf20Sopenharmony_ci	beqs		no_e3_2
978c2ecf20Sopenharmony_ci|
988c2ecf20Sopenharmony_ci| Clear dirty bit on dest resister in the frame before branching
998c2ecf20Sopenharmony_ci| to b1238_fix.
1008c2ecf20Sopenharmony_ci|
1018c2ecf20Sopenharmony_ci	bfextu		CMDREG3B(%a6){#6:#3},%d0	|get dest reg no
1028c2ecf20Sopenharmony_ci	bclrb		%d0,FPR_DIRTY_BITS(%a6)	|clr dest dirty bit
1038c2ecf20Sopenharmony_ci	bsrl		b1238_fix		|test for bug1238 case
1048c2ecf20Sopenharmony_ci	movel		USER_FPSR(%a6),FPSR_SHADOW(%a6)
1058c2ecf20Sopenharmony_ci	orl		#sx_mask,E_BYTE(%a6)
1068c2ecf20Sopenharmony_cino_e3_2:
1078c2ecf20Sopenharmony_ci	moveb		#INEX_VEC,EXC_VEC+1(%a6)
1088c2ecf20Sopenharmony_ci	moveml         USER_DA(%a6),%d0-%d1/%a0-%a1
1098c2ecf20Sopenharmony_ci	fmovemx        USER_FP0(%a6),%fp0-%fp3
1108c2ecf20Sopenharmony_ci	fmoveml        USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
1118c2ecf20Sopenharmony_ci	frestore        (%a7)+
1128c2ecf20Sopenharmony_ci	unlk            %a6
1138c2ecf20Sopenharmony_ci	bral		real_inex
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ciunfl_done:
1168c2ecf20Sopenharmony_ci	bclrb		#E3,E_BYTE(%a6)
1178c2ecf20Sopenharmony_ci	beqs		e1_set		|if set then branch
1188c2ecf20Sopenharmony_ci|
1198c2ecf20Sopenharmony_ci| Clear dirty bit on dest resister in the frame before branching
1208c2ecf20Sopenharmony_ci| to b1238_fix.
1218c2ecf20Sopenharmony_ci|
1228c2ecf20Sopenharmony_ci	bfextu		CMDREG3B(%a6){#6:#3},%d0		|get dest reg no
1238c2ecf20Sopenharmony_ci	bclrb		%d0,FPR_DIRTY_BITS(%a6)	|clr dest dirty bit
1248c2ecf20Sopenharmony_ci	bsrl		b1238_fix		|test for bug1238 case
1258c2ecf20Sopenharmony_ci	movel		USER_FPSR(%a6),FPSR_SHADOW(%a6)
1268c2ecf20Sopenharmony_ci	orl		#sx_mask,E_BYTE(%a6)
1278c2ecf20Sopenharmony_ci	moveml		USER_DA(%a6),%d0-%d1/%a0-%a1
1288c2ecf20Sopenharmony_ci	fmovemx	USER_FP0(%a6),%fp0-%fp3
1298c2ecf20Sopenharmony_ci	fmoveml	USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
1308c2ecf20Sopenharmony_ci	frestore	(%a7)+
1318c2ecf20Sopenharmony_ci	unlk		%a6
1328c2ecf20Sopenharmony_ci	bral		fpsp_done
1338c2ecf20Sopenharmony_cie1_set:
1348c2ecf20Sopenharmony_ci	moveml		USER_DA(%a6),%d0-%d1/%a0-%a1
1358c2ecf20Sopenharmony_ci	fmovemx	USER_FP0(%a6),%fp0-%fp3
1368c2ecf20Sopenharmony_ci	fmoveml	USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
1378c2ecf20Sopenharmony_ci	unlk		%a6
1388c2ecf20Sopenharmony_ci	bral		fpsp_done
1398c2ecf20Sopenharmony_ci|
1408c2ecf20Sopenharmony_ci|	unf_res --- underflow result calculation
1418c2ecf20Sopenharmony_ci|
1428c2ecf20Sopenharmony_ciunf_res:
1438c2ecf20Sopenharmony_ci	bsrl		g_rndpr		|returns RND_PREC in d0 0=ext,
1448c2ecf20Sopenharmony_ci|					;1=sgl, 2=dbl
1458c2ecf20Sopenharmony_ci|					;we need the RND_PREC in the
1468c2ecf20Sopenharmony_ci|					;upper word for round
1478c2ecf20Sopenharmony_ci	movew		#0,-(%a7)
1488c2ecf20Sopenharmony_ci	movew		%d0,-(%a7)	|copy RND_PREC to stack
1498c2ecf20Sopenharmony_ci|
1508c2ecf20Sopenharmony_ci|
1518c2ecf20Sopenharmony_ci| If the exception bit set is E3, the exceptional operand from the
1528c2ecf20Sopenharmony_ci| fpu is in WBTEMP; else it is in FPTEMP.
1538c2ecf20Sopenharmony_ci|
1548c2ecf20Sopenharmony_ci	btstb		#E3,E_BYTE(%a6)
1558c2ecf20Sopenharmony_ci	beqs		unf_E1
1568c2ecf20Sopenharmony_ciunf_E3:
1578c2ecf20Sopenharmony_ci	lea		WBTEMP(%a6),%a0	|a0 now points to operand
1588c2ecf20Sopenharmony_ci|
1598c2ecf20Sopenharmony_ci| Test for fsgldiv and fsglmul.  If the inst was one of these, then
1608c2ecf20Sopenharmony_ci| force the precision to extended for the denorm routine.  Use
1618c2ecf20Sopenharmony_ci| the user's precision for the round routine.
1628c2ecf20Sopenharmony_ci|
1638c2ecf20Sopenharmony_ci	movew		CMDREG3B(%a6),%d1	|check for fsgldiv or fsglmul
1648c2ecf20Sopenharmony_ci	andiw		#0x7f,%d1
1658c2ecf20Sopenharmony_ci	cmpiw		#0x30,%d1		|check for sgldiv
1668c2ecf20Sopenharmony_ci	beqs		unf_sgl
1678c2ecf20Sopenharmony_ci	cmpiw		#0x33,%d1		|check for sglmul
1688c2ecf20Sopenharmony_ci	bnes		unf_cont	|if not, use fpcr prec in round
1698c2ecf20Sopenharmony_ciunf_sgl:
1708c2ecf20Sopenharmony_ci	clrl		%d0
1718c2ecf20Sopenharmony_ci	movew		#0x1,(%a7)	|override g_rndpr precision
1728c2ecf20Sopenharmony_ci|					;force single
1738c2ecf20Sopenharmony_ci	bras		unf_cont
1748c2ecf20Sopenharmony_ciunf_E1:
1758c2ecf20Sopenharmony_ci	lea		FPTEMP(%a6),%a0	|a0 now points to operand
1768c2ecf20Sopenharmony_ciunf_cont:
1778c2ecf20Sopenharmony_ci	bclrb		#sign_bit,LOCAL_EX(%a0)	|clear sign bit
1788c2ecf20Sopenharmony_ci	sne		LOCAL_SGN(%a0)		|store sign
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	bsrl		denorm		|returns denorm, a0 points to it
1818c2ecf20Sopenharmony_ci|
1828c2ecf20Sopenharmony_ci| WARNING:
1838c2ecf20Sopenharmony_ci|				;d0 has guard,round sticky bit
1848c2ecf20Sopenharmony_ci|				;make sure that it is not corrupted
1858c2ecf20Sopenharmony_ci|				;before it reaches the round subroutine
1868c2ecf20Sopenharmony_ci|				;also ensure that a0 isn't corrupted
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci|
1898c2ecf20Sopenharmony_ci| Set up d1 for round subroutine d1 contains the PREC/MODE
1908c2ecf20Sopenharmony_ci| information respectively on upper/lower register halves.
1918c2ecf20Sopenharmony_ci|
1928c2ecf20Sopenharmony_ci	bfextu		FPCR_MODE(%a6){#2:#2},%d1	|get mode from FPCR
1938c2ecf20Sopenharmony_ci|						;mode in lower d1
1948c2ecf20Sopenharmony_ci	addl		(%a7)+,%d1		|merge PREC/MODE
1958c2ecf20Sopenharmony_ci|
1968c2ecf20Sopenharmony_ci| WARNING: a0 and d0 are assumed to be intact between the denorm and
1978c2ecf20Sopenharmony_ci| round subroutines. All code between these two subroutines
1988c2ecf20Sopenharmony_ci| must not corrupt a0 and d0.
1998c2ecf20Sopenharmony_ci|
2008c2ecf20Sopenharmony_ci|
2018c2ecf20Sopenharmony_ci| Perform Round
2028c2ecf20Sopenharmony_ci|	Input:		a0 points to input operand
2038c2ecf20Sopenharmony_ci|			d0{31:29} has guard, round, sticky
2048c2ecf20Sopenharmony_ci|			d1{01:00} has rounding mode
2058c2ecf20Sopenharmony_ci|			d1{17:16} has rounding precision
2068c2ecf20Sopenharmony_ci|	Output:		a0 points to rounded operand
2078c2ecf20Sopenharmony_ci|
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	bsrl		round		|returns rounded denorm at (a0)
2108c2ecf20Sopenharmony_ci|
2118c2ecf20Sopenharmony_ci| Differentiate between store to memory vs. store to register
2128c2ecf20Sopenharmony_ci|
2138c2ecf20Sopenharmony_ciunf_store:
2148c2ecf20Sopenharmony_ci	bsrl		g_opcls		|returns opclass in d0{2:0}
2158c2ecf20Sopenharmony_ci	cmpib		#0x3,%d0
2168c2ecf20Sopenharmony_ci	bnes		not_opc011
2178c2ecf20Sopenharmony_ci|
2188c2ecf20Sopenharmony_ci| At this point, a store to memory is pending
2198c2ecf20Sopenharmony_ci|
2208c2ecf20Sopenharmony_ciopc011:
2218c2ecf20Sopenharmony_ci	bsrl		g_dfmtou
2228c2ecf20Sopenharmony_ci	tstb		%d0
2238c2ecf20Sopenharmony_ci	beqs		ext_opc011	|If extended, do not subtract
2248c2ecf20Sopenharmony_ci|				;If destination format is sgl/dbl,
2258c2ecf20Sopenharmony_ci	tstb		LOCAL_HI(%a0)	|If rounded result is normal,don't
2268c2ecf20Sopenharmony_ci|					;subtract
2278c2ecf20Sopenharmony_ci	bmis		ext_opc011
2288c2ecf20Sopenharmony_ci	subqw		#1,LOCAL_EX(%a0)	|account for denorm bias vs.
2298c2ecf20Sopenharmony_ci|				;normalized bias
2308c2ecf20Sopenharmony_ci|				;          normalized   denormalized
2318c2ecf20Sopenharmony_ci|				;single       $7f           $7e
2328c2ecf20Sopenharmony_ci|				;double       $3ff          $3fe
2338c2ecf20Sopenharmony_ci|
2348c2ecf20Sopenharmony_ciext_opc011:
2358c2ecf20Sopenharmony_ci	bsrl		store		|stores to memory
2368c2ecf20Sopenharmony_ci	bras		unf_done	|finish up
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci|
2398c2ecf20Sopenharmony_ci| At this point, a store to a float register is pending
2408c2ecf20Sopenharmony_ci|
2418c2ecf20Sopenharmony_cinot_opc011:
2428c2ecf20Sopenharmony_ci	bsrl		store	|stores to float register
2438c2ecf20Sopenharmony_ci|				;a0 is not corrupted on a store to a
2448c2ecf20Sopenharmony_ci|				;float register.
2458c2ecf20Sopenharmony_ci|
2468c2ecf20Sopenharmony_ci| Set the condition codes according to result
2478c2ecf20Sopenharmony_ci|
2488c2ecf20Sopenharmony_ci	tstl		LOCAL_HI(%a0)	|check upper mantissa
2498c2ecf20Sopenharmony_ci	bnes		ck_sgn
2508c2ecf20Sopenharmony_ci	tstl		LOCAL_LO(%a0)	|check lower mantissa
2518c2ecf20Sopenharmony_ci	bnes		ck_sgn
2528c2ecf20Sopenharmony_ci	bsetb		#z_bit,FPSR_CC(%a6) |set condition codes if zero
2538c2ecf20Sopenharmony_cick_sgn:
2548c2ecf20Sopenharmony_ci	btstb		#sign_bit,LOCAL_EX(%a0)	|check the sign bit
2558c2ecf20Sopenharmony_ci	beqs		unf_done
2568c2ecf20Sopenharmony_ci	bsetb		#neg_bit,FPSR_CC(%a6)
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci|
2598c2ecf20Sopenharmony_ci| Finish.
2608c2ecf20Sopenharmony_ci|
2618c2ecf20Sopenharmony_ciunf_done:
2628c2ecf20Sopenharmony_ci	btstb		#inex2_bit,FPSR_EXCEPT(%a6)
2638c2ecf20Sopenharmony_ci	beqs		no_aunfl
2648c2ecf20Sopenharmony_ci	bsetb		#aunfl_bit,FPSR_AEXCEPT(%a6)
2658c2ecf20Sopenharmony_cino_aunfl:
2668c2ecf20Sopenharmony_ci	rts
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	|end
269