Back to home page

LXR

 
 

    


0001 |
0002 |   gen_except.sa 3.7 1/16/92
0003 |
0004 |   gen_except --- FPSP routine to detect reportable exceptions
0005 |
0006 |   This routine compares the exception enable byte of the
0007 |   user_fpcr on the stack with the exception status byte
0008 |   of the user_fpsr.
0009 |
0010 |   Any routine which may report an exceptions must load
0011 |   the stack frame in memory with the exceptional operand(s).
0012 |
0013 |   Priority for exceptions is:
0014 |
0015 |   Highest:    bsun
0016 |           snan
0017 |           operr
0018 |           ovfl
0019 |           unfl
0020 |           dz
0021 |           inex2
0022 |   Lowest:     inex1
0023 |
0024 |   Note: The IEEE standard specifies that inex2 is to be
0025 |   reported if ovfl occurs and the ovfl enable bit is not
0026 |   set but the inex2 enable bit is.
0027 |
0028 |
0029 |       Copyright (C) Motorola, Inc. 1990
0030 |           All Rights Reserved
0031 |
0032 |       For details on the license for this file, please see the
0033 |       file, README, in this same directory.
0034 
0035 GEN_EXCEPT:    |idnt    2,1 | Motorola 040 Floating Point Software Package
0036 
0037     |section 8
0038 
0039 #include "fpsp.h"
0040 
0041     |xref   real_trace
0042     |xref   fpsp_done
0043     |xref   fpsp_fmt_error
0044 
0045 exc_tbl:
0046     .long   bsun_exc
0047     .long   commonE1
0048     .long   commonE1
0049     .long   ovfl_unfl
0050     .long   ovfl_unfl
0051     .long   commonE1
0052     .long   commonE3
0053     .long   commonE3
0054     .long   no_match
0055 
0056     .global gen_except
0057 gen_except:
0058     cmpib   #IDLE_SIZE-4,1(%a7) |test for idle frame
0059     beq do_check        |go handle idle frame
0060     cmpib   #UNIMP_40_SIZE-4,1(%a7) |test for orig unimp frame
0061     beqs    unimp_x         |go handle unimp frame
0062     cmpib   #UNIMP_41_SIZE-4,1(%a7) |test for rev unimp frame
0063     beqs    unimp_x         |go handle unimp frame
0064     cmpib   #BUSY_SIZE-4,1(%a7) |if size <> $60, fmt error
0065     bnel    fpsp_fmt_error
0066     leal    BUSY_SIZE+LOCAL_SIZE(%a7),%a1 |init a1 so fpsp.h
0067 |                   ;equates will work
0068 | Fix up the new busy frame with entries from the unimp frame
0069 |
0070     movel   ETEMP_EX(%a6),ETEMP_EX(%a1) |copy etemp from unimp
0071     movel   ETEMP_HI(%a6),ETEMP_HI(%a1) |frame to busy frame
0072     movel   ETEMP_LO(%a6),ETEMP_LO(%a1)
0073     movel   CMDREG1B(%a6),CMDREG1B(%a1) |set inst in frame to unimp
0074     movel   CMDREG1B(%a6),%d0       |fix cmd1b to make it
0075     andl    #0x03c30000,%d0     |work for cmd3b
0076     bfextu  CMDREG1B(%a6){#13:#1},%d1   |extract bit 2
0077     lsll    #5,%d1
0078     swap    %d1
0079     orl %d1,%d0         |put it in the right place
0080     bfextu  CMDREG1B(%a6){#10:#3},%d1   |extract bit 3,4,5
0081     lsll    #2,%d1
0082     swap    %d1
0083     orl %d1,%d0         |put them in the right place
0084     movel   %d0,CMDREG3B(%a1)       |in the busy frame
0085 |
0086 | Or in the FPSR from the emulation with the USER_FPSR on the stack.
0087 |
0088     fmovel  %FPSR,%d0
0089     orl %d0,USER_FPSR(%a6)
0090     movel   USER_FPSR(%a6),FPSR_SHADOW(%a1) |set exc bits
0091     orl #sx_mask,E_BYTE(%a1)
0092     bra do_clean
0093 
0094 |
0095 | Frame is an unimp frame possible resulting from an fmove <ea>,fp0
0096 | that caused an exception
0097 |
0098 | a1 is modified to point into the new frame allowing fpsp equates
0099 | to be valid.
0100 |
0101 unimp_x:
0102     cmpib   #UNIMP_40_SIZE-4,1(%a7) |test for orig unimp frame
0103     bnes    test_rev
0104     leal    UNIMP_40_SIZE+LOCAL_SIZE(%a7),%a1
0105     bras    unimp_con
0106 test_rev:
0107     cmpib   #UNIMP_41_SIZE-4,1(%a7) |test for rev unimp frame
0108     bnel    fpsp_fmt_error      |if not $28 or $30
0109     leal    UNIMP_41_SIZE+LOCAL_SIZE(%a7),%a1
0110 
0111 unimp_con:
0112 |
0113 | Fix up the new unimp frame with entries from the old unimp frame
0114 |
0115     movel   CMDREG1B(%a6),CMDREG1B(%a1) |set inst in frame to unimp
0116 |
0117 | Or in the FPSR from the emulation with the USER_FPSR on the stack.
0118 |
0119     fmovel  %FPSR,%d0
0120     orl %d0,USER_FPSR(%a6)
0121     bra do_clean
0122 
0123 |
0124 | Frame is idle, so check for exceptions reported through
0125 | USER_FPSR and set the unimp frame accordingly.
0126 | A7 must be incremented to the point before the
0127 | idle fsave vector to the unimp vector.
0128 |
0129 
0130 do_check:
0131     addl    #4,%a7          |point A7 back to unimp frame
0132 |
0133 | Or in the FPSR from the emulation with the USER_FPSR on the stack.
0134 |
0135     fmovel  %FPSR,%d0
0136     orl %d0,USER_FPSR(%a6)
0137 |
0138 | On a busy frame, we must clear the nmnexc bits.
0139 |
0140     cmpib   #BUSY_SIZE-4,1(%a7) |check frame type
0141     bnes    check_fr        |if busy, clr nmnexc
0142     clrw    NMNEXC(%a6)     |clr nmnexc & nmcexc
0143     btstb   #5,CMDREG1B(%a6)        |test for fmove out
0144     bnes    frame_com
0145     movel   USER_FPSR(%a6),FPSR_SHADOW(%a6) |set exc bits
0146     orl #sx_mask,E_BYTE(%a6)
0147     bras    frame_com
0148 check_fr:
0149     cmpb    #UNIMP_40_SIZE-4,1(%a7)
0150     beqs    frame_com
0151     clrw    NMNEXC(%a6)
0152 frame_com:
0153     moveb   FPCR_ENABLE(%a6),%d0    |get fpcr enable byte
0154     andb    FPSR_EXCEPT(%a6),%d0    |and in the fpsr exc byte
0155     bfffo   %d0{#24:#8},%d1     |test for first set bit
0156     leal    exc_tbl,%a0     |load jmp table address
0157     subib   #24,%d1         |normalize bit offset to 0-8
0158     movel   (%a0,%d1.w*4),%a0       |load routine address based
0159 |                   ;based on first enabled exc
0160     jmp (%a0)           |jump to routine
0161 |
0162 | Bsun is not possible in unimp or unsupp
0163 |
0164 bsun_exc:
0165     bra do_clean
0166 |
0167 | The typical work to be done to the unimp frame to report an
0168 | exception is to set the E1/E3 byte and clr the U flag.
0169 | commonE1 does this for E1 exceptions, which are snan,
0170 | operr, and dz.  commonE3 does this for E3 exceptions, which
0171 | are inex2 and inex1, and also clears the E1 exception bit
0172 | left over from the unimp exception.
0173 |
0174 commonE1:
0175     bsetb   #E1,E_BYTE(%a6)     |set E1 flag
0176     bra commonE         |go clean and exit
0177 
0178 commonE3:
0179     tstb    UFLG_TMP(%a6)       |test flag for unsup/unimp state
0180     bnes    unsE3
0181 uniE3:
0182     bsetb   #E3,E_BYTE(%a6)     |set E3 flag
0183     bclrb   #E1,E_BYTE(%a6)     |clr E1 from unimp
0184     bra commonE
0185 
0186 unsE3:
0187     tstb    RES_FLG(%a6)
0188     bnes    unsE3_0
0189 unsE3_1:
0190     bsetb   #E3,E_BYTE(%a6)     |set E3 flag
0191 unsE3_0:
0192     bclrb   #E1,E_BYTE(%a6)     |clr E1 flag
0193     movel   CMDREG1B(%a6),%d0
0194     andl    #0x03c30000,%d0     |work for cmd3b
0195     bfextu  CMDREG1B(%a6){#13:#1},%d1   |extract bit 2
0196     lsll    #5,%d1
0197     swap    %d1
0198     orl %d1,%d0         |put it in the right place
0199     bfextu  CMDREG1B(%a6){#10:#3},%d1   |extract bit 3,4,5
0200     lsll    #2,%d1
0201     swap    %d1
0202     orl %d1,%d0         |put them in the right place
0203     movel   %d0,CMDREG3B(%a6)       |in the busy frame
0204 
0205 commonE:
0206     bclrb   #UFLAG,T_BYTE(%a6)  |clr U flag from unimp
0207     bra do_clean        |go clean and exit
0208 |
0209 | No bits in the enable byte match existing exceptions.  Check for
0210 | the case of the ovfl exc without the ovfl enabled, but with
0211 | inex2 enabled.
0212 |
0213 no_match:
0214     btstb   #inex2_bit,FPCR_ENABLE(%a6) |check for ovfl/inex2 case
0215     beqs    no_exc          |if clear, exit
0216     btstb   #ovfl_bit,FPSR_EXCEPT(%a6) |now check ovfl
0217     beqs    no_exc          |if clear, exit
0218     bras    ovfl_unfl       |go to unfl_ovfl to determine if
0219 |                   ;it is an unsupp or unimp exc
0220 
0221 | No exceptions are to be reported.  If the instruction was
0222 | unimplemented, no FPU restore is necessary.  If it was
0223 | unsupported, we must perform the restore.
0224 no_exc:
0225     tstb    UFLG_TMP(%a6)   |test flag for unsupp/unimp state
0226     beqs    uni_no_exc
0227 uns_no_exc:
0228     tstb    RES_FLG(%a6)    |check if frestore is needed
0229     bne do_clean    |if clear, no frestore needed
0230 uni_no_exc:
0231     moveml  USER_DA(%a6),%d0-%d1/%a0-%a1
0232     fmovemx USER_FP0(%a6),%fp0-%fp3
0233     fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
0234     unlk    %a6
0235     bra finish_up
0236 |
0237 | Unsupported Data Type Handler:
0238 | Ovfl:
0239 |   An fmoveout that results in an overflow is reported this way.
0240 | Unfl:
0241 |   An fmoveout that results in an underflow is reported this way.
0242 |
0243 | Unimplemented Instruction Handler:
0244 | Ovfl:
0245 |   Only scosh, setox, ssinh, stwotox, and scale can set overflow in
0246 |   this manner.
0247 | Unfl:
0248 |   Stwotox, setox, and scale can set underflow in this manner.
0249 |   Any of the other Library Routines such that f(x)=x in which
0250 |   x is an extended denorm can report an underflow exception.
0251 |   It is the responsibility of the exception-causing exception
0252 |   to make sure that WBTEMP is correct.
0253 |
0254 |   The exceptional operand is in FP_SCR1.
0255 |
0256 ovfl_unfl:
0257     tstb    UFLG_TMP(%a6)   |test flag for unsupp/unimp state
0258     beqs    ofuf_con
0259 |
0260 | The caller was from an unsupported data type trap.  Test if the
0261 | caller set CU_ONLY.  If so, the exceptional operand is expected in
0262 | FPTEMP, rather than WBTEMP.
0263 |
0264     tstb    CU_ONLY(%a6)        |test if inst is cu-only
0265     beq unsE3
0266 |   move.w  #$fe,CU_SAVEPC(%a6)
0267     clrb    CU_SAVEPC(%a6)
0268     bsetb   #E1,E_BYTE(%a6)     |set E1 exception flag
0269     movew   ETEMP_EX(%a6),FPTEMP_EX(%a6)
0270     movel   ETEMP_HI(%a6),FPTEMP_HI(%a6)
0271     movel   ETEMP_LO(%a6),FPTEMP_LO(%a6)
0272     bsetb   #fptemp15_bit,DTAG(%a6) |set fpte15
0273     bclrb   #UFLAG,T_BYTE(%a6)  |clr U flag from unimp
0274     bra do_clean        |go clean and exit
0275 
0276 ofuf_con:
0277     moveb   (%a7),VER_TMP(%a6)  |save version number
0278     cmpib   #BUSY_SIZE-4,1(%a7) |check for busy frame
0279     beqs    busy_fr         |if unimp, grow to busy
0280     cmpib   #VER_40,(%a7)       |test for orig unimp frame
0281     bnes    try_41          |if not, test for rev frame
0282     moveql  #13,%d0         |need to zero 14 lwords
0283     bras    ofuf_fin
0284 try_41:
0285     cmpib   #VER_41,(%a7)       |test for rev unimp frame
0286     bnel    fpsp_fmt_error      |if neither, exit with error
0287     moveql  #11,%d0         |need to zero 12 lwords
0288 
0289 ofuf_fin:
0290     clrl    (%a7)
0291 loop1:
0292     clrl    -(%a7)          |clear and dec a7
0293     dbra    %d0,loop1
0294     moveb   VER_TMP(%a6),(%a7)
0295     moveb   #BUSY_SIZE-4,1(%a7)     |write busy fmt word.
0296 busy_fr:
0297     movel   FP_SCR1(%a6),WBTEMP_EX(%a6) |write
0298     movel   FP_SCR1+4(%a6),WBTEMP_HI(%a6)   |exceptional op to
0299     movel   FP_SCR1+8(%a6),WBTEMP_LO(%a6)   |wbtemp
0300     bsetb   #E3,E_BYTE(%a6)         |set E3 flag
0301     bclrb   #E1,E_BYTE(%a6)         |make sure E1 is clear
0302     bclrb   #UFLAG,T_BYTE(%a6)      |clr U flag
0303     movel   USER_FPSR(%a6),FPSR_SHADOW(%a6)
0304     orl #sx_mask,E_BYTE(%a6)
0305     movel   CMDREG1B(%a6),%d0       |fix cmd1b to make it
0306     andl    #0x03c30000,%d0     |work for cmd3b
0307     bfextu  CMDREG1B(%a6){#13:#1},%d1   |extract bit 2
0308     lsll    #5,%d1
0309     swap    %d1
0310     orl %d1,%d0         |put it in the right place
0311     bfextu  CMDREG1B(%a6){#10:#3},%d1   |extract bit 3,4,5
0312     lsll    #2,%d1
0313     swap    %d1
0314     orl %d1,%d0         |put them in the right place
0315     movel   %d0,CMDREG3B(%a6)       |in the busy frame
0316 
0317 |
0318 | Check if the frame to be restored is busy or unimp.
0319 |** NOTE *** Bug fix for errata (0d43b #3)
0320 | If the frame is unimp, we must create a busy frame to
0321 | fix the bug with the nmnexc bits in cases in which they
0322 | are set by a previous instruction and not cleared by
0323 | the save. The frame will be unimp only if the final
0324 | instruction in an emulation routine caused the exception
0325 | by doing an fmove <ea>,fp0.  The exception operand, in
0326 | internal format, is in fptemp.
0327 |
0328 do_clean:
0329     cmpib   #UNIMP_40_SIZE-4,1(%a7)
0330     bnes    do_con
0331     moveql  #13,%d0         |in orig, need to zero 14 lwords
0332     bras    do_build
0333 do_con:
0334     cmpib   #UNIMP_41_SIZE-4,1(%a7)
0335     bnes    do_restore      |frame must be busy
0336     moveql  #11,%d0         |in rev, need to zero 12 lwords
0337 
0338 do_build:
0339     moveb   (%a7),VER_TMP(%a6)
0340     clrl    (%a7)
0341 loop2:
0342     clrl    -(%a7)          |clear and dec a7
0343     dbra    %d0,loop2
0344 |
0345 | Use a1 as pointer into new frame.  a6 is not correct if an unimp or
0346 | busy frame was created as the result of an exception on the final
0347 | instruction of an emulation routine.
0348 |
0349 | We need to set the nmcexc bits if the exception is E1. Otherwise,
0350 | the exc taken will be inex2.
0351 |
0352     leal    BUSY_SIZE+LOCAL_SIZE(%a7),%a1   |init a1 for new frame
0353     moveb   VER_TMP(%a6),(%a7)  |write busy fmt word
0354     moveb   #BUSY_SIZE-4,1(%a7)
0355     movel   FP_SCR1(%a6),WBTEMP_EX(%a1) |write
0356     movel   FP_SCR1+4(%a6),WBTEMP_HI(%a1)   |exceptional op to
0357     movel   FP_SCR1+8(%a6),WBTEMP_LO(%a1)   |wbtemp
0358 |   btst.b  #E1,E_BYTE(%a1)
0359 |   beq.b   do_restore
0360     bfextu  USER_FPSR(%a6){#17:#4},%d0  |get snan/operr/ovfl/unfl bits
0361     bfins   %d0,NMCEXC(%a1){#4:#4}  |and insert them in nmcexc
0362     movel   USER_FPSR(%a6),FPSR_SHADOW(%a1) |set exc bits
0363     orl #sx_mask,E_BYTE(%a1)
0364 
0365 do_restore:
0366     moveml  USER_DA(%a6),%d0-%d1/%a0-%a1
0367     fmovemx USER_FP0(%a6),%fp0-%fp3
0368     fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
0369     frestore (%a7)+
0370     tstb    RES_FLG(%a6)    |RES_FLG indicates a "continuation" frame
0371     beq cont
0372     bsr bug1384
0373 cont:
0374     unlk    %a6
0375 |
0376 | If trace mode enabled, then go to trace handler.  This handler
0377 | cannot have any fp instructions.  If there are fp inst's and an
0378 | exception has been restored into the machine then the exception
0379 | will occur upon execution of the fp inst.  This is not desirable
0380 | in the kernel (supervisor mode).  See MC68040 manual Section 9.3.8.
0381 |
0382 finish_up:
0383     btstb   #7,(%a7)        |test T1 in SR
0384     bnes    g_trace
0385     btstb   #6,(%a7)        |test T0 in SR
0386     bnes    g_trace
0387     bral    fpsp_done
0388 |
0389 | Change integer stack to look like trace stack
0390 | The address of the instruction that caused the
0391 | exception is already in the integer stack (is
0392 | the same as the saved friar)
0393 |
0394 | If the current frame is already a 6-word stack then all
0395 | that needs to be done is to change the vector# to TRACE.
0396 | If the frame is only a 4-word stack (meaning we got here
0397 | on an Unsupported data type exception), then we need to grow
0398 | the stack an extra 2 words and get the FPIAR from the FPU.
0399 |
0400 g_trace:
0401     bftst   EXC_VEC-4(%sp){#0:#4}
0402     bne g_easy
0403 
0404     subw    #4,%sp      | make room
0405     movel   4(%sp),(%sp)
0406     movel   8(%sp),4(%sp)
0407     subw    #BUSY_SIZE,%sp
0408     fsave   (%sp)
0409     fmovel  %fpiar,BUSY_SIZE+EXC_EA-4(%sp)
0410     frestore (%sp)
0411     addw    #BUSY_SIZE,%sp
0412 
0413 g_easy:
0414     movew   #TRACE_VEC,EXC_VEC-4(%a7)
0415     bral    real_trace
0416 |
0417 |  This is a work-around for hardware bug 1384.
0418 |
0419 bug1384:
0420     link    %a5,#0
0421     fsave   -(%sp)
0422     cmpib   #0x41,(%sp) | check for correct frame
0423     beq frame_41
0424     bgt nofix       | if more advanced mask, do nada
0425 
0426 frame_40:
0427     tstb    1(%sp)      | check to see if idle
0428     bne notidle
0429 idle40:
0430     clrl    (%sp)       | get rid of old fsave frame
0431         movel  %d1,USER_D1(%a6)  | save d1
0432     movew   #8,%d1      | place unimp frame instead
0433 loop40: clrl    -(%sp)
0434     dbra    %d1,loop40
0435         movel  USER_D1(%a6),%d1  | restore d1
0436     movel   #0x40280000,-(%sp)
0437     frestore (%sp)+
0438     unlk    %a5
0439     rts
0440 
0441 frame_41:
0442     tstb    1(%sp)      | check to see if idle
0443     bne notidle
0444 idle41:
0445     clrl    (%sp)       | get rid of old fsave frame
0446         movel  %d1,USER_D1(%a6)  | save d1
0447     movew   #10,%d1     | place unimp frame instead
0448 loop41: clrl    -(%sp)
0449     dbra    %d1,loop41
0450         movel  USER_D1(%a6),%d1  | restore d1
0451     movel   #0x41300000,-(%sp)
0452     frestore (%sp)+
0453     unlk    %a5
0454     rts
0455 
0456 notidle:
0457     bclrb   #etemp15_bit,-40(%a5)
0458     frestore (%sp)+
0459     unlk    %a5
0460     rts
0461 
0462 nofix:
0463     frestore (%sp)+
0464     unlk    %a5
0465     rts
0466 
0467     |end