520 lines
14 KiB
Plaintext
520 lines
14 KiB
Plaintext
* $NetBSD: kernel_ex.sa,v 1.2 1994/10/26 07:49:12 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.
|
|
|
|
*
|
|
* 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
|