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

518 lines
14 KiB
Plaintext

* 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.
*
* kernel_ex.sa 3.3 12/19/90
*
* This file contains routines to force exception status in the
* fpu for exceptional cases detected or reported within the
* transcendental functions. Typically, the t_xx routine will
* set the appropriate bits in the USER_FPSR word on the stack.
* The bits are tested in gen_except.sa to determine if an exceptional
* situation needs to be created on return from the FPSP.
*
KERNEL_EX IDNT 2,1 Motorola 040 Floating Point Software Package
section 8
include fpsp.h
mns_inf dc.l $ffff0000,$00000000,$00000000
pls_inf dc.l $7fff0000,$00000000,$00000000
nan dc.l $7fff0000,$ffffffff,$ffffffff
huge dc.l $7ffe0000,$ffffffff,$ffffffff
xref ovf_r_k
xref unf_sub
xref nrm_set
xdef t_dz
xdef t_dz2
xdef t_operr
xdef t_unfl
xdef t_ovfl
xdef t_ovfl2
xdef t_inx2
xdef t_frcinx
xdef t_extdnrm
xdef t_resdnrm
xdef dst_nan
xdef src_nan
*
* DZ exception
*
*
* if dz trap disabled
* store properly signed inf (use sign of etemp) into fp0
* set FPSR exception status dz bit, condition code
* inf bit, and accrued dz bit
* return
* frestore the frame into the machine (done by unimp_hd)
*
* else dz trap enabled
* set exception status bit & accrued bits in FPSR
* set flag to disable sto_res from corrupting fp register
* return
* frestore the frame into the machine (done by unimp_hd)
*
* t_dz2 is used by monadic functions such as flogn (from do_func).
* t_dz is used by monadic functions such as satanh (from the
* transcendental function).
*
t_dz2:
bset.b #neg_bit,FPSR_CC(a6) ;set neg bit in FPSR
fmove.l #0,FPSR ;clr status bits (Z set)
btst.b #dz_bit,FPCR_ENABLE(a6) ;test FPCR for dz exc enabled
bne.b dz_ena_end
bra.b m_inf ;flogx always returns -inf
t_dz:
fmove.l #0,FPSR ;clr status bits (Z set)
btst.b #dz_bit,FPCR_ENABLE(a6) ;test FPCR for dz exc enabled
bne.b dz_ena
*
* dz disabled
*
btst.b #sign_bit,ETEMP_EX(a6) ;check sign for neg or pos
beq.b p_inf ;branch if pos sign
m_inf:
fmovem.x mns_inf,fp0 ;load -inf
bset.b #neg_bit,FPSR_CC(a6) ;set neg bit in FPSR
bra.b set_fpsr
p_inf:
fmovem.x pls_inf,fp0 ;load +inf
set_fpsr:
or.l #dzinf_mask,USER_FPSR(a6) ;set I,DZ,ADZ
rts
*
* dz enabled
*
dz_ena:
btst.b #sign_bit,ETEMP_EX(a6) ;check sign for neg or pos
beq.b dz_ena_end
bset.b #neg_bit,FPSR_CC(a6) ;set neg bit in FPSR
dz_ena_end:
or.l #dzinf_mask,USER_FPSR(a6) ;set I,DZ,ADZ
st.b STORE_FLG(a6)
rts
*
* OPERR exception
*
* if (operr trap disabled)
* set FPSR exception status operr bit, condition code
* nan bit; Store default NAN into fp0
* frestore the frame into the machine (done by unimp_hd)
*
* else (operr trap enabled)
* set FPSR exception status operr bit, accrued operr bit
* set flag to disable sto_res from corrupting fp register
* frestore the frame into the machine (done by unimp_hd)
*
t_operr:
or.l #opnan_mask,USER_FPSR(a6) ;set NaN, OPERR, AIOP
btst.b #operr_bit,FPCR_ENABLE(a6) ;test FPCR for operr enabled
bne.b op_ena
fmovem.x nan,fp0 ;load default nan
rts
op_ena:
st.b STORE_FLG(a6) ;do not corrupt destination
rts
*
* t_unfl --- UNFL exception
*
* This entry point is used by all routines requiring unfl, inex2,
* aunfl, and ainex to be set on exit.
*
* On entry, a0 points to the exceptional operand. The final exceptional
* operand is built in FP_SCR1 and only the sign from the original operand
* is used.
*
t_unfl:
clr.l FP_SCR1(a6) ;set exceptional operand to zero
clr.l FP_SCR1+4(a6)
clr.l FP_SCR1+8(a6)
tst.b (a0) ;extract sign from caller's exop
bpl.b unfl_signok
bset #sign_bit,FP_SCR1(a6)
unfl_signok:
lea.l FP_SCR1(a6),a0
or.l #unfinx_mask,USER_FPSR(a6)
* ;set UNFL, INEX2, AUNFL, AINEX
unfl_con:
btst.b #unfl_bit,FPCR_ENABLE(a6)
beq.b unfl_dis
unfl_ena:
bfclr STAG(a6){5:3} ;clear wbtm66,wbtm1,wbtm0
bset.b #wbtemp15_bit,WB_BYTE(a6) ;set wbtemp15
bset.b #sticky_bit,STICKY(a6) ;set sticky bit
bclr.b #E1,E_BYTE(a6)
unfl_dis:
bfextu FPCR_MODE(a6){0:2},d0 ;get round precision
bclr.b #sign_bit,LOCAL_EX(a0)
sne LOCAL_SGN(a0) ;convert to internal ext format
bsr unf_sub ;returns IEEE result at a0
* ;and sets FPSR_CC accordingly
bfclr LOCAL_SGN(a0){0:8} ;convert back to IEEE ext format
beq.b unfl_fin
bset.b #sign_bit,LOCAL_EX(a0)
bset.b #sign_bit,FP_SCR1(a6) ;set sign bit of exc operand
unfl_fin:
fmovem.x (a0),fp0 ;store result in fp0
rts
*
* t_ovfl2 --- OVFL exception (without inex2 returned)
*
* This entry is used by scale to force catastrophic overflow. The
* ovfl, aovfl, and ainex bits are set, but not the inex2 bit.
*
t_ovfl2:
or.l #ovfl_inx_mask,USER_FPSR(a6)
move.l ETEMP(a6),FP_SCR1(a6)
move.l ETEMP_HI(a6),FP_SCR1+4(a6)
move.l ETEMP_LO(a6),FP_SCR1+8(a6)
*
* Check for single or double round precision. If single, check if
* the lower 40 bits of ETEMP are zero; if not, set inex2. If double,
* check if the lower 21 bits are zero; if not, set inex2.
*
move.b FPCR_MODE(a6),d0
andi.b #$c0,d0
beq.w t_work ;if extended, finish ovfl processing
cmpi.b #$40,d0 ;test for single
bne.b t_dbl
t_sgl:
tst.b ETEMP_LO(a6)
bne.b t_setinx2
move.l ETEMP_HI(a6),d0
andi.l #$ff,d0 ;look at only lower 8 bits
bne.b t_setinx2
bra.w t_work
t_dbl:
move.l ETEMP_LO(a6),d0
andi.l #$7ff,d0 ;look at only lower 11 bits
beq.w t_work
t_setinx2:
or.l #inex2_mask,USER_FPSR(a6)
bra.b t_work
*
* t_ovfl --- OVFL exception
*
*** Note: the exc operand is returned in ETEMP.
*
t_ovfl:
or.l #ovfinx_mask,USER_FPSR(a6)
t_work:
btst.b #ovfl_bit,FPCR_ENABLE(a6) ;test FPCR for ovfl enabled
beq.b ovf_dis
ovf_ena:
clr.l FP_SCR1(a6) ;set exceptional operand
clr.l FP_SCR1+4(a6)
clr.l FP_SCR1+8(a6)
bfclr STAG(a6){5:3} ;clear wbtm66,wbtm1,wbtm0
bclr.b #wbtemp15_bit,WB_BYTE(a6) ;clear wbtemp15
bset.b #sticky_bit,STICKY(a6) ;set sticky bit
bclr.b #E1,E_BYTE(a6)
* ;fall through to disabled case
* For disabled overflow call 'ovf_r_k'. This routine loads the
* correct result based on the rounding precision, destination
* format, rounding mode and sign.
*
ovf_dis:
bsr ovf_r_k ;returns unsigned ETEMP_EX
* ;and sets FPSR_CC accordingly.
bfclr ETEMP_SGN(a6){0:8} ;fix sign
beq.b ovf_pos
bset.b #sign_bit,ETEMP_EX(a6)
bset.b #sign_bit,FP_SCR1(a6) ;set exceptional operand sign
ovf_pos:
fmovem.x ETEMP(a6),fp0 ;move the result to fp0
rts
*
* INEX2 exception
*
* The inex2 and ainex bits are set.
*
t_inx2:
or.l #inx2a_mask,USER_FPSR(a6) ;set INEX2, AINEX
rts
*
* Force Inex2
*
* This routine is called by the transcendental routines to force
* the inex2 exception bits set in the FPSR. If the underflow bit
* is set, but the underflow trap was not taken, the aunfl bit in
* the FPSR must be set.
*
t_frcinx:
or.l #inx2a_mask,USER_FPSR(a6) ;set INEX2, AINEX
btst.b #unfl_bit,FPSR_EXCEPT(a6) ;test for unfl bit set
beq.b no_uacc1 ;if clear, do not set aunfl
bset.b #aunfl_bit,FPSR_AEXCEPT(a6)
no_uacc1:
rts
*
* DST_NAN
*
* Determine if the destination nan is signalling or non-signalling,
* and set the FPSR bits accordingly. See the MC68040 User's Manual
* section 3.2.2.5 NOT-A-NUMBERS.
*
dst_nan:
btst.b #sign_bit,FPTEMP_EX(a6) ;test sign of nan
beq.b dst_pos ;if clr, it was positive
bset.b #neg_bit,FPSR_CC(a6) ;set N bit
dst_pos:
btst.b #signan_bit,FPTEMP_HI(a6) ;check if signalling
beq.b dst_snan ;branch if signalling
fmove.l d1,fpcr ;restore user's rmode/prec
fmove.x FPTEMP(a6),fp0 ;return the non-signalling nan
*
* Check the source nan. If it is signalling, snan will be reported.
*
move.b STAG(a6),d0
andi.b #$e0,d0
cmpi.b #$60,d0
bne.b no_snan
btst.b #signan_bit,ETEMP_HI(a6) ;check if signalling
bne.b no_snan
or.l #snaniop_mask,USER_FPSR(a6) ;set NAN, SNAN, AIOP
no_snan:
rts
dst_snan:
btst.b #snan_bit,FPCR_ENABLE(a6) ;check if trap enabled
beq.b dst_dis ;branch if disabled
or.b #nan_tag,DTAG(a6) ;set up dtag for nan
st.b STORE_FLG(a6) ;do not store a result
or.l #snaniop_mask,USER_FPSR(a6) ;set NAN, SNAN, AIOP
rts
dst_dis:
bset.b #signan_bit,FPTEMP_HI(a6) ;set SNAN bit in sop
fmove.l d1,fpcr ;restore user's rmode/prec
fmove.x FPTEMP(a6),fp0 ;load non-sign. nan
or.l #snaniop_mask,USER_FPSR(a6) ;set NAN, SNAN, AIOP
rts
*
* SRC_NAN
*
* Determine if the source nan is signalling or non-signalling,
* and set the FPSR bits accordingly. See the MC68040 User's Manual
* section 3.2.2.5 NOT-A-NUMBERS.
*
src_nan:
btst.b #sign_bit,ETEMP_EX(a6) ;test sign of nan
beq.b src_pos ;if clr, it was positive
bset.b #neg_bit,FPSR_CC(a6) ;set N bit
src_pos:
btst.b #signan_bit,ETEMP_HI(a6) ;check if signalling
beq.b src_snan ;branch if signalling
fmove.l d1,fpcr ;restore user's rmode/prec
fmove.x ETEMP(a6),fp0 ;return the non-signalling nan
rts
src_snan:
btst.b #snan_bit,FPCR_ENABLE(a6) ;check if trap enabled
beq.b src_dis ;branch if disabled
bset.b #signan_bit,ETEMP_HI(a6) ;set SNAN bit in sop
or.b #norm_tag,DTAG(a6) ;set up dtag for norm
or.b #nan_tag,STAG(a6) ;set up stag for nan
st.b STORE_FLG(a6) ;do not store a result
or.l #snaniop_mask,USER_FPSR(a6) ;set NAN, SNAN, AIOP
rts
src_dis:
bset.b #signan_bit,ETEMP_HI(a6) ;set SNAN bit in sop
fmove.l d1,fpcr ;restore user's rmode/prec
fmove.x ETEMP(a6),fp0 ;load non-sign. nan
or.l #snaniop_mask,USER_FPSR(a6) ;set NAN, SNAN, AIOP
rts
*
* For all functions that have a denormalized input and that f(x)=x,
* this is the entry point
*
t_extdnrm:
or.l #unfinx_mask,USER_FPSR(a6)
* ;set UNFL, INEX2, AUNFL, AINEX
bra.b xdnrm_con
*
* Entry point for scale with extended denorm. The function does
* not set inex2, aunfl, or ainex.
*
t_resdnrm:
or.l #unfl_mask,USER_FPSR(a6)
xdnrm_con:
btst.b #unfl_bit,FPCR_ENABLE(a6)
beq.b xdnrm_dis
*
* If exceptions are enabled, the additional task of setting up WBTEMP
* is needed so that when the underflow exception handler is entered,
* the user perceives no difference between what the 040 provides vs.
* what the FPSP provides.
*
xdnrm_ena:
move.l a0,-(a7)
move.l LOCAL_EX(a0),FP_SCR1(a6)
move.l LOCAL_HI(a0),FP_SCR1+4(a6)
move.l LOCAL_LO(a0),FP_SCR1+8(a6)
lea FP_SCR1(a6),a0
bclr.b #sign_bit,LOCAL_EX(a0)
sne LOCAL_SGN(a0) ;convert to internal ext format
tst.w LOCAL_EX(a0) ;check if input is denorm
beq.b xdnrm_dn ;if so, skip nrm_set
bsr nrm_set ;normalize the result (exponent
* ;will be negative
xdnrm_dn:
bclr.b #sign_bit,LOCAL_EX(a0) ;take off false sign
bfclr LOCAL_SGN(a0){0:8} ;change back to IEEE ext format
beq.b xdep
bset.b #sign_bit,LOCAL_EX(a0)
xdep:
bfclr STAG(a6){5:3} ;clear wbtm66,wbtm1,wbtm0
bset.b #wbtemp15_bit,WB_BYTE(a6) ;set wbtemp15
bclr.b #sticky_bit,STICKY(a6) ;clear sticky bit
bclr.b #E1,E_BYTE(a6)
move.l (a7)+,a0
xdnrm_dis:
bfextu FPCR_MODE(a6){0:2},d0 ;get round precision
bne.b not_ext ;if not round extended, store
* ;IEEE defaults
is_ext:
btst.b #sign_bit,LOCAL_EX(a0)
beq.b xdnrm_store
bset.b #neg_bit,FPSR_CC(a6) ;set N bit in FPSR_CC
bra.b xdnrm_store
not_ext:
bclr.b #sign_bit,LOCAL_EX(a0)
sne LOCAL_SGN(a0) ;convert to internal ext format
bsr unf_sub ;returns IEEE result pointed by
* ;a0; sets FPSR_CC accordingly
bfclr LOCAL_SGN(a0){0:8} ;convert back to IEEE ext format
beq.b xdnrm_store
bset.b #sign_bit,LOCAL_EX(a0)
xdnrm_store:
fmovem.x (a0),fp0 ;store result in fp0
rts
*
* This subroutine is used for dyadic operations that use an extended
* denorm within the kernel. The approach used is to capture the frame,
* fix/restore.
*
xdef t_avoid_unsupp
t_avoid_unsupp:
link a2,#-LOCAL_SIZE ;so that a2 fpsp.h negative
* ;offsets may be used
fsave -(a7)
tst.b 1(a7) ;check if idle, exit if so
beq.w idle_end
btst.b #E1,E_BYTE(a2) ;check for an E1 exception if
* ;enabled, there is an unsupp
beq.w end_avun ;else, exit
btst.b #7,DTAG(a2) ;check for denorm destination
beq.b src_den ;else, must be a source denorm
*
* handle destination denorm
*
lea FPTEMP(a2),a0
btst.b #sign_bit,LOCAL_EX(a0)
sne LOCAL_SGN(a0) ;convert to internal ext format
bclr.b #7,DTAG(a2) ;set DTAG to norm
bsr nrm_set ;normalize result, exponent
* ;will become negative
bclr.b #sign_bit,LOCAL_EX(a0) ;get rid of fake sign
bfclr LOCAL_SGN(a0){0:8} ;convert back to IEEE ext format
beq.b ck_src_den ;check if source is also denorm
bset.b #sign_bit,LOCAL_EX(a0)
ck_src_den:
btst.b #7,STAG(a2)
beq.b end_avun
src_den:
lea ETEMP(a2),a0
btst.b #sign_bit,LOCAL_EX(a0)
sne LOCAL_SGN(a0) ;convert to internal ext format
bclr.b #7,STAG(a2) ;set STAG to norm
bsr nrm_set ;normalize result, exponent
* ;will become negative
bclr.b #sign_bit,LOCAL_EX(a0) ;get rid of fake sign
bfclr LOCAL_SGN(a0){0:8} ;convert back to IEEE ext format
beq.b den_com
bset.b #sign_bit,LOCAL_EX(a0)
den_com:
move.b #$fe,CU_SAVEPC(a2) ;set continue frame
clr.w NMNEXC(a2) ;clear NMNEXC
bclr.b #E1,E_BYTE(a2)
* fmove.l FPSR,FPSR_SHADOW(a2)
* bset.b #SFLAG,E_BYTE(a2)
* bset.b #XFLAG,T_BYTE(a2)
end_avun:
frestore (a7)+
unlk a2
rts
idle_end:
add.l #4,a7
unlk a2
rts
end