sys7.1-doc-wip/OS/FPUEmulation/KerneLex.a
2019-07-27 22:37:48 +08:00

537 lines
15 KiB
Plaintext

;
; File: KernelEx.a
;
; Contains: Routines to force exception status in the FPU for
; exceptional cases detected or reported within the
; transcendental functions
;
; Originally Written by: Motorola Inc.
; Adapted to Apple/MPW: Jon Okada
;
; Copyright: © 1990, 1991 by Apple Computer, Inc., all rights reserved.
;
; This file is used in these builds: Mac32
;
; Change History (most recent first):
;
; <3> 6/24/91 BG Modified "src_nan" to not quiet signaling NaN input
; when SNaN exception is enabled. Modified "t_resdnrm" to set UNFL, AUNFL, INEX2, and AINEX
; in USER_FPSR(a6) when rounding precision is narrower
; than extended. Modified "t_unfl" and "t_resdnrm" to normalize unnormalized
; results and produce zeros with zero exponent.
; <2> 3/30/91 BG Rolling in Jon Okada's latest changes.
; <1> 12/14/90 BG First checked into TERROR/BBS.
; kernelex.a
; Based upon Motorola file 'kernel_ex.sa'
; CHANGE LOG:
; 04 Jan 91 JPO Deleted constant "huge" (not referenced).
; 28 May 91 JPO Modified "src_nan" to not quiet signaling NaN input
; when SNaN exception is enabled.
; 14 Jun 91 JPO Modified "t_resdnrm" to set UNFL, AUNFL, INEX2, and AINEX
; in USER_FPSR(a6) when rounding precision is narrower
; than extended.
; 17 Jun 91 JPO Modified "t_unfl" and "t_resdnrm" to normalize unnormalized
; results and produce zeros with zero exponent.
;
*
* kernel_ex.sa 3.1 12/10/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.
*
* Copyright (C) Motorola, Inc. 1990
* All Rights Reserved
*
* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA
* The copyright notice above does not evidence any
* actual or intended publication of such source code.
* KERNEL_EX IDNT 2,1 Motorola 040 Floating Point Software Package
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 ; deleted <1/4/91, JPO>
*
* 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
; If result is unnormalized, normalize it here. If result is zero with nonzero <T3> thru next <T3>
; exponent, zero exponent here. Only possible values at this point are zero,
; extended denorm, or extended unnormal (due to single/double denorm). <6/17/91, JPO>
unfl_fin:
move.w LOCAL_EX(a0),d1 ; isolate exponent <6/17/91, JPO>
andi.w #$7fff,d1 ; <6/17/91, JPO>
beq.b @2 ; zero exponent means all OK <6/17/91, JPO>
tst.l LOCAL_HI(a0) ; test high mantissa <6/17/91, JPO>
bmi.b @2 ; normal <6/17/91, JPO>
bne.b @1 ; unnormalized <6/17/91, JPO>
tst.l LOCAL_LO(a0) ; test low mantissa <6/17/91, JPO>
bne.b @1 ; unnormalized <6/17/91, JPO>
bfclr LOCAL_EX(a0){1:15} ; zero result. zero exponent <6/17/91, JPO>
bra.b @2
@1: ; label ADDED <6/17/91, JPO>
bsr nrm_set ; normalize unnormal <6/17/91, JPO>
@2: ; label added <6/17/91, JPO> <T3>
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.b 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.b t_work
t_dbl:
move.l ETEMP_LO(a6),d0
andi.l #$7ff,d0 ;look at only lower 11 bits
beq.b 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 - DELETED <5/28/91, JPO> <T3>
; or.b #norm_tag,DTAG(a6) ;set up dtag for norm - DELETED <5/28/91, JPO> <T3>
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:
or.l #unfinx_mask,USER_FPSR(a6) ; set UNFL, AUNFL, INEX2, AINEX <6/14/91, JPO> <T3>
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:
bra unfl_fin ; continue above <6/17/91, JPO> <T3>
; fmovem.x (a0),fp0 ;store result in fp0 - DELETED <6/17/91, JPO> <T3>
; rts ; DELETED <6/17/91, JPO> <T3>
*
* 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.
*
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.b idle_end
btst.b #E1,E_BYTE(a2) ;check for an E1 exception if
* ;enabled, there is an unsupp
beq.b 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