123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468 |
- |
- | gen_except.sa 3.7 1/16/92
- |
- | gen_except --- FPSP routine to detect reportable exceptions
- |
- | This routine compares the exception enable byte of the
- | user_fpcr on the stack with the exception status byte
- | of the user_fpsr.
- |
- | Any routine which may report an exceptions must load
- | the stack frame in memory with the exceptional operand(s).
- |
- | Priority for exceptions is:
- |
- | Highest: bsun
- | snan
- | operr
- | ovfl
- | unfl
- | dz
- | inex2
- | Lowest: inex1
- |
- | Note: The IEEE standard specifies that inex2 is to be
- | reported if ovfl occurs and the ovfl enable bit is not
- | set but the inex2 enable bit is.
- |
- |
- | Copyright (C) Motorola, Inc. 1990
- | All Rights Reserved
- |
- | For details on the license for this file, please see the
- | file, README, in this same directory.
- GEN_EXCEPT: |idnt 2,1 | Motorola 040 Floating Point Software Package
- |section 8
- #include "fpsp.h"
- |xref real_trace
- |xref fpsp_done
- |xref fpsp_fmt_error
- exc_tbl:
- .long bsun_exc
- .long commonE1
- .long commonE1
- .long ovfl_unfl
- .long ovfl_unfl
- .long commonE1
- .long commonE3
- .long commonE3
- .long no_match
- .global gen_except
- gen_except:
- cmpib #IDLE_SIZE-4,1(%a7) |test for idle frame
- beq do_check |go handle idle frame
- cmpib #UNIMP_40_SIZE-4,1(%a7) |test for orig unimp frame
- beqs unimp_x |go handle unimp frame
- cmpib #UNIMP_41_SIZE-4,1(%a7) |test for rev unimp frame
- beqs unimp_x |go handle unimp frame
- cmpib #BUSY_SIZE-4,1(%a7) |if size <> $60, fmt error
- bnel fpsp_fmt_error
- leal BUSY_SIZE+LOCAL_SIZE(%a7),%a1 |init a1 so fpsp.h
- | ;equates will work
- | Fix up the new busy frame with entries from the unimp frame
- |
- movel ETEMP_EX(%a6),ETEMP_EX(%a1) |copy etemp from unimp
- movel ETEMP_HI(%a6),ETEMP_HI(%a1) |frame to busy frame
- movel ETEMP_LO(%a6),ETEMP_LO(%a1)
- movel CMDREG1B(%a6),CMDREG1B(%a1) |set inst in frame to unimp
- movel CMDREG1B(%a6),%d0 |fix cmd1b to make it
- andl #0x03c30000,%d0 |work for cmd3b
- bfextu CMDREG1B(%a6){#13:#1},%d1 |extract bit 2
- lsll #5,%d1
- swap %d1
- orl %d1,%d0 |put it in the right place
- bfextu CMDREG1B(%a6){#10:#3},%d1 |extract bit 3,4,5
- lsll #2,%d1
- swap %d1
- orl %d1,%d0 |put them in the right place
- movel %d0,CMDREG3B(%a1) |in the busy frame
- |
- | Or in the FPSR from the emulation with the USER_FPSR on the stack.
- |
- fmovel %FPSR,%d0
- orl %d0,USER_FPSR(%a6)
- movel USER_FPSR(%a6),FPSR_SHADOW(%a1) |set exc bits
- orl #sx_mask,E_BYTE(%a1)
- bra do_clean
- |
- | Frame is an unimp frame possible resulting from an fmove <ea>,fp0
- | that caused an exception
- |
- | a1 is modified to point into the new frame allowing fpsp equates
- | to be valid.
- |
- unimp_x:
- cmpib #UNIMP_40_SIZE-4,1(%a7) |test for orig unimp frame
- bnes test_rev
- leal UNIMP_40_SIZE+LOCAL_SIZE(%a7),%a1
- bras unimp_con
- test_rev:
- cmpib #UNIMP_41_SIZE-4,1(%a7) |test for rev unimp frame
- bnel fpsp_fmt_error |if not $28 or $30
- leal UNIMP_41_SIZE+LOCAL_SIZE(%a7),%a1
- unimp_con:
- |
- | Fix up the new unimp frame with entries from the old unimp frame
- |
- movel CMDREG1B(%a6),CMDREG1B(%a1) |set inst in frame to unimp
- |
- | Or in the FPSR from the emulation with the USER_FPSR on the stack.
- |
- fmovel %FPSR,%d0
- orl %d0,USER_FPSR(%a6)
- bra do_clean
- |
- | Frame is idle, so check for exceptions reported through
- | USER_FPSR and set the unimp frame accordingly.
- | A7 must be incremented to the point before the
- | idle fsave vector to the unimp vector.
- |
- do_check:
- addl #4,%a7 |point A7 back to unimp frame
- |
- | Or in the FPSR from the emulation with the USER_FPSR on the stack.
- |
- fmovel %FPSR,%d0
- orl %d0,USER_FPSR(%a6)
- |
- | On a busy frame, we must clear the nmnexc bits.
- |
- cmpib #BUSY_SIZE-4,1(%a7) |check frame type
- bnes check_fr |if busy, clr nmnexc
- clrw NMNEXC(%a6) |clr nmnexc & nmcexc
- btstb #5,CMDREG1B(%a6) |test for fmove out
- bnes frame_com
- movel USER_FPSR(%a6),FPSR_SHADOW(%a6) |set exc bits
- orl #sx_mask,E_BYTE(%a6)
- bras frame_com
- check_fr:
- cmpb #UNIMP_40_SIZE-4,1(%a7)
- beqs frame_com
- clrw NMNEXC(%a6)
- frame_com:
- moveb FPCR_ENABLE(%a6),%d0 |get fpcr enable byte
- andb FPSR_EXCEPT(%a6),%d0 |and in the fpsr exc byte
- bfffo %d0{#24:#8},%d1 |test for first set bit
- leal exc_tbl,%a0 |load jmp table address
- subib #24,%d1 |normalize bit offset to 0-8
- movel (%a0,%d1.w*4),%a0 |load routine address based
- | ;based on first enabled exc
- jmp (%a0) |jump to routine
- |
- | Bsun is not possible in unimp or unsupp
- |
- bsun_exc:
- bra do_clean
- |
- | The typical work to be done to the unimp frame to report an
- | exception is to set the E1/E3 byte and clr the U flag.
- | commonE1 does this for E1 exceptions, which are snan,
- | operr, and dz. commonE3 does this for E3 exceptions, which
- | are inex2 and inex1, and also clears the E1 exception bit
- | left over from the unimp exception.
- |
- commonE1:
- bsetb #E1,E_BYTE(%a6) |set E1 flag
- bra commonE |go clean and exit
- commonE3:
- tstb UFLG_TMP(%a6) |test flag for unsup/unimp state
- bnes unsE3
- uniE3:
- bsetb #E3,E_BYTE(%a6) |set E3 flag
- bclrb #E1,E_BYTE(%a6) |clr E1 from unimp
- bra commonE
- unsE3:
- tstb RES_FLG(%a6)
- bnes unsE3_0
- unsE3_1:
- bsetb #E3,E_BYTE(%a6) |set E3 flag
- unsE3_0:
- bclrb #E1,E_BYTE(%a6) |clr E1 flag
- movel CMDREG1B(%a6),%d0
- andl #0x03c30000,%d0 |work for cmd3b
- bfextu CMDREG1B(%a6){#13:#1},%d1 |extract bit 2
- lsll #5,%d1
- swap %d1
- orl %d1,%d0 |put it in the right place
- bfextu CMDREG1B(%a6){#10:#3},%d1 |extract bit 3,4,5
- lsll #2,%d1
- swap %d1
- orl %d1,%d0 |put them in the right place
- movel %d0,CMDREG3B(%a6) |in the busy frame
- commonE:
- bclrb #UFLAG,T_BYTE(%a6) |clr U flag from unimp
- bra do_clean |go clean and exit
- |
- | No bits in the enable byte match existing exceptions. Check for
- | the case of the ovfl exc without the ovfl enabled, but with
- | inex2 enabled.
- |
- no_match:
- btstb #inex2_bit,FPCR_ENABLE(%a6) |check for ovfl/inex2 case
- beqs no_exc |if clear, exit
- btstb #ovfl_bit,FPSR_EXCEPT(%a6) |now check ovfl
- beqs no_exc |if clear, exit
- bras ovfl_unfl |go to unfl_ovfl to determine if
- | ;it is an unsupp or unimp exc
- | No exceptions are to be reported. If the instruction was
- | unimplemented, no FPU restore is necessary. If it was
- | unsupported, we must perform the restore.
- no_exc:
- tstb UFLG_TMP(%a6) |test flag for unsupp/unimp state
- beqs uni_no_exc
- uns_no_exc:
- tstb RES_FLG(%a6) |check if frestore is needed
- bne do_clean |if clear, no frestore needed
- uni_no_exc:
- moveml USER_DA(%a6),%d0-%d1/%a0-%a1
- fmovemx USER_FP0(%a6),%fp0-%fp3
- fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
- unlk %a6
- bra finish_up
- |
- | Unsupported Data Type Handler:
- | Ovfl:
- | An fmoveout that results in an overflow is reported this way.
- | Unfl:
- | An fmoveout that results in an underflow is reported this way.
- |
- | Unimplemented Instruction Handler:
- | Ovfl:
- | Only scosh, setox, ssinh, stwotox, and scale can set overflow in
- | this manner.
- | Unfl:
- | Stwotox, setox, and scale can set underflow in this manner.
- | Any of the other Library Routines such that f(x)=x in which
- | x is an extended denorm can report an underflow exception.
- | It is the responsibility of the exception-causing exception
- | to make sure that WBTEMP is correct.
- |
- | The exceptional operand is in FP_SCR1.
- |
- ovfl_unfl:
- tstb UFLG_TMP(%a6) |test flag for unsupp/unimp state
- beqs ofuf_con
- |
- | The caller was from an unsupported data type trap. Test if the
- | caller set CU_ONLY. If so, the exceptional operand is expected in
- | FPTEMP, rather than WBTEMP.
- |
- tstb CU_ONLY(%a6) |test if inst is cu-only
- beq unsE3
- | move.w #$fe,CU_SAVEPC(%a6)
- clrb CU_SAVEPC(%a6)
- bsetb #E1,E_BYTE(%a6) |set E1 exception flag
- movew ETEMP_EX(%a6),FPTEMP_EX(%a6)
- movel ETEMP_HI(%a6),FPTEMP_HI(%a6)
- movel ETEMP_LO(%a6),FPTEMP_LO(%a6)
- bsetb #fptemp15_bit,DTAG(%a6) |set fpte15
- bclrb #UFLAG,T_BYTE(%a6) |clr U flag from unimp
- bra do_clean |go clean and exit
- ofuf_con:
- moveb (%a7),VER_TMP(%a6) |save version number
- cmpib #BUSY_SIZE-4,1(%a7) |check for busy frame
- beqs busy_fr |if unimp, grow to busy
- cmpib #VER_40,(%a7) |test for orig unimp frame
- bnes try_41 |if not, test for rev frame
- moveql #13,%d0 |need to zero 14 lwords
- bras ofuf_fin
- try_41:
- cmpib #VER_41,(%a7) |test for rev unimp frame
- bnel fpsp_fmt_error |if neither, exit with error
- moveql #11,%d0 |need to zero 12 lwords
- ofuf_fin:
- clrl (%a7)
- loop1:
- clrl -(%a7) |clear and dec a7
- dbra %d0,loop1
- moveb VER_TMP(%a6),(%a7)
- moveb #BUSY_SIZE-4,1(%a7) |write busy fmt word.
- busy_fr:
- movel FP_SCR1(%a6),WBTEMP_EX(%a6) |write
- movel FP_SCR1+4(%a6),WBTEMP_HI(%a6) |exceptional op to
- movel FP_SCR1+8(%a6),WBTEMP_LO(%a6) |wbtemp
- bsetb #E3,E_BYTE(%a6) |set E3 flag
- bclrb #E1,E_BYTE(%a6) |make sure E1 is clear
- bclrb #UFLAG,T_BYTE(%a6) |clr U flag
- movel USER_FPSR(%a6),FPSR_SHADOW(%a6)
- orl #sx_mask,E_BYTE(%a6)
- movel CMDREG1B(%a6),%d0 |fix cmd1b to make it
- andl #0x03c30000,%d0 |work for cmd3b
- bfextu CMDREG1B(%a6){#13:#1},%d1 |extract bit 2
- lsll #5,%d1
- swap %d1
- orl %d1,%d0 |put it in the right place
- bfextu CMDREG1B(%a6){#10:#3},%d1 |extract bit 3,4,5
- lsll #2,%d1
- swap %d1
- orl %d1,%d0 |put them in the right place
- movel %d0,CMDREG3B(%a6) |in the busy frame
- |
- | Check if the frame to be restored is busy or unimp.
- |** NOTE *** Bug fix for errata (0d43b #3)
- | If the frame is unimp, we must create a busy frame to
- | fix the bug with the nmnexc bits in cases in which they
- | are set by a previous instruction and not cleared by
- | the save. The frame will be unimp only if the final
- | instruction in an emulation routine caused the exception
- | by doing an fmove <ea>,fp0. The exception operand, in
- | internal format, is in fptemp.
- |
- do_clean:
- cmpib #UNIMP_40_SIZE-4,1(%a7)
- bnes do_con
- moveql #13,%d0 |in orig, need to zero 14 lwords
- bras do_build
- do_con:
- cmpib #UNIMP_41_SIZE-4,1(%a7)
- bnes do_restore |frame must be busy
- moveql #11,%d0 |in rev, need to zero 12 lwords
- do_build:
- moveb (%a7),VER_TMP(%a6)
- clrl (%a7)
- loop2:
- clrl -(%a7) |clear and dec a7
- dbra %d0,loop2
- |
- | Use a1 as pointer into new frame. a6 is not correct if an unimp or
- | busy frame was created as the result of an exception on the final
- | instruction of an emulation routine.
- |
- | We need to set the nmcexc bits if the exception is E1. Otherwise,
- | the exc taken will be inex2.
- |
- leal BUSY_SIZE+LOCAL_SIZE(%a7),%a1 |init a1 for new frame
- moveb VER_TMP(%a6),(%a7) |write busy fmt word
- moveb #BUSY_SIZE-4,1(%a7)
- movel FP_SCR1(%a6),WBTEMP_EX(%a1) |write
- movel FP_SCR1+4(%a6),WBTEMP_HI(%a1) |exceptional op to
- movel FP_SCR1+8(%a6),WBTEMP_LO(%a1) |wbtemp
- | btst.b #E1,E_BYTE(%a1)
- | beq.b do_restore
- bfextu USER_FPSR(%a6){#17:#4},%d0 |get snan/operr/ovfl/unfl bits
- bfins %d0,NMCEXC(%a1){#4:#4} |and insert them in nmcexc
- movel USER_FPSR(%a6),FPSR_SHADOW(%a1) |set exc bits
- orl #sx_mask,E_BYTE(%a1)
- do_restore:
- moveml USER_DA(%a6),%d0-%d1/%a0-%a1
- fmovemx USER_FP0(%a6),%fp0-%fp3
- fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
- frestore (%a7)+
- tstb RES_FLG(%a6) |RES_FLG indicates a "continuation" frame
- beq cont
- bsr bug1384
- cont:
- unlk %a6
- |
- | If trace mode enabled, then go to trace handler. This handler
- | cannot have any fp instructions. If there are fp inst's and an
- | exception has been restored into the machine then the exception
- | will occur upon execution of the fp inst. This is not desirable
- | in the kernel (supervisor mode). See MC68040 manual Section 9.3.8.
- |
- finish_up:
- btstb #7,(%a7) |test T1 in SR
- bnes g_trace
- btstb #6,(%a7) |test T0 in SR
- bnes g_trace
- bral fpsp_done
- |
- | Change integer stack to look like trace stack
- | The address of the instruction that caused the
- | exception is already in the integer stack (is
- | the same as the saved friar)
- |
- | If the current frame is already a 6-word stack then all
- | that needs to be done is to change the vector# to TRACE.
- | If the frame is only a 4-word stack (meaning we got here
- | on an Unsupported data type exception), then we need to grow
- | the stack an extra 2 words and get the FPIAR from the FPU.
- |
- g_trace:
- bftst EXC_VEC-4(%sp){#0:#4}
- bne g_easy
- subw #4,%sp | make room
- movel 4(%sp),(%sp)
- movel 8(%sp),4(%sp)
- subw #BUSY_SIZE,%sp
- fsave (%sp)
- fmovel %fpiar,BUSY_SIZE+EXC_EA-4(%sp)
- frestore (%sp)
- addw #BUSY_SIZE,%sp
- g_easy:
- movew #TRACE_VEC,EXC_VEC-4(%a7)
- bral real_trace
- |
- | This is a work-around for hardware bug 1384.
- |
- bug1384:
- link %a5,#0
- fsave -(%sp)
- cmpib #0x41,(%sp) | check for correct frame
- beq frame_41
- bgt nofix | if more advanced mask, do nada
- frame_40:
- tstb 1(%sp) | check to see if idle
- bne notidle
- idle40:
- clrl (%sp) | get rid of old fsave frame
- movel %d1,USER_D1(%a6) | save d1
- movew #8,%d1 | place unimp frame instead
- loop40: clrl -(%sp)
- dbra %d1,loop40
- movel USER_D1(%a6),%d1 | restore d1
- movel #0x40280000,-(%sp)
- frestore (%sp)+
- unlk %a5
- rts
- frame_41:
- tstb 1(%sp) | check to see if idle
- bne notidle
- idle41:
- clrl (%sp) | get rid of old fsave frame
- movel %d1,USER_D1(%a6) | save d1
- movew #10,%d1 | place unimp frame instead
- loop41: clrl -(%sp)
- dbra %d1,loop41
- movel USER_D1(%a6),%d1 | restore d1
- movel #0x41300000,-(%sp)
- frestore (%sp)+
- unlk %a5
- rts
- notidle:
- bclrb #etemp15_bit,-40(%a5)
- frestore (%sp)+
- unlk %a5
- rts
- nofix:
- frestore (%sp)+
- unlk %a5
- rts
- |end
|