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 "../kernel/m68k_defs.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 SYMBOL_NAME(trap_c) 77 addql #4,%sp 78 bral SYMBOL_NAME(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 SYMBOL_NAME(trap_c) 168 addql #4,%sp 169 bral SYMBOL_NAME(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 SYMBOL_NAME(trap_c) 194 addql #4,%sp 195 bral SYMBOL_NAME(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 SYMBOL_NAME(trap_c) 220 addql #4,%sp 221 bral SYMBOL_NAME(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 SYMBOL_NAME(trap_c) 242 addql #4,%sp 243 bral SYMBOL_NAME(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 SYMBOL_NAME(trap_c) 264 addql #4,%sp 265 bral SYMBOL_NAME(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 SYMBOL_NAME(trap_c) 292 addql #4,%sp 293 bral SYMBOL_NAME(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 SYMBOL_NAME(trap_c) 313 addql #4,%sp 314 bral SYMBOL_NAME(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 SYMBOL_NAME(trap_c) 335 addql #4,%sp 336 bral SYMBOL_NAME(ret_from_exception) 337 338| 339| Trace exception 340| 341 .global real_trace 342real_trace: 343 | 344 bral SYMBOL_NAME(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 tstl %curptr@(TASK_NEEDRESCHED) 385 jne SYMBOL_NAME(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 412mem_write: 413 btstb #5,EXC_SR(%a6) |check for supervisor state 414 beqs user_write 415super_write: 416 moveb (%a0)+,(%a1)+ 417 subql #1,%d0 418 bnes super_write 419 rts 420user_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 451mem_read: 452 btstb #5,EXC_SR(%a6) |check for supervisor state 453 beqs user_read 454super_read: 455 moveb (%a0)+,(%a1)+ 456 subql #1,%d0 457 bnes super_read 458 rts 459user_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| 474copyout: 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 483moreout: 484 moveb (%a0)+,%d1 | fetch supervisor byte 485out_ea: 486 movesb %d1,(%a1)+ | write user byte 487 dbf %d0,moreout 488 rts 489 490copyin: 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 498morein: 499in_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 5071: 508 jbra SYMBOL_NAME(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 517