| | | |
| | 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 |