URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
[/] [openrisc/] [trunk/] [rtos/] [rtems/] [c/] [src/] [lib/] [libcpu/] [m68k/] [m68040/] [fpsp/] [res_func.S] - Rev 173
Compare with Previous | Blame | View Log
//// $Id: res_func.S,v 1.2 2001-09-27 12:01:22 chris 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=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 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
