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