diff options
Diffstat (limited to 'arch/m68k/fpsp040/skeleton.S')
-rw-r--r-- | arch/m68k/fpsp040/skeleton.S | 516 |
1 files changed, 516 insertions, 0 deletions
diff --git a/arch/m68k/fpsp040/skeleton.S b/arch/m68k/fpsp040/skeleton.S new file mode 100644 index 000000000000..dbc1255a5e99 --- /dev/null +++ b/arch/m68k/fpsp040/skeleton.S | |||
@@ -0,0 +1,516 @@ | |||
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 <asm/offsets.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 | ||
65 | dz: | ||
66 | real_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 trap_c | ||
77 | addql #4,%sp | ||
78 | bral 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 | ||
103 | inex: | ||
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 | ||
117 | inex_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 | ||
124 | inex_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 | | | ||
136 | not_b1232: | ||
137 | addl #4,%sp | ||
138 | frestore (%sp)+ | ||
139 | unlk %a6 | ||
140 | |||
141 | real_inex: | ||
142 | |||
143 | link %a6,#-LOCAL_SIZE | ||
144 | fsave -(%sp) | ||
145 | not_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 | ||
158 | inex_cke1: | ||
159 | bclrb #E1,E_BYTE(%a6) | ||
160 | inex_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 trap_c | ||
168 | addql #4,%sp | ||
169 | bral ret_from_exception | ||
170 | |||
171 | | | ||
172 | | Overflow exception | ||
173 | | | ||
174 | |xref fpsp_ovfl | ||
175 | .global real_ovfl | ||
176 | .global ovfl | ||
177 | ovfl: | ||
178 | jmp fpsp_ovfl | ||
179 | real_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) | ||
186 | ovfl_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 trap_c | ||
194 | addql #4,%sp | ||
195 | bral ret_from_exception | ||
196 | |||
197 | | | ||
198 | | Underflow exception | ||
199 | | | ||
200 | |xref fpsp_unfl | ||
201 | .global real_unfl | ||
202 | .global unfl | ||
203 | unfl: | ||
204 | jmp fpsp_unfl | ||
205 | real_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) | ||
212 | unfl_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 trap_c | ||
220 | addql #4,%sp | ||
221 | bral ret_from_exception | ||
222 | |||
223 | | | ||
224 | | Signalling NAN exception | ||
225 | | | ||
226 | |xref fpsp_snan | ||
227 | .global real_snan | ||
228 | .global snan | ||
229 | snan: | ||
230 | jmp fpsp_snan | ||
231 | real_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 trap_c | ||
242 | addql #4,%sp | ||
243 | bral ret_from_exception | ||
244 | |||
245 | | | ||
246 | | Operand Error exception | ||
247 | | | ||
248 | |xref fpsp_operr | ||
249 | .global real_operr | ||
250 | .global operr | ||
251 | operr: | ||
252 | jmp fpsp_operr | ||
253 | real_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 trap_c | ||
264 | addql #4,%sp | ||
265 | bral 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 | ||
276 | bsun: | ||
277 | jmp fpsp_bsun | ||
278 | real_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 trap_c | ||
292 | addql #4,%sp | ||
293 | bral 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 | ||
305 | fline: | ||
306 | jmp fpsp_fline | ||
307 | real_fline: | ||
308 | |||
309 | SAVE_ALL_INT | ||
310 | GET_CURRENT(%d0) | ||
311 | movel %sp,%sp@- | stack frame pointer argument | ||
312 | bsrl trap_c | ||
313 | addql #4,%sp | ||
314 | bral ret_from_exception | ||
315 | |||
316 | | | ||
317 | | Unsupported data type exception | ||
318 | | | ||
319 | |xref fpsp_unsupp | ||
320 | .global real_unsupp | ||
321 | .global unsupp | ||
322 | unsupp: | ||
323 | jmp fpsp_unsupp | ||
324 | real_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 trap_c | ||
335 | addql #4,%sp | ||
336 | bral ret_from_exception | ||
337 | |||
338 | | | ||
339 | | Trace exception | ||
340 | | | ||
341 | .global real_trace | ||
342 | real_trace: | ||
343 | | | ||
344 | bral 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 | ||
363 | fpsp_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 | ||
377 | fpsp_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 | tstb %curptr@(TASK_NEEDRESCHED) | ||
385 | jne 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 | ||
412 | mem_write: | ||
413 | btstb #5,EXC_SR(%a6) |check for supervisor state | ||
414 | beqs user_write | ||
415 | super_write: | ||
416 | moveb (%a0)+,(%a1)+ | ||
417 | subql #1,%d0 | ||
418 | bnes super_write | ||
419 | rts | ||
420 | user_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 | ||
451 | mem_read: | ||
452 | btstb #5,EXC_SR(%a6) |check for supervisor state | ||
453 | beqs user_read | ||
454 | super_read: | ||
455 | moveb (%a0)+,(%a1)+ | ||
456 | subql #1,%d0 | ||
457 | bnes super_read | ||
458 | rts | ||
459 | user_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 | | | ||
474 | copyout: | ||
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 | ||
483 | moreout: | ||
484 | moveb (%a0)+,%d1 | fetch supervisor byte | ||
485 | out_ea: | ||
486 | movesb %d1,(%a1)+ | write user byte | ||
487 | dbf %d0,moreout | ||
488 | rts | ||
489 | |||
490 | copyin: | ||
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 | ||
498 | morein: | ||
499 | in_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 | ||
507 | 1: | ||
508 | jbra 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 | ||