Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:48

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