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