1|
2|	gen_except.sa 3.7 1/16/92
3|
4|	gen_except --- FPSP routine to detect reportable exceptions
5|
6|	This routine compares the exception enable byte of the
7|	user_fpcr on the stack with the exception status byte
8|	of the user_fpsr.
9|
10|	Any routine which may report an exceptions must load
11|	the stack frame in memory with the exceptional operand(s).
12|
13|	Priority for exceptions is:
14|
15|	Highest:	bsun
16|			snan
17|			operr
18|			ovfl
19|			unfl
20|			dz
21|			inex2
22|	Lowest:		inex1
23|
24|	Note: The IEEE standard specifies that inex2 is to be
25|	reported if ovfl occurs and the ovfl enable bit is not
26|	set but the inex2 enable bit is.
27|
28|
29|		Copyright (C) Motorola, Inc. 1990
30|			All Rights Reserved
31|
32|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA
33|	The copyright notice above does not evidence any
34|	actual or intended publication of such source code.
35
36GEN_EXCEPT:    |idnt    2,1 | Motorola 040 Floating Point Software Package
37
38	|section 8
39
40	.include "fpsp.h"
41
42	|xref	real_trace
43	|xref	fpsp_done
44	|xref	fpsp_fmt_error
45
46exc_tbl:
47	.long	bsun_exc
48	.long	commonE1
49	.long	commonE1
50	.long	ovfl_unfl
51	.long	ovfl_unfl
52	.long	commonE1
53	.long	commonE3
54	.long	commonE3
55	.long	no_match
56
57	.global	gen_except
58gen_except:
59	cmpib	#IDLE_SIZE-4,1(%a7)	|test for idle frame
60	beq	do_check		|go handle idle frame
61	cmpib	#UNIMP_40_SIZE-4,1(%a7)	|test for orig unimp frame
62	beqs	unimp_x			|go handle unimp frame
63	cmpib	#UNIMP_41_SIZE-4,1(%a7)	|test for rev unimp frame
64	beqs	unimp_x			|go handle unimp frame
65	cmpib	#BUSY_SIZE-4,1(%a7)	|if size <> $60, fmt error
66	bnel	fpsp_fmt_error
67	leal	BUSY_SIZE+LOCAL_SIZE(%a7),%a1 |init a1 so fpsp.h
68|					;equates will work
69| Fix up the new busy frame with entries from the unimp frame
70|
71	movel	ETEMP_EX(%a6),ETEMP_EX(%a1) |copy etemp from unimp
72	movel	ETEMP_HI(%a6),ETEMP_HI(%a1) |frame to busy frame
73	movel	ETEMP_LO(%a6),ETEMP_LO(%a1)
74	movel	CMDREG1B(%a6),CMDREG1B(%a1) |set inst in frame to unimp
75	movel	CMDREG1B(%a6),%d0		|fix cmd1b to make it
76	andl	#0x03c30000,%d0		|work for cmd3b
77	bfextu	CMDREG1B(%a6){#13:#1},%d1	|extract bit 2
78	lsll	#5,%d1
79	swap	%d1
80	orl	%d1,%d0			|put it in the right place
81	bfextu	CMDREG1B(%a6){#10:#3},%d1	|extract bit 3,4,5
82	lsll	#2,%d1
83	swap	%d1
84	orl	%d1,%d0			|put them in the right place
85	movel	%d0,CMDREG3B(%a1)		|in the busy frame
86|
87| Or in the FPSR from the emulation with the USER_FPSR on the stack.
88|
89	fmovel	%FPSR,%d0
90	orl	%d0,USER_FPSR(%a6)
91	movel	USER_FPSR(%a6),FPSR_SHADOW(%a1) |set exc bits
92	orl	#sx_mask,E_BYTE(%a1)
93	bra	do_clean
94
95|
96| Frame is an unimp frame possible resulting from an fmove <ea>,fp0
97| that caused an exception
98|
99| a1 is modified to point into the new frame allowing fpsp equates
100| to be valid.
101|
102unimp_x:
103	cmpib	#UNIMP_40_SIZE-4,1(%a7)	|test for orig unimp frame
104	bnes	test_rev
105	leal	UNIMP_40_SIZE+LOCAL_SIZE(%a7),%a1
106	bras	unimp_con
107test_rev:
108	cmpib	#UNIMP_41_SIZE-4,1(%a7)	|test for rev unimp frame
109	bnel	fpsp_fmt_error		|if not $28 or $30
110	leal	UNIMP_41_SIZE+LOCAL_SIZE(%a7),%a1
111
112unimp_con:
113|
114| Fix up the new unimp frame with entries from the old unimp frame
115|
116	movel	CMDREG1B(%a6),CMDREG1B(%a1) |set inst in frame to unimp
117|
118| Or in the FPSR from the emulation with the USER_FPSR on the stack.
119|
120	fmovel	%FPSR,%d0
121	orl	%d0,USER_FPSR(%a6)
122	bra	do_clean
123
124|
125| Frame is idle, so check for exceptions reported through
126| USER_FPSR and set the unimp frame accordingly.
127| A7 must be incremented to the point before the
128| idle fsave vector to the unimp vector.
129|
130
131do_check:
132	addl	#4,%a7			|point A7 back to unimp frame
133|
134| Or in the FPSR from the emulation with the USER_FPSR on the stack.
135|
136	fmovel	%FPSR,%d0
137	orl	%d0,USER_FPSR(%a6)
138|
139| On a busy frame, we must clear the nmnexc bits.
140|
141	cmpib	#BUSY_SIZE-4,1(%a7)	|check frame type
142	bnes	check_fr		|if busy, clr nmnexc
143	clrw	NMNEXC(%a6)		|clr nmnexc & nmcexc
144	btstb	#5,CMDREG1B(%a6)		|test for fmove out
145	bnes	frame_com
146	movel	USER_FPSR(%a6),FPSR_SHADOW(%a6) |set exc bits
147	orl	#sx_mask,E_BYTE(%a6)
148	bras	frame_com
149check_fr:
150	cmpb	#UNIMP_40_SIZE-4,1(%a7)
151	beqs	frame_com
152	clrw	NMNEXC(%a6)
153frame_com:
154	moveb	FPCR_ENABLE(%a6),%d0	|get fpcr enable byte
155	andb	FPSR_EXCEPT(%a6),%d0	|and in the fpsr exc byte
156	bfffo	%d0{#24:#8},%d1		|test for first set bit
157	leal	exc_tbl,%a0		|load jmp table address
158	subib	#24,%d1			|normalize bit offset to 0-8
159	movel	(%a0,%d1.w*4),%a0		|load routine address based
160|					;based on first enabled exc
161	jmp	(%a0)			|jump to routine
162|
163| Bsun is not possible in unimp or unsupp
164|
165bsun_exc:
166	bra	do_clean
167|
168| The typical work to be done to the unimp frame to report an
169| exception is to set the E1/E3 byte and clr the U flag.
170| commonE1 does this for E1 exceptions, which are snan,
171| operr, and dz.  commonE3 does this for E3 exceptions, which
172| are inex2 and inex1, and also clears the E1 exception bit
173| left over from the unimp exception.
174|
175commonE1:
176	bsetb	#E1,E_BYTE(%a6)		|set E1 flag
177	bra	commonE			|go clean and exit
178
179commonE3:
180	tstb	UFLG_TMP(%a6)		|test flag for unsup/unimp state
181	bnes	unsE3
182uniE3:
183	bsetb	#E3,E_BYTE(%a6)		|set E3 flag
184	bclrb	#E1,E_BYTE(%a6)		|clr E1 from unimp
185	bra	commonE
186
187unsE3:
188	tstb	RES_FLG(%a6)
189	bnes	unsE3_0
190unsE3_1:
191	bsetb	#E3,E_BYTE(%a6)		|set E3 flag
192unsE3_0:
193	bclrb	#E1,E_BYTE(%a6)		|clr E1 flag
194	movel	CMDREG1B(%a6),%d0
195	andl	#0x03c30000,%d0		|work for cmd3b
196	bfextu	CMDREG1B(%a6){#13:#1},%d1	|extract bit 2
197	lsll	#5,%d1
198	swap	%d1
199	orl	%d1,%d0			|put it in the right place
200	bfextu	CMDREG1B(%a6){#10:#3},%d1	|extract bit 3,4,5
201	lsll	#2,%d1
202	swap	%d1
203	orl	%d1,%d0			|put them in the right place
204	movel	%d0,CMDREG3B(%a6)		|in the busy frame
205
206commonE:
207	bclrb	#UFLAG,T_BYTE(%a6)	|clr U flag from unimp
208	bra	do_clean		|go clean and exit
209|
210| No bits in the enable byte match existing exceptions.  Check for
211| the case of the ovfl exc without the ovfl enabled, but with
212| inex2 enabled.
213|
214no_match:
215	btstb	#inex2_bit,FPCR_ENABLE(%a6) |check for ovfl/inex2 case
216	beqs	no_exc			|if clear, exit
217	btstb	#ovfl_bit,FPSR_EXCEPT(%a6) |now check ovfl
218	beqs	no_exc			|if clear, exit
219	bras	ovfl_unfl		|go to unfl_ovfl to determine if
220|					;it is an unsupp or unimp exc
221
222| No exceptions are to be reported.  If the instruction was
223| unimplemented, no FPU restore is necessary.  If it was
224| unsupported, we must perform the restore.
225no_exc:
226	tstb	UFLG_TMP(%a6)	|test flag for unsupp/unimp state
227	beqs	uni_no_exc
228uns_no_exc:
229	tstb	RES_FLG(%a6)	|check if frestore is needed
230	bne	do_clean 	|if clear, no frestore needed
231uni_no_exc:
232	moveml	USER_DA(%a6),%d0-%d1/%a0-%a1
233	fmovemx USER_FP0(%a6),%fp0-%fp3
234	fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
235	unlk	%a6
236	bra	finish_up
237|
238| Unsupported Data Type Handler:
239| Ovfl:
240|   An fmoveout that results in an overflow is reported this way.
241| Unfl:
242|   An fmoveout that results in an underflow is reported this way.
243|
244| Unimplemented Instruction Handler:
245| Ovfl:
246|   Only scosh, setox, ssinh, stwotox, and scale can set overflow in
247|   this manner.
248| Unfl:
249|   Stwotox, setox, and scale can set underflow in this manner.
250|   Any of the other Library Routines such that f(x)=x in which
251|   x is an extended denorm can report an underflow exception.
252|   It is the responsibility of the exception-causing exception
253|   to make sure that WBTEMP is correct.
254|
255|   The exceptional operand is in FP_SCR1.
256|
257ovfl_unfl:
258	tstb	UFLG_TMP(%a6)	|test flag for unsupp/unimp state
259	beqs	ofuf_con
260|
261| The caller was from an unsupported data type trap.  Test if the
262| caller set CU_ONLY.  If so, the exceptional operand is expected in
263| FPTEMP, rather than WBTEMP.
264|
265	tstb	CU_ONLY(%a6)		|test if inst is cu-only
266	beq	unsE3
267|	move.w	#$fe,CU_SAVEPC(%a6)
268	clrb	CU_SAVEPC(%a6)
269	bsetb	#E1,E_BYTE(%a6)		|set E1 exception flag
270	movew	ETEMP_EX(%a6),FPTEMP_EX(%a6)
271	movel	ETEMP_HI(%a6),FPTEMP_HI(%a6)
272	movel	ETEMP_LO(%a6),FPTEMP_LO(%a6)
273	bsetb	#fptemp15_bit,DTAG(%a6)	|set fpte15
274	bclrb	#UFLAG,T_BYTE(%a6)	|clr U flag from unimp
275	bra	do_clean		|go clean and exit
276
277ofuf_con:
278	moveb	(%a7),VER_TMP(%a6)	|save version number
279	cmpib	#BUSY_SIZE-4,1(%a7)	|check for busy frame
280	beqs	busy_fr			|if unimp, grow to busy
281	cmpib	#VER_40,(%a7)		|test for orig unimp frame
282	bnes	try_41			|if not, test for rev frame
283	moveql	#13,%d0			|need to zero 14 lwords
284	bras	ofuf_fin
285try_41:
286	cmpib	#VER_41,(%a7)		|test for rev unimp frame
287	bnel	fpsp_fmt_error		|if neither, exit with error
288	moveql	#11,%d0			|need to zero 12 lwords
289
290ofuf_fin:
291	clrl	(%a7)
292loop1:
293	clrl	-(%a7)			|clear and dec a7
294	dbra	%d0,loop1
295	moveb	VER_TMP(%a6),(%a7)
296	moveb	#BUSY_SIZE-4,1(%a7)		|write busy fmt word.
297busy_fr:
298	movel	FP_SCR1(%a6),WBTEMP_EX(%a6)	|write
299	movel	FP_SCR1+4(%a6),WBTEMP_HI(%a6)	|exceptional op to
300	movel	FP_SCR1+8(%a6),WBTEMP_LO(%a6)	|wbtemp
301	bsetb	#E3,E_BYTE(%a6)			|set E3 flag
302	bclrb	#E1,E_BYTE(%a6)			|make sure E1 is clear
303	bclrb	#UFLAG,T_BYTE(%a6)		|clr U flag
304	movel	USER_FPSR(%a6),FPSR_SHADOW(%a6)
305	orl	#sx_mask,E_BYTE(%a6)
306	movel	CMDREG1B(%a6),%d0		|fix cmd1b to make it
307	andl	#0x03c30000,%d0		|work for cmd3b
308	bfextu	CMDREG1B(%a6){#13:#1},%d1	|extract bit 2
309	lsll	#5,%d1
310	swap	%d1
311	orl	%d1,%d0			|put it in the right place
312	bfextu	CMDREG1B(%a6){#10:#3},%d1	|extract bit 3,4,5
313	lsll	#2,%d1
314	swap	%d1
315	orl	%d1,%d0			|put them in the right place
316	movel	%d0,CMDREG3B(%a6)		|in the busy frame
317
318|
319| Check if the frame to be restored is busy or unimp.
320|** NOTE *** Bug fix for errata (0d43b #3)
321| If the frame is unimp, we must create a busy frame to
322| fix the bug with the nmnexc bits in cases in which they
323| are set by a previous instruction and not cleared by
324| the save. The frame will be unimp only if the final
325| instruction in an emulation routine caused the exception
326| by doing an fmove <ea>,fp0.  The exception operand, in
327| internal format, is in fptemp.
328|
329do_clean:
330	cmpib	#UNIMP_40_SIZE-4,1(%a7)
331	bnes	do_con
332	moveql	#13,%d0			|in orig, need to zero 14 lwords
333	bras	do_build
334do_con:
335	cmpib	#UNIMP_41_SIZE-4,1(%a7)
336	bnes	do_restore		|frame must be busy
337	moveql	#11,%d0			|in rev, need to zero 12 lwords
338
339do_build:
340	moveb	(%a7),VER_TMP(%a6)
341	clrl	(%a7)
342loop2:
343	clrl	-(%a7)			|clear and dec a7
344	dbra	%d0,loop2
345|
346| Use a1 as pointer into new frame.  a6 is not correct if an unimp or
347| busy frame was created as the result of an exception on the final
348| instruction of an emulation routine.
349|
350| We need to set the nmcexc bits if the exception is E1. Otherwise,
351| the exc taken will be inex2.
352|
353	leal	BUSY_SIZE+LOCAL_SIZE(%a7),%a1	|init a1 for new frame
354	moveb	VER_TMP(%a6),(%a7)	|write busy fmt word
355	moveb	#BUSY_SIZE-4,1(%a7)
356	movel	FP_SCR1(%a6),WBTEMP_EX(%a1) 	|write
357	movel	FP_SCR1+4(%a6),WBTEMP_HI(%a1)	|exceptional op to
358	movel	FP_SCR1+8(%a6),WBTEMP_LO(%a1)	|wbtemp
359|	btst.b	#E1,E_BYTE(%a1)
360|	beq.b	do_restore
361	bfextu	USER_FPSR(%a6){#17:#4},%d0	|get snan/operr/ovfl/unfl bits
362	bfins	%d0,NMCEXC(%a1){#4:#4}	|and insert them in nmcexc
363	movel	USER_FPSR(%a6),FPSR_SHADOW(%a1) |set exc bits
364	orl	#sx_mask,E_BYTE(%a1)
365
366do_restore:
367	moveml	USER_DA(%a6),%d0-%d1/%a0-%a1
368	fmovemx USER_FP0(%a6),%fp0-%fp3
369	fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
370	frestore (%a7)+
371	tstb	RES_FLG(%a6)	|RES_FLG indicates a "continuation" frame
372	beq	cont
373	bsr	bug1384
374cont:
375	unlk	%a6
376|
377| If trace mode enabled, then go to trace handler.  This handler
378| cannot have any fp instructions.  If there are fp inst's and an
379| exception has been restored into the machine then the exception
380| will occur upon execution of the fp inst.  This is not desirable
381| in the kernel (supervisor mode).  See MC68040 manual Section 9.3.8.
382|
383finish_up:
384	btstb	#7,(%a7)		|test T1 in SR
385	bnes	g_trace
386	btstb	#6,(%a7)		|test T0 in SR
387	bnes	g_trace
388	bral	fpsp_done
389|
390| Change integer stack to look like trace stack
391| The address of the instruction that caused the
392| exception is already in the integer stack (is
393| the same as the saved friar)
394|
395| If the current frame is already a 6-word stack then all
396| that needs to be done is to change the vector# to TRACE.
397| If the frame is only a 4-word stack (meaning we got here
398| on an Unsupported data type exception), then we need to grow
399| the stack an extra 2 words and get the FPIAR from the FPU.
400|
401g_trace:
402	bftst	EXC_VEC-4(%sp){#0:#4}
403	bne	g_easy
404
405	subw	#4,%sp		| make room
406	movel	4(%sp),(%sp)
407	movel	8(%sp),4(%sp)
408	subw	#BUSY_SIZE,%sp
409	fsave	(%sp)
410	fmovel	%fpiar,BUSY_SIZE+EXC_EA-4(%sp)
411	frestore (%sp)
412	addw	#BUSY_SIZE,%sp
413
414g_easy:
415	movew	#TRACE_VEC,EXC_VEC-4(%a7)
416	bral	real_trace
417|
418|  This is a work-around for hardware bug 1384.
419|
420bug1384:
421	link	%a5,#0
422	fsave	-(%sp)
423	cmpib	#0x41,(%sp)	| check for correct frame
424	beq	frame_41
425	bgt	nofix		| if more advanced mask, do nada
426
427frame_40:
428	tstb	1(%sp)		| check to see if idle
429	bne	notidle
430idle40:
431	clrl	(%sp)		| get rid of old fsave frame
432        movel  %d1,USER_D1(%a6)  | save d1
433	movew	#8,%d1		| place unimp frame instead
434loop40:	clrl	-(%sp)
435	dbra	%d1,loop40
436        movel  USER_D1(%a6),%d1  | restore d1
437	movel	#0x40280000,-(%sp)
438	frestore (%sp)+
439	unlk  	%a5
440	rts
441
442frame_41:
443	tstb	1(%sp)		| check to see if idle
444	bne	notidle
445idle41:
446	clrl	(%sp)		| get rid of old fsave frame
447        movel  %d1,USER_D1(%a6)  | save d1
448	movew	#10,%d1		| place unimp frame instead
449loop41:	clrl	-(%sp)
450	dbra	%d1,loop41
451        movel  USER_D1(%a6),%d1  | restore d1
452	movel	#0x41300000,-(%sp)
453	frestore (%sp)+
454	unlk	%a5
455	rts
456
457notidle:
458	bclrb	#etemp15_bit,-40(%a5)
459	frestore (%sp)+
460	unlk	%a5
461	rts
462
463nofix:
464	frestore (%sp)+
465	unlk	%a5
466	rts
467
468	|end
469