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
64 dz:
65 real_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
102 inex:
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
116 inex_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
123 inex_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 |
135 not_b1232:
136 	addl		#4,%sp
137 	frestore	(%sp)+
138 	unlk		%a6
139 
140 real_inex:
141 
142 	link		%a6,#-LOCAL_SIZE
143 	fsave		-(%sp)
144 not_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
157 inex_cke1:
158 	bclrb		#E1,E_BYTE(%a6)
159 inex_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
176 ovfl:
177 	jmp	fpsp_ovfl
178 real_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)
185 ovfl_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
202 unfl:
203 	jmp	fpsp_unfl
204 real_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)
211 unfl_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
228 snan:
229 	jmp	fpsp_snan
230 real_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
250 operr:
251 	jmp	fpsp_operr
252 real_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
275 bsun:
276 	jmp	fpsp_bsun
277 real_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
304 fline:
305 	jmp	fpsp_fline
306 real_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
321 unsupp:
322 	jmp	fpsp_unsupp
323 real_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
341 real_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
362 fpsp_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
376 fpsp_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
409 mem_write:
410 	btstb	#5,EXC_SR(%a6)	|check for supervisor state
411 	beqs	user_write
412 super_write:
413 	moveb	(%a0)+,(%a1)+
414 	subql	#1,%d0
415 	bnes	super_write
416 	rts
417 user_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
448 mem_read:
449 	btstb	#5,EXC_SR(%a6)	|check for supervisor state
450 	beqs	user_read
451 super_read:
452 	moveb	(%a0)+,(%a1)+
453 	subql	#1,%d0
454 	bnes	super_read
455 	rts
456 user_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 |
471 copyout:
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
480 moreout:
481 	moveb	(%a0)+,%d1	| fetch supervisor byte
482 out_ea:
483 	movesb	%d1,(%a1)+	| write user byte
484 	dbf	%d0,moreout
485 	rts
486 
487 copyin:
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
495 morein:
496 in_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
504 1:
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