root/arch/m68k/fpsp040/gen_except.S

/* [<][>][^][v][top][bottom][index][help] */
   1 |
   2 |       gen_except.sa 3.7 1/16/92
   3 |
   4 |       gen_except --- FPSP routine to detect reportable exceptions
   5 |
   6 |       This routine compares the exception enable byte of the
   7 |       user_fpcr on the stack with the exception status byte
   8 |       of the user_fpsr.
   9 |
  10 |       Any routine which may report an exceptions must load
  11 |       the stack frame in memory with the exceptional operand(s).
  12 |
  13 |       Priority for exceptions is:
  14 |
  15 |       Highest:        bsun
  16 |                       snan
  17 |                       operr
  18 |                       ovfl
  19 |                       unfl
  20 |                       dz
  21 |                       inex2
  22 |       Lowest:         inex1
  23 |
  24 |       Note: The IEEE standard specifies that inex2 is to be
  25 |       reported if ovfl occurs and the ovfl enable bit is not
  26 |       set but the inex2 enable bit is.
  27 |
  28 |
  29 |               Copyright (C) Motorola, Inc. 1990
  30 |                       All Rights Reserved
  31 |
  32 |       For details on the license for this file, please see the
  33 |       file, README, in this same directory.
  34 
  35 GEN_EXCEPT:    |idnt    2,1 | Motorola 040 Floating Point Software Package
  36 
  37         |section 8
  38 
  39 #include "fpsp.h"
  40 
  41         |xref   real_trace
  42         |xref   fpsp_done
  43         |xref   fpsp_fmt_error
  44 
  45 exc_tbl:
  46         .long   bsun_exc
  47         .long   commonE1
  48         .long   commonE1
  49         .long   ovfl_unfl
  50         .long   ovfl_unfl
  51         .long   commonE1
  52         .long   commonE3
  53         .long   commonE3
  54         .long   no_match
  55 
  56         .global gen_except
  57 gen_except:
  58         cmpib   #IDLE_SIZE-4,1(%a7)     |test for idle frame
  59         beq     do_check                |go handle idle frame
  60         cmpib   #UNIMP_40_SIZE-4,1(%a7) |test for orig unimp frame
  61         beqs    unimp_x                 |go handle unimp frame
  62         cmpib   #UNIMP_41_SIZE-4,1(%a7) |test for rev unimp frame
  63         beqs    unimp_x                 |go handle unimp frame
  64         cmpib   #BUSY_SIZE-4,1(%a7)     |if size <> $60, fmt error
  65         bnel    fpsp_fmt_error
  66         leal    BUSY_SIZE+LOCAL_SIZE(%a7),%a1 |init a1 so fpsp.h
  67 |                                       ;equates will work
  68 | Fix up the new busy frame with entries from the unimp frame
  69 |
  70         movel   ETEMP_EX(%a6),ETEMP_EX(%a1) |copy etemp from unimp
  71         movel   ETEMP_HI(%a6),ETEMP_HI(%a1) |frame to busy frame
  72         movel   ETEMP_LO(%a6),ETEMP_LO(%a1)
  73         movel   CMDREG1B(%a6),CMDREG1B(%a1) |set inst in frame to unimp
  74         movel   CMDREG1B(%a6),%d0               |fix cmd1b to make it
  75         andl    #0x03c30000,%d0         |work for cmd3b
  76         bfextu  CMDREG1B(%a6){#13:#1},%d1       |extract bit 2
  77         lsll    #5,%d1
  78         swap    %d1
  79         orl     %d1,%d0                 |put it in the right place
  80         bfextu  CMDREG1B(%a6){#10:#3},%d1       |extract bit 3,4,5
  81         lsll    #2,%d1
  82         swap    %d1
  83         orl     %d1,%d0                 |put them in the right place
  84         movel   %d0,CMDREG3B(%a1)               |in the busy frame
  85 |
  86 | Or in the FPSR from the emulation with the USER_FPSR on the stack.
  87 |
  88         fmovel  %FPSR,%d0
  89         orl     %d0,USER_FPSR(%a6)
  90         movel   USER_FPSR(%a6),FPSR_SHADOW(%a1) |set exc bits
  91         orl     #sx_mask,E_BYTE(%a1)
  92         bra     do_clean
  93 
  94 |
  95 | Frame is an unimp frame possible resulting from an fmove <ea>,fp0
  96 | that caused an exception
  97 |
  98 | a1 is modified to point into the new frame allowing fpsp equates
  99 | to be valid.
 100 |
 101 unimp_x:
 102         cmpib   #UNIMP_40_SIZE-4,1(%a7) |test for orig unimp frame
 103         bnes    test_rev
 104         leal    UNIMP_40_SIZE+LOCAL_SIZE(%a7),%a1
 105         bras    unimp_con
 106 test_rev:
 107         cmpib   #UNIMP_41_SIZE-4,1(%a7) |test for rev unimp frame
 108         bnel    fpsp_fmt_error          |if not $28 or $30
 109         leal    UNIMP_41_SIZE+LOCAL_SIZE(%a7),%a1
 110 
 111 unimp_con:
 112 |
 113 | Fix up the new unimp frame with entries from the old unimp frame
 114 |
 115         movel   CMDREG1B(%a6),CMDREG1B(%a1) |set inst in frame to unimp
 116 |
 117 | Or in the FPSR from the emulation with the USER_FPSR on the stack.
 118 |
 119         fmovel  %FPSR,%d0
 120         orl     %d0,USER_FPSR(%a6)
 121         bra     do_clean
 122 
 123 |
 124 | Frame is idle, so check for exceptions reported through
 125 | USER_FPSR and set the unimp frame accordingly.
 126 | A7 must be incremented to the point before the
 127 | idle fsave vector to the unimp vector.
 128 |
 129 
 130 do_check:
 131         addl    #4,%a7                  |point A7 back to unimp frame
 132 |
 133 | Or in the FPSR from the emulation with the USER_FPSR on the stack.
 134 |
 135         fmovel  %FPSR,%d0
 136         orl     %d0,USER_FPSR(%a6)
 137 |
 138 | On a busy frame, we must clear the nmnexc bits.
 139 |
 140         cmpib   #BUSY_SIZE-4,1(%a7)     |check frame type
 141         bnes    check_fr                |if busy, clr nmnexc
 142         clrw    NMNEXC(%a6)             |clr nmnexc & nmcexc
 143         btstb   #5,CMDREG1B(%a6)                |test for fmove out
 144         bnes    frame_com
 145         movel   USER_FPSR(%a6),FPSR_SHADOW(%a6) |set exc bits
 146         orl     #sx_mask,E_BYTE(%a6)
 147         bras    frame_com
 148 check_fr:
 149         cmpb    #UNIMP_40_SIZE-4,1(%a7)
 150         beqs    frame_com
 151         clrw    NMNEXC(%a6)
 152 frame_com:
 153         moveb   FPCR_ENABLE(%a6),%d0    |get fpcr enable byte
 154         andb    FPSR_EXCEPT(%a6),%d0    |and in the fpsr exc byte
 155         bfffo   %d0{#24:#8},%d1         |test for first set bit
 156         leal    exc_tbl,%a0             |load jmp table address
 157         subib   #24,%d1                 |normalize bit offset to 0-8
 158         movel   (%a0,%d1.w*4),%a0               |load routine address based
 159 |                                       ;based on first enabled exc
 160         jmp     (%a0)                   |jump to routine
 161 |
 162 | Bsun is not possible in unimp or unsupp
 163 |
 164 bsun_exc:
 165         bra     do_clean
 166 |
 167 | The typical work to be done to the unimp frame to report an
 168 | exception is to set the E1/E3 byte and clr the U flag.
 169 | commonE1 does this for E1 exceptions, which are snan,
 170 | operr, and dz.  commonE3 does this for E3 exceptions, which
 171 | are inex2 and inex1, and also clears the E1 exception bit
 172 | left over from the unimp exception.
 173 |
 174 commonE1:
 175         bsetb   #E1,E_BYTE(%a6)         |set E1 flag
 176         bra     commonE                 |go clean and exit
 177 
 178 commonE3:
 179         tstb    UFLG_TMP(%a6)           |test flag for unsup/unimp state
 180         bnes    unsE3
 181 uniE3:
 182         bsetb   #E3,E_BYTE(%a6)         |set E3 flag
 183         bclrb   #E1,E_BYTE(%a6)         |clr E1 from unimp
 184         bra     commonE
 185 
 186 unsE3:
 187         tstb    RES_FLG(%a6)
 188         bnes    unsE3_0
 189 unsE3_1:
 190         bsetb   #E3,E_BYTE(%a6)         |set E3 flag
 191 unsE3_0:
 192         bclrb   #E1,E_BYTE(%a6)         |clr E1 flag
 193         movel   CMDREG1B(%a6),%d0
 194         andl    #0x03c30000,%d0         |work for cmd3b
 195         bfextu  CMDREG1B(%a6){#13:#1},%d1       |extract bit 2
 196         lsll    #5,%d1
 197         swap    %d1
 198         orl     %d1,%d0                 |put it in the right place
 199         bfextu  CMDREG1B(%a6){#10:#3},%d1       |extract bit 3,4,5
 200         lsll    #2,%d1
 201         swap    %d1
 202         orl     %d1,%d0                 |put them in the right place
 203         movel   %d0,CMDREG3B(%a6)               |in the busy frame
 204 
 205 commonE:
 206         bclrb   #UFLAG,T_BYTE(%a6)      |clr U flag from unimp
 207         bra     do_clean                |go clean and exit
 208 |
 209 | No bits in the enable byte match existing exceptions.  Check for
 210 | the case of the ovfl exc without the ovfl enabled, but with
 211 | inex2 enabled.
 212 |
 213 no_match:
 214         btstb   #inex2_bit,FPCR_ENABLE(%a6) |check for ovfl/inex2 case
 215         beqs    no_exc                  |if clear, exit
 216         btstb   #ovfl_bit,FPSR_EXCEPT(%a6) |now check ovfl
 217         beqs    no_exc                  |if clear, exit
 218         bras    ovfl_unfl               |go to unfl_ovfl to determine if
 219 |                                       ;it is an unsupp or unimp exc
 220 
 221 | No exceptions are to be reported.  If the instruction was
 222 | unimplemented, no FPU restore is necessary.  If it was
 223 | unsupported, we must perform the restore.
 224 no_exc:
 225         tstb    UFLG_TMP(%a6)   |test flag for unsupp/unimp state
 226         beqs    uni_no_exc
 227 uns_no_exc:
 228         tstb    RES_FLG(%a6)    |check if frestore is needed
 229         bne     do_clean        |if clear, no frestore needed
 230 uni_no_exc:
 231         moveml  USER_DA(%a6),%d0-%d1/%a0-%a1
 232         fmovemx USER_FP0(%a6),%fp0-%fp3
 233         fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
 234         unlk    %a6
 235         bra     finish_up
 236 |
 237 | Unsupported Data Type Handler:
 238 | Ovfl:
 239 |   An fmoveout that results in an overflow is reported this way.
 240 | Unfl:
 241 |   An fmoveout that results in an underflow is reported this way.
 242 |
 243 | Unimplemented Instruction Handler:
 244 | Ovfl:
 245 |   Only scosh, setox, ssinh, stwotox, and scale can set overflow in
 246 |   this manner.
 247 | Unfl:
 248 |   Stwotox, setox, and scale can set underflow in this manner.
 249 |   Any of the other Library Routines such that f(x)=x in which
 250 |   x is an extended denorm can report an underflow exception.
 251 |   It is the responsibility of the exception-causing exception
 252 |   to make sure that WBTEMP is correct.
 253 |
 254 |   The exceptional operand is in FP_SCR1.
 255 |
 256 ovfl_unfl:
 257         tstb    UFLG_TMP(%a6)   |test flag for unsupp/unimp state
 258         beqs    ofuf_con
 259 |
 260 | The caller was from an unsupported data type trap.  Test if the
 261 | caller set CU_ONLY.  If so, the exceptional operand is expected in
 262 | FPTEMP, rather than WBTEMP.
 263 |
 264         tstb    CU_ONLY(%a6)            |test if inst is cu-only
 265         beq     unsE3
 266 |       move.w  #$fe,CU_SAVEPC(%a6)
 267         clrb    CU_SAVEPC(%a6)
 268         bsetb   #E1,E_BYTE(%a6)         |set E1 exception flag
 269         movew   ETEMP_EX(%a6),FPTEMP_EX(%a6)
 270         movel   ETEMP_HI(%a6),FPTEMP_HI(%a6)
 271         movel   ETEMP_LO(%a6),FPTEMP_LO(%a6)
 272         bsetb   #fptemp15_bit,DTAG(%a6) |set fpte15
 273         bclrb   #UFLAG,T_BYTE(%a6)      |clr U flag from unimp
 274         bra     do_clean                |go clean and exit
 275 
 276 ofuf_con:
 277         moveb   (%a7),VER_TMP(%a6)      |save version number
 278         cmpib   #BUSY_SIZE-4,1(%a7)     |check for busy frame
 279         beqs    busy_fr                 |if unimp, grow to busy
 280         cmpib   #VER_40,(%a7)           |test for orig unimp frame
 281         bnes    try_41                  |if not, test for rev frame
 282         moveql  #13,%d0                 |need to zero 14 lwords
 283         bras    ofuf_fin
 284 try_41:
 285         cmpib   #VER_41,(%a7)           |test for rev unimp frame
 286         bnel    fpsp_fmt_error          |if neither, exit with error
 287         moveql  #11,%d0                 |need to zero 12 lwords
 288 
 289 ofuf_fin:
 290         clrl    (%a7)
 291 loop1:
 292         clrl    -(%a7)                  |clear and dec a7
 293         dbra    %d0,loop1
 294         moveb   VER_TMP(%a6),(%a7)
 295         moveb   #BUSY_SIZE-4,1(%a7)             |write busy fmt word.
 296 busy_fr:
 297         movel   FP_SCR1(%a6),WBTEMP_EX(%a6)     |write
 298         movel   FP_SCR1+4(%a6),WBTEMP_HI(%a6)   |exceptional op to
 299         movel   FP_SCR1+8(%a6),WBTEMP_LO(%a6)   |wbtemp
 300         bsetb   #E3,E_BYTE(%a6)                 |set E3 flag
 301         bclrb   #E1,E_BYTE(%a6)                 |make sure E1 is clear
 302         bclrb   #UFLAG,T_BYTE(%a6)              |clr U flag
 303         movel   USER_FPSR(%a6),FPSR_SHADOW(%a6)
 304         orl     #sx_mask,E_BYTE(%a6)
 305         movel   CMDREG1B(%a6),%d0               |fix cmd1b to make it
 306         andl    #0x03c30000,%d0         |work for cmd3b
 307         bfextu  CMDREG1B(%a6){#13:#1},%d1       |extract bit 2
 308         lsll    #5,%d1
 309         swap    %d1
 310         orl     %d1,%d0                 |put it in the right place
 311         bfextu  CMDREG1B(%a6){#10:#3},%d1       |extract bit 3,4,5
 312         lsll    #2,%d1
 313         swap    %d1
 314         orl     %d1,%d0                 |put them in the right place
 315         movel   %d0,CMDREG3B(%a6)               |in the busy frame
 316 
 317 |
 318 | Check if the frame to be restored is busy or unimp.
 319 |** NOTE *** Bug fix for errata (0d43b #3)
 320 | If the frame is unimp, we must create a busy frame to
 321 | fix the bug with the nmnexc bits in cases in which they
 322 | are set by a previous instruction and not cleared by
 323 | the save. The frame will be unimp only if the final
 324 | instruction in an emulation routine caused the exception
 325 | by doing an fmove <ea>,fp0.  The exception operand, in
 326 | internal format, is in fptemp.
 327 |
 328 do_clean:
 329         cmpib   #UNIMP_40_SIZE-4,1(%a7)
 330         bnes    do_con
 331         moveql  #13,%d0                 |in orig, need to zero 14 lwords
 332         bras    do_build
 333 do_con:
 334         cmpib   #UNIMP_41_SIZE-4,1(%a7)
 335         bnes    do_restore              |frame must be busy
 336         moveql  #11,%d0                 |in rev, need to zero 12 lwords
 337 
 338 do_build:
 339         moveb   (%a7),VER_TMP(%a6)
 340         clrl    (%a7)
 341 loop2:
 342         clrl    -(%a7)                  |clear and dec a7
 343         dbra    %d0,loop2
 344 |
 345 | Use a1 as pointer into new frame.  a6 is not correct if an unimp or
 346 | busy frame was created as the result of an exception on the final
 347 | instruction of an emulation routine.
 348 |
 349 | We need to set the nmcexc bits if the exception is E1. Otherwise,
 350 | the exc taken will be inex2.
 351 |
 352         leal    BUSY_SIZE+LOCAL_SIZE(%a7),%a1   |init a1 for new frame
 353         moveb   VER_TMP(%a6),(%a7)      |write busy fmt word
 354         moveb   #BUSY_SIZE-4,1(%a7)
 355         movel   FP_SCR1(%a6),WBTEMP_EX(%a1)     |write
 356         movel   FP_SCR1+4(%a6),WBTEMP_HI(%a1)   |exceptional op to
 357         movel   FP_SCR1+8(%a6),WBTEMP_LO(%a1)   |wbtemp
 358 |       btst.b  #E1,E_BYTE(%a1)
 359 |       beq.b   do_restore
 360         bfextu  USER_FPSR(%a6){#17:#4},%d0      |get snan/operr/ovfl/unfl bits
 361         bfins   %d0,NMCEXC(%a1){#4:#4}  |and insert them in nmcexc
 362         movel   USER_FPSR(%a6),FPSR_SHADOW(%a1) |set exc bits
 363         orl     #sx_mask,E_BYTE(%a1)
 364 
 365 do_restore:
 366         moveml  USER_DA(%a6),%d0-%d1/%a0-%a1
 367         fmovemx USER_FP0(%a6),%fp0-%fp3
 368         fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
 369         frestore (%a7)+
 370         tstb    RES_FLG(%a6)    |RES_FLG indicates a "continuation" frame
 371         beq     cont
 372         bsr     bug1384
 373 cont:
 374         unlk    %a6
 375 |
 376 | If trace mode enabled, then go to trace handler.  This handler
 377 | cannot have any fp instructions.  If there are fp inst's and an
 378 | exception has been restored into the machine then the exception
 379 | will occur upon execution of the fp inst.  This is not desirable
 380 | in the kernel (supervisor mode).  See MC68040 manual Section 9.3.8.
 381 |
 382 finish_up:
 383         btstb   #7,(%a7)                |test T1 in SR
 384         bnes    g_trace
 385         btstb   #6,(%a7)                |test T0 in SR
 386         bnes    g_trace
 387         bral    fpsp_done
 388 |
 389 | Change integer stack to look like trace stack
 390 | The address of the instruction that caused the
 391 | exception is already in the integer stack (is
 392 | the same as the saved friar)
 393 |
 394 | If the current frame is already a 6-word stack then all
 395 | that needs to be done is to change the vector# to TRACE.
 396 | If the frame is only a 4-word stack (meaning we got here
 397 | on an Unsupported data type exception), then we need to grow
 398 | the stack an extra 2 words and get the FPIAR from the FPU.
 399 |
 400 g_trace:
 401         bftst   EXC_VEC-4(%sp){#0:#4}
 402         bne     g_easy
 403 
 404         subw    #4,%sp          | make room
 405         movel   4(%sp),(%sp)
 406         movel   8(%sp),4(%sp)
 407         subw    #BUSY_SIZE,%sp
 408         fsave   (%sp)
 409         fmovel  %fpiar,BUSY_SIZE+EXC_EA-4(%sp)
 410         frestore (%sp)
 411         addw    #BUSY_SIZE,%sp
 412 
 413 g_easy:
 414         movew   #TRACE_VEC,EXC_VEC-4(%a7)
 415         bral    real_trace
 416 |
 417 |  This is a work-around for hardware bug 1384.
 418 |
 419 bug1384:
 420         link    %a5,#0
 421         fsave   -(%sp)
 422         cmpib   #0x41,(%sp)     | check for correct frame
 423         beq     frame_41
 424         bgt     nofix           | if more advanced mask, do nada
 425 
 426 frame_40:
 427         tstb    1(%sp)          | check to see if idle
 428         bne     notidle
 429 idle40:
 430         clrl    (%sp)           | get rid of old fsave frame
 431         movel  %d1,USER_D1(%a6)  | save d1
 432         movew   #8,%d1          | place unimp frame instead
 433 loop40: clrl    -(%sp)
 434         dbra    %d1,loop40
 435         movel  USER_D1(%a6),%d1  | restore d1
 436         movel   #0x40280000,-(%sp)
 437         frestore (%sp)+
 438         unlk    %a5
 439         rts
 440 
 441 frame_41:
 442         tstb    1(%sp)          | check to see if idle
 443         bne     notidle
 444 idle41:
 445         clrl    (%sp)           | get rid of old fsave frame
 446         movel  %d1,USER_D1(%a6)  | save d1
 447         movew   #10,%d1         | place unimp frame instead
 448 loop41: clrl    -(%sp)
 449         dbra    %d1,loop41
 450         movel  USER_D1(%a6),%d1  | restore d1
 451         movel   #0x41300000,-(%sp)
 452         frestore (%sp)+
 453         unlk    %a5
 454         rts
 455 
 456 notidle:
 457         bclrb   #etemp15_bit,-40(%a5)
 458         frestore (%sp)+
 459         unlk    %a5
 460         rts
 461 
 462 nofix:
 463         frestore (%sp)+
 464         unlk    %a5
 465         rts
 466 
 467         |end

/* [<][>][^][v][top][bottom][index][help] */