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