linux/arch/m68k/fpsp040/skeleton.S
<<
>>
Prefs
   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        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
 514