URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [arch/] [m68k/] [fpsp040/] [res_func.S] - Rev 1765
Compare with Previous | Blame | View Log
|| 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.h"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=011beqs monadic |then branch| ;else denorm| HANDLE DESTINATION DENORM HERE| ;set dtag to norm| ;write the tag & fpte15 to the fstackleal FPTEMP(%a6),%a0bclrb #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 signbfclr LOCAL_SGN(%a0){#0:#8} |change back to IEEE ext formatbeqs dposbsetb #sign_bit,LOCAL_EX(%a0)dpos:bfclr DTAG(%a6){#0:#4} |set tag to normalized, FPTE15 = 0bsetb #4,DTAG(%a6) |set FPTE15orb #0x0f,DNRM_FLG(%a6)monadic:leal ETEMP(%a6),%a0btstb #direction_bit,CMDREG1B(%a6) |check directionbne 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=011bne mon_dnrm |else denormtstb DY_MO_FLG(%a6) |all cases of dyadic instructions wouldbne 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 registerandil #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,%d0bne 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 flagmovew CMDREG1B(%a6),%d0andib #0x3b,%d0 |isolate bits to select insttstb %d0beql cu_nmove |if zero, it is an fmovecmpib #0x18,%d0beql cu_nabs |if $18, it is fabscmpib #0x1a,%d0beql 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),%d0bclrl #15,%d0sne LOCAL_SGN(%a0)beqs cu_ntpoorl #neg_mask,USER_FPSR(%a6) |set Ncu_ntpo:cmpiw #0x7fff,%d0 |test for inf/nanbnes cu_ntcztstl LOCAL_HI(%a0)bnes cu_ntntstl LOCAL_LO(%a0)bnes cu_ntnorl #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 handlerrtscu_ntcz:tstl LOCAL_HI(%a0)bnel cu_ntsxtstl LOCAL_LO(%a0)bnel cu_ntsxorl #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),%d0btstl #5,%d0 |test for NaN or zerobne wr_etemp |if either, simply write itbclrb #7,LOCAL_EX(%a0) |do absbras 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),%d0btstl #5,%d0 |test for NaN or zerobne wr_etemp |if either, simply write itbchgb #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),%d0andib #0xe0,%d0 |isolate stag bitsbne wr_etemp |if not norm, simply write itbtstb #2,CMDREG1B+1(%a6) |check for rdbne cu_nmrdbtstb #6,CMDREG1B+1(%a6) |check for rsbne 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},%d0tstb %d0 |check for extendedbeq cu_wrexn |if so, just write resultcmpib #1,%d0 |check for singlebeq 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 denormmovew LOCAL_EX(%a0),%d1 |compare exponent to double thresholdandw #0x7fff,%d1cmpw #0x3c01,%d1bls cu_nunflbfextu FPCR_MODE(%a6){#2:#2},%d1 |get rmodeorl #0x00020000,%d1 |or in rprec (double)clrl %d0 |clear g,r,s for roundbclrb #sign_bit,LOCAL_EX(%a0) |convert to internal formatsne LOCAL_SGN(%a0)bsrl roundbfclr LOCAL_SGN(%a0){#0:#8}beqs cu_nmrdcbsetb #sign_bit,LOCAL_EX(%a0)cu_nmrdc:movew LOCAL_EX(%a0),%d1 |check for overflowandw #0x7fff,%d1cmpw #0x43ff,%d1bge cu_novfl |take care of overflow casebra cu_wrexn|| The move is fsmove or round precision is single.|cu_nmrs:movel #1,%d0movew LOCAL_EX(%a0),%d1andw #0x7fff,%d1cmpw #0x3f81,%d1bls cu_nunflbfextu FPCR_MODE(%a6){#2:#2},%d1orl #0x00010000,%d1clrl %d0bclrb #sign_bit,LOCAL_EX(%a0)sne LOCAL_SGN(%a0)bsrl roundbfclr LOCAL_SGN(%a0){#0:#8}beqs cu_nmrscbsetb #sign_bit,LOCAL_EX(%a0)cu_nmrsc:movew LOCAL_EX(%a0),%d1andw #0x7FFF,%d1cmpw #0x407f,%d1blt cu_wrexn|| The operand is above precision boundaries. Use t_ovfl to| generate the correct value.|cu_novfl:bsr t_ovflbra 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 denormbfclr LOCAL_SGN(%a0){#0:#8} |change back to IEEE ext formatbeqs cu_nucontbsetb #sign_bit,LOCAL_EX(%a0)cu_nucont:bfextu FPCR_MODE(%a6){#2:#2},%d1btstb #2,CMDREG1B+1(%a6) |check for rdbne inst_dbtstb #6,CMDREG1B+1(%a6) |check for rsbne inst_sswap %d1moveb FPCR_MODE(%a6),%d1lsrb #6,%d1swap %d1bra inst_sdinst_d:orl #0x00020000,%d1bra inst_sdinst_s:orl #0x00010000,%d1inst_sd:bclrb #sign_bit,LOCAL_EX(%a0)sne LOCAL_SGN(%a0)bsrl roundbfclr LOCAL_SGN(%a0){#0:#8}beqs cu_nuflpbsetb #sign_bit,LOCAL_EX(%a0)cu_nuflp:btstb #inex2_bit,FPSR_EXCEPT(%a6)beqs cu_nuninxorl #aunfl_mask,USER_FPSR(%a6) |if the round was inex, set AUNFLcu_nuninx:tstl LOCAL_HI(%a0) |test for zerobnes cu_nunzrotstl 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),%d0andil #0x30,%d0 |isolate rmodecmpil #0x20,%d0blts cu_nzrobnes cu_nrpcu_nrm:tstw LOCAL_EX(%a0) |if positive, set lsbbges cu_nzrobtstb #7,FPCR_MODE(%a6) |check for doublebeqs cu_nincsbras cu_nincdcu_nrp:tstw LOCAL_EX(%a0) |if positive, set lsbblts cu_nzrobtstb #7,FPCR_MODE(%a6) |check for doublebeqs cu_nincscu_nincd:orl #0x800,LOCAL_LO(%a0) |inc for doublebra cu_nunzrocu_nincs:orl #0x100,LOCAL_HI(%a0) |inc for singlebra cu_nunzrocu_nzro:orl #z_mask,USER_FPSR(%a6)moveb STAG(%a6),%d0andib #0xe0,%d0cmpib #0x40,%d0 |check if input was tagged zerobeqs 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 zerobeqs cu_wrzerocmpw #0x8000,LOCAL_EX(%a0) |test for zerobnes cu_wreoncu_wrzero:orl #z_mask,USER_FPSR(%a6) |set Z bitcu_wreon:tstw LOCAL_EX(%a0)bpl wr_etemporl #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 wouldbnes 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 registerandil #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,%d0bnes nrm_src |weed out fsqrt instructionsst CU_ONLY(%a6) |set cu-only inst flagbra 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 signbfclr LOCAL_SGN(%a0){#0:#8} |change back to IEEE ext formatbeqs sposbsetb #sign_bit,LOCAL_EX(%a0)spos:bfclr STAG(%a6){#0:#4} |set tag to normalized, FPTE15 = 0bsetb #4,STAG(%a6) |set ETE15orb #0xf0,DNRM_FLG(%a6)normal:tstb DNRM_FLG(%a6) |check if any of the ops were denormsbne 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 neededrts|| 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),%d0andib #0x3b,%d0 |isolate bits to select insttstb %d0beql cu_dmove |if zero, it is an fmovecmpib #0x18,%d0beql cu_dabs |if $18, it is fabscmpib #0x1a,%d0beql 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),%d0bclrl #15,%d0sne LOCAL_SGN(%a0)beqs cu_dtpoorl #neg_mask,USER_FPSR(%a6) |set Ncu_dtpo:cmpiw #0x7fff,%d0 |test for inf/nanbnes cu_dtcztstl LOCAL_HI(%a0)bnes cu_dtntstl LOCAL_LO(%a0)bnes cu_dtnorl #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 handlerrtscu_dtcz:tstl LOCAL_HI(%a0)bnel cu_dtsxtstl LOCAL_LO(%a0)bnel cu_dtsxorl #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 absbras 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 rdbne cu_dmrdbtstb #6,CMDREG1B+1(%a6) |check for rsbne 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},%d0tstb %d0 |check for extendedbeq cu_wrexd |if so, just write resultcmpib #1,%d0 |check for singlebeq 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 rmodetstw LOCAL_EX(%a0) |check signblts cu_dmdncmpib #3,%d1 |check for rpbne cu_dpd |load double pos zerobra cu_dpdr |load double pos zero w/lsbcu_dmdn:cmpib #2,%d1 |check for rmbne cu_dnd |load double neg zerobra cu_dndr |load double neg zero w/lsb|| 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 rmodetstw LOCAL_EX(%a0) |check signblts cu_dmsncmpib #3,%d1 |check for rpbne cu_spd |load single pos zerobra cu_spdr |load single pos zero w/lsbcu_dmsn:cmpib #2,%d1 |check for rmbne cu_snd |load single neg zerobra 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_etemporl #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 zeroclrl 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 zeroclrl LOCAL_HI(%a0)movel #0x800,LOCAL_LO(%a0) |with lsb setorl #unfinx_mask,USER_FPSR(%a6)bra wr_etempcu_dnd:movel #0xbc010000,LOCAL_EX(%a0) |force pos double zeroclrl 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 zeroclrl LOCAL_HI(%a0)movel #0x800,LOCAL_LO(%a0) |with lsb setorl #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 zeroclrl 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 zeromovel #0x100,LOCAL_HI(%a0) |with lsb setclrl LOCAL_LO(%a0)orl #unfinx_mask,USER_FPSR(%a6)bra wr_etempcu_snd:movel #0xbf810000,LOCAL_EX(%a0) |force pos single zeroclrl 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 zeromovel #0x100,LOCAL_HI(%a0) |with lsb setclrl 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 fsqrtbeq fix_stk |if zero, it is fsqrtmovew CMDREG1B(%a6),%d0andiw #0x3b,%d0 |strip to command bitscmpiw #addcode,%d0beq wrap_addcmpiw #subcode,%d0beq wrap_subcmpiw #mulcode,%d0beq wrap_mulcmpiw #cmpcode,%d0beq 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 denormbnes div_srcddiv_destd:bsrl ckinf_nsbne fix_stkbfextu 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 srccmpl #0x7fff,%d0blt fix_stk |if less, not wrap caseclrb WBTEMP_SGN(%a6)movew ETEMP_EX(%a6),%d0 |find the sign of the resultmovew FPTEMP_EX(%a6),%d1eorw %d1,%d0andiw #0x8000,%d0beq force_unfst WBTEMP_SGN(%a6)bra force_unfckinf_ns:moveb STAG(%a6),%d0 |check source tag for inf or nanbra ck_in_comckinf_nd:moveb DTAG(%a6),%d0 |check destination tag for inf or nanck_in_com:andib #0x60,%d0 |isolate tag bitscmpb #0x40,%d0 |is it inf?beq nan_or_inf |not wrap casecmpb #0x60,%d0 |is it nan?beq nan_or_inf |yes, not wrap case?cmpb #0x20,%d0 |is it a zero?beq nan_or_inf |yesclrl %d0rts |then ; it is either a zero of norm,| ;check wrap casenan_or_inf:moveql #-1,%d0rtsdiv_srcd:bsrl ckinf_ndbne fix_stkbfextu 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 destcmpl #0x8000,%d0blt fix_stk |if less, not wrap caseclrb WBTEMP_SGN(%a6)movew ETEMP_EX(%a6),%d0 |find the sign of the resultmovew FPTEMP_EX(%a6),%d1eorw %d1,%d0andiw #0x8000,%d0beqs force_ovfst 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 locationmovew CMDREG1B(%a6),%d0btstl #6,%d0 |test for forced precisionbeqs frcovf_fpcrbtstl #2,%d0 |check for doublebnes frcovf_dblmovel #0x1,%d0 |inst is forced singlebras frcovf_rndfrcovf_dbl:movel #0x2,%d0 |inst is forced doublebras 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 formatbfclr WBTEMP_SGN(%a6){#0:#8}beq frcfpnbsetb #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 denormbnes add_srcdadd_destd:bsrl ckinf_nsbne fix_stkbfextu 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 srccmpl #0x8000,%d0blt fix_stk |if less, not wrap casebra add_wrapadd_srcd:bsrl ckinf_ndbne fix_stkbfextu 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 destcmpl #0x8000,%d0blt 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),%d0movew FPTEMP_EX(%a6),%d1eorw %d1,%d0andiw #0x8000,%d0beq add_same|| The signs are unlike.|cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm?bnes add_u_srcdmovew FPTEMP_EX(%a6),%d0andiw #0x8000,%d0orw #0x3fff,%d0 |force the exponent to +/- 1movew %d0,FPTEMP_EX(%a6) |in the denormmovel USER_FPCR(%a6),%d0andil #0x30,%d0fmovel %d0,%fpcr |set up users rmode and Xfmovex ETEMP(%a6),%fp0faddx FPTEMP(%a6),%fp0leal WBTEMP(%a6),%a0 |point a0 to wbtemp in framefmovel %fpsr,%d1orl %d1,USER_FPSR(%a6) |capture cc's and inex from faddfmovex %fp0,WBTEMP(%a6) |write result to memorylsrl #4,%d0 |put rmode in lower 2 bitsmovel USER_FPCR(%a6),%d1andil #0xc0,%d1lsrl #6,%d1 |put precision in upper wordswap %d1orl %d0,%d1 |set up for round callclrl %d0 |force sticky to zerobclrb #sign_bit,WBTEMP_EX(%a6)sne WBTEMP_SGN(%a6)bsrl round |round result to users rmode & precbfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext formatbeq frcfpnrbsetb #sign_bit,WBTEMP_EX(%a6)bra frcfpnradd_u_srcd:movew ETEMP_EX(%a6),%d0andiw #0x8000,%d0orw #0x3fff,%d0 |force the exponent to +/- 1movew %d0,ETEMP_EX(%a6) |in the denormmovel USER_FPCR(%a6),%d0andil #0x30,%d0fmovel %d0,%fpcr |set up users rmode and Xfmovex ETEMP(%a6),%fp0faddx FPTEMP(%a6),%fp0fmovel %fpsr,%d1orl %d1,USER_FPSR(%a6) |capture cc's and inex from faddleal WBTEMP(%a6),%a0 |point a0 to wbtemp in framefmovex %fp0,WBTEMP(%a6) |write result to memorylsrl #4,%d0 |put rmode in lower 2 bitsmovel USER_FPCR(%a6),%d1andil #0xc0,%d1lsrl #6,%d1 |put precision in upper wordswap %d1orl %d0,%d1 |set up for round callclrl %d0 |force sticky to zerobclrb #sign_bit,WBTEMP_EX(%a6)sne WBTEMP_SGN(%a6) |use internal format for roundbsrl round |round result to users rmode & precbfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext formatbeq frcfpnrbsetb #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),%a0movel USER_FPCR(%a6),%d0andil #0x30,%d0lsrl #4,%d0 |put rmode in lower 2 bitsmovel USER_FPCR(%a6),%d1andil #0xc0,%d1lsrl #6,%d1 |put precision in upper wordswap %d1orl %d0,%d1 |set up for round callmovel #0x20000000,%d0 |set sticky for roundbclrb #sign_bit,ETEMP_EX(%a6)sne ETEMP_SGN(%a6)bsrl round |round result to users rmode & precbfclr ETEMP_SGN(%a6){#0:#8} |convert back to IEEE ext formatbeqs add_s_dclrbsetb #sign_bit,ETEMP_EX(%a6)add_s_dclr:leal WBTEMP(%a6),%a0movel ETEMP(%a6),(%a0) |write result to wbtempmovel ETEMP_HI(%a6),4(%a0)movel ETEMP_LO(%a6),8(%a0)tstw ETEMP_EX(%a6)bgt add_ckovforl #neg_mask,USER_FPSR(%a6)bra add_ckovfadd_s_srcd:leal FPTEMP(%a6),%a0movel USER_FPCR(%a6),%d0andil #0x30,%d0lsrl #4,%d0 |put rmode in lower 2 bitsmovel USER_FPCR(%a6),%d1andil #0xc0,%d1lsrl #6,%d1 |put precision in upper wordswap %d1orl %d0,%d1 |set up for round callmovel #0x20000000,%d0 |set sticky for roundbclrb #sign_bit,FPTEMP_EX(%a6)sne FPTEMP_SGN(%a6)bsrl round |round result to users rmode & precbfclr FPTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext formatbeqs add_s_sclrbsetb #sign_bit,FPTEMP_EX(%a6)add_s_sclr:leal WBTEMP(%a6),%a0movel FPTEMP(%a6),(%a0) |write result to wbtempmovel FPTEMP_HI(%a6),4(%a0)movel FPTEMP_LO(%a6),8(%a0)tstw FPTEMP_EX(%a6)bgt add_ckovforl #neg_mask,USER_FPSR(%a6)add_ckovf:movew WBTEMP_EX(%a6),%d0andiw #0x7fff,%d0cmpiw #0x7fff,%d0bne 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 denormbnes sub_srcdsub_destd:bsrl ckinf_nsbne fix_stkbfextu 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 destcmpl #0x8000,%d0blt fix_stk |if less, not wrap casebra sub_wrapsub_srcd:bsrl ckinf_ndbne fix_stkbfextu 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 srccmpl #0x8000,%d0blt 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),%d0movew FPTEMP_EX(%a6),%d1eorw %d1,%d0andiw #0x8000,%d0bne sub_diff|| The signs are alike.|cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm?bnes sub_u_srcdmovew FPTEMP_EX(%a6),%d0andiw #0x8000,%d0orw #0x3fff,%d0 |force the exponent to +/- 1movew %d0,FPTEMP_EX(%a6) |in the denormmovel USER_FPCR(%a6),%d0andil #0x30,%d0fmovel %d0,%fpcr |set up users rmode and Xfmovex FPTEMP(%a6),%fp0fsubx ETEMP(%a6),%fp0fmovel %fpsr,%d1orl %d1,USER_FPSR(%a6) |capture cc's and inex from faddleal WBTEMP(%a6),%a0 |point a0 to wbtemp in framefmovex %fp0,WBTEMP(%a6) |write result to memorylsrl #4,%d0 |put rmode in lower 2 bitsmovel USER_FPCR(%a6),%d1andil #0xc0,%d1lsrl #6,%d1 |put precision in upper wordswap %d1orl %d0,%d1 |set up for round callclrl %d0 |force sticky to zerobclrb #sign_bit,WBTEMP_EX(%a6)sne WBTEMP_SGN(%a6)bsrl round |round result to users rmode & precbfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext formatbeq frcfpnrbsetb #sign_bit,WBTEMP_EX(%a6)bra frcfpnrsub_u_srcd:movew ETEMP_EX(%a6),%d0andiw #0x8000,%d0orw #0x3fff,%d0 |force the exponent to +/- 1movew %d0,ETEMP_EX(%a6) |in the denormmovel USER_FPCR(%a6),%d0andil #0x30,%d0fmovel %d0,%fpcr |set up users rmode and Xfmovex FPTEMP(%a6),%fp0fsubx ETEMP(%a6),%fp0fmovel %fpsr,%d1orl %d1,USER_FPSR(%a6) |capture cc's and inex from faddleal WBTEMP(%a6),%a0 |point a0 to wbtemp in framefmovex %fp0,WBTEMP(%a6) |write result to memorylsrl #4,%d0 |put rmode in lower 2 bitsmovel USER_FPCR(%a6),%d1andil #0xc0,%d1lsrl #6,%d1 |put precision in upper wordswap %d1orl %d0,%d1 |set up for round callclrl %d0 |force sticky to zerobclrb #sign_bit,WBTEMP_EX(%a6)sne WBTEMP_SGN(%a6)bsrl round |round result to users rmode & precbfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext formatbeq frcfpnrbsetb #sign_bit,WBTEMP_EX(%a6)bra frcfpnr|| Signs are unlike:|sub_diff:cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm?bnes sub_s_srcdsub_s_destd:leal ETEMP(%a6),%a0movel USER_FPCR(%a6),%d0andil #0x30,%d0lsrl #4,%d0 |put rmode in lower 2 bitsmovel USER_FPCR(%a6),%d1andil #0xc0,%d1lsrl #6,%d1 |put precision in upper wordswap %d1orl %d0,%d1 |set up for round callmovel #0x20000000,%d0 |set sticky for round|| Since the dest is the denorm, the sign is the opposite of the| norm sign.|eoriw #0x8000,ETEMP_EX(%a6) |flip sign on resulttstw ETEMP_EX(%a6)bgts sub_s_dwrorl #neg_mask,USER_FPSR(%a6)sub_s_dwr:bclrb #sign_bit,ETEMP_EX(%a6)sne ETEMP_SGN(%a6)bsrl round |round result to users rmode & precbfclr ETEMP_SGN(%a6){#0:#8} |convert back to IEEE ext formatbeqs sub_s_dclrbsetb #sign_bit,ETEMP_EX(%a6)sub_s_dclr:leal WBTEMP(%a6),%a0movel ETEMP(%a6),(%a0) |write result to wbtempmovel ETEMP_HI(%a6),4(%a0)movel ETEMP_LO(%a6),8(%a0)bra sub_ckovfsub_s_srcd:leal FPTEMP(%a6),%a0movel USER_FPCR(%a6),%d0andil #0x30,%d0lsrl #4,%d0 |put rmode in lower 2 bitsmovel USER_FPCR(%a6),%d1andil #0xc0,%d1lsrl #6,%d1 |put precision in upper wordswap %d1orl %d0,%d1 |set up for round callmovel #0x20000000,%d0 |set sticky for roundbclrb #sign_bit,FPTEMP_EX(%a6)sne FPTEMP_SGN(%a6)bsrl round |round result to users rmode & precbfclr FPTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext formatbeqs sub_s_sclrbsetb #sign_bit,FPTEMP_EX(%a6)sub_s_sclr:leal WBTEMP(%a6),%a0movel FPTEMP(%a6),(%a0) |write result to wbtempmovel FPTEMP_HI(%a6),4(%a0)movel FPTEMP_LO(%a6),8(%a0)tstw FPTEMP_EX(%a6)bgt sub_ckovforl #neg_mask,USER_FPSR(%a6)sub_ckovf:movew WBTEMP_EX(%a6),%d0andiw #0x7fff,%d0cmpiw #0x7fff,%d0bne 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 fcmp.|wrap_cmp: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 denormbnes cmp_srcdcmp_destd:bsrl ckinf_nsbne fix_stkbfextu 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 srccmpl #0x8000,%d0blt fix_stk |if less, not wrap casetstw ETEMP_EX(%a6) |set N to ~sign_of(src)bge cmp_setnrtscmp_srcd:bsrl ckinf_ndbne fix_stkbfextu 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 destcmpl #0x8000,%d0blt fix_stk |if less, not wrap casetstw FPTEMP_EX(%a6) |set N to sign_of(dest)blt cmp_setnrtscmp_setn:orl #neg_mask,USER_FPSR(%a6)rts|| Inst is fmul.|wrap_mul:cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm,beq force_unf |force an underflow (really!)|| One of the ops is denormalized. Test for wrap condition| and complete the instruction.|cmpb #0x0f,DNRM_FLG(%a6) |check for dest denormbnes mul_srcdmul_destd:bsrl ckinf_nsbne fix_stkbfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos)bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg)addl %d1,%d0 |subtract dest from srcbgt fix_stkbra force_unfmul_srcd:bsrl ckinf_ndbne fix_stkbfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos)bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg)addl %d1,%d0 |subtract src from destbgt fix_stk|| This code handles the case of the instruction resulting in| an underflow condition.|force_unf:bclrb #E1,E_BYTE(%a6)orl #unfinx_mask,USER_FPSR(%a6)clrw NMNEXC(%a6)clrb WBTEMP_SGN(%a6)movew ETEMP_EX(%a6),%d0 |find the sign of the resultmovew FPTEMP_EX(%a6),%d1eorw %d1,%d0andiw #0x8000,%d0beqs frcunfcontst WBTEMP_SGN(%a6)frcunfcont:lea WBTEMP(%a6),%a0 |point a0 to memory locationmovew CMDREG1B(%a6),%d0btstl #6,%d0 |test for forced precisionbeqs frcunf_fpcrbtstl #2,%d0 |check for doublebnes frcunf_dblmovel #0x1,%d0 |inst is forced singlebras frcunf_rndfrcunf_dbl:movel #0x2,%d0 |inst is forced doublebras frcunf_rndfrcunf_fpcr:bfextu FPCR_MODE(%a6){#0:#2},%d0 |inst not forced - use fpcr precfrcunf_rnd:bsrl unf_sub |get correct result based on| ;round precision/mode. This| ;sets FPSR_CC correctlybfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext formatbeqs frcfpnbsetb #sign_bit,WBTEMP_EX(%a6)bra frcfpn|| Write the result to the user's fpn. All results must be HUGE to be| written; otherwise the results would have overflowed or underflowed.| If the rounding precision is single or double, the ovf_res routine| is needed to correctly supply the max value.|frcfpnr:movew CMDREG1B(%a6),%d0btstl #6,%d0 |test for forced precisionbeqs frcfpn_fpcrbtstl #2,%d0 |check for doublebnes frcfpn_dblmovel #0x1,%d0 |inst is forced singlebras frcfpn_rndfrcfpn_dbl:movel #0x2,%d0 |inst is forced doublebras frcfpn_rndfrcfpn_fpcr:bfextu FPCR_MODE(%a6){#0:#2},%d0 |inst not forced - use fpcr prectstb %d0beqs frcfpn |if extended, write what you gotfrcfpn_rnd:bclrb #sign_bit,WBTEMP_EX(%a6)sne WBTEMP_SGN(%a6)bsrl ovf_res |get correct result based on| ;round precision/mode. This| ;sets FPSR_CC correctlybfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext formatbeqs frcfpn_clrbsetb #sign_bit,WBTEMP_EX(%a6)frcfpn_clr:orl #ovfinx_mask,USER_FPSR(%a6)|| Perform the write.|frcfpn:bfextu CMDREG1B(%a6){#6:#3},%d0 |extract fp destination registercmpib #3,%d0bles frc0123 |check if dest is fp0-fp3movel #7,%d1subl %d0,%d1clrl %d0bsetl %d1,%d0fmovemx WBTEMP(%a6),%d0rtsfrc0123:cmpib #0,%d0beqs frc0_dstcmpib #1,%d0beqs frc1_dstcmpib #2,%d0beqs frc2_dstfrc3_dst:movel WBTEMP_EX(%a6),USER_FP3(%a6)movel WBTEMP_HI(%a6),USER_FP3+4(%a6)movel WBTEMP_LO(%a6),USER_FP3+8(%a6)rtsfrc2_dst:movel WBTEMP_EX(%a6),USER_FP2(%a6)movel WBTEMP_HI(%a6),USER_FP2+4(%a6)movel WBTEMP_LO(%a6),USER_FP2+8(%a6)rtsfrc1_dst:movel WBTEMP_EX(%a6),USER_FP1(%a6)movel WBTEMP_HI(%a6),USER_FP1+4(%a6)movel WBTEMP_LO(%a6),USER_FP1+8(%a6)rtsfrc0_dst:movel WBTEMP_EX(%a6),USER_FP0(%a6)movel WBTEMP_HI(%a6),USER_FP0+4(%a6)movel WBTEMP_LO(%a6),USER_FP0+8(%a6)rts|| Write etemp to fpn.| A check is made on enabled and signalled snan exceptions,| and the destination is not overwritten if this condition exists.| This code is designed to make fmoveins of unsupported data types| faster.|wr_etemp:btstb #snan_bit,FPSR_EXCEPT(%a6) |if snan is set, andbeqs fmoveinc |enabled, force restorebtstb #snan_bit,FPCR_ENABLE(%a6) |and don't overwritebeqs fmoveinc |the destmovel ETEMP_EX(%a6),FPTEMP_EX(%a6) |set up fptemp sign for| ;snan handlertstb ETEMP(%a6) |check for negativeblts snan_negrtssnan_neg:orl #neg_bit,USER_FPSR(%a6) |snan is negative; set Nrtsfmoveinc:clrw NMNEXC(%a6)bclrb #E1,E_BYTE(%a6)moveb STAG(%a6),%d0 |check if stag is infandib #0xe0,%d0cmpib #0x40,%d0bnes fminc_cnanorl #inf_mask,USER_FPSR(%a6) |if inf, nothing yet has set Itstw LOCAL_EX(%a0) |check signbges fminc_conorl #neg_mask,USER_FPSR(%a6)bra fminc_confminc_cnan:cmpib #0x60,%d0 |check if stag is NaNbnes fminc_czeroorl #nan_mask,USER_FPSR(%a6) |if nan, nothing yet has set NaNmovel ETEMP_EX(%a6),FPTEMP_EX(%a6) |set up fptemp sign for| ;snan handlertstw LOCAL_EX(%a0) |check signbges fminc_conorl #neg_mask,USER_FPSR(%a6)bra fminc_confminc_czero:cmpib #0x20,%d0 |check if zerobnes fminc_conorl #z_mask,USER_FPSR(%a6) |if zero, set Ztstw LOCAL_EX(%a0) |check signbges fminc_conorl #neg_mask,USER_FPSR(%a6)fminc_con:bfextu CMDREG1B(%a6){#6:#3},%d0 |extract fp destination registercmpib #3,%d0bles fp0123 |check if dest is fp0-fp3movel #7,%d1subl %d0,%d1clrl %d0bsetl %d1,%d0fmovemx ETEMP(%a6),%d0rtsfp0123:cmpib #0,%d0beqs fp0_dstcmpib #1,%d0beqs fp1_dstcmpib #2,%d0beqs fp2_dstfp3_dst:movel ETEMP_EX(%a6),USER_FP3(%a6)movel ETEMP_HI(%a6),USER_FP3+4(%a6)movel ETEMP_LO(%a6),USER_FP3+8(%a6)rtsfp2_dst:movel ETEMP_EX(%a6),USER_FP2(%a6)movel ETEMP_HI(%a6),USER_FP2+4(%a6)movel ETEMP_LO(%a6),USER_FP2+8(%a6)rtsfp1_dst:movel ETEMP_EX(%a6),USER_FP1(%a6)movel ETEMP_HI(%a6),USER_FP1+4(%a6)movel ETEMP_LO(%a6),USER_FP1+8(%a6)rtsfp0_dst:movel ETEMP_EX(%a6),USER_FP0(%a6)movel ETEMP_HI(%a6),USER_FP0+4(%a6)movel ETEMP_LO(%a6),USER_FP0+8(%a6)rtsopclass3:st CU_ONLY(%a6)movew CMDREG1B(%a6),%d0 |check if packed moveoutandiw #0x0c00,%d0 |isolate last 2 bits of size fieldcmpiw #0x0c00,%d0 |if size is 011 or 111, it is packedbeq pack_out |else it is norm or denormbra mv_out|| MOVE OUT|mv_tbl:.long li.long sgp.long xp.long mvout_end |should never be taken.long wi.long dp.long bi.long mvout_end |should never be takenmv_out:bfextu CMDREG1B(%a6){#3:#3},%d1 |put source specifier in d1leal mv_tbl,%a0movel %a0@(%d1:l:4),%a0jmp (%a0)|| This exit is for move-out to memory. The aunfl bit is| set if the result is inex and unfl is signalled.|mvout_end:btstb #inex2_bit,FPSR_EXCEPT(%a6)beqs no_auflbtstb #unfl_bit,FPSR_EXCEPT(%a6)beqs no_auflbsetb #aunfl_bit,FPSR_AEXCEPT(%a6)no_aufl:clrw NMNEXC(%a6)bclrb #E1,E_BYTE(%a6)fmovel #0,%FPSR |clear any cc bits from res_func|| Return ETEMP to extended format from internal extended format so| that gen_except will have a correctly signed value for ovfl/unfl| handlers.|bfclr ETEMP_SGN(%a6){#0:#8}beqs mvout_conbsetb #sign_bit,ETEMP_EX(%a6)mvout_con:rts|| This exit is for move-out to int register. The aunfl bit is| not set in any case for this move.|mvouti_end:clrw NMNEXC(%a6)bclrb #E1,E_BYTE(%a6)fmovel #0,%FPSR |clear any cc bits from res_func|| Return ETEMP to extended format from internal extended format so| that gen_except will have a correctly signed value for ovfl/unfl| handlers.|bfclr ETEMP_SGN(%a6){#0:#8}beqs mvouti_conbsetb #sign_bit,ETEMP_EX(%a6)mvouti_con:rts|| li is used to handle a long integer source specifier|li:moveql #4,%d0 |set byte countbtstb #7,STAG(%a6) |check for extended denormbne int_dnrm |if so, branchfmovemx ETEMP(%a6),%fp0-%fp0fcmpd #0x41dfffffffc00000,%fp0| 41dfffffffc00000 in dbl prec = 401d0000fffffffe00000000 in ext precfbge lo_plrgfcmpd #0xc1e0000000000000,%fp0| c1e0000000000000 in dbl prec = c01e00008000000000000000 in ext precfble lo_nlrg|| at this point, the answer is between the largest pos and neg values|movel USER_FPCR(%a6),%d1 |use user's rounding modeandil #0x30,%d1fmovel %d1,%fpcrfmovel %fp0,L_SCR1(%a6) |let the 040 perform conversionfmovel %fpsr,%d1orl %d1,USER_FPSR(%a6) |capture inex2/ainex if setbra int_wrtlo_plrg:movel #0x7fffffff,L_SCR1(%a6) |answer is largest positive intfbeq int_wrt |exact answerfcmpd #0x41dfffffffe00000,%fp0| 41dfffffffe00000 in dbl prec = 401d0000ffffffff00000000 in ext precfbge int_operr |set operrbra int_inx |set inexactlo_nlrg:movel #0x80000000,L_SCR1(%a6)fbeq int_wrt |exact answerfcmpd #0xc1e0000000100000,%fp0| c1e0000000100000 in dbl prec = c01e00008000000080000000 in ext precfblt int_operr |set operrbra int_inx |set inexact|| wi is used to handle a word integer source specifier|wi:moveql #2,%d0 |set byte countbtstb #7,STAG(%a6) |check for extended denormbne int_dnrm |branch if sofmovemx ETEMP(%a6),%fp0-%fp0fcmps #0x46fffe00,%fp0| 46fffe00 in sgl prec = 400d0000fffe000000000000 in ext precfbge wo_plrgfcmps #0xc7000000,%fp0| c7000000 in sgl prec = c00e00008000000000000000 in ext precfble wo_nlrg|| at this point, the answer is between the largest pos and neg values|movel USER_FPCR(%a6),%d1 |use user's rounding modeandil #0x30,%d1fmovel %d1,%fpcrfmovew %fp0,L_SCR1(%a6) |let the 040 perform conversionfmovel %fpsr,%d1orl %d1,USER_FPSR(%a6) |capture inex2/ainex if setbra int_wrtwo_plrg:movew #0x7fff,L_SCR1(%a6) |answer is largest positive intfbeq int_wrt |exact answerfcmps #0x46ffff00,%fp0| 46ffff00 in sgl prec = 400d0000ffff000000000000 in ext precfbge int_operr |set operrbra int_inx |set inexactwo_nlrg:movew #0x8000,L_SCR1(%a6)fbeq int_wrt |exact answerfcmps #0xc7000080,%fp0| c7000080 in sgl prec = c00e00008000800000000000 in ext precfblt int_operr |set operrbra int_inx |set inexact|| bi is used to handle a byte integer source specifier|bi:moveql #1,%d0 |set byte countbtstb #7,STAG(%a6) |check for extended denormbne int_dnrm |branch if sofmovemx ETEMP(%a6),%fp0-%fp0fcmps #0x42fe0000,%fp0| 42fe0000 in sgl prec = 40050000fe00000000000000 in ext precfbge by_plrgfcmps #0xc3000000,%fp0| c3000000 in sgl prec = c00600008000000000000000 in ext precfble by_nlrg|| at this point, the answer is between the largest pos and neg values|movel USER_FPCR(%a6),%d1 |use user's rounding modeandil #0x30,%d1fmovel %d1,%fpcrfmoveb %fp0,L_SCR1(%a6) |let the 040 perform conversionfmovel %fpsr,%d1orl %d1,USER_FPSR(%a6) |capture inex2/ainex if setbra int_wrtby_plrg:moveb #0x7f,L_SCR1(%a6) |answer is largest positive intfbeq int_wrt |exact answerfcmps #0x42ff0000,%fp0| 42ff0000 in sgl prec = 40050000ff00000000000000 in ext precfbge int_operr |set operrbra int_inx |set inexactby_nlrg:moveb #0x80,L_SCR1(%a6)fbeq int_wrt |exact answerfcmps #0xc3008000,%fp0| c3008000 in sgl prec = c00600008080000000000000 in ext precfblt int_operr |set operrbra int_inx |set inexact|| Common integer routines|| int_drnrm---account for possible nonzero result for round up with positive| operand and round down for negative answer. In the first case (result = 1)| byte-width (store in d0) of result must be honored. In the second case,| -1 in L_SCR1(a6) will cover all contingencies (FMOVE.B/W/L out).int_dnrm:movel #0,L_SCR1(%a6) | initialize result to 0bfextu FPCR_MODE(%a6){#2:#2},%d1 | d1 is the rounding modecmpb #2,%d1bmis int_inx | if RN or RZ, donebnes int_rp | if RP, continue belowtstw ETEMP(%a6) | RM: store -1 in L_SCR1 if src is negativebpls int_inx | otherwise result is 0movel #-1,L_SCR1(%a6)bras int_inxint_rp:tstw ETEMP(%a6) | RP: store +1 of proper width in L_SCR1 if| ; source is greater than 0bmis int_inx | otherwise, result is 0lea L_SCR1(%a6),%a1 | a1 is address of L_SCR1addal %d0,%a1 | offset by destination width -1subal #1,%a1bsetb #0,(%a1) | set low bit at a1 addressint_inx:oril #inx2a_mask,USER_FPSR(%a6)bras int_wrtint_operr:fmovemx %fp0-%fp0,FPTEMP(%a6) |FPTEMP must contain the extended| ;precision source that needs to be| ;converted to integer this is required| ;if the operr exception is enabled.| ;set operr/aiop (no inex2 on int ovfl)oril #opaop_mask,USER_FPSR(%a6)| ;fall through to perform int_wrtint_wrt:movel EXC_EA(%a6),%a1 |load destination addresststl %a1 |check to see if it is a dest registerbeqs wrt_dn |write data registerlea L_SCR1(%a6),%a0 |point to supervisor source addressbsrl mem_writebra mvouti_endwrt_dn:movel %d0,-(%sp) |d0 currently contains the size to writebsrl get_fline |get_fline returns Dn in d0andiw #0x7,%d0 |isolate registermovel (%sp)+,%d1 |get sizecmpil #4,%d1 |most frequent casebeqs sz_longcmpil #2,%d1bnes sz_conorl #8,%d0 |add 'word' size to register#bras sz_consz_long:orl #0x10,%d0 |add 'long' size to register#sz_con:movel %d0,%d1 |reg_dest expects size:reg in d1bsrl reg_dest |load proper data registerbra mvouti_endxp:lea ETEMP(%a6),%a0bclrb #sign_bit,LOCAL_EX(%a0)sne LOCAL_SGN(%a0)btstb #7,STAG(%a6) |check for extended denormbne xdnrmclrl %d0bras do_fp |do normal casesgp:lea ETEMP(%a6),%a0bclrb #sign_bit,LOCAL_EX(%a0)sne LOCAL_SGN(%a0)btstb #7,STAG(%a6) |check for extended denormbne sp_catas |branch if somovew LOCAL_EX(%a0),%d0lea sp_bnds,%a1cmpw (%a1),%d0blt sp_undercmpw 2(%a1),%d0bgt sp_overmovel #1,%d0 |set destination format to singlebras do_fp |do normal casedp:lea ETEMP(%a6),%a0bclrb #sign_bit,LOCAL_EX(%a0)sne LOCAL_SGN(%a0)btstb #7,STAG(%a6) |check for extended denormbne dp_catas |branch if somovew LOCAL_EX(%a0),%d0lea dp_bnds,%a1cmpw (%a1),%d0blt dp_undercmpw 2(%a1),%d0bgt dp_overmovel #2,%d0 |set destination format to double| ;fall through to do_fp|do_fp:bfextu FPCR_MODE(%a6){#2:#2},%d1 |rnd mode in d1swap %d0 |rnd prec in upper wordaddl %d0,%d1 |d1 has PREC/MODE infoclrl %d0 |clear g,r,sbsrl round |roundmovel %a0,%a1movel EXC_EA(%a6),%a0bfextu CMDREG1B(%a6){#3:#3},%d1 |extract destination format| ;at this point only the dest| ;formats sgl, dbl, ext are| ;possiblecmpb #2,%d1bgts ddbl |double=5, extended=2, single=1bnes dsgl| ;fall through to dextdext:bsrl dest_extbra mvout_enddsgl:bsrl dest_sglbra mvout_endddbl:bsrl dest_dblbra mvout_end|| Handle possible denorm or catastrophic underflow cases here|xdnrm:bsr set_xop |initialize WBTEMPbsetb #wbtemp15_bit,WB_BYTE(%a6) |set wbtemp15movel %a0,%a1movel EXC_EA(%a6),%a0 |a0 has the destination pointerbsrl dest_ext |store to memorybsetb #unfl_bit,FPSR_EXCEPT(%a6)bra mvout_endsp_under:bsetb #etemp15_bit,STAG(%a6)cmpw 4(%a1),%d0blts sp_catas |catastrophic underflow casemovel #1,%d0 |load in round precisionmovel #sgl_thresh,%d1 |load in single denorm thresholdbsrl dpspdnrm |expects d1 to have the proper| ;denorm thresholdbsrl dest_sgl |stores value to destinationbsetb #unfl_bit,FPSR_EXCEPT(%a6)bra mvout_end |exitdp_under:bsetb #etemp15_bit,STAG(%a6)cmpw 4(%a1),%d0blts dp_catas |catastrophic underflow casemovel #dbl_thresh,%d1 |load in double precision thresholdmovel #2,%d0bsrl dpspdnrm |expects d1 to have proper| ;denorm threshold| ;expects d0 to have round precisionbsrl dest_dbl |store value to destinationbsetb #unfl_bit,FPSR_EXCEPT(%a6)bra mvout_end |exit|| Handle catastrophic underflow cases here|sp_catas:| Temp fix for z bit set in unf_submovel USER_FPSR(%a6),-(%a7)movel #1,%d0 |set round precision to sglbsrl unf_sub |a0 points to resultmovel (%a7)+,USER_FPSR(%a6)movel #1,%d0subw %d0,LOCAL_EX(%a0) |account for difference between| ;denorm/norm biasmovel %a0,%a1 |a1 has the operand inputmovel EXC_EA(%a6),%a0 |a0 has the destination pointerbsrl dest_sgl |store the resultoril #unfinx_mask,USER_FPSR(%a6)bra mvout_enddp_catas:| Temp fix for z bit set in unf_submovel USER_FPSR(%a6),-(%a7)movel #2,%d0 |set round precision to dblbsrl unf_sub |a0 points to resultmovel (%a7)+,USER_FPSR(%a6)movel #1,%d0subw %d0,LOCAL_EX(%a0) |account for difference between| ;denorm/norm biasmovel %a0,%a1 |a1 has the operand inputmovel EXC_EA(%a6),%a0 |a0 has the destination pointerbsrl dest_dbl |store the resultoril #unfinx_mask,USER_FPSR(%a6)bra mvout_end|| Handle catastrophic overflow cases here|sp_over:| Temp fix for z bit set in unf_submovel USER_FPSR(%a6),-(%a7)movel #1,%d0leal FP_SCR1(%a6),%a0 |use FP_SCR1 for creating resultmovel ETEMP_EX(%a6),(%a0)movel ETEMP_HI(%a6),4(%a0)movel ETEMP_LO(%a6),8(%a0)bsrl ovf_resmovel (%a7)+,USER_FPSR(%a6)movel %a0,%a1movel EXC_EA(%a6),%a0bsrl dest_sglorl #ovfinx_mask,USER_FPSR(%a6)bra mvout_enddp_over:| Temp fix for z bit set in ovf_resmovel USER_FPSR(%a6),-(%a7)movel #2,%d0leal FP_SCR1(%a6),%a0 |use FP_SCR1 for creating resultmovel ETEMP_EX(%a6),(%a0)movel ETEMP_HI(%a6),4(%a0)movel ETEMP_LO(%a6),8(%a0)bsrl ovf_resmovel (%a7)+,USER_FPSR(%a6)movel %a0,%a1movel EXC_EA(%a6),%a0bsrl dest_dblorl #ovfinx_mask,USER_FPSR(%a6)bra mvout_end|| DPSPDNRM|| This subroutine takes an extended normalized number and denormalizes| it to the given round precision. This subroutine also decrements| the input operand's exponent by 1 to account for the fact that| dest_sgl or dest_dbl expects a normalized number's bias.|| Input: a0 points to a normalized number in internal extended format| d0 is the round precision (=1 for sgl; =2 for dbl)| d1 is the single precision or double precision| denorm threshold|| Output: (In the format for dest_sgl or dest_dbl)| a0 points to the destination| a1 points to the operand|| Exceptions: Reports inexact 2 exception by setting USER_FPSR bits|dpspdnrm:movel %d0,-(%a7) |save round precisionclrl %d0 |clear initial g,r,sbsrl dnrm_lp |careful with d0, it's needed by roundbfextu FPCR_MODE(%a6){#2:#2},%d1 |get rounding modeswap %d1movew 2(%a7),%d1 |set rounding precisionswap %d1 |at this point d1 has PREC/MODE infobsrl round |round result, sets the inex bit in| ;USER_FPSR if neededmovew #1,%d0subw %d0,LOCAL_EX(%a0) |account for difference in denorm| ;vs norm biasmovel %a0,%a1 |a1 has the operand inputmovel EXC_EA(%a6),%a0 |a0 has the destination pointeraddw #4,%a7 |pop stackrts|| SET_XOP initialized WBTEMP with the value pointed to by a0| input: a0 points to input operand in the internal extended format|set_xop:movel LOCAL_EX(%a0),WBTEMP_EX(%a6)movel LOCAL_HI(%a0),WBTEMP_HI(%a6)movel LOCAL_LO(%a0),WBTEMP_LO(%a6)bfclr WBTEMP_SGN(%a6){#0:#8}beqs sxopbsetb #sign_bit,WBTEMP_EX(%a6)sxop:bfclr STAG(%a6){#5:#4} |clear wbtm66,wbtm1,wbtm0,sbitrts|| P_MOVE|p_movet:.long p_move.long p_movez.long p_movei.long p_moven.long p_movep_regd:.long p_dyd0.long p_dyd1.long p_dyd2.long p_dyd3.long p_dyd4.long p_dyd5.long p_dyd6.long p_dyd7pack_out:leal p_movet,%a0 |load jmp table addressmovew STAG(%a6),%d0 |get source tagbfextu %d0{#16:#3},%d0 |isolate source bitsmovel (%a0,%d0.w*4),%a0 |load a0 with routine label for tagjmp (%a0) |go to the routinep_write:movel #0x0c,%d0 |get byte countmovel EXC_EA(%a6),%a1 |get the destination addressbsr mem_write |write the user's destinationmoveb #0,CU_SAVEPC(%a6) |set the cu save pc to all 0's|| Also note that the dtag must be set to norm here - this is because| the 040 uses the dtag to execute the correct microcode.|bfclr DTAG(%a6){#0:#3} |set dtag to normrts| Notes on handling of special case (zero, inf, and nan) inputs:| 1. Operr is not signalled if the k-factor is greater than 18.| 2. Per the manual, status bits are not set.|p_move:movew CMDREG1B(%a6),%d0btstl #kfact_bit,%d0 |test for dynamic k-factorbeqs statick |if clear, k-factor is staticdynamick:bfextu %d0{#25:#3},%d0 |isolate register for dynamic k-factorlea p_regd,%a0movel %a0@(%d0:l:4),%a0jmp (%a0)statick:andiw #0x007f,%d0 |get k-factorbfexts %d0{#25:#7},%d0 |sign extend d0 for bindecleal ETEMP(%a6),%a0 |a0 will point to the packed decimalbsrl bindec |perform the convert; data at a6leal FP_SCR1(%a6),%a0 |load a0 with result addressbral p_writep_movez:leal ETEMP(%a6),%a0 |a0 will point to the packed decimalclrw 2(%a0) |clear lower word of expclrl 4(%a0) |load second lword of ZEROclrl 8(%a0) |load third lword of ZERObra p_write |go write resultsp_movei:fmovel #0,%FPSR |clear aiopleal ETEMP(%a6),%a0 |a0 will point to the packed decimalclrw 2(%a0) |clear lower word of expbra p_write |go write the resultp_moven:leal ETEMP(%a6),%a0 |a0 will point to the packed decimalclrw 2(%a0) |clear lower word of expbra p_write |go write the result|| Routines to read the dynamic k-factor from Dn.|p_dyd0:movel USER_D0(%a6),%d0bras statickp_dyd1:movel USER_D1(%a6),%d0bras statickp_dyd2:movel %d2,%d0bras statickp_dyd3:movel %d3,%d0bras statickp_dyd4:movel %d4,%d0bras statickp_dyd5:movel %d5,%d0bras statickp_dyd6:movel %d6,%d0bra statickp_dyd7:movel %d7,%d0bra statick|end
