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 | | | |
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 |