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 64dz: 65real_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 102inex: 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 116inex_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 123inex_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| 135not_b1232: 136 addl #4,%sp 137 frestore (%sp)+ 138 unlk %a6 139 140real_inex: 141 142 link %a6,#-LOCAL_SIZE 143 fsave -(%sp) 144not_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 157inex_cke1: 158 bclrb #E1,E_BYTE(%a6) 159inex_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 176ovfl: 177 jmp fpsp_ovfl 178real_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) 185ovfl_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 202unfl: 203 jmp fpsp_unfl 204real_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) 211unfl_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 228snan: 229 jmp fpsp_snan 230real_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 250operr: 251 jmp fpsp_operr 252real_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 275bsun: 276 jmp fpsp_bsun 277real_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 304fline: 305 jmp fpsp_fline 306real_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 321unsupp: 322 jmp fpsp_unsupp 323real_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 341real_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 362fpsp_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 376fpsp_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 409mem_write: 410 btstb #5,EXC_SR(%a6) |check for supervisor state 411 beqs user_write 412super_write: 413 moveb (%a0)+,(%a1)+ 414 subql #1,%d0 415 bnes super_write 416 rts 417user_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 448mem_read: 449 btstb #5,EXC_SR(%a6) |check for supervisor state 450 beqs user_read 451super_read: 452 moveb (%a0)+,(%a1)+ 453 subql #1,%d0 454 bnes super_read 455 rts 456user_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| 471copyout: 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 480moreout: 481 moveb (%a0)+,%d1 | fetch supervisor byte 482out_ea: 483 movesb %d1,(%a1)+ | write user byte 484 dbf %d0,moreout 485 rts 486 487copyin: 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 495morein: 496in_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 5041: 505 jbsr fpsp040_die 506 jbra .Lnotkern 507 508 .section __ex_table,#alloc 509 .align 4 510 511 .long in_ea,1b 512 .long out_ea,1b 513 514 |end 515