]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
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 | | | |
e00d82d0 MW |
33 | | For details on the license for this file, please see the |
34 | | file, README, in this same directory. | |
1da177e4 LT |
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> | |
0013a854 | 42 | #include <asm/asm-offsets.h> |
1da177e4 LT |
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) | |
3b66a1ed RZ |
383 | | deliver signals, reschedule etc.. |
384 | jra ret_from_exception | |
1da177e4 LT |
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,#alloc,#execinstr | |
503 | .even | |
504 | 1: | |
505 | jbra fpsp040_die | |
506 | ||
507 | .section __ex_table,#alloc | |
508 | .align 4 | |
509 | ||
510 | .long in_ea,1b | |
511 | .long out_ea,1b | |
512 | ||
513 | |end |