NetBSD/sys/arch/m68k/fpsp/gen_except.sa

494 lines
14 KiB
Plaintext

* $NetBSD: gen_except.sa,v 1.3 1994/10/26 07:49:07 cgd Exp $
* MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP
* M68000 Hi-Performance Microprocessor Division
* M68040 Software Package
*
* M68040 Software Package Copyright (c) 1993, 1994 Motorola Inc.
* All rights reserved.
*
* THE SOFTWARE is provided on an "AS IS" basis and without warranty.
* To the maximum extent permitted by applicable law,
* MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED,
* INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A
* PARTICULAR PURPOSE and any warranty against infringement with
* regard to the SOFTWARE (INCLUDING ANY MODIFIED VERSIONS THEREOF)
* and any accompanying written materials.
*
* To the maximum extent permitted by applicable law,
* IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER
* (INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS
* PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR
* OTHER PECUNIARY LOSS) ARISING OF THE USE OR INABILITY TO USE THE
* SOFTWARE. Motorola assumes no responsibility for the maintenance
* and support of the SOFTWARE.
*
* You are hereby granted a copyright license to use, modify, and
* distribute the SOFTWARE so long as this entire notice is retained
* without alteration in any modified and/or redistributed versions,
* and that such modified versions are clearly identified as such.
* No licenses are granted by implication, estoppel or otherwise
* under any patents or trademarks of Motorola, Inc.
*
* 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.
*
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:
dc.l bsun_exc
dc.l commonE1
dc.l commonE1
dc.l ovfl_unfl
dc.l ovfl_unfl
dc.l commonE1
dc.l commonE3
dc.l commonE3
dc.l no_match
xdef gen_except
gen_except:
cmpi.b #IDLE_SIZE-4,1(a7) ;test for idle frame
beq.w do_check ;go handle idle frame
cmpi.b #UNIMP_40_SIZE-4,1(a7) ;test for orig unimp frame
beq.b unimp_x ;go handle unimp frame
cmpi.b #UNIMP_41_SIZE-4,1(a7) ;test for rev unimp frame
beq.b unimp_x ;go handle unimp frame
cmpi.b #BUSY_SIZE-4,1(a7) ;if size <> $60, fmt error
bne.l fpsp_fmt_error
lea.l 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
*
move.l ETEMP_EX(a6),ETEMP_EX(a1) ;copy etemp from unimp
move.l ETEMP_HI(a6),ETEMP_HI(a1) ;frame to busy frame
move.l ETEMP_LO(a6),ETEMP_LO(a1)
move.l CMDREG1B(a6),CMDREG1B(a1) ;set inst in frame to unimp
move.l CMDREG1B(a6),d0 ;fix cmd1b to make it
and.l #$03c30000,d0 ;work for cmd3b
bfextu CMDREG1B(a6){13:1},d1 ;extract bit 2
lsl.l #5,d1
swap d1
or.l d1,d0 ;put it in the right place
bfextu CMDREG1B(a6){10:3},d1 ;extract bit 3,4,5
lsl.l #2,d1
swap d1
or.l d1,d0 ;put them in the right place
move.l d0,CMDREG3B(a1) ;in the busy frame
*
* Or in the FPSR from the emulation with the USER_FPSR on the stack.
*
fmove.l FPSR,d0
or.l d0,USER_FPSR(a6)
move.l USER_FPSR(a6),FPSR_SHADOW(a1) ;set exc bits
or.l #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:
cmpi.b #UNIMP_40_SIZE-4,1(a7) ;test for orig unimp frame
bne.b test_rev
lea.l UNIMP_40_SIZE+LOCAL_SIZE(a7),a1
bra.b unimp_con
test_rev:
cmpi.b #UNIMP_41_SIZE-4,1(a7) ;test for rev unimp frame
bne.l fpsp_fmt_error ;if not $28 or $30
lea.l UNIMP_41_SIZE+LOCAL_SIZE(a7),a1
unimp_con:
*
* Fix up the new unimp frame with entries from the old unimp frame
*
move.l CMDREG1B(a6),CMDREG1B(a1) ;set inst in frame to unimp
*
* Or in the FPSR from the emulation with the USER_FPSR on the stack.
*
fmove.l FPSR,d0
or.l 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:
add.l #4,A7 ;point A7 back to unimp frame
*
* Or in the FPSR from the emulation with the USER_FPSR on the stack.
*
fmove.l FPSR,d0
or.l d0,USER_FPSR(a6)
*
* On a busy frame, we must clear the nmnexc bits.
*
cmpi.b #BUSY_SIZE-4,1(a7) ;check frame type
bne.b check_fr ;if busy, clr nmnexc
clr.w NMNEXC(a6) ;clr nmnexc & nmcexc
btst.b #5,CMDREG1B(a6) ;test for fmove out
bne.b frame_com
move.l USER_FPSR(a6),FPSR_SHADOW(a6) ;set exc bits
or.l #sx_mask,E_BYTE(a6)
bra.b frame_com
check_fr:
cmp.b #UNIMP_40_SIZE-4,1(a7)
beq.b frame_com
clr.w NMNEXC(a6)
frame_com:
move.b FPCR_ENABLE(a6),d0 ;get fpcr enable byte
and.b FPSR_EXCEPT(a6),d0 ;and in the fpsr exc byte
bfffo d0{24:8},d1 ;test for first set bit
lea.l exc_tbl,a0 ;load jmp table address
subi.b #24,d1 ;normalize bit offset to 0-8
move.l (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:
bset.b #E1,E_BYTE(a6) ;set E1 flag
bra.w commonE ;go clean and exit
commonE3:
tst.b UFLG_TMP(a6) ;test flag for unsup/unimp state
bne.b unsE3
uniE3:
bset.b #E3,E_BYTE(a6) ;set E3 flag
bclr.b #E1,E_BYTE(a6) ;clr E1 from unimp
bra.w commonE
unsE3:
tst.b RES_FLG(a6)
bne.b unsE3_0
unsE3_1:
bset.b #E3,E_BYTE(a6) ;set E3 flag
unsE3_0:
bclr.b #E1,E_BYTE(a6) ;clr E1 flag
move.l CMDREG1B(a6),d0
and.l #$03c30000,d0 ;work for cmd3b
bfextu CMDREG1B(a6){13:1},d1 ;extract bit 2
lsl.l #5,d1
swap d1
or.l d1,d0 ;put it in the right place
bfextu CMDREG1B(a6){10:3},d1 ;extract bit 3,4,5
lsl.l #2,d1
swap d1
or.l d1,d0 ;put them in the right place
move.l d0,CMDREG3B(a6) ;in the busy frame
commonE:
bclr.b #UFLAG,T_BYTE(a6) ;clr U flag from unimp
bra.w 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:
btst.b #inex2_bit,FPCR_ENABLE(a6) ;check for ovfl/inex2 case
beq.b no_exc ;if clear, exit
btst.b #ovfl_bit,FPSR_EXCEPT(a6) ;now check ovfl
beq.b no_exc ;if clear, exit
bra.b 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:
tst.b UFLG_TMP(a6) ;test flag for unsupp/unimp state
beq.b uni_no_exc
uns_no_exc:
tst.b RES_FLG(a6) ;check if frestore is needed
bne.w do_clean ;if clear, no frestore needed
uni_no_exc:
movem.l USER_DA(a6),d0-d1/a0-a1
fmovem.x USER_FP0(a6),fp0-fp3
fmovem.l 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:
tst.b UFLG_TMP(a6) ;test flag for unsupp/unimp state
beq.b 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.
*
tst.b CU_ONLY(a6) ;test if inst is cu-only
beq.w unsE3
* move.w #$fe,CU_SAVEPC(a6)
clr.b CU_SAVEPC(a6)
bset.b #E1,E_BYTE(a6) ;set E1 exception flag
move.w ETEMP_EX(a6),FPTEMP_EX(a6)
move.l ETEMP_HI(a6),FPTEMP_HI(a6)
move.l ETEMP_LO(a6),FPTEMP_LO(a6)
bset.b #fptemp15_bit,DTAG(a6) ;set fpte15
bclr.b #UFLAG,T_BYTE(a6) ;clr U flag from unimp
bra.w do_clean ;go clean and exit
ofuf_con:
move.b (a7),VER_TMP(a6) ;save version number
cmpi.b #BUSY_SIZE-4,1(a7) ;check for busy frame
beq.b busy_fr ;if unimp, grow to busy
cmpi.b #VER_40,(a7) ;test for orig unimp frame
bne.b try_41 ;if not, test for rev frame
moveq.l #13,d0 ;need to zero 14 lwords
bra.b ofuf_fin
try_41:
cmpi.b #VER_41,(a7) ;test for rev unimp frame
bne.l fpsp_fmt_error ;if neither, exit with error
moveq.l #11,d0 ;need to zero 12 lwords
ofuf_fin:
clr.l (a7)
loop1:
clr.l -(a7) ;clear and dec a7
dbra.w d0,loop1
move.b VER_TMP(a6),(a7)
move.b #BUSY_SIZE-4,1(a7) ;write busy fmt word.
busy_fr:
move.l FP_SCR1(a6),WBTEMP_EX(a6) ;write
move.l FP_SCR1+4(a6),WBTEMP_HI(a6) ;execptional op to
move.l FP_SCR1+8(a6),WBTEMP_LO(a6) ;wbtemp
bset.b #E3,E_BYTE(a6) ;set E3 flag
bclr.b #E1,E_BYTE(a6) ;make sure E1 is clear
bclr.b #UFLAG,T_BYTE(a6) ;clr U flag
move.l USER_FPSR(a6),FPSR_SHADOW(a6)
or.l #sx_mask,E_BYTE(a6)
move.l CMDREG1B(a6),d0 ;fix cmd1b to make it
and.l #$03c30000,d0 ;work for cmd3b
bfextu CMDREG1B(a6){13:1},d1 ;extract bit 2
lsl.l #5,d1
swap d1
or.l d1,d0 ;put it in the right place
bfextu CMDREG1B(a6){10:3},d1 ;extract bit 3,4,5
lsl.l #2,d1
swap d1
or.l d1,d0 ;put them in the right place
move.l 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:
cmpi.b #UNIMP_40_SIZE-4,1(a7)
bne.b do_con
moveq.l #13,d0 ;in orig, need to zero 14 lwords
bra.b do_build
do_con:
cmpi.b #UNIMP_41_SIZE-4,1(a7)
bne.b do_restore ;frame must be busy
moveq.l #11,d0 ;in rev, need to zero 12 lwords
do_build:
move.b (a7),VER_TMP(a6)
clr.l (a7)
loop2:
clr.l -(a7) ;clear and dec a7
dbra.w 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.
*
lea.l BUSY_SIZE+LOCAL_SIZE(a7),a1 ;init a1 for new frame
move.b VER_TMP(a6),(a7) ;write busy fmt word
move.b #BUSY_SIZE-4,1(a7)
move.l FP_SCR1(a6),WBTEMP_EX(a1) ;write
move.l FP_SCR1+4(a6),WBTEMP_HI(a1) ;exceptional op to
move.l 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
move.l USER_FPSR(a6),FPSR_SHADOW(a1) ;set exc bits
or.l #sx_mask,E_BYTE(a1)
do_restore:
movem.l USER_DA(a6),d0-d1/a0-a1
fmovem.x USER_FP0(a6),fp0-fp3
fmovem.l USER_FPCR(a6),fpcr/fpsr/fpiar
frestore (a7)+
tst.b 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:
btst.b #7,(a7) ;test T1 in SR
bne.b g_trace
btst.b #6,(a7) ;test T0 in SR
bne.b g_trace
bra.l 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
subq.l #4,sp make room
move.l 4(sp),(sp)
move.l 8(sp),4(sp)
sub.l #BUSY_SIZE,sp
fsave (sp)
fmove.l fpiar,BUSY_SIZE+EXC_EA-4(sp)
frestore (sp)
add.l #BUSY_SIZE,sp
g_easy:
move.w #TRACE_VEC,EXC_VEC-4(a7)
bra.l real_trace
*
* This is a work-around for hardware bug 1384.
*
bug1384:
link a5,#0
fsave -(sp)
cmpi.b #$41,(sp) ; check for correct frame
beq frame_41
bgt nofix ; if more advanced mask, do nada
frame_40:
tst.b 1(sp) ; check to see if idle
bne notidle
idle40:
clr.l (sp) ; get rid of old fsave frame
move.l d1,USER_D1(a6) ; save d1
move.w #8,d1 ; place unimp frame instead
loop40: clr.l -(sp)
dbra d1,loop40
move.l USER_D1(a6),d1 ; restore d1
move.l #$40280000,-(sp)
frestore (sp)+
unlk a5
rts
frame_41:
tst.b 1(sp) ; check to see if idle
bne notidle
idle41:
clr.l (sp) ; get rid of old fsave frame
move.l d1,USER_D1(a6) ; save d1
move.w #10,d1 ; place unimp frame instead
loop41: clr.l -(sp)
dbra d1,loop41
move.l USER_D1(a6),d1 ; restore d1
move.l #$41300000,-(sp)
frestore (sp)+
unlk a5
rts
notidle:
bclr.b #etemp15_bit,-40(a5)
frestore (sp)+
unlk a5
rts
nofix:
frestore (sp)+
unlk a5
rts
end