1|
2|	x_unfl.sa 3.4 7/1/91
3|
4|	fpsp_unfl --- FPSP handler for underflow exception
5|
6| Trap disabled results
7|	For 881/2 compatibility, sw must denormalize the intermediate
8| result, then store the result.  Denormalization is accomplished
9| by taking the intermediate result (which is always normalized) and
10| shifting the mantissa right while incrementing the exponent until
11| it is equal to the denormalized exponent for the destination
12| format.  After denormalization, the result is rounded to the
13| destination format.
14|
15| Trap enabled results
16| 	All trap disabled code applies.	In addition the exceptional
17| operand needs to made available to the user with a bias of $6000
18| added to the exponent.
19|
20
21|		Copyright (C) Motorola, Inc. 1990
22|			All Rights Reserved
23|
24|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA
25|	The copyright notice above does not evidence any
26|	actual or intended publication of such source code.
27
28X_UNFL:	|idnt    2,1 | Motorola 040 Floating Point Software Package
29
30	|section	8
31
32	.include "fpsp.h"
33
34	|xref	denorm
35	|xref	round
36	|xref	store
37	|xref	g_rndpr
38	|xref	g_opcls
39	|xref	g_dfmtou
40	|xref	real_unfl
41	|xref	real_inex
42	|xref	fpsp_done
43	|xref	b1238_fix
44
45	.global	fpsp_unfl
46fpsp_unfl:
47	link		%a6,#-LOCAL_SIZE
48	fsave		-(%a7)
49	moveml		%d0-%d1/%a0-%a1,USER_DA(%a6)
50	fmovemx	%fp0-%fp3,USER_FP0(%a6)
51	fmoveml	%fpcr/%fpsr/%fpiar,USER_FPCR(%a6)
52
53|
54	bsrl		unf_res	|denormalize, round & store interm op
55|
56| If underflow exceptions are not enabled, check for inexact
57| exception
58|
59	btstb		#unfl_bit,FPCR_ENABLE(%a6)
60	beqs		ck_inex
61
62	btstb		#E3,E_BYTE(%a6)
63	beqs		no_e3_1
64|
65| Clear dirty bit on dest resister in the frame before branching
66| to b1238_fix.
67|
68	bfextu		CMDREG3B(%a6){#6:#3},%d0	|get dest reg no
69	bclrb		%d0,FPR_DIRTY_BITS(%a6)	|clr dest dirty bit
70	bsrl		b1238_fix		|test for bug1238 case
71	movel		USER_FPSR(%a6),FPSR_SHADOW(%a6)
72	orl		#sx_mask,E_BYTE(%a6)
73no_e3_1:
74	moveml		USER_DA(%a6),%d0-%d1/%a0-%a1
75	fmovemx	USER_FP0(%a6),%fp0-%fp3
76	fmoveml	USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
77	frestore	(%a7)+
78	unlk		%a6
79	bral		real_unfl
80|
81| It is possible to have either inex2 or inex1 exceptions with the
82| unfl.  If the inex enable bit is set in the FPCR, and either
83| inex2 or inex1 occurred, we must clean up and branch to the
84| real inex handler.
85|
86ck_inex:
87	moveb		FPCR_ENABLE(%a6),%d0
88	andb		FPSR_EXCEPT(%a6),%d0
89	andib		#0x3,%d0
90	beqs		unfl_done
91
92|
93| Inexact enabled and reported, and we must take an inexact exception
94|
95take_inex:
96	btstb		#E3,E_BYTE(%a6)
97	beqs		no_e3_2
98|
99| Clear dirty bit on dest resister in the frame before branching
100| to b1238_fix.
101|
102	bfextu		CMDREG3B(%a6){#6:#3},%d0	|get dest reg no
103	bclrb		%d0,FPR_DIRTY_BITS(%a6)	|clr dest dirty bit
104	bsrl		b1238_fix		|test for bug1238 case
105	movel		USER_FPSR(%a6),FPSR_SHADOW(%a6)
106	orl		#sx_mask,E_BYTE(%a6)
107no_e3_2:
108	moveb		#INEX_VEC,EXC_VEC+1(%a6)
109	moveml         USER_DA(%a6),%d0-%d1/%a0-%a1
110	fmovemx        USER_FP0(%a6),%fp0-%fp3
111	fmoveml        USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
112	frestore        (%a7)+
113	unlk            %a6
114	bral		real_inex
115
116unfl_done:
117	bclrb		#E3,E_BYTE(%a6)
118	beqs		e1_set		|if set then branch
119|
120| Clear dirty bit on dest resister in the frame before branching
121| to b1238_fix.
122|
123	bfextu		CMDREG3B(%a6){#6:#3},%d0		|get dest reg no
124	bclrb		%d0,FPR_DIRTY_BITS(%a6)	|clr dest dirty bit
125	bsrl		b1238_fix		|test for bug1238 case
126	movel		USER_FPSR(%a6),FPSR_SHADOW(%a6)
127	orl		#sx_mask,E_BYTE(%a6)
128	moveml		USER_DA(%a6),%d0-%d1/%a0-%a1
129	fmovemx	USER_FP0(%a6),%fp0-%fp3
130	fmoveml	USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
131	frestore	(%a7)+
132	unlk		%a6
133	bral		fpsp_done
134e1_set:
135	moveml		USER_DA(%a6),%d0-%d1/%a0-%a1
136	fmovemx	USER_FP0(%a6),%fp0-%fp3
137	fmoveml	USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
138	unlk		%a6
139	bral		fpsp_done
140|
141|	unf_res --- underflow result calculation
142|
143unf_res:
144	bsrl		g_rndpr		|returns RND_PREC in d0 0=ext,
145|					;1=sgl, 2=dbl
146|					;we need the RND_PREC in the
147|					;upper word for round
148	movew		#0,-(%a7)
149	movew		%d0,-(%a7)	|copy RND_PREC to stack
150|
151|
152| If the exception bit set is E3, the exceptional operand from the
153| fpu is in WBTEMP; else it is in FPTEMP.
154|
155	btstb		#E3,E_BYTE(%a6)
156	beqs		unf_E1
157unf_E3:
158	lea		WBTEMP(%a6),%a0	|a0 now points to operand
159|
160| Test for fsgldiv and fsglmul.  If the inst was one of these, then
161| force the precision to extended for the denorm routine.  Use
162| the user's precision for the round routine.
163|
164	movew		CMDREG3B(%a6),%d1	|check for fsgldiv or fsglmul
165	andiw		#0x7f,%d1
166	cmpiw		#0x30,%d1		|check for sgldiv
167	beqs		unf_sgl
168	cmpiw		#0x33,%d1		|check for sglmul
169	bnes		unf_cont	|if not, use fpcr prec in round
170unf_sgl:
171	clrl		%d0
172	movew		#0x1,(%a7)	|override g_rndpr precision
173|					;force single
174	bras		unf_cont
175unf_E1:
176	lea		FPTEMP(%a6),%a0	|a0 now points to operand
177unf_cont:
178	bclrb		#sign_bit,LOCAL_EX(%a0)	|clear sign bit
179	sne		LOCAL_SGN(%a0)		|store sign
180
181	bsrl		denorm		|returns denorm, a0 points to it
182|
183| WARNING:
184|				;d0 has guard,round sticky bit
185|				;make sure that it is not corrupted
186|				;before it reaches the round subroutine
187|				;also ensure that a0 isn't corrupted
188
189|
190| Set up d1 for round subroutine d1 contains the PREC/MODE
191| information respectively on upper/lower register halves.
192|
193	bfextu		FPCR_MODE(%a6){#2:#2},%d1	|get mode from FPCR
194|						;mode in lower d1
195	addl		(%a7)+,%d1		|merge PREC/MODE
196|
197| WARNING: a0 and d0 are assumed to be intact between the denorm and
198| round subroutines. All code between these two subroutines
199| must not corrupt a0 and d0.
200|
201|
202| Perform Round
203|	Input:		a0 points to input operand
204|			d0{31:29} has guard, round, sticky
205|			d1{01:00} has rounding mode
206|			d1{17:16} has rounding precision
207|	Output:		a0 points to rounded operand
208|
209
210	bsrl		round		|returns rounded denorm at (a0)
211|
212| Differentiate between store to memory vs. store to register
213|
214unf_store:
215	bsrl		g_opcls		|returns opclass in d0{2:0}
216	cmpib		#0x3,%d0
217	bnes		not_opc011
218|
219| At this point, a store to memory is pending
220|
221opc011:
222	bsrl		g_dfmtou
223	tstb		%d0
224	beqs		ext_opc011	|If extended, do not subtract
225| 				;If destination format is sgl/dbl,
226	tstb		LOCAL_HI(%a0)	|If rounded result is normal,don't
227|					;subtract
228	bmis		ext_opc011
229	subqw		#1,LOCAL_EX(%a0)	|account for denorm bias vs.
230|				;normalized bias
231|				;          normalized   denormalized
232|				;single       $7f           $7e
233|				;double       $3ff          $3fe
234|
235ext_opc011:
236	bsrl		store		|stores to memory
237	bras		unf_done	|finish up
238
239|
240| At this point, a store to a float register is pending
241|
242not_opc011:
243	bsrl		store	|stores to float register
244|				;a0 is not corrupted on a store to a
245|				;float register.
246|
247| Set the condition codes according to result
248|
249	tstl		LOCAL_HI(%a0)	|check upper mantissa
250	bnes		ck_sgn
251	tstl		LOCAL_LO(%a0)	|check lower mantissa
252	bnes		ck_sgn
253	bsetb		#z_bit,FPSR_CC(%a6) |set condition codes if zero
254ck_sgn:
255	btstb 		#sign_bit,LOCAL_EX(%a0)	|check the sign bit
256	beqs		unf_done
257	bsetb		#neg_bit,FPSR_CC(%a6)
258
259|
260| Finish.
261|
262unf_done:
263	btstb		#inex2_bit,FPSR_EXCEPT(%a6)
264	beqs		no_aunfl
265	bsetb		#aunfl_bit,FPSR_AEXCEPT(%a6)
266no_aunfl:
267	rts
268
269	|end
270