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