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/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 65dz: 66real_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 103inex: 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 117inex_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 124inex_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| 136not_b1232: 137 addl #4,%sp 138 frestore (%sp)+ 139 unlk %a6 140 141real_inex: 142 143 link %a6,#-LOCAL_SIZE 144 fsave -(%sp) 145not_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 158inex_cke1: 159 bclrb #E1,E_BYTE(%a6) 160inex_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 177ovfl: 178 jmp fpsp_ovfl 179real_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) 186ovfl_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 203unfl: 204 jmp fpsp_unfl 205real_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) 212unfl_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 229snan: 230 jmp fpsp_snan 231real_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 251operr: 252 jmp fpsp_operr 253real_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 276bsun: 277 jmp fpsp_bsun 278real_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 305fline: 306 jmp fpsp_fline 307real_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 322unsupp: 323 jmp fpsp_unsupp 324real_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 342real_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 363fpsp_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 377fpsp_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 | deliver signals, reschedule etc.. 385 jra ret_from_exception 386 387| 388| mem_write --- write to user or supervisor address space 389| 390| Writes to memory while in supervisor mode. copyout accomplishes 391| this via a 'moves' instruction. copyout is a UNIX SVR3 (and later) function. 392| If you don't have copyout, use the local copy of the function below. 393| 394| a0 - supervisor source address 395| a1 - user destination address 396| d0 - number of bytes to write (maximum count is 12) 397| 398| The supervisor source address is guaranteed to point into the supervisor 399| stack. The result is that a UNIX 400| process is allowed to sleep as a consequence of a page fault during 401| copyout. The probability of a page fault is exceedingly small because 402| the 68040 always reads the destination address and thus the page 403| faults should have already been handled. 404| 405| If the EXC_SR shows that the exception was from supervisor space, 406| then just do a dumb (and slow) memory move. In a UNIX environment 407| there shouldn't be any supervisor mode floating point exceptions. 408| 409 .global mem_write 410mem_write: 411 btstb #5,EXC_SR(%a6) |check for supervisor state 412 beqs user_write 413super_write: 414 moveb (%a0)+,(%a1)+ 415 subql #1,%d0 416 bnes super_write 417 rts 418user_write: 419 movel %d1,-(%sp) |preserve d1 just in case 420 movel %d0,-(%sp) 421 movel %a1,-(%sp) 422 movel %a0,-(%sp) 423 jsr copyout 424 addw #12,%sp 425 movel (%sp)+,%d1 426 rts 427| 428| mem_read --- read from user or supervisor address space 429| 430| Reads from memory while in supervisor mode. copyin accomplishes 431| this via a 'moves' instruction. copyin is a UNIX SVR3 (and later) function. 432| If you don't have copyin, use the local copy of the function below. 433| 434| The FPSP calls mem_read to read the original F-line instruction in order 435| to extract the data register number when the 'Dn' addressing mode is 436| used. 437| 438|Input: 439| a0 - user source address 440| a1 - supervisor destination address 441| d0 - number of bytes to read (maximum count is 12) 442| 443| Like mem_write, mem_read always reads with a supervisor 444| destination address on the supervisor stack. Also like mem_write, 445| the EXC_SR is checked and a simple memory copy is done if reading 446| from supervisor space is indicated. 447| 448 .global mem_read 449mem_read: 450 btstb #5,EXC_SR(%a6) |check for supervisor state 451 beqs user_read 452super_read: 453 moveb (%a0)+,(%a1)+ 454 subql #1,%d0 455 bnes super_read 456 rts 457user_read: 458 movel %d1,-(%sp) |preserve d1 just in case 459 movel %d0,-(%sp) 460 movel %a1,-(%sp) 461 movel %a0,-(%sp) 462 jsr copyin 463 addw #12,%sp 464 movel (%sp)+,%d1 465 rts 466 467| 468| Use these routines if your kernel doesn't have copyout/copyin equivalents. 469| Assumes that D0/D1/A0/A1 are scratch registers. copyout overwrites DFC, 470| and copyin overwrites SFC. 471| 472copyout: 473 movel 4(%sp),%a0 | source 474 movel 8(%sp),%a1 | destination 475 movel 12(%sp),%d0 | count 476 subl #1,%d0 | dec count by 1 for dbra 477 movel #1,%d1 478 479| DFC is already set 480| movec %d1,%DFC | set dfc for user data space 481moreout: 482 moveb (%a0)+,%d1 | fetch supervisor byte 483out_ea: 484 movesb %d1,(%a1)+ | write user byte 485 dbf %d0,moreout 486 rts 487 488copyin: 489 movel 4(%sp),%a0 | source 490 movel 8(%sp),%a1 | destination 491 movel 12(%sp),%d0 | count 492 subl #1,%d0 | dec count by 1 for dbra 493 movel #1,%d1 494| SFC is already set 495| movec %d1,%SFC | set sfc for user space 496morein: 497in_ea: 498 movesb (%a0)+,%d1 | fetch user byte 499 moveb %d1,(%a1)+ | write supervisor byte 500 dbf %d0,morein 501 rts 502 503 .section .fixup,#alloc,#execinstr 504 .even 5051: 506 jbra fpsp040_die 507 508 .section __ex_table,#alloc 509 .align 4 510 511 .long in_ea,1b 512 .long out_ea,1b 513 514 |end 515