diff options
Diffstat (limited to 'c/src/lib/libcpu/m68k/m68040/fpsp/scale.S')
-rw-r--r-- | c/src/lib/libcpu/m68k/m68040/fpsp/scale.S | 373 |
1 files changed, 373 insertions, 0 deletions
diff --git a/c/src/lib/libcpu/m68k/m68040/fpsp/scale.S b/c/src/lib/libcpu/m68k/m68040/fpsp/scale.S new file mode 100644 index 0000000000..4a5129d19c --- /dev/null +++ b/c/src/lib/libcpu/m68k/m68040/fpsp/scale.S @@ -0,0 +1,373 @@ +// +// $Id$ +// +// scale.sa 3.3 7/30/91 +// +// The entry point sSCALE computes the destination operand +// scaled by the source operand. If the absolute value of +// the source operand is (>= 2^14) an overflow or underflow +// is returned. +// +// The entry point sscale is called from do_func to emulate +// the fscale unimplemented instruction. +// +// Input: Double-extended destination operand in FPTEMP, +// double-extended source operand in ETEMP. +// +// Output: The function returns scale(X,Y) to fp0. +// +// Modifies: fp0. +// +// Algorithm: +// +// 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. + +//SCALE idnt 2,1 | Motorola 040 Floating Point Software Package + + |section 8 + +#include "fpsp.defs" + + |xref t_ovfl2 + |xref t_unfl + |xref round + |xref t_resdnrm + +SRC_BNDS: .short 0x3fff,0x400c + +// +// This entry point is used by the unimplemented instruction exception +// handler. +// +// +// +// FSCALE +// + .global sscale +sscale: + fmovel #0,%fpcr //clr user enabled exc + clrl %d1 + movew FPTEMP(%a6),%d1 //get dest exponent + smi L_SCR1(%a6) //use L_SCR1 to hold sign + andil #0x7fff,%d1 //strip sign + movew ETEMP(%a6),%d0 //check src bounds + andiw #0x7fff,%d0 //clr sign bit + cmp2w SRC_BNDS,%d0 + bccs src_in + cmpiw #0x400c,%d0 //test for too large + bge src_out +// +// The source input is below 1, so we check for denormalized numbers +// and set unfl. +// +src_small: + moveb DTAG(%a6),%d0 + andib #0xe0,%d0 + tstb %d0 + beqs no_denorm + st STORE_FLG(%a6) //dest already contains result + orl #unfl_mask,USER_FPSR(%a6) //set UNFL +den_done: + leal FPTEMP(%a6),%a0 + bra t_resdnrm +no_denorm: + fmovel USER_FPCR(%a6),%FPCR + fmovex FPTEMP(%a6),%fp0 //simply return dest + rts + + +// +// Source is within 2^14 range. To perform the int operation, +// move it to d0. +// +src_in: + fmovex ETEMP(%a6),%fp0 //move in src for int + fmovel #rz_mode,%fpcr //force rz for src conversion + fmovel %fp0,%d0 //int src to d0 + fmovel #0,%FPSR //clr status from above + tstw ETEMP(%a6) //check src sign + blt src_neg +// +// Source is positive. Add the src to the dest exponent. +// The result can be denormalized, if src = 0, or overflow, +// if the result of the add sets a bit in the upper word. +// +src_pos: + tstw %d1 //check for denorm + beq dst_dnrm + addl %d0,%d1 //add src to dest exp + beqs denorm //if zero, result is denorm + cmpil #0x7fff,%d1 //test for overflow + bges ovfl + tstb L_SCR1(%a6) + beqs spos_pos + orw #0x8000,%d1 +spos_pos: + movew %d1,FPTEMP(%a6) //result in FPTEMP + fmovel USER_FPCR(%a6),%FPCR + fmovex FPTEMP(%a6),%fp0 //write result to fp0 + rts +ovfl: + tstb L_SCR1(%a6) + beqs sovl_pos + orw #0x8000,%d1 +sovl_pos: + movew FPTEMP(%a6),ETEMP(%a6) //result in ETEMP + movel FPTEMP_HI(%a6),ETEMP_HI(%a6) + movel FPTEMP_LO(%a6),ETEMP_LO(%a6) + bra t_ovfl2 + +denorm: + tstb L_SCR1(%a6) + beqs den_pos + orw #0x8000,%d1 +den_pos: + tstl FPTEMP_HI(%a6) //check j bit + blts nden_exit //if set, not denorm + movew %d1,ETEMP(%a6) //input expected in ETEMP + movel FPTEMP_HI(%a6),ETEMP_HI(%a6) + movel FPTEMP_LO(%a6),ETEMP_LO(%a6) + orl #unfl_bit,USER_FPSR(%a6) //set unfl + leal ETEMP(%a6),%a0 + bra t_resdnrm +nden_exit: + movew %d1,FPTEMP(%a6) //result in FPTEMP + fmovel USER_FPCR(%a6),%FPCR + fmovex FPTEMP(%a6),%fp0 //write result to fp0 + rts + +// +// Source is negative. Add the src to the dest exponent. +// (The result exponent will be reduced). The result can be +// denormalized. +// +src_neg: + addl %d0,%d1 //add src to dest + beqs denorm //if zero, result is denorm + blts fix_dnrm //if negative, result is +// ;needing denormalization + tstb L_SCR1(%a6) + beqs sneg_pos + orw #0x8000,%d1 +sneg_pos: + movew %d1,FPTEMP(%a6) //result in FPTEMP + fmovel USER_FPCR(%a6),%FPCR + fmovex FPTEMP(%a6),%fp0 //write result to fp0 + rts + + +// +// The result exponent is below denorm value. Test for catastrophic +// underflow and force zero if true. If not, try to shift the +// mantissa right until a zero exponent exists. +// +fix_dnrm: + cmpiw #0xffc0,%d1 //lower bound for normalization + blt fix_unfl //if lower, catastrophic unfl + movew %d1,%d0 //use d0 for exp + movel %d2,-(%a7) //free d2 for norm + movel FPTEMP_HI(%a6),%d1 + movel FPTEMP_LO(%a6),%d2 + clrl L_SCR2(%a6) +fix_loop: + addw #1,%d0 //drive d0 to 0 + lsrl #1,%d1 //while shifting the + roxrl #1,%d2 //mantissa to the right + bccs no_carry + st L_SCR2(%a6) //use L_SCR2 to capture inex +no_carry: + tstw %d0 //it is finished when + blts fix_loop //d0 is zero or the mantissa + tstb L_SCR2(%a6) + beqs tst_zero + orl #unfl_inx_mask,USER_FPSR(%a6) +// ;set unfl, aunfl, ainex +// +// Test for zero. If zero, simply use fmove to return +/- zero +// to the fpu. +// +tst_zero: + clrw FPTEMP_EX(%a6) + tstb L_SCR1(%a6) //test for sign + beqs tst_con + orw #0x8000,FPTEMP_EX(%a6) //set sign bit +tst_con: + movel %d1,FPTEMP_HI(%a6) + movel %d2,FPTEMP_LO(%a6) + movel (%a7)+,%d2 + tstl %d1 + bnes not_zero + tstl FPTEMP_LO(%a6) + bnes not_zero +// +// Result is zero. Check for rounding mode to set lsb. If the +// mode is rp, and the zero is positive, return smallest denorm. +// If the mode is rm, and the zero is negative, return smallest +// negative denorm. +// + btstb #5,FPCR_MODE(%a6) //test if rm or rp + beqs no_dir + btstb #4,FPCR_MODE(%a6) //check which one + beqs zer_rm +zer_rp: + tstb L_SCR1(%a6) //check sign + bnes no_dir //if set, neg op, no inc + movel #1,FPTEMP_LO(%a6) //set lsb + bras sm_dnrm +zer_rm: + tstb L_SCR1(%a6) //check sign + beqs no_dir //if clr, neg op, no inc + movel #1,FPTEMP_LO(%a6) //set lsb + orl #neg_mask,USER_FPSR(%a6) //set N + bras sm_dnrm +no_dir: + fmovel USER_FPCR(%a6),%FPCR + fmovex FPTEMP(%a6),%fp0 //use fmove to set cc's + rts + +// +// The rounding mode changed the zero to a smallest denorm. Call +// t_resdnrm with exceptional operand in ETEMP. +// +sm_dnrm: + movel FPTEMP_EX(%a6),ETEMP_EX(%a6) + movel FPTEMP_HI(%a6),ETEMP_HI(%a6) + movel FPTEMP_LO(%a6),ETEMP_LO(%a6) + leal ETEMP(%a6),%a0 + bra t_resdnrm + +// +// Result is still denormalized. +// +not_zero: + orl #unfl_mask,USER_FPSR(%a6) //set unfl + tstb L_SCR1(%a6) //check for sign + beqs fix_exit + orl #neg_mask,USER_FPSR(%a6) //set N +fix_exit: + bras sm_dnrm + + +// +// The result has underflowed to zero. Return zero and set +// unfl, aunfl, and ainex. +// +fix_unfl: + orl #unfl_inx_mask,USER_FPSR(%a6) + btstb #5,FPCR_MODE(%a6) //test if rm or rp + beqs no_dir2 + btstb #4,FPCR_MODE(%a6) //check which one + beqs zer_rm2 +zer_rp2: + tstb L_SCR1(%a6) //check sign + bnes no_dir2 //if set, neg op, no inc + clrl FPTEMP_EX(%a6) + clrl FPTEMP_HI(%a6) + movel #1,FPTEMP_LO(%a6) //set lsb + bras sm_dnrm //return smallest denorm +zer_rm2: + tstb L_SCR1(%a6) //check sign + beqs no_dir2 //if clr, neg op, no inc + movew #0x8000,FPTEMP_EX(%a6) + clrl FPTEMP_HI(%a6) + movel #1,FPTEMP_LO(%a6) //set lsb + orl #neg_mask,USER_FPSR(%a6) //set N + bra sm_dnrm //return smallest denorm + +no_dir2: + tstb L_SCR1(%a6) + bges pos_zero +neg_zero: + clrl FP_SCR1(%a6) //clear the exceptional operand + clrl FP_SCR1+4(%a6) //for gen_except. + clrl FP_SCR1+8(%a6) + fmoves #0x80000000,%fp0 + rts +pos_zero: + clrl FP_SCR1(%a6) //clear the exceptional operand + clrl FP_SCR1+4(%a6) //for gen_except. + clrl FP_SCR1+8(%a6) + fmoves #0x00000000,%fp0 + rts + +// +// The destination is a denormalized number. It must be handled +// by first shifting the bits in the mantissa until it is normalized, +// then adding the remainder of the source to the exponent. +// +dst_dnrm: + moveml %d2/%d3,-(%a7) + movew FPTEMP_EX(%a6),%d1 + movel FPTEMP_HI(%a6),%d2 + movel FPTEMP_LO(%a6),%d3 +dst_loop: + tstl %d2 //test for normalized result + blts dst_norm //exit loop if so + tstl %d0 //otherwise, test shift count + beqs dst_fin //if zero, shifting is done + subil #1,%d0 //dec src + lsll #1,%d3 + roxll #1,%d2 + bras dst_loop +// +// Destination became normalized. Simply add the remaining +// portion of the src to the exponent. +// +dst_norm: + addw %d0,%d1 //dst is normalized; add src + tstb L_SCR1(%a6) + beqs dnrm_pos + orl #0x8000,%d1 +dnrm_pos: + movemw %d1,FPTEMP_EX(%a6) + moveml %d2,FPTEMP_HI(%a6) + moveml %d3,FPTEMP_LO(%a6) + fmovel USER_FPCR(%a6),%FPCR + fmovex FPTEMP(%a6),%fp0 + moveml (%a7)+,%d2/%d3 + rts + +// +// Destination remained denormalized. Call t_excdnrm with +// exceptional operand in ETEMP. +// +dst_fin: + tstb L_SCR1(%a6) //check for sign + beqs dst_exit + orl #neg_mask,USER_FPSR(%a6) //set N + orl #0x8000,%d1 +dst_exit: + movemw %d1,ETEMP_EX(%a6) + moveml %d2,ETEMP_HI(%a6) + moveml %d3,ETEMP_LO(%a6) + orl #unfl_mask,USER_FPSR(%a6) //set unfl + moveml (%a7)+,%d2/%d3 + leal ETEMP(%a6),%a0 + bra t_resdnrm + +// +// Source is outside of 2^14 range. Test the sign and branch +// to the appropriate exception handler. +// +src_out: + tstb L_SCR1(%a6) + beqs scro_pos + orl #0x8000,%d1 +scro_pos: + movel FPTEMP_HI(%a6),ETEMP_HI(%a6) + movel FPTEMP_LO(%a6),ETEMP_LO(%a6) + tstw ETEMP(%a6) + blts res_neg +res_pos: + movew %d1,ETEMP(%a6) //result in ETEMP + bra t_ovfl2 +res_neg: + movew %d1,ETEMP(%a6) //result in ETEMP + leal ETEMP(%a6),%a0 + bra t_unfl + |end |