📄 res_func.s
字号:
| The move is fsmove or round precision is single. Result is zero.| Check for rp or rm and set lsb accordingly.|cu_dmrs: bfextu FPCR_MODE(%a6){#2:#2},%d1 |get rmode tstw LOCAL_EX(%a0) |check sign blts cu_dmsn cmpib #3,%d1 |check for rp bne cu_spd |load single pos zero bra cu_spdr |load single pos zero w/lsbcu_dmsn: cmpib #2,%d1 |check for rm bne cu_snd |load single neg zero bra cu_sndr |load single neg zero w/lsb|| The precision is extended, so the result in etemp is correct.| Simply set unfl (not inex2 or aunfl) and write the result to| the correct fp register.cu_wrexd: orl #unfl_mask,USER_FPSR(%a6) tstw LOCAL_EX(%a0) beq wr_etemp orl #neg_mask,USER_FPSR(%a6) bra wr_etemp|| These routines write +/- zero in double format. The routines| cu_dpdr and cu_dndr set the double lsb.|cu_dpd: movel #0x3c010000,LOCAL_EX(%a0) |force pos double zero clrl LOCAL_HI(%a0) clrl LOCAL_LO(%a0) orl #z_mask,USER_FPSR(%a6) orl #unfinx_mask,USER_FPSR(%a6) bra wr_etempcu_dpdr: movel #0x3c010000,LOCAL_EX(%a0) |force pos double zero clrl LOCAL_HI(%a0) movel #0x800,LOCAL_LO(%a0) |with lsb set orl #unfinx_mask,USER_FPSR(%a6) bra wr_etempcu_dnd: movel #0xbc010000,LOCAL_EX(%a0) |force pos double zero clrl LOCAL_HI(%a0) clrl LOCAL_LO(%a0) orl #z_mask,USER_FPSR(%a6) orl #neg_mask,USER_FPSR(%a6) orl #unfinx_mask,USER_FPSR(%a6) bra wr_etempcu_dndr: movel #0xbc010000,LOCAL_EX(%a0) |force pos double zero clrl LOCAL_HI(%a0) movel #0x800,LOCAL_LO(%a0) |with lsb set orl #neg_mask,USER_FPSR(%a6) orl #unfinx_mask,USER_FPSR(%a6) bra wr_etemp|| These routines write +/- zero in single format. The routines| cu_dpdr and cu_dndr set the single lsb.|cu_spd: movel #0x3f810000,LOCAL_EX(%a0) |force pos single zero clrl LOCAL_HI(%a0) clrl LOCAL_LO(%a0) orl #z_mask,USER_FPSR(%a6) orl #unfinx_mask,USER_FPSR(%a6) bra wr_etempcu_spdr: movel #0x3f810000,LOCAL_EX(%a0) |force pos single zero movel #0x100,LOCAL_HI(%a0) |with lsb set clrl LOCAL_LO(%a0) orl #unfinx_mask,USER_FPSR(%a6) bra wr_etempcu_snd: movel #0xbf810000,LOCAL_EX(%a0) |force pos single zero clrl LOCAL_HI(%a0) clrl LOCAL_LO(%a0) orl #z_mask,USER_FPSR(%a6) orl #neg_mask,USER_FPSR(%a6) orl #unfinx_mask,USER_FPSR(%a6) bra wr_etempcu_sndr: movel #0xbf810000,LOCAL_EX(%a0) |force pos single zero movel #0x100,LOCAL_HI(%a0) |with lsb set clrl LOCAL_LO(%a0) orl #neg_mask,USER_FPSR(%a6) orl #unfinx_mask,USER_FPSR(%a6) bra wr_etemp|| This code checks for 16-bit overflow conditions on dyadic| operations which are not restorable into the floating-point| unit and must be completed in software. Basically, this| condition exists with a very large norm and a denorm. One| of the operands must be denormalized to enter this code.|| Flags used:| DY_MO_FLG contains 0 for monadic op, $ff for dyadic| DNRM_FLG contains $00 for neither op denormalized| $0f for the destination op denormalized| $f0 for the source op denormalized| $ff for both ops denormalized|| The wrap-around condition occurs for add, sub, div, and cmp| when|| abs(dest_exp - src_exp) >= $8000|| and for mul when|| (dest_exp + src_exp) < $0|| we must process the operation here if this case is true.|| The rts following the frcfpn routine is the exit from res_func| for this condition. The restore flag (RES_FLG) is left clear.| No frestore is done unless an exception is to be reported.|| For fadd:| if(sign_of(dest) != sign_of(src))| replace exponent of src with $3fff (keep sign)| use fpu to perform dest+new_src (user's rmode and X)| clr sticky| else| set sticky| call round with user's precision and mode| move result to fpn and wbtemp|| For fsub:| if(sign_of(dest) == sign_of(src))| replace exponent of src with $3fff (keep sign)| use fpu to perform dest+new_src (user's rmode and X)| clr sticky| else| set sticky| call round with user's precision and mode| move result to fpn and wbtemp|| For fdiv/fsgldiv:| if(both operands are denorm)| restore_to_fpu;| if(dest is norm)| force_ovf;| else(dest is denorm)| force_unf:|| For fcmp:| if(dest is norm)| N = sign_of(dest);| else(dest is denorm)| N = sign_of(src);|| For fmul:| if(both operands are denorm)| force_unf;| if((dest_exp + src_exp) < 0)| force_unf:| else| restore_to_fpu;|| local equates: .set addcode,0x22 .set subcode,0x28 .set mulcode,0x23 .set divcode,0x20 .set cmpcode,0x38ck_wrap: | tstb DY_MO_FLG(%a6) ;check for fsqrt beq fix_stk |if zero, it is fsqrt movew CMDREG1B(%a6),%d0 andiw #0x3b,%d0 |strip to command bits cmpiw #addcode,%d0 beq wrap_add cmpiw #subcode,%d0 beq wrap_sub cmpiw #mulcode,%d0 beq wrap_mul cmpiw #cmpcode,%d0 beq wrap_cmp|| Inst is fdiv.|wrap_div: cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm, beq fix_stk |restore to fpu|| One of the ops is denormalized. Test for wrap condition| and force the result.| cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm bnes div_srcddiv_destd: bsrl ckinf_ns bne fix_stk bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos) bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg) subl %d1,%d0 |subtract dest from src cmpl #0x7fff,%d0 blt fix_stk |if less, not wrap case clrb WBTEMP_SGN(%a6) movew ETEMP_EX(%a6),%d0 |find the sign of the result movew FPTEMP_EX(%a6),%d1 eorw %d1,%d0 andiw #0x8000,%d0 beq force_unf st WBTEMP_SGN(%a6) bra force_unfckinf_ns: moveb STAG(%a6),%d0 |check source tag for inf or nan bra ck_in_comckinf_nd: moveb DTAG(%a6),%d0 |check destination tag for inf or nanck_in_com: andib #0x60,%d0 |isolate tag bits cmpb #0x40,%d0 |is it inf? beq nan_or_inf |not wrap case cmpb #0x60,%d0 |is it nan? beq nan_or_inf |yes, not wrap case? cmpb #0x20,%d0 |is it a zero? beq nan_or_inf |yes clrl %d0 rts |then ; it is either a zero of norm,| ;check wrap casenan_or_inf: moveql #-1,%d0 rtsdiv_srcd: bsrl ckinf_nd bne fix_stk bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos) bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg) subl %d1,%d0 |subtract src from dest cmpl #0x8000,%d0 blt fix_stk |if less, not wrap case clrb WBTEMP_SGN(%a6) movew ETEMP_EX(%a6),%d0 |find the sign of the result movew FPTEMP_EX(%a6),%d1 eorw %d1,%d0 andiw #0x8000,%d0 beqs force_ovf st WBTEMP_SGN(%a6)|| This code handles the case of the instruction resulting in| an overflow condition.|force_ovf: bclrb #E1,E_BYTE(%a6) orl #ovfl_inx_mask,USER_FPSR(%a6) clrw NMNEXC(%a6) leal WBTEMP(%a6),%a0 |point a0 to memory location movew CMDREG1B(%a6),%d0 btstl #6,%d0 |test for forced precision beqs frcovf_fpcr btstl #2,%d0 |check for double bnes frcovf_dbl movel #0x1,%d0 |inst is forced single bras frcovf_rndfrcovf_dbl: movel #0x2,%d0 |inst is forced double bras frcovf_rndfrcovf_fpcr: bfextu FPCR_MODE(%a6){#0:#2},%d0 |inst not forced - use fpcr precfrcovf_rnd:| The 881/882 does not set inex2 for the following case, so the| line is commented out to be compatible with 881/882| tst.b %d0| beq.b frcovf_x| or.l #inex2_mask,USER_FPSR(%a6) ;if prec is s or d, set inex2|frcovf_x: bsrl ovf_res |get correct result based on| ;round precision/mode. This| ;sets FPSR_CC correctly| ;returns in external format bfclr WBTEMP_SGN(%a6){#0:#8} beq frcfpn bsetb #sign_bit,WBTEMP_EX(%a6) bra frcfpn|| Inst is fadd.|wrap_add: cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm, beq fix_stk |restore to fpu|| One of the ops is denormalized. Test for wrap condition| and complete the instruction.| cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm bnes add_srcdadd_destd: bsrl ckinf_ns bne fix_stk bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos) bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg) subl %d1,%d0 |subtract dest from src cmpl #0x8000,%d0 blt fix_stk |if less, not wrap case bra add_wrapadd_srcd: bsrl ckinf_nd bne fix_stk bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos) bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg) subl %d1,%d0 |subtract src from dest cmpl #0x8000,%d0 blt fix_stk |if less, not wrap case|| Check the signs of the operands. If they are unlike, the fpu| can be used to add the norm and 1.0 with the sign of the| denorm and it will correctly generate the result in extended| precision. We can then call round with no sticky and the result| will be correct for the user's rounding mode and precision. If| the signs are the same, we call round with the sticky bit set| and the result will be correct for the user's rounding mode and| precision.|add_wrap: movew ETEMP_EX(%a6),%d0 movew FPTEMP_EX(%a6),%d1 eorw %d1,%d0 andiw #0x8000,%d0 beq add_same|| The signs are unlike.| cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm? bnes add_u_srcd movew FPTEMP_EX(%a6),%d0 andiw #0x8000,%d0 orw #0x3fff,%d0 |force the exponent to +/- 1 movew %d0,FPTEMP_EX(%a6) |in the denorm movel USER_FPCR(%a6),%d0 andil #0x30,%d0 fmovel %d0,%fpcr |set up users rmode and X fmovex ETEMP(%a6),%fp0 faddx FPTEMP(%a6),%fp0 leal WBTEMP(%a6),%a0 |point a0 to wbtemp in frame fmovel %fpsr,%d1 orl %d1,USER_FPSR(%a6) |capture cc's and inex from fadd fmovex %fp0,WBTEMP(%a6) |write result to memory lsrl #4,%d0 |put rmode in lower 2 bits movel USER_FPCR(%a6),%d1 andil #0xc0,%d1 lsrl #6,%d1 |put precision in upper word swap %d1 orl %d0,%d1 |set up for round call clrl %d0 |force sticky to zero bclrb #sign_bit,WBTEMP_EX(%a6) sne WBTEMP_SGN(%a6) bsrl round |round result to users rmode & prec bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format beq frcfpnr bsetb #sign_bit,WBTEMP_EX(%a6) bra frcfpnradd_u_srcd: movew ETEMP_EX(%a6),%d0 andiw #0x8000,%d0 orw #0x3fff,%d0 |force the exponent to +/- 1 movew %d0,ETEMP_EX(%a6) |in the denorm movel USER_FPCR(%a6),%d0 andil #0x30,%d0 fmovel %d0,%fpcr |set up users rmode and X fmovex ETEMP(%a6),%fp0 faddx FPTEMP(%a6),%fp0 fmovel %fpsr,%d1 orl %d1,USER_FPSR(%a6) |capture cc's and inex from fadd leal WBTEMP(%a6),%a0 |point a0 to wbtemp in frame fmovex %fp0,WBTEMP(%a6) |write result to memory lsrl #4,%d0 |put rmode in lower 2 bits movel USER_FPCR(%a6),%d1 andil #0xc0,%d1 lsrl #6,%d1 |put precision in upper word swap %d1 orl %d0,%d1 |set up for round call clrl %d0 |force sticky to zero bclrb #sign_bit,WBTEMP_EX(%a6) sne WBTEMP_SGN(%a6) |use internal format for round bsrl round |round result to users rmode & prec bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format beq frcfpnr bsetb #sign_bit,WBTEMP_EX(%a6) bra frcfpnr|| Signs are alike:|add_same: cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm? bnes add_s_srcdadd_s_destd: leal ETEMP(%a6),%a0 movel USER_FPCR(%a6),%d0 andil #0x30,%d0 lsrl #4,%d0 |put rmode in lower 2 bits movel USER_FPCR(%a6),%d1 andil #0xc0,%d1 lsrl #6,%d1 |put precision in upper word swap %d1 orl %d0,%d1 |set up for round call movel #0x20000000,%d0 |set sticky for round bclrb #sign_bit,ETEMP_EX(%a6) sne ETEMP_SGN(%a6) bsrl round |round result to users rmode & prec bfclr ETEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format beqs add_s_dclr bsetb #sign_bit,ETEMP_EX(%a6)add_s_dclr: leal WBTEMP(%a6),%a0 movel ETEMP(%a6),(%a0) |write result to wbtemp movel ETEMP_HI(%a6),4(%a0) movel ETEMP_LO(%a6),8(%a0) tstw ETEMP_EX(%a6) bgt add_ckovf orl #neg_mask,USER_FPSR(%a6) bra add_ckovfadd_s_srcd: leal FPTEMP(%a6),%a0 movel USER_FPCR(%a6),%d0 andil #0x30,%d0 lsrl #4,%d0 |put rmode in lower 2 bits movel USER_FPCR(%a6),%d1 andil #0xc0,%d1 lsrl #6,%d1 |put precision in upper word swap %d1 orl %d0,%d1 |set up for round call movel #0x20000000,%d0 |set sticky for round bclrb #sign_bit,FPTEMP_EX(%a6) sne FPTEMP_SGN(%a6) bsrl round |round result to users rmode & prec bfclr FPTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format beqs add_s_sclr bsetb #sign_bit,FPTEMP_EX(%a6)add_s_sclr: leal WBTEMP(%a6),%a0 movel FPTEMP(%a6),(%a0) |write result to wbtemp movel FPTEMP_HI(%a6),4(%a0) movel FPTEMP_LO(%a6),8(%a0) tstw FPTEMP_EX(%a6) bgt add_ckovf orl #neg_mask,USER_FPSR(%a6)add_ckovf: movew WBTEMP_EX(%a6),%d0 andiw #0x7fff,%d0 cmpiw #0x7fff,%d0 bne frcfpnr|| The result has overflowed to $7fff exponent. Set I, ovfl,| and aovfl, and clr the mantissa (incorrectly set by the| round routine.)| orl #inf_mask+ovfl_inx_mask,USER_FPSR(%a6) clrl 4(%a0) bra frcfpnr|| Inst is fsub.|wrap_sub: cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm, beq fix_stk |restore to fpu|| One of the ops is denormalized. Test for wrap condition| and complete the instruction.| cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm bnes sub_srcdsub_destd: bsrl ckinf_ns bne fix_stk bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos) bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg) subl %d1,%d0 |subtract src from dest cmpl #0x8000,%d0 blt fix_stk |if less, not wrap case bra sub_wrapsub_srcd: bsrl ckinf_nd bne fix_stk bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos) bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg) subl %d1,%d0 |subtract dest from src cmpl #0x8000,%d0 blt fix_stk |if less, not wrap case|| Check the signs of the operands. If they are alike, the fpu| can be used to subtract from the norm 1.0 with the sign of the| denorm and it will correctly generate the result in extended| precision. We can then call round with no sticky and the result| will be correct for the user's rounding mode and precision. If| the signs are unlike, we call round with the sticky bit set| and the result will be correct for the user's rounding mode and| precision.|sub_wrap: movew ETEMP_EX(%a6),%d0 movew FPTEMP_EX(%a6),%d1 eorw %d1,%d0 andiw #0x8000,%d0 bne sub_diff|| The signs are alike.| cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm? bnes sub_u_srcd movew FPTEMP_EX(%a6),%d0 andiw #0x8000,%d0 orw #0x3fff,%d0 |force the exponent to +/- 1
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -