diff options
Diffstat (limited to 'kernel/arch/m68k/fpsp040/kernel_ex.S')
-rw-r--r-- | kernel/arch/m68k/fpsp040/kernel_ex.S | 493 |
1 files changed, 493 insertions, 0 deletions
diff --git a/kernel/arch/m68k/fpsp040/kernel_ex.S b/kernel/arch/m68k/fpsp040/kernel_ex.S new file mode 100644 index 000000000..45bcf3455 --- /dev/null +++ b/kernel/arch/m68k/fpsp040/kernel_ex.S @@ -0,0 +1,493 @@ +| +| 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. +| + +| 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. + +KERNEL_EX: |idnt 2,1 | Motorola 040 Floating Point Software Package + + |section 8 + +#include "fpsp.h" + +mns_inf: .long 0xffff0000,0x00000000,0x00000000 +pls_inf: .long 0x7fff0000,0x00000000,0x00000000 +nan: .long 0x7fff0000,0xffffffff,0xffffffff +huge: .long 0x7ffe0000,0xffffffff,0xffffffff + + |xref ovf_r_k + |xref unf_sub + |xref nrm_set + + .global t_dz + .global t_dz2 + .global t_operr + .global t_unfl + .global t_ovfl + .global t_ovfl2 + .global t_inx2 + .global t_frcinx + .global t_extdnrm + .global t_resdnrm + .global dst_nan + .global 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: + bsetb #neg_bit,FPSR_CC(%a6) |set neg bit in FPSR + fmovel #0,%FPSR |clr status bits (Z set) + btstb #dz_bit,FPCR_ENABLE(%a6) |test FPCR for dz exc enabled + bnes dz_ena_end + bras m_inf |flogx always returns -inf +t_dz: + fmovel #0,%FPSR |clr status bits (Z set) + btstb #dz_bit,FPCR_ENABLE(%a6) |test FPCR for dz exc enabled + bnes dz_ena +| +| dz disabled +| + btstb #sign_bit,ETEMP_EX(%a6) |check sign for neg or pos + beqs p_inf |branch if pos sign + +m_inf: + fmovemx mns_inf,%fp0-%fp0 |load -inf + bsetb #neg_bit,FPSR_CC(%a6) |set neg bit in FPSR + bras set_fpsr +p_inf: + fmovemx pls_inf,%fp0-%fp0 |load +inf +set_fpsr: + orl #dzinf_mask,USER_FPSR(%a6) |set I,DZ,ADZ + rts +| +| dz enabled +| +dz_ena: + btstb #sign_bit,ETEMP_EX(%a6) |check sign for neg or pos + beqs dz_ena_end + bsetb #neg_bit,FPSR_CC(%a6) |set neg bit in FPSR +dz_ena_end: + orl #dzinf_mask,USER_FPSR(%a6) |set I,DZ,ADZ + st 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: + orl #opnan_mask,USER_FPSR(%a6) |set NaN, OPERR, AIOP + + btstb #operr_bit,FPCR_ENABLE(%a6) |test FPCR for operr enabled + bnes op_ena + + fmovemx nan,%fp0-%fp0 |load default nan + rts +op_ena: + st 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: + clrl FP_SCR1(%a6) |set exceptional operand to zero + clrl FP_SCR1+4(%a6) + clrl FP_SCR1+8(%a6) + tstb (%a0) |extract sign from caller's exop + bpls unfl_signok + bset #sign_bit,FP_SCR1(%a6) +unfl_signok: + leal FP_SCR1(%a6),%a0 + orl #unfinx_mask,USER_FPSR(%a6) +| ;set UNFL, INEX2, AUNFL, AINEX +unfl_con: + btstb #unfl_bit,FPCR_ENABLE(%a6) + beqs unfl_dis + +unfl_ena: + bfclr STAG(%a6){#5:#3} |clear wbtm66,wbtm1,wbtm0 + bsetb #wbtemp15_bit,WB_BYTE(%a6) |set wbtemp15 + bsetb #sticky_bit,STICKY(%a6) |set sticky bit + + bclrb #E1,E_BYTE(%a6) + +unfl_dis: + bfextu FPCR_MODE(%a6){#0:#2},%d0 |get round precision + + bclrb #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 + beqs unfl_fin + + bsetb #sign_bit,LOCAL_EX(%a0) + bsetb #sign_bit,FP_SCR1(%a6) |set sign bit of exc operand + +unfl_fin: + fmovemx (%a0),%fp0-%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: + orl #ovfl_inx_mask,USER_FPSR(%a6) + movel ETEMP(%a6),FP_SCR1(%a6) + movel ETEMP_HI(%a6),FP_SCR1+4(%a6) + movel 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. +| + moveb FPCR_MODE(%a6),%d0 + andib #0xc0,%d0 + beq t_work |if extended, finish ovfl processing + cmpib #0x40,%d0 |test for single + bnes t_dbl +t_sgl: + tstb ETEMP_LO(%a6) + bnes t_setinx2 + movel ETEMP_HI(%a6),%d0 + andil #0xff,%d0 |look at only lower 8 bits + bnes t_setinx2 + bra t_work +t_dbl: + movel ETEMP_LO(%a6),%d0 + andil #0x7ff,%d0 |look at only lower 11 bits + beq t_work +t_setinx2: + orl #inex2_mask,USER_FPSR(%a6) + bras t_work +| +| t_ovfl --- OVFL exception +| +|** Note: the exc operand is returned in ETEMP. +| +t_ovfl: + orl #ovfinx_mask,USER_FPSR(%a6) +t_work: + btstb #ovfl_bit,FPCR_ENABLE(%a6) |test FPCR for ovfl enabled + beqs ovf_dis + +ovf_ena: + clrl FP_SCR1(%a6) |set exceptional operand + clrl FP_SCR1+4(%a6) + clrl FP_SCR1+8(%a6) + + bfclr STAG(%a6){#5:#3} |clear wbtm66,wbtm1,wbtm0 + bclrb #wbtemp15_bit,WB_BYTE(%a6) |clear wbtemp15 + bsetb #sticky_bit,STICKY(%a6) |set sticky bit + + bclrb #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 + beqs ovf_pos + bsetb #sign_bit,ETEMP_EX(%a6) + bsetb #sign_bit,FP_SCR1(%a6) |set exceptional operand sign +ovf_pos: + fmovemx ETEMP(%a6),%fp0-%fp0 |move the result to fp0 + rts + + +| +| INEX2 exception +| +| The inex2 and ainex bits are set. +| +t_inx2: + orl #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: + orl #inx2a_mask,USER_FPSR(%a6) |set INEX2, AINEX + btstb #unfl_bit,FPSR_EXCEPT(%a6) |test for unfl bit set + beqs no_uacc1 |if clear, do not set aunfl + bsetb #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: + btstb #sign_bit,FPTEMP_EX(%a6) |test sign of nan + beqs dst_pos |if clr, it was positive + bsetb #neg_bit,FPSR_CC(%a6) |set N bit +dst_pos: + btstb #signan_bit,FPTEMP_HI(%a6) |check if signalling + beqs dst_snan |branch if signalling + + fmovel %d1,%fpcr |restore user's rmode/prec + fmovex FPTEMP(%a6),%fp0 |return the non-signalling nan +| +| Check the source nan. If it is signalling, snan will be reported. +| + moveb STAG(%a6),%d0 + andib #0xe0,%d0 + cmpib #0x60,%d0 + bnes no_snan + btstb #signan_bit,ETEMP_HI(%a6) |check if signalling + bnes no_snan + orl #snaniop_mask,USER_FPSR(%a6) |set NAN, SNAN, AIOP +no_snan: + rts + +dst_snan: + btstb #snan_bit,FPCR_ENABLE(%a6) |check if trap enabled + beqs dst_dis |branch if disabled + + orb #nan_tag,DTAG(%a6) |set up dtag for nan + st STORE_FLG(%a6) |do not store a result + orl #snaniop_mask,USER_FPSR(%a6) |set NAN, SNAN, AIOP + rts + +dst_dis: + bsetb #signan_bit,FPTEMP_HI(%a6) |set SNAN bit in sop + fmovel %d1,%fpcr |restore user's rmode/prec + fmovex FPTEMP(%a6),%fp0 |load non-sign. nan + orl #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: + btstb #sign_bit,ETEMP_EX(%a6) |test sign of nan + beqs src_pos |if clr, it was positive + bsetb #neg_bit,FPSR_CC(%a6) |set N bit +src_pos: + btstb #signan_bit,ETEMP_HI(%a6) |check if signalling + beqs src_snan |branch if signalling + fmovel %d1,%fpcr |restore user's rmode/prec + fmovex ETEMP(%a6),%fp0 |return the non-signalling nan + rts + +src_snan: + btstb #snan_bit,FPCR_ENABLE(%a6) |check if trap enabled + beqs src_dis |branch if disabled + bsetb #signan_bit,ETEMP_HI(%a6) |set SNAN bit in sop + orb #norm_tag,DTAG(%a6) |set up dtag for norm + orb #nan_tag,STAG(%a6) |set up stag for nan + st STORE_FLG(%a6) |do not store a result + orl #snaniop_mask,USER_FPSR(%a6) |set NAN, SNAN, AIOP + rts + +src_dis: + bsetb #signan_bit,ETEMP_HI(%a6) |set SNAN bit in sop + fmovel %d1,%fpcr |restore user's rmode/prec + fmovex ETEMP(%a6),%fp0 |load non-sign. nan + orl #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: + orl #unfinx_mask,USER_FPSR(%a6) +| ;set UNFL, INEX2, AUNFL, AINEX + bras xdnrm_con +| +| Entry point for scale with extended denorm. The function does +| not set inex2, aunfl, or ainex. +| +t_resdnrm: + orl #unfl_mask,USER_FPSR(%a6) + +xdnrm_con: + btstb #unfl_bit,FPCR_ENABLE(%a6) + beqs 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: + movel %a0,-(%a7) + + movel LOCAL_EX(%a0),FP_SCR1(%a6) + movel LOCAL_HI(%a0),FP_SCR1+4(%a6) + movel LOCAL_LO(%a0),FP_SCR1+8(%a6) + + lea FP_SCR1(%a6),%a0 + + bclrb #sign_bit,LOCAL_EX(%a0) + sne LOCAL_SGN(%a0) |convert to internal ext format + tstw LOCAL_EX(%a0) |check if input is denorm + beqs xdnrm_dn |if so, skip nrm_set + bsr nrm_set |normalize the result (exponent +| ;will be negative +xdnrm_dn: + bclrb #sign_bit,LOCAL_EX(%a0) |take off false sign + bfclr LOCAL_SGN(%a0){#0:#8} |change back to IEEE ext format + beqs xdep + bsetb #sign_bit,LOCAL_EX(%a0) +xdep: + bfclr STAG(%a6){#5:#3} |clear wbtm66,wbtm1,wbtm0 + bsetb #wbtemp15_bit,WB_BYTE(%a6) |set wbtemp15 + bclrb #sticky_bit,STICKY(%a6) |clear sticky bit + bclrb #E1,E_BYTE(%a6) + movel (%a7)+,%a0 +xdnrm_dis: + bfextu FPCR_MODE(%a6){#0:#2},%d0 |get round precision + bnes not_ext |if not round extended, store +| ;IEEE defaults +is_ext: + btstb #sign_bit,LOCAL_EX(%a0) + beqs xdnrm_store + + bsetb #neg_bit,FPSR_CC(%a6) |set N bit in FPSR_CC + + bras xdnrm_store + +not_ext: + bclrb #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 + beqs xdnrm_store + bsetb #sign_bit,LOCAL_EX(%a0) +xdnrm_store: + fmovemx (%a0),%fp0-%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. +| + .global t_avoid_unsupp +t_avoid_unsupp: + link %a2,#-LOCAL_SIZE |so that a2 fpsp.h negative +| ;offsets may be used + fsave -(%a7) + tstb 1(%a7) |check if idle, exit if so + beq idle_end + btstb #E1,E_BYTE(%a2) |check for an E1 exception if +| ;enabled, there is an unsupp + beq end_avun |else, exit + btstb #7,DTAG(%a2) |check for denorm destination + beqs src_den |else, must be a source denorm +| +| handle destination denorm +| + lea FPTEMP(%a2),%a0 + btstb #sign_bit,LOCAL_EX(%a0) + sne LOCAL_SGN(%a0) |convert to internal ext format + bclrb #7,DTAG(%a2) |set DTAG to norm + bsr nrm_set |normalize result, exponent +| ;will become negative + bclrb #sign_bit,LOCAL_EX(%a0) |get rid of fake sign + bfclr LOCAL_SGN(%a0){#0:#8} |convert back to IEEE ext format + beqs ck_src_den |check if source is also denorm + bsetb #sign_bit,LOCAL_EX(%a0) +ck_src_den: + btstb #7,STAG(%a2) + beqs end_avun +src_den: + lea ETEMP(%a2),%a0 + btstb #sign_bit,LOCAL_EX(%a0) + sne LOCAL_SGN(%a0) |convert to internal ext format + bclrb #7,STAG(%a2) |set STAG to norm + bsr nrm_set |normalize result, exponent +| ;will become negative + bclrb #sign_bit,LOCAL_EX(%a0) |get rid of fake sign + bfclr LOCAL_SGN(%a0){#0:#8} |convert back to IEEE ext format + beqs den_com + bsetb #sign_bit,LOCAL_EX(%a0) +den_com: + moveb #0xfe,CU_SAVEPC(%a2) |set continue frame + clrw NMNEXC(%a2) |clear NMNEXC + bclrb #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: + addl #4,%a7 + unlk %a2 + rts + |end |