📄 res_func.s
字号:
//// $Id: res_func.S,v 1.1 1998/12/14 23:15:22 joel Exp $//// res_func.sa 3.9 7/29/91//// Normalizes denormalized numbers if necessary and updates the// stack frame. The function is then restored back into the// machine and the 040 completes the operation. This routine// is only used by the unsupported data type/format handler.// (Exception vector 55).//// For packed move out (fmove.p fpm,<ea>) the operation is// completed here; data is packed and moved to user memory. // The stack is restored to the 040 only in the case of a// reportable exception in the conversion.////// 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.RES_FUNC: //idnt 2,1 | Motorola 040 Floating Point Software Package |section 8#include "fpsp.defs"sp_bnds: .short 0x3f81,0x407e .short 0x3f6a,0x0000dp_bnds: .short 0x3c01,0x43fe .short 0x3bcd,0x0000 |xref mem_write |xref bindec |xref get_fline |xref round |xref denorm |xref dest_ext |xref dest_dbl |xref dest_sgl |xref unf_sub |xref nrm_set |xref dnrm_lp |xref ovf_res |xref reg_dest |xref t_ovfl |xref t_unfl .global res_func .global p_moveres_func: clrb DNRM_FLG(%a6) clrb RES_FLG(%a6) clrb CU_ONLY(%a6) tstb DY_MO_FLG(%a6) beqs monadicdyadic: btstb #7,DTAG(%a6) //if dop = norm=000, zero=001,// ;inf=010 or nan=011 beqs monadic //then branch// ;else denorm// HANDLE DESTINATION DENORM HERE// ;set dtag to norm// ;write the tag & fpte15 to the fstack leal FPTEMP(%a6),%a0 bclrb #sign_bit,LOCAL_EX(%a0) sne LOCAL_SGN(%a0) bsr nrm_set //normalize number (exp will go negative) bclrb #sign_bit,LOCAL_EX(%a0) //get rid of false sign bfclr LOCAL_SGN(%a0){#0:#8} //change back to IEEE ext format beqs dpos bsetb #sign_bit,LOCAL_EX(%a0)dpos: bfclr DTAG(%a6){#0:#4} //set tag to normalized, FPTE15 = 0 bsetb #4,DTAG(%a6) //set FPTE15 orb #0x0f,DNRM_FLG(%a6)monadic: leal ETEMP(%a6),%a0 btstb #direction_bit,CMDREG1B(%a6) //check direction bne opclass3 //it is a mv out//// At this point, only opclass 0 and 2 possible// btstb #7,STAG(%a6) //if sop = norm=000, zero=001,// ;inf=010 or nan=011 bne mon_dnrm //else denorm tstb DY_MO_FLG(%a6) //all cases of dyadic instructions would bne normal //require normalization of denorm// At this point:// monadic instructions: fabs = $18 fneg = $1a ftst = $3a// fmove = $00 fsmove = $40 fdmove = $44// fsqrt = $05* fssqrt = $41 fdsqrt = $45// (*fsqrt reencoded to $05)// movew CMDREG1B(%a6),%d0 //get command register andil #0x7f,%d0 //strip to only command word//// At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and // fdsqrt are possible.// For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize)// For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize)// btstl #0,%d0 bne normal //weed out fsqrt instructions//// cu_norm handles fmove in instructions with normalized inputs.// The routine round is used to correctly round the input for the// destination precision and mode.//cu_norm: st CU_ONLY(%a6) //set cu-only inst flag movew CMDREG1B(%a6),%d0 andib #0x3b,%d0 //isolate bits to select inst tstb %d0 beql cu_nmove //if zero, it is an fmove cmpib #0x18,%d0 beql cu_nabs //if $18, it is fabs cmpib #0x1a,%d0 beql cu_nneg //if $1a, it is fneg//// Inst is ftst. Check the source operand and set the cc's accordingly.// No write is done, so simply rts.//cu_ntst: movew LOCAL_EX(%a0),%d0 bclrl #15,%d0 sne LOCAL_SGN(%a0) beqs cu_ntpo orl #neg_mask,USER_FPSR(%a6) //set Ncu_ntpo: cmpiw #0x7fff,%d0 //test for inf/nan bnes cu_ntcz tstl LOCAL_HI(%a0) bnes cu_ntn tstl LOCAL_LO(%a0) bnes cu_ntn orl #inf_mask,USER_FPSR(%a6) rtscu_ntn: orl #nan_mask,USER_FPSR(%a6) movel ETEMP_EX(%a6),FPTEMP_EX(%a6) //set up fptemp sign for // ;snan handler rtscu_ntcz: tstl LOCAL_HI(%a0) bnel cu_ntsx tstl LOCAL_LO(%a0) bnel cu_ntsx orl #z_mask,USER_FPSR(%a6)cu_ntsx: rts//// Inst is fabs. Execute the absolute value function on the input.// Branch to the fmove code. If the operand is NaN, do nothing.//cu_nabs: moveb STAG(%a6),%d0 btstl #5,%d0 //test for NaN or zero bne wr_etemp //if either, simply write it bclrb #7,LOCAL_EX(%a0) //do abs bras cu_nmove //fmove code will finish//// Inst is fneg. Execute the negate value function on the input.// Fall though to the fmove code. If the operand is NaN, do nothing.//cu_nneg: moveb STAG(%a6),%d0 btstl #5,%d0 //test for NaN or zero bne wr_etemp //if either, simply write it bchgb #7,LOCAL_EX(%a0) //do neg//// Inst is fmove. This code also handles all result writes.// If bit 2 is set, round is forced to double. If it is clear,// and bit 6 is set, round is forced to single. If both are clear,// the round precision is found in the fpcr. If the rounding precision// is double or single, round the result before the write.//cu_nmove: moveb STAG(%a6),%d0 andib #0xe0,%d0 //isolate stag bits bne wr_etemp //if not norm, simply write it btstb #2,CMDREG1B+1(%a6) //check for rd bne cu_nmrd btstb #6,CMDREG1B+1(%a6) //check for rs bne cu_nmrs//// The move or operation is not with forced precision. Test for// nan or inf as the input; if so, simply write it to FPn. Use the// FPCR_MODE byte to get rounding on norms and zeros.//cu_nmnr: bfextu FPCR_MODE(%a6){#0:#2},%d0 tstb %d0 //check for extended beq cu_wrexn //if so, just write result cmpib #1,%d0 //check for single beq cu_nmrs //fall through to double//// The move is fdmove or round precision is double.//cu_nmrd: movel #2,%d0 //set up the size for denorm movew LOCAL_EX(%a0),%d1 //compare exponent to double threshold andw #0x7fff,%d1 cmpw #0x3c01,%d1 bls cu_nunfl bfextu FPCR_MODE(%a6){#2:#2},%d1 //get rmode orl #0x00020000,%d1 //or in rprec (double) clrl %d0 //clear g,r,s for round bclrb #sign_bit,LOCAL_EX(%a0) //convert to internal format sne LOCAL_SGN(%a0) bsrl round bfclr LOCAL_SGN(%a0){#0:#8} beqs cu_nmrdc bsetb #sign_bit,LOCAL_EX(%a0)cu_nmrdc: movew LOCAL_EX(%a0),%d1 //check for overflow andw #0x7fff,%d1 cmpw #0x43ff,%d1 bge cu_novfl //take care of overflow case bra cu_wrexn//// The move is fsmove or round precision is single.//cu_nmrs: movel #1,%d0 movew LOCAL_EX(%a0),%d1 andw #0x7fff,%d1 cmpw #0x3f81,%d1 bls cu_nunfl bfextu FPCR_MODE(%a6){#2:#2},%d1 orl #0x00010000,%d1 clrl %d0 bclrb #sign_bit,LOCAL_EX(%a0) sne LOCAL_SGN(%a0) bsrl round bfclr LOCAL_SGN(%a0){#0:#8} beqs cu_nmrsc bsetb #sign_bit,LOCAL_EX(%a0)cu_nmrsc: movew LOCAL_EX(%a0),%d1 andw #0x7FFF,%d1 cmpw #0x407f,%d1 blt cu_wrexn//// The operand is above precision boundaries. Use t_ovfl to// generate the correct value.//cu_novfl: bsr t_ovfl bra cu_wrexn//// The operand is below precision boundaries. Use denorm to// generate the correct value.//cu_nunfl: bclrb #sign_bit,LOCAL_EX(%a0) sne LOCAL_SGN(%a0) bsr denorm bfclr LOCAL_SGN(%a0){#0:#8} //change back to IEEE ext format beqs cu_nucont bsetb #sign_bit,LOCAL_EX(%a0)cu_nucont: bfextu FPCR_MODE(%a6){#2:#2},%d1 btstb #2,CMDREG1B+1(%a6) //check for rd bne inst_d btstb #6,CMDREG1B+1(%a6) //check for rs bne inst_s swap %d1 moveb FPCR_MODE(%a6),%d1 lsrb #6,%d1 swap %d1 bra inst_sdinst_d: orl #0x00020000,%d1 bra inst_sdinst_s: orl #0x00010000,%d1inst_sd: bclrb #sign_bit,LOCAL_EX(%a0) sne LOCAL_SGN(%a0) bsrl round bfclr LOCAL_SGN(%a0){#0:#8} beqs cu_nuflp bsetb #sign_bit,LOCAL_EX(%a0)cu_nuflp: btstb #inex2_bit,FPSR_EXCEPT(%a6) beqs cu_nuninx orl #aunfl_mask,USER_FPSR(%a6) //if the round was inex, set AUNFLcu_nuninx: tstl LOCAL_HI(%a0) //test for zero bnes cu_nunzro tstl LOCAL_LO(%a0) bnes cu_nunzro//// The mantissa is zero from the denorm loop. Check sign and rmode// to see if rounding should have occurred which would leave the lsb.// movel USER_FPCR(%a6),%d0 andil #0x30,%d0 //isolate rmode cmpil #0x20,%d0 blts cu_nzro bnes cu_nrpcu_nrm: tstw LOCAL_EX(%a0) //if positive, set lsb bges cu_nzro btstb #7,FPCR_MODE(%a6) //check for double beqs cu_nincs bras cu_nincdcu_nrp: tstw LOCAL_EX(%a0) //if positive, set lsb blts cu_nzro btstb #7,FPCR_MODE(%a6) //check for double beqs cu_nincscu_nincd: orl #0x800,LOCAL_LO(%a0) //inc for double bra cu_nunzrocu_nincs: orl #0x100,LOCAL_HI(%a0) //inc for single bra cu_nunzrocu_nzro: orl #z_mask,USER_FPSR(%a6) moveb STAG(%a6),%d0 andib #0xe0,%d0 cmpib #0x40,%d0 //check if input was tagged zero beqs cu_numvcu_nunzro: orl #unfl_mask,USER_FPSR(%a6) //set unflcu_numv: movel (%a0),ETEMP(%a6) movel 4(%a0),ETEMP_HI(%a6) movel 8(%a0),ETEMP_LO(%a6)//// Write the result to memory, setting the fpsr cc bits. NaN and Inf// bypass cu_wrexn.//cu_wrexn: tstw LOCAL_EX(%a0) //test for zero beqs cu_wrzero cmpw #0x8000,LOCAL_EX(%a0) //test for zero bnes cu_wreoncu_wrzero: orl #z_mask,USER_FPSR(%a6) //set Z bitcu_wreon: tstw LOCAL_EX(%a0) bpl wr_etemp orl #neg_mask,USER_FPSR(%a6) bra wr_etemp//// HANDLE SOURCE DENORM HERE//// ;clear denorm stag to norm// ;write the new tag & ete15 to the fstackmon_dnrm://// At this point, check for the cases in which normalizing the // denorm produces incorrect results.// tstb DY_MO_FLG(%a6) //all cases of dyadic instructions would bnes nrm_src //require normalization of denorm// At this point:// monadic instructions: fabs = $18 fneg = $1a ftst = $3a// fmove = $00 fsmove = $40 fdmove = $44// fsqrt = $05* fssqrt = $41 fdsqrt = $45// (*fsqrt reencoded to $05)// movew CMDREG1B(%a6),%d0 //get command register andil #0x7f,%d0 //strip to only command word//// At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and // fdsqrt are possible.// For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize)// For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize)// btstl #0,%d0 bnes nrm_src //weed out fsqrt instructions st CU_ONLY(%a6) //set cu-only inst flag bra cu_dnrm //fmove, fabs, fneg, ftst // ;cases go to cu_dnrmnrm_src: bclrb #sign_bit,LOCAL_EX(%a0) sne LOCAL_SGN(%a0) bsr nrm_set //normalize number (exponent will go // ; negative) bclrb #sign_bit,LOCAL_EX(%a0) //get rid of false sign bfclr LOCAL_SGN(%a0){#0:#8} //change back to IEEE ext format beqs spos bsetb #sign_bit,LOCAL_EX(%a0)spos: bfclr STAG(%a6){#0:#4} //set tag to normalized, FPTE15 = 0 bsetb #4,STAG(%a6) //set ETE15 orb #0xf0,DNRM_FLG(%a6)normal: tstb DNRM_FLG(%a6) //check if any of the ops were denorms bne ck_wrap //if so, check if it is a potential// ;wrap-around casefix_stk: moveb #0xfe,CU_SAVEPC(%a6) bclrb #E1,E_BYTE(%a6) clrw NMNEXC(%a6) st RES_FLG(%a6) //indicate that a restore is needed rts//// cu_dnrm handles all cu-only instructions (fmove, fabs, fneg, and// ftst) completely in software without an frestore to the 040. //cu_dnrm: st CU_ONLY(%a6) movew CMDREG1B(%a6),%d0 andib #0x3b,%d0 //isolate bits to select inst tstb %d0 beql cu_dmove //if zero, it is an fmove cmpib #0x18,%d0 beql cu_dabs //if $18, it is fabs cmpib #0x1a,%d0 beql cu_dneg //if $1a, it is fneg//// Inst is ftst. Check the source operand and set the cc's accordingly.// No write is done, so simply rts.//cu_dtst: movew LOCAL_EX(%a0),%d0 bclrl #15,%d0 sne LOCAL_SGN(%a0) beqs cu_dtpo orl #neg_mask,USER_FPSR(%a6) //set Ncu_dtpo: cmpiw #0x7fff,%d0 //test for inf/nan bnes cu_dtcz tstl LOCAL_HI(%a0) bnes cu_dtn tstl LOCAL_LO(%a0) bnes cu_dtn orl #inf_mask,USER_FPSR(%a6) rtscu_dtn: orl #nan_mask,USER_FPSR(%a6) movel ETEMP_EX(%a6),FPTEMP_EX(%a6) //set up fptemp sign for // ;snan handler rtscu_dtcz: tstl LOCAL_HI(%a0) bnel cu_dtsx tstl LOCAL_LO(%a0) bnel cu_dtsx orl #z_mask,USER_FPSR(%a6)cu_dtsx: rts//// Inst is fabs. Execute the absolute value function on the input.// Branch to the fmove code.//cu_dabs: bclrb #7,LOCAL_EX(%a0) //do abs bras cu_dmove //fmove code will finish//// Inst is fneg. Execute the negate value function on the input.// Fall though to the fmove code.//cu_dneg: bchgb #7,LOCAL_EX(%a0) //do neg//// Inst is fmove. This code also handles all result writes.// If bit 2 is set, round is forced to double. If it is clear,// and bit 6 is set, round is forced to single. If both are clear,// the round precision is found in the fpcr. If the rounding precision// is double or single, the result is zero, and the mode is checked// to determine if the lsb of the result should be set.//cu_dmove: btstb #2,CMDREG1B+1(%a6) //check for rd bne cu_dmrd btstb #6,CMDREG1B+1(%a6) //check for rs bne cu_dmrs//// The move or operation is not with forced precision. Use the// FPCR_MODE byte to get rounding.//cu_dmnr: bfextu FPCR_MODE(%a6){#0:#2},%d0 tstb %d0 //check for extended beq cu_wrexd //if so, just write result cmpib #1,%d0 //check for single beq cu_dmrs //fall through to double//// The move is fdmove or round precision is double. Result is zero.// Check rmode for rp or rm and set lsb accordingly.//cu_dmrd: bfextu FPCR_MODE(%a6){#2:#2},%d1 //get rmode tstw LOCAL_EX(%a0) //check sign blts cu_dmdn cmpib #3,%d1 //check for rp bne cu_dpd //load double pos zero bra cu_dpdr //load double pos zero w/lsbcu_dmdn: cmpib #2,%d1 //check for rm bne cu_dnd //load double neg zero
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -