1|
2|	skeleton.sa 3.2 4/26/91
3|
4|	This file contains code that is system dependent and will
5|	need to be modified to install the FPSP.
6|
7|	Each entry point for exception 'xxxx' begins with a 'jmp fpsp_xxxx'.
8|	Put any target system specific handling that must be done immediately
9|	before the jump instruction.  If there no handling necessary, then
10|	the 'fpsp_xxxx' handler entry point should be placed in the exception
11|	table so that the 'jmp' can be eliminated. If the FPSP determines that the
12|	exception is one that must be reported then there will be a
13|	return from the package by a 'jmp real_xxxx'.  At that point
14|	the machine state will be identical to the state before
15|	the FPSP was entered.  In particular, whatever condition
16|	that caused the exception will still be pending when the FPSP
17|	package returns.  Thus, there will be system specific code
18|	to handle the exception.
19|
20|	If the exception was completely handled by the package, then
21|	the return will be via a 'jmp fpsp_done'.  Unless there is
22|	OS specific work to be done (such as handling a context switch or
23|	interrupt) the user program can be resumed via 'rte'.
24|
25|	In the following skeleton code, some typical 'real_xxxx' handling
26|	code is shown.  This code may need to be moved to an appropriate
27|	place in the target system, or rewritten.
28|
29
30|		Copyright (C) Motorola, Inc. 1990
31|			All Rights Reserved
32|
33|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA
34|	The copyright notice above does not evidence any
35|	actual or intended publication of such source code.
36
37|
38|	Modified for Linux-1.3.x by Jes Sorensen (jds@kom.auc.dk)
39|
40
41#include <linux/linkage.h>
42#include <asm/entry.h>
43#include "../kernel/m68k_defs.h"
44
45|SKELETON	idnt    2,1 | Motorola 040 Floating Point Software Package
46
47	|section 15
48|
49|	The following counters are used for standalone testing
50|
51
52	|section 8
53
54	.include "fpsp.h"
55
56	|xref	b1238_fix
57
58|
59|	Divide by Zero exception
60|
61|	All dz exceptions are 'real', hence no fpsp_dz entry point.
62|
63	.global	dz
64	.global	real_dz
65dz:
66real_dz:
67	link		%a6,#-LOCAL_SIZE
68	fsave		-(%sp)
69	bclrb		#E1,E_BYTE(%a6)
70	frestore	(%sp)+
71	unlk		%a6
72
73	SAVE_ALL_INT
74	GET_CURRENT(%d0)
75	movel	%sp,%sp@- 		| stack frame pointer argument
76	bsrl	SYMBOL_NAME(trap_c)
77	addql	#4,%sp
78	bral	SYMBOL_NAME(ret_from_exception)
79
80|
81|	Inexact exception
82|
83|	All inexact exceptions are real, but the 'real' handler
84|	will probably want to clear the pending exception.
85|	The provided code will clear the E3 exception (if pending),
86|	otherwise clear the E1 exception.  The frestore is not really
87|	necessary for E1 exceptions.
88|
89| Code following the 'inex' label is to handle bug #1232.  In this
90| bug, if an E1 snan, ovfl, or unfl occurred, and the process was
91| swapped out before taking the exception, the exception taken on
92| return was inex, rather than the correct exception.  The snan, ovfl,
93| and unfl exception to be taken must not have been enabled.  The
94| fix is to check for E1, and the existence of one of snan, ovfl,
95| or unfl bits set in the fpsr.  If any of these are set, branch
96| to the appropriate  handler for the exception in the fpsr.  Note
97| that this fix is only for d43b parts, and is skipped if the
98| version number is not $40.
99|
100|
101	.global	real_inex
102	.global	inex
103inex:
104	link		%a6,#-LOCAL_SIZE
105	fsave		-(%sp)
106	cmpib		#VER_40,(%sp)		|test version number
107	bnes		not_fmt40
108	fmovel		%fpsr,-(%sp)
109	btstb		#E1,E_BYTE(%a6)		|test for E1 set
110	beqs		not_b1232
111	btstb		#snan_bit,2(%sp) |test for snan
112	beq		inex_ckofl
113	addl		#4,%sp
114	frestore	(%sp)+
115	unlk		%a6
116	bra		snan
117inex_ckofl:
118	btstb		#ovfl_bit,2(%sp) |test for ovfl
119	beq		inex_ckufl
120	addl		#4,%sp
121	frestore	(%sp)+
122	unlk		%a6
123	bra		ovfl
124inex_ckufl:
125	btstb		#unfl_bit,2(%sp) |test for unfl
126	beq		not_b1232
127	addl		#4,%sp
128	frestore	(%sp)+
129	unlk		%a6
130	bra		unfl
131
132|
133| We do not have the bug 1232 case.  Clean up the stack and call
134| real_inex.
135|
136not_b1232:
137	addl		#4,%sp
138	frestore	(%sp)+
139	unlk		%a6
140
141real_inex:
142
143	link		%a6,#-LOCAL_SIZE
144	fsave		-(%sp)
145not_fmt40:
146	bclrb		#E3,E_BYTE(%a6)		|clear and test E3 flag
147	beqs		inex_cke1
148|
149| Clear dirty bit on dest resister in the frame before branching
150| to b1238_fix.
151|
152	moveml		%d0/%d1,USER_DA(%a6)
153	bfextu		CMDREG1B(%a6){#6:#3},%d0		|get dest reg no
154	bclrb		%d0,FPR_DIRTY_BITS(%a6)	|clr dest dirty bit
155	bsrl		b1238_fix		|test for bug1238 case
156	moveml		USER_DA(%a6),%d0/%d1
157	bras		inex_done
158inex_cke1:
159	bclrb		#E1,E_BYTE(%a6)
160inex_done:
161	frestore	(%sp)+
162	unlk		%a6
163
164	SAVE_ALL_INT
165	GET_CURRENT(%d0)
166	movel	%sp,%sp@- 		| stack frame pointer argument
167	bsrl	SYMBOL_NAME(trap_c)
168	addql	#4,%sp
169	bral	SYMBOL_NAME(ret_from_exception)
170
171|
172|	Overflow exception
173|
174	|xref	fpsp_ovfl
175	.global	real_ovfl
176	.global	ovfl
177ovfl:
178	jmp	fpsp_ovfl
179real_ovfl:
180
181	link		%a6,#-LOCAL_SIZE
182	fsave		-(%sp)
183	bclrb		#E3,E_BYTE(%a6)		|clear and test E3 flag
184	bnes		ovfl_done
185	bclrb		#E1,E_BYTE(%a6)
186ovfl_done:
187	frestore	(%sp)+
188	unlk		%a6
189
190	SAVE_ALL_INT
191	GET_CURRENT(%d0)
192	movel	%sp,%sp@- 		| stack frame pointer argument
193	bsrl	SYMBOL_NAME(trap_c)
194	addql	#4,%sp
195	bral	SYMBOL_NAME(ret_from_exception)
196
197|
198|	Underflow exception
199|
200	|xref	fpsp_unfl
201	.global	real_unfl
202	.global	unfl
203unfl:
204	jmp	fpsp_unfl
205real_unfl:
206
207	link		%a6,#-LOCAL_SIZE
208	fsave		-(%sp)
209	bclrb		#E3,E_BYTE(%a6)		|clear and test E3 flag
210	bnes		unfl_done
211	bclrb		#E1,E_BYTE(%a6)
212unfl_done:
213	frestore	(%sp)+
214	unlk		%a6
215
216	SAVE_ALL_INT
217	GET_CURRENT(%d0)
218	movel	%sp,%sp@- 		| stack frame pointer argument
219	bsrl	SYMBOL_NAME(trap_c)
220	addql	#4,%sp
221	bral	SYMBOL_NAME(ret_from_exception)
222
223|
224|	Signalling NAN exception
225|
226	|xref	fpsp_snan
227	.global	real_snan
228	.global	snan
229snan:
230	jmp	fpsp_snan
231real_snan:
232	link		%a6,#-LOCAL_SIZE
233	fsave		-(%sp)
234	bclrb		#E1,E_BYTE(%a6)	|snan is always an E1 exception
235	frestore	(%sp)+
236	unlk		%a6
237
238	SAVE_ALL_INT
239	GET_CURRENT(%d0)
240	movel	%sp,%sp@- 		| stack frame pointer argument
241	bsrl	SYMBOL_NAME(trap_c)
242	addql	#4,%sp
243	bral	SYMBOL_NAME(ret_from_exception)
244
245|
246|	Operand Error exception
247|
248	|xref	fpsp_operr
249	.global	real_operr
250	.global	operr
251operr:
252	jmp	fpsp_operr
253real_operr:
254	link		%a6,#-LOCAL_SIZE
255	fsave		-(%sp)
256	bclrb		#E1,E_BYTE(%a6)	|operr is always an E1 exception
257	frestore	(%sp)+
258	unlk		%a6
259
260	SAVE_ALL_INT
261	GET_CURRENT(%d0)
262	movel	%sp,%sp@- 		| stack frame pointer argument
263	bsrl	SYMBOL_NAME(trap_c)
264	addql	#4,%sp
265	bral	SYMBOL_NAME(ret_from_exception)
266
267
268|
269|	BSUN exception
270|
271|	This sample handler simply clears the nan bit in the FPSR.
272|
273	|xref	fpsp_bsun
274	.global	real_bsun
275	.global	bsun
276bsun:
277	jmp	fpsp_bsun
278real_bsun:
279	link		%a6,#-LOCAL_SIZE
280	fsave		-(%sp)
281	bclrb		#E1,E_BYTE(%a6)	|bsun is always an E1 exception
282	fmovel		%FPSR,-(%sp)
283	bclrb		#nan_bit,(%sp)
284	fmovel		(%sp)+,%FPSR
285	frestore	(%sp)+
286	unlk		%a6
287
288	SAVE_ALL_INT
289	GET_CURRENT(%d0)
290	movel	%sp,%sp@- 		| stack frame pointer argument
291	bsrl	SYMBOL_NAME(trap_c)
292	addql	#4,%sp
293	bral	SYMBOL_NAME(ret_from_exception)
294
295|
296|	F-line exception
297|
298|	A 'real' F-line exception is one that the FPSP isn't supposed to
299|	handle. E.g. an instruction with a co-processor ID that is not 1.
300|
301|
302	|xref	fpsp_fline
303	.global	real_fline
304	.global	fline
305fline:
306	jmp	fpsp_fline
307real_fline:
308
309	SAVE_ALL_INT
310	GET_CURRENT(%d0)
311	movel	%sp,%sp@- 		| stack frame pointer argument
312	bsrl	SYMBOL_NAME(trap_c)
313	addql	#4,%sp
314	bral	SYMBOL_NAME(ret_from_exception)
315
316|
317|	Unsupported data type exception
318|
319	|xref	fpsp_unsupp
320	.global	real_unsupp
321	.global	unsupp
322unsupp:
323	jmp	fpsp_unsupp
324real_unsupp:
325	link		%a6,#-LOCAL_SIZE
326	fsave		-(%sp)
327	bclrb		#E1,E_BYTE(%a6)	|unsupp is always an E1 exception
328	frestore	(%sp)+
329	unlk		%a6
330
331	SAVE_ALL_INT
332	GET_CURRENT(%d0)
333	movel	%sp,%sp@- 		| stack frame pointer argument
334	bsrl	SYMBOL_NAME(trap_c)
335	addql	#4,%sp
336	bral	SYMBOL_NAME(ret_from_exception)
337
338|
339|	Trace exception
340|
341	.global	real_trace
342real_trace:
343	|
344	bral	SYMBOL_NAME(trap)
345
346|
347|	fpsp_fmt_error --- exit point for frame format error
348|
349|	The fpu stack frame does not match the frames existing
350|	or planned at the time of this writing.  The fpsp is
351|	unable to handle frame sizes not in the following
352|	version:size pairs:
353|
354|	{4060, 4160} - busy frame
355|	{4028, 4130} - unimp frame
356|	{4000, 4100} - idle frame
357|
358|	This entry point simply holds an f-line illegal value.
359|	Replace this with a call to your kernel panic code or
360|	code to handle future revisions of the fpu.
361|
362	.global	fpsp_fmt_error
363fpsp_fmt_error:
364
365	.long	0xf27f0000	|f-line illegal
366
367|
368|	fpsp_done --- FPSP exit point
369|
370|	The exception has been handled by the package and we are ready
371|	to return to user mode, but there may be OS specific code
372|	to execute before we do.  If there is, do it now.
373|
374|
375
376	.global	fpsp_done
377fpsp_done:
378	btst	#0x5,%sp@		| supervisor bit set in saved SR?
379	beq	.Lnotkern
380	rte
381.Lnotkern:
382	SAVE_ALL_INT
383	GET_CURRENT(%d0)
384	tstl	%curptr@(TASK_NEEDRESCHED)
385	jne	SYMBOL_NAME(ret_from_exception)	| deliver signals,
386						| reschedule etc..
387	RESTORE_ALL
388
389|
390|	mem_write --- write to user or supervisor address space
391|
392| Writes to memory while in supervisor mode.  copyout accomplishes
393| this via a 'moves' instruction.  copyout is a UNIX SVR3 (and later) function.
394| If you don't have copyout, use the local copy of the function below.
395|
396|	a0 - supervisor source address
397|	a1 - user destination address
398|	d0 - number of bytes to write (maximum count is 12)
399|
400| The supervisor source address is guaranteed to point into the supervisor
401| stack.  The result is that a UNIX
402| process is allowed to sleep as a consequence of a page fault during
403| copyout.  The probability of a page fault is exceedingly small because
404| the 68040 always reads the destination address and thus the page
405| faults should have already been handled.
406|
407| If the EXC_SR shows that the exception was from supervisor space,
408| then just do a dumb (and slow) memory move.  In a UNIX environment
409| there shouldn't be any supervisor mode floating point exceptions.
410|
411	.global	mem_write
412mem_write:
413	btstb	#5,EXC_SR(%a6)	|check for supervisor state
414	beqs	user_write
415super_write:
416	moveb	(%a0)+,(%a1)+
417	subql	#1,%d0
418	bnes	super_write
419	rts
420user_write:
421	movel	%d1,-(%sp)	|preserve d1 just in case
422	movel	%d0,-(%sp)
423	movel	%a1,-(%sp)
424	movel	%a0,-(%sp)
425	jsr		copyout
426	addw	#12,%sp
427	movel	(%sp)+,%d1
428	rts
429|
430|	mem_read --- read from user or supervisor address space
431|
432| Reads from memory while in supervisor mode.  copyin accomplishes
433| this via a 'moves' instruction.  copyin is a UNIX SVR3 (and later) function.
434| If you don't have copyin, use the local copy of the function below.
435|
436| The FPSP calls mem_read to read the original F-line instruction in order
437| to extract the data register number when the 'Dn' addressing mode is
438| used.
439|
440|Input:
441|	a0 - user source address
442|	a1 - supervisor destination address
443|	d0 - number of bytes to read (maximum count is 12)
444|
445| Like mem_write, mem_read always reads with a supervisor
446| destination address on the supervisor stack.  Also like mem_write,
447| the EXC_SR is checked and a simple memory copy is done if reading
448| from supervisor space is indicated.
449|
450	.global	mem_read
451mem_read:
452	btstb	#5,EXC_SR(%a6)	|check for supervisor state
453	beqs	user_read
454super_read:
455	moveb	(%a0)+,(%a1)+
456	subql	#1,%d0
457	bnes	super_read
458	rts
459user_read:
460	movel	%d1,-(%sp)	|preserve d1 just in case
461	movel	%d0,-(%sp)
462	movel	%a1,-(%sp)
463	movel	%a0,-(%sp)
464	jsr	copyin
465	addw	#12,%sp
466	movel	(%sp)+,%d1
467	rts
468
469|
470| Use these routines if your kernel doesn't have copyout/copyin equivalents.
471| Assumes that D0/D1/A0/A1 are scratch registers. copyout overwrites DFC,
472| and copyin overwrites SFC.
473|
474copyout:
475	movel	4(%sp),%a0	| source
476	movel	8(%sp),%a1	| destination
477	movel	12(%sp),%d0	| count
478	subl	#1,%d0		| dec count by 1 for dbra
479	movel	#1,%d1
480
481|	DFC is already set
482|	movec	%d1,%DFC		| set dfc for user data space
483moreout:
484	moveb	(%a0)+,%d1	| fetch supervisor byte
485out_ea:
486	movesb	%d1,(%a1)+	| write user byte
487	dbf	%d0,moreout
488	rts
489
490copyin:
491	movel	4(%sp),%a0	| source
492	movel	8(%sp),%a1	| destination
493	movel	12(%sp),%d0	| count
494	subl	#1,%d0		| dec count by 1 for dbra
495	movel	#1,%d1
496|	SFC is already set
497|	movec	%d1,%SFC		| set sfc for user space
498morein:
499in_ea:
500	movesb	(%a0)+,%d1	| fetch user byte
501	moveb	%d1,(%a1)+	| write supervisor byte
502	dbf	%d0,morein
503	rts
504
505	.section .fixup,#alloc,#execinstr
506	.even
5071:
508	jbra	SYMBOL_NAME(fpsp040_die)
509
510	.section __ex_table,#alloc
511	.align	4
512
513	.long	in_ea,1b
514	.long	out_ea,1b
515
516	|end
517