162306a36Sopenharmony_ci|
262306a36Sopenharmony_ci|	x_unfl.sa 3.4 7/1/91
362306a36Sopenharmony_ci|
462306a36Sopenharmony_ci|	fpsp_unfl --- FPSP handler for underflow exception
562306a36Sopenharmony_ci|
662306a36Sopenharmony_ci| Trap disabled results
762306a36Sopenharmony_ci|	For 881/2 compatibility, sw must denormalize the intermediate
862306a36Sopenharmony_ci| result, then store the result.  Denormalization is accomplished
962306a36Sopenharmony_ci| by taking the intermediate result (which is always normalized) and
1062306a36Sopenharmony_ci| shifting the mantissa right while incrementing the exponent until
1162306a36Sopenharmony_ci| it is equal to the denormalized exponent for the destination
1262306a36Sopenharmony_ci| format.  After denormalization, the result is rounded to the
1362306a36Sopenharmony_ci| destination format.
1462306a36Sopenharmony_ci|
1562306a36Sopenharmony_ci| Trap enabled results
1662306a36Sopenharmony_ci|	All trap disabled code applies.	In addition the exceptional
1762306a36Sopenharmony_ci| operand needs to made available to the user with a bias of $6000
1862306a36Sopenharmony_ci| added to the exponent.
1962306a36Sopenharmony_ci|
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci|		Copyright (C) Motorola, Inc. 1990
2262306a36Sopenharmony_ci|			All Rights Reserved
2362306a36Sopenharmony_ci|
2462306a36Sopenharmony_ci|       For details on the license for this file, please see the
2562306a36Sopenharmony_ci|       file, README, in this same directory.
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ciX_UNFL:	|idnt    2,1 | Motorola 040 Floating Point Software Package
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	|section	8
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#include "fpsp.h"
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	|xref	denorm
3462306a36Sopenharmony_ci	|xref	round
3562306a36Sopenharmony_ci	|xref	store
3662306a36Sopenharmony_ci	|xref	g_rndpr
3762306a36Sopenharmony_ci	|xref	g_opcls
3862306a36Sopenharmony_ci	|xref	g_dfmtou
3962306a36Sopenharmony_ci	|xref	real_unfl
4062306a36Sopenharmony_ci	|xref	real_inex
4162306a36Sopenharmony_ci	|xref	fpsp_done
4262306a36Sopenharmony_ci	|xref	b1238_fix
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	.global	fpsp_unfl
4562306a36Sopenharmony_cifpsp_unfl:
4662306a36Sopenharmony_ci	link		%a6,#-LOCAL_SIZE
4762306a36Sopenharmony_ci	fsave		-(%a7)
4862306a36Sopenharmony_ci	moveml		%d0-%d1/%a0-%a1,USER_DA(%a6)
4962306a36Sopenharmony_ci	fmovemx	%fp0-%fp3,USER_FP0(%a6)
5062306a36Sopenharmony_ci	fmoveml	%fpcr/%fpsr/%fpiar,USER_FPCR(%a6)
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci|
5362306a36Sopenharmony_ci	bsrl		unf_res	|denormalize, round & store interm op
5462306a36Sopenharmony_ci|
5562306a36Sopenharmony_ci| If underflow exceptions are not enabled, check for inexact
5662306a36Sopenharmony_ci| exception
5762306a36Sopenharmony_ci|
5862306a36Sopenharmony_ci	btstb		#unfl_bit,FPCR_ENABLE(%a6)
5962306a36Sopenharmony_ci	beqs		ck_inex
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	btstb		#E3,E_BYTE(%a6)
6262306a36Sopenharmony_ci	beqs		no_e3_1
6362306a36Sopenharmony_ci|
6462306a36Sopenharmony_ci| Clear dirty bit on dest resister in the frame before branching
6562306a36Sopenharmony_ci| to b1238_fix.
6662306a36Sopenharmony_ci|
6762306a36Sopenharmony_ci	bfextu		CMDREG3B(%a6){#6:#3},%d0	|get dest reg no
6862306a36Sopenharmony_ci	bclrb		%d0,FPR_DIRTY_BITS(%a6)	|clr dest dirty bit
6962306a36Sopenharmony_ci	bsrl		b1238_fix		|test for bug1238 case
7062306a36Sopenharmony_ci	movel		USER_FPSR(%a6),FPSR_SHADOW(%a6)
7162306a36Sopenharmony_ci	orl		#sx_mask,E_BYTE(%a6)
7262306a36Sopenharmony_cino_e3_1:
7362306a36Sopenharmony_ci	moveml		USER_DA(%a6),%d0-%d1/%a0-%a1
7462306a36Sopenharmony_ci	fmovemx	USER_FP0(%a6),%fp0-%fp3
7562306a36Sopenharmony_ci	fmoveml	USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
7662306a36Sopenharmony_ci	frestore	(%a7)+
7762306a36Sopenharmony_ci	unlk		%a6
7862306a36Sopenharmony_ci	bral		real_unfl
7962306a36Sopenharmony_ci|
8062306a36Sopenharmony_ci| It is possible to have either inex2 or inex1 exceptions with the
8162306a36Sopenharmony_ci| unfl.  If the inex enable bit is set in the FPCR, and either
8262306a36Sopenharmony_ci| inex2 or inex1 occurred, we must clean up and branch to the
8362306a36Sopenharmony_ci| real inex handler.
8462306a36Sopenharmony_ci|
8562306a36Sopenharmony_cick_inex:
8662306a36Sopenharmony_ci	moveb		FPCR_ENABLE(%a6),%d0
8762306a36Sopenharmony_ci	andb		FPSR_EXCEPT(%a6),%d0
8862306a36Sopenharmony_ci	andib		#0x3,%d0
8962306a36Sopenharmony_ci	beqs		unfl_done
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci|
9262306a36Sopenharmony_ci| Inexact enabled and reported, and we must take an inexact exception
9362306a36Sopenharmony_ci|
9462306a36Sopenharmony_citake_inex:
9562306a36Sopenharmony_ci	btstb		#E3,E_BYTE(%a6)
9662306a36Sopenharmony_ci	beqs		no_e3_2
9762306a36Sopenharmony_ci|
9862306a36Sopenharmony_ci| Clear dirty bit on dest resister in the frame before branching
9962306a36Sopenharmony_ci| to b1238_fix.
10062306a36Sopenharmony_ci|
10162306a36Sopenharmony_ci	bfextu		CMDREG3B(%a6){#6:#3},%d0	|get dest reg no
10262306a36Sopenharmony_ci	bclrb		%d0,FPR_DIRTY_BITS(%a6)	|clr dest dirty bit
10362306a36Sopenharmony_ci	bsrl		b1238_fix		|test for bug1238 case
10462306a36Sopenharmony_ci	movel		USER_FPSR(%a6),FPSR_SHADOW(%a6)
10562306a36Sopenharmony_ci	orl		#sx_mask,E_BYTE(%a6)
10662306a36Sopenharmony_cino_e3_2:
10762306a36Sopenharmony_ci	moveb		#INEX_VEC,EXC_VEC+1(%a6)
10862306a36Sopenharmony_ci	moveml         USER_DA(%a6),%d0-%d1/%a0-%a1
10962306a36Sopenharmony_ci	fmovemx        USER_FP0(%a6),%fp0-%fp3
11062306a36Sopenharmony_ci	fmoveml        USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
11162306a36Sopenharmony_ci	frestore        (%a7)+
11262306a36Sopenharmony_ci	unlk            %a6
11362306a36Sopenharmony_ci	bral		real_inex
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ciunfl_done:
11662306a36Sopenharmony_ci	bclrb		#E3,E_BYTE(%a6)
11762306a36Sopenharmony_ci	beqs		e1_set		|if set then branch
11862306a36Sopenharmony_ci|
11962306a36Sopenharmony_ci| Clear dirty bit on dest resister in the frame before branching
12062306a36Sopenharmony_ci| to b1238_fix.
12162306a36Sopenharmony_ci|
12262306a36Sopenharmony_ci	bfextu		CMDREG3B(%a6){#6:#3},%d0		|get dest reg no
12362306a36Sopenharmony_ci	bclrb		%d0,FPR_DIRTY_BITS(%a6)	|clr dest dirty bit
12462306a36Sopenharmony_ci	bsrl		b1238_fix		|test for bug1238 case
12562306a36Sopenharmony_ci	movel		USER_FPSR(%a6),FPSR_SHADOW(%a6)
12662306a36Sopenharmony_ci	orl		#sx_mask,E_BYTE(%a6)
12762306a36Sopenharmony_ci	moveml		USER_DA(%a6),%d0-%d1/%a0-%a1
12862306a36Sopenharmony_ci	fmovemx	USER_FP0(%a6),%fp0-%fp3
12962306a36Sopenharmony_ci	fmoveml	USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
13062306a36Sopenharmony_ci	frestore	(%a7)+
13162306a36Sopenharmony_ci	unlk		%a6
13262306a36Sopenharmony_ci	bral		fpsp_done
13362306a36Sopenharmony_cie1_set:
13462306a36Sopenharmony_ci	moveml		USER_DA(%a6),%d0-%d1/%a0-%a1
13562306a36Sopenharmony_ci	fmovemx	USER_FP0(%a6),%fp0-%fp3
13662306a36Sopenharmony_ci	fmoveml	USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
13762306a36Sopenharmony_ci	unlk		%a6
13862306a36Sopenharmony_ci	bral		fpsp_done
13962306a36Sopenharmony_ci|
14062306a36Sopenharmony_ci|	unf_res --- underflow result calculation
14162306a36Sopenharmony_ci|
14262306a36Sopenharmony_ciunf_res:
14362306a36Sopenharmony_ci	bsrl		g_rndpr		|returns RND_PREC in d0 0=ext,
14462306a36Sopenharmony_ci|					;1=sgl, 2=dbl
14562306a36Sopenharmony_ci|					;we need the RND_PREC in the
14662306a36Sopenharmony_ci|					;upper word for round
14762306a36Sopenharmony_ci	movew		#0,-(%a7)
14862306a36Sopenharmony_ci	movew		%d0,-(%a7)	|copy RND_PREC to stack
14962306a36Sopenharmony_ci|
15062306a36Sopenharmony_ci|
15162306a36Sopenharmony_ci| If the exception bit set is E3, the exceptional operand from the
15262306a36Sopenharmony_ci| fpu is in WBTEMP; else it is in FPTEMP.
15362306a36Sopenharmony_ci|
15462306a36Sopenharmony_ci	btstb		#E3,E_BYTE(%a6)
15562306a36Sopenharmony_ci	beqs		unf_E1
15662306a36Sopenharmony_ciunf_E3:
15762306a36Sopenharmony_ci	lea		WBTEMP(%a6),%a0	|a0 now points to operand
15862306a36Sopenharmony_ci|
15962306a36Sopenharmony_ci| Test for fsgldiv and fsglmul.  If the inst was one of these, then
16062306a36Sopenharmony_ci| force the precision to extended for the denorm routine.  Use
16162306a36Sopenharmony_ci| the user's precision for the round routine.
16262306a36Sopenharmony_ci|
16362306a36Sopenharmony_ci	movew		CMDREG3B(%a6),%d1	|check for fsgldiv or fsglmul
16462306a36Sopenharmony_ci	andiw		#0x7f,%d1
16562306a36Sopenharmony_ci	cmpiw		#0x30,%d1		|check for sgldiv
16662306a36Sopenharmony_ci	beqs		unf_sgl
16762306a36Sopenharmony_ci	cmpiw		#0x33,%d1		|check for sglmul
16862306a36Sopenharmony_ci	bnes		unf_cont	|if not, use fpcr prec in round
16962306a36Sopenharmony_ciunf_sgl:
17062306a36Sopenharmony_ci	clrl		%d0
17162306a36Sopenharmony_ci	movew		#0x1,(%a7)	|override g_rndpr precision
17262306a36Sopenharmony_ci|					;force single
17362306a36Sopenharmony_ci	bras		unf_cont
17462306a36Sopenharmony_ciunf_E1:
17562306a36Sopenharmony_ci	lea		FPTEMP(%a6),%a0	|a0 now points to operand
17662306a36Sopenharmony_ciunf_cont:
17762306a36Sopenharmony_ci	bclrb		#sign_bit,LOCAL_EX(%a0)	|clear sign bit
17862306a36Sopenharmony_ci	sne		LOCAL_SGN(%a0)		|store sign
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	bsrl		denorm		|returns denorm, a0 points to it
18162306a36Sopenharmony_ci|
18262306a36Sopenharmony_ci| WARNING:
18362306a36Sopenharmony_ci|				;d0 has guard,round sticky bit
18462306a36Sopenharmony_ci|				;make sure that it is not corrupted
18562306a36Sopenharmony_ci|				;before it reaches the round subroutine
18662306a36Sopenharmony_ci|				;also ensure that a0 isn't corrupted
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci|
18962306a36Sopenharmony_ci| Set up d1 for round subroutine d1 contains the PREC/MODE
19062306a36Sopenharmony_ci| information respectively on upper/lower register halves.
19162306a36Sopenharmony_ci|
19262306a36Sopenharmony_ci	bfextu		FPCR_MODE(%a6){#2:#2},%d1	|get mode from FPCR
19362306a36Sopenharmony_ci|						;mode in lower d1
19462306a36Sopenharmony_ci	addl		(%a7)+,%d1		|merge PREC/MODE
19562306a36Sopenharmony_ci|
19662306a36Sopenharmony_ci| WARNING: a0 and d0 are assumed to be intact between the denorm and
19762306a36Sopenharmony_ci| round subroutines. All code between these two subroutines
19862306a36Sopenharmony_ci| must not corrupt a0 and d0.
19962306a36Sopenharmony_ci|
20062306a36Sopenharmony_ci|
20162306a36Sopenharmony_ci| Perform Round
20262306a36Sopenharmony_ci|	Input:		a0 points to input operand
20362306a36Sopenharmony_ci|			d0{31:29} has guard, round, sticky
20462306a36Sopenharmony_ci|			d1{01:00} has rounding mode
20562306a36Sopenharmony_ci|			d1{17:16} has rounding precision
20662306a36Sopenharmony_ci|	Output:		a0 points to rounded operand
20762306a36Sopenharmony_ci|
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	bsrl		round		|returns rounded denorm at (a0)
21062306a36Sopenharmony_ci|
21162306a36Sopenharmony_ci| Differentiate between store to memory vs. store to register
21262306a36Sopenharmony_ci|
21362306a36Sopenharmony_ciunf_store:
21462306a36Sopenharmony_ci	bsrl		g_opcls		|returns opclass in d0{2:0}
21562306a36Sopenharmony_ci	cmpib		#0x3,%d0
21662306a36Sopenharmony_ci	bnes		not_opc011
21762306a36Sopenharmony_ci|
21862306a36Sopenharmony_ci| At this point, a store to memory is pending
21962306a36Sopenharmony_ci|
22062306a36Sopenharmony_ciopc011:
22162306a36Sopenharmony_ci	bsrl		g_dfmtou
22262306a36Sopenharmony_ci	tstb		%d0
22362306a36Sopenharmony_ci	beqs		ext_opc011	|If extended, do not subtract
22462306a36Sopenharmony_ci|				;If destination format is sgl/dbl,
22562306a36Sopenharmony_ci	tstb		LOCAL_HI(%a0)	|If rounded result is normal,don't
22662306a36Sopenharmony_ci|					;subtract
22762306a36Sopenharmony_ci	bmis		ext_opc011
22862306a36Sopenharmony_ci	subqw		#1,LOCAL_EX(%a0)	|account for denorm bias vs.
22962306a36Sopenharmony_ci|				;normalized bias
23062306a36Sopenharmony_ci|				;          normalized   denormalized
23162306a36Sopenharmony_ci|				;single       $7f           $7e
23262306a36Sopenharmony_ci|				;double       $3ff          $3fe
23362306a36Sopenharmony_ci|
23462306a36Sopenharmony_ciext_opc011:
23562306a36Sopenharmony_ci	bsrl		store		|stores to memory
23662306a36Sopenharmony_ci	bras		unf_done	|finish up
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci|
23962306a36Sopenharmony_ci| At this point, a store to a float register is pending
24062306a36Sopenharmony_ci|
24162306a36Sopenharmony_cinot_opc011:
24262306a36Sopenharmony_ci	bsrl		store	|stores to float register
24362306a36Sopenharmony_ci|				;a0 is not corrupted on a store to a
24462306a36Sopenharmony_ci|				;float register.
24562306a36Sopenharmony_ci|
24662306a36Sopenharmony_ci| Set the condition codes according to result
24762306a36Sopenharmony_ci|
24862306a36Sopenharmony_ci	tstl		LOCAL_HI(%a0)	|check upper mantissa
24962306a36Sopenharmony_ci	bnes		ck_sgn
25062306a36Sopenharmony_ci	tstl		LOCAL_LO(%a0)	|check lower mantissa
25162306a36Sopenharmony_ci	bnes		ck_sgn
25262306a36Sopenharmony_ci	bsetb		#z_bit,FPSR_CC(%a6) |set condition codes if zero
25362306a36Sopenharmony_cick_sgn:
25462306a36Sopenharmony_ci	btstb		#sign_bit,LOCAL_EX(%a0)	|check the sign bit
25562306a36Sopenharmony_ci	beqs		unf_done
25662306a36Sopenharmony_ci	bsetb		#neg_bit,FPSR_CC(%a6)
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci|
25962306a36Sopenharmony_ci| Finish.
26062306a36Sopenharmony_ci|
26162306a36Sopenharmony_ciunf_done:
26262306a36Sopenharmony_ci	btstb		#inex2_bit,FPSR_EXCEPT(%a6)
26362306a36Sopenharmony_ci	beqs		no_aunfl
26462306a36Sopenharmony_ci	bsetb		#aunfl_bit,FPSR_AEXCEPT(%a6)
26562306a36Sopenharmony_cino_aunfl:
26662306a36Sopenharmony_ci	rts
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	|end
269