; ; File: Scale.a ; ; Contains: Emulation of the FSCALE unimplemented instruction ; ; Originally Written by: Motorola Inc. ; Adapted to Apple/MPW: Jon Okada ; ; Copyright: © 1990, 1991 by Apple Computer, Inc., all rights reserved. ; ; This file is used in these builds: Mac32 ; ; Change History (most recent first): ; ; <1+> 6/24/91 BG Modified "src_small" not to set STORE_FLG (in case ; rounding precision is narrower than extended) and not ; to set UNFL bit in USER_FPSR (since t_resdnrm will do it). ; <1> 3/30/91 BG First checked into TERROR/BBS. ; ; scale.a ; Based upon Motorola file 'scale.sa'. ; CHANGE LOG: ; 07 Jan 91 JPO Deleted unreferenced labels "src_small", "den_done", ; "src_pos", "zer_rp", "zer_rp2", "neg_zero", and ; "res_pos". Renamed labels "ovfl", "denorm", ; "not_zero", and "pos_zero" to "sc_ovfl", "sc_denorm", ; "sc_notzero", and "sc_poszero", respectively, to avoid ; duplicate symbols. ; 07 Feb 91 JPO Modified "fix_dnrm" routine to keep track of guard/round ; bits in order to correctly round the result. For ; inexact underflows, set unfl/aunfl/inex2/inex bits ; in USER_FPSR(a6). Modified order of tests in "dst_loop" ; in order to avoid spurious underflow signaling for ; normal FSCALE results with zero exponent resulting ; from nonnegative scale factors. ; 08 Feb 91 JPO Prior to calling "t_resdnrm", put subnormal results in ; FPTEMP(a6) and set a0 to point to FPTEMP(a6). This ; avoids clobbering of ETEMP with result value. ; * * scale.sa 3.1 12/10/90 * * 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 SRC_BNDS dc.w $3fff,$400c * * This entry point is used by the unimplemented instruction exception * handler. * * * * FSCALE * sscale: fmove.l #0,fpcr ;clr user enabled exc clr.l d1 move.w FPTEMP(a6),d1 ;get dest exponent smi L_SCR1(a6) ;use L_SCR1 to hold sign andi.l #$7fff,d1 ;strip sign move.w ETEMP(a6),d0 ;check src bounds andi.w #$7fff,d0 ;clr sign bit cmp2.w SRC_BNDS,d0 bcc.b src_in cmpi.w #$400c,d0 ;test for too large bge.w src_out * * The source input is below 1, so we check for denormalized numbers * and set unfl. * ;src_small: ; label not referenced <1/7/91, JPO> move.b DTAG(a6),d0 andi.b #$e0,d0 tst.b d0 beq.b no_denorm ; st STORE_FLG(a6) ;dest already contains result - DELETED <6/13/91, JPO> ; or.l #unfl_mask,USER_FPSR(a6) ;set UNFL - DELETED <6/13/91, JPO> ;den_done: ; label not referenced <1/7/91, JPO> lea.l FPTEMP(a6),a0 bra t_resdnrm no_denorm: fmove.l USER_FPCR(a6),FPCR fmove.x FPTEMP(a6),fp0 ;simply return dest rts * * Source is within 2^14 range. To perform the int operation, * move it to d0. * src_in: fmove.x ETEMP(a6),fp0 ;move in src for int fmove.l #rz_mode,fpcr ;force rz for src conversion fmove.l fp0,d0 ;int src to d0 fmove.l #0,FPSR ;clr status from above tst.w ETEMP(a6) ;check src sign blt.w 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: ; label not referenced <1/7/91, JPO> tst.w d1 ;check for denorm beq.w dst_dnrm add.l d0,d1 ;add src to dest exp beq.b sc_denorm ;if zero, result is denorm - label renamed <1/7/91, JPO> cmpi.l #$7fff,d1 ;test for overflow bge.b sc_ovfl ; label renamed <1/7/91, JPO> tst.b L_SCR1(a6) beq.b spos_pos or.w #$8000,d1 spos_pos: move.w d1,FPTEMP(a6) ;result in FPTEMP fmove.l USER_FPCR(a6),FPCR fmove.x FPTEMP(a6),fp0 ;write result to fp0 rts sc_ovfl: ; label renamed <1/7/91, JPO> tst.b L_SCR1(a6) beq.b sovl_pos or.w #$8000,d1 sovl_pos: move.w FPTEMP(a6),ETEMP(a6) ;result in ETEMP move.l FPTEMP_HI(a6),ETEMP_HI(a6) move.l FPTEMP_LO(a6),ETEMP_LO(a6) bra t_ovfl2 sc_denorm: ; label renamed <1/7/91, JPO> tst.b L_SCR1(a6) beq.b den_pos or.w #$8000,d1 den_pos: tst.l FPTEMP_HI(a6) ;check j bit blt.b nden_exit ;if set, not denorm ;;; move.w d1,ETEMP(a6) ;input expected in ETEMP - DELETED <2/8/91, JPO> move.w d1,FPTEMP(a6) ; input can be in FPTEMP <2/8/91, JPO> ;;; move.l FPTEMP_HI(a6),ETEMP_HI(a6) ; DELETED <2/8/91, JPO> ;;; move.l FPTEMP_LO(a6),ETEMP_LO(a6) ; DELETED <2/8/91, JPO> ; or.l #unfl_bit,USER_FPSR(a6) ;set unfl - DELETED <2/7/91, JPO> or.l #unfl_mask,USER_FPSR(a6) ; set unfl <2/7/91, JPO> ;;; lea.l ETEMP(a6),a0 ; DELETED <2/8/91, JPO> lea.l FPTEMP(a6),a0 ; <2/8/91, JPO> bra t_resdnrm nden_exit: move.w d1,FPTEMP(a6) ;result in FPTEMP fmove.l USER_FPCR(a6),FPCR fmove.x 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: add.l d0,d1 ;add src to dest beq.b sc_denorm ;if zero, result is denorm - label renamed <1/7/91, JPO> blt.b fix_dnrm ;if negative, result is * ;needing denormalization tst.b L_SCR1(a6) beq.b sneg_pos or.w #$8000,d1 sneg_pos: move.w d1,FPTEMP(a6) ;result in FPTEMP fmove.l USER_FPCR(a6),FPCR fmove.x 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: ; cmpi.w #$ffc0,d1 ;lower bound for normalization - DELETED <2/7/91> ; blt.w fix_unfl ;if lower, catastrophic unfl - DELETED <2/7/91> move.w d1,d0 ;use d0 for exp ; move.l d2,-(a7) ;free d2 for norm - DELETED <2/7/91> movem.l d2-d3,-(a7) ; free d2/d3 for norm <2/7/91> move.l FPTEMP_HI(a6),d1 move.l FPTEMP_LO(a6),d2 ; clr.l L_SCR2(a6) ; DELETED <2/7/91> clr.l d3 ; initialize stickies <2/7/91> cmpi.w #$ffe0,d0 ; shift count >= 32 bits? <2/7/91> bgt.b fix_loop ; no, do shift <2/7/91> move.l d2,d3 ; yes, shift 32 bits <2/7/91> move.l d1,d2 ; <2/7/91> clr.l d1 ; high significand is zero <2/7/91> add.w #32,d0 ; adjust shift counter <2/7/91> beq.b done_fix ; don't shift if zero <2/7/91> cmpi.w #$ffe0,d0 ; new shift count > 32 bits? <2/7/91> bge.b fix_loop ; no, do shift <2/7/91> clr.l d2 ; yes, result is 0 with a sticky <2/7/91> moveq.l #1,d3 ; <2/7/91> bra.b done_fix ; <2/7/91> fix_loop: ; add.w #1,d0 ;drive d0 to 0 - DELETED <2/7/91> lsr.l #1,d1 ;while shifting the roxr.l #1,d2 ;mantissa to the right roxr.l #1,d3 ; into the guard/stickies (d3) bcc.b no_carry ; st L_SCR2(a6) ;use L_SCR2 to capture inex - DELETED <2/7/91> ori.b #1,d3 ; don't lose low sticky <2/7/91> no_carry: ; tst.w d0 ;it is finished when - DELETED <2/7/91> ; blt.b fix_loop ;d0 is zero or the mantissa - DELETED <2/7/91> add.w #1,d0 ; drive loop count in d0 to 0 <2/7/91> bne.b fix_loop ; <2/7/91> done_fix: ; label added <2/7/91> ; tst.b L_SCR2(a6) ; DELETED <2/7/91> ; beq.b tst_zero ; DELETED <2/7/91> ; or.l #unfl_inx_mask,USER_FPSR(a6) ; DELETED <2/7/91> * ;set aunfl, aunfl, ainex * * Test for zero. If zero, simply use fmove to return +/- zero * to the fpu. * ;tst_zero: ; label DELETED <2/7/91> clr.w FPTEMP_EX(a6) tst.b L_SCR1(a6) ;test for sign ; beq.b tst_con ; DELETED <2/7/91> beq.b sc_round ; new label <2/7/91> or.w #$8000,FPTEMP_EX(a6) ;set sign bit ; ; Round result to extended precision, honoring rounding direction ; in USER_FPCR(a6) and setting appropriate exceptions - <2/7/91> ; sc_round: ; new label <2/7/91> or.l #unfl_mask,USER_FPSR(a6) ; set unfl at very least <2/7/91> tst.l d3 ; check for inexact <2/7/91> beq.b sc_rddone ; exact, no rounding necessary <2/7/91> ; ; Inexact result may require rounding tweak ; or.l #unfinx_mask,USER_FPSR(a6) ; set unfl/aunfl/inex2/ainex, also <2/7/91> bfextu FPCR_MODE(a6){2:2},d0 ; rounding direction in d0.low <2/7/91> beq.b sc_rn ; to nearest mode <2/7/91> btst.l #1,d0 ; check for round toward ±inf <2/7/91> beq.b sc_rddone ; toward zero rounding -> done <2/7/91> btst.l #0,d0 ; round toward +inf or -inf? <2/7/91> bne.b sc_rp ; +inf <2/7/91> ; ; Rounding toward -inf. Increment significand if sign is negative <2/7/91> ; tst.b L_SCR1(a6) ; check sign <2/7/91> bne.b sc_rdinc ; negative -> incr signif <2/7/91> bra.b sc_rddone ; positive -> done <2/7/91> ; ; Rounding toward +inf. Increment significand if sign is positive <2/7/91> ; sc_rp: ; <2/7/91> tst.b L_SCR1(a6) ; check sign <2/7/91> beq.b sc_rdinc ; positive -> incr signif <2/7/91> bra.b sc_rddone ; negative -> done <2/7/91> ; ; Round to nearest mode <2/7/91> ; sc_rn: ; <2/7/91> tst.l d3 ; test guard bit <2/7/91> bpl.b sc_rddone ; clear -> done <2/7/91> bftst d3{1:31} ; test stickies <2/7/91> bne.b sc_rdinc ; set -> incr signif <2/7/91> btst.l #0,d2 ; test lowest bit of signif <2/7/91> beq.b sc_rddone ; clear -> done <2/7/91> ; ; Rounding requires increment of significand <2/7/91> ; sc_rdinc: ; <2/7/91> clr.l d0 ; clear d0 <2/7/91> addq.l #1,d2 ; incr signif <2/7/91> addx.l d0,d1 ; high result will not generate carry <2/7/91> ; ; Rounding done. Store significand result in FPTEMP and test ; for zero result. ; ;tst_con: ; label deleted <2/7/91> sc_rddone: ; new label <2/7/91> move.l d1,FPTEMP_HI(a6) move.l d2,FPTEMP_LO(a6) move.l d2,d0 ; save low signif in d0 <2/7/91> ; move.l (a7)+,d2 ; DELETED <2/7/91> movem.l (a7)+,d2-d3 ; restore d2/d3 ; tst.l d1 ; DELETED <2/7/91> ; bne.b sc_notzero ; label renamed <1/7/91, JPO> - DELETED <2/7/91> ; tst.l FPTEMP_LO(a6) ; DELETED <2/7/91> or.l d1,d0 ; zero result? <2/7/91> bne.b sc_notzero ; no - label RENAMED <1/7/91, JPO> * * 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. * ; btst.b #5,FPCR_MODE(a6) ;test if rm or rp - DELETED <1/7/91, JPO> ; beq.b no_dir ; DELETED <1/7/91, JPO> ; btst.b #4,FPCR_MODE(a6) ;check which one - DELETED <1/7/91, JPO> ; beq.b zer_rm ; DELETED <1/7/91, JPO> ;zer_rp: ; label not referenced <1/7/91, JPO> - DELETED <1/7/91, JPO> ; tst.b L_SCR1(a6) ;check sign - DELETED <1/7/91, JPO> ; bne.b no_dir ;if set, neg op, no inc - DELETED <1/7/91, JPO> ; move.l #1,FPTEMP_LO(a6) ;set lsb - DELETED <1/7/91, JPO> ; bra.b sm_dnrm ; DELETED <1/7/91, JPO> ;zer_rm: ; label DELETED <1/7/91, JPO> ; tst.b L_SCR1(a6) ;check sign - DELETED <1/7/91, JPO> ; beq.b no_dir ;if clr, neg op, no inc - DELETED <1/7/91, JPO> ; move.l #1,FPTEMP_LO(a6) ;set lsb - DELETED <1/7/91, JPO> ; or.l #neg_mask,USER_FPSR(a6) ;set N - DELETED <1/7/91, JPO> ; bra.b sm_dnrm ; DELETED <1/7/91, JPO> ;no_dir: ; label DELETED <1/7/91, JPO> fmove.l USER_FPCR(a6),FPCR fmove.x 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: ; label DELETED <1/7/91, JPO> ; move.l FPTEMP_EX(a6),ETEMP_EX(a6) ; MOVED below "fix_exit" below <1/7/91, JPO> ; move.l FPTEMP_HI(a6),ETEMP_HI(a6) ; <1/7/91, JPO> ; move.l FPTEMP_LO(a6),ETEMP_LO(a6) ; <1/7/91, JPO> ; lea.l ETEMP(a6),a0 ; <1/7/91, JPO> ; bra t_resdnrm ; <1/7/91, JPO> * * Result is still denormalized. * sc_notzero: ;label renamed <1/7/91, JPO> or.l #unfl_mask,USER_FPSR(a6) ;set unfl tst.b L_SCR1(a6) ;check for sign beq.b fix_exit or.l #neg_mask,USER_FPSR(a6) ;set N fix_exit: ; bra.b sm_dnrm ; DELETED <1/7/91, JPO> ;;; move.l FPTEMP_EX(a6),ETEMP_EX(a6) ; MOVED from above <1/7/91, JPO> - DELETED <2/8/91, JPO> ;;; move.l FPTEMP_HI(a6),ETEMP_HI(a6) ; <1/7/91, JPO> - DELETED <2/8/91, JPO> ;;; move.l FPTEMP_LO(a6),ETEMP_LO(a6) ; <1/7/91, JPO> - DELETED <2/8/91, JPO> ;;; lea.l ETEMP(a6),a0 ; <1/7/91, JPO> - DELETED <2/8/91, JPO> lea.l FPTEMP(a6),a0 ; exceptional op in FPTEMP <2/8/91, JPO> bra t_resdnrm ; <1/7/91, JPO> * * The result has underflowed to zero. Return zero and set * unfl, aunfl, and ainex. DELETED <1/7/91, JPO> * ;fix_unfl: ; DELETED routine <1/7/91, JPO> ; or.l #unfl_inx_mask,USER_FPSR(a6) ; btst.b #5,FPCR_MODE(a6) ;test if rm or rp ; beq.b no_dir2 ; btst.b #4,FPCR_MODE(a6) ;check which one ; beq.b zer_rm2 ;zer_rp2: ; label not referenced <1/7/91, JPO> ; tst.b L_SCR1(a6) ;check sign ; bne.b no_dir2 ;if set, neg op, no inc ; clr.l FPTEMP_EX(a6) ; clr.l FPTEMP_HI(a6) ; move.l #1,FPTEMP_LO(a6) ;set lsb ; bra.b sm_dnrm ;return smallest denorm ;zer_rm2: ; tst.b L_SCR1(a6) ;check sign ; beq.b no_dir2 ;if clr, neg op, no inc ; move.w #$8000,FPTEMP_EX(a6) ; clr.l FPTEMP_HI(a6) ; move.l #1,FPTEMP_LO(a6) ;set lsb ; or.l #neg_mask,USER_FPSR(a6) ;set N ; bra.w sm_dnrm ;return smallest denorm ; ;no_dir2: ; tst.b L_SCR1(a6) ; bge.b sc_poszero ; label renamed <1/7/91, JPO> ;neg_zero: ; label not referenced <1/7/91, JPO> ; fmove.s #"$80000000",fp0 ; rts ;sc_poszero: ; label renamed <1/7/91, JPO> ; fmove.s #"$00000000",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: movem.l d2/d3,-(a7) move.w FPTEMP_EX(a6),d1 move.l FPTEMP_HI(a6),d2 move.l FPTEMP_LO(a6),d3 dst_loop: ; tst.l d0 ;check if src is zero - test MOVED below following test <1/7/91, JPO> ; beq.b dst_fin ; <1/7/91, JPO> tst.l d2 ;test for j-bit set blt.b dst_norm tst.l d0 ;check if src is zero - test MOVED from above <1/7/91, JPO> beq.b dst_fin ; <1/7/91, JPO> subi.l #1,d0 ;dec src lsl.l #1,d3 roxl.l #1,d2 bra.b dst_loop * * Destination became normalized. Simply add the remaining * portion of the src to the exponent. * dst_norm: add.w d0,d1 ;dst is normalized; add src tst.b L_SCR1(a6) beq.b dnrm_pos or.l #$8000,d1 dnrm_pos: movem.w d1,FPTEMP_EX(a6) movem.l d2,FPTEMP_HI(a6) movem.l d3,FPTEMP_LO(a6) fmove.l USER_FPCR(a6),FPCR fmove.x FPTEMP(a6),fp0 movem.l (a7)+,d2/d3 rts * * Destination remained denormalized. Call t_excdnrm with * exceptional operand in ETEMP. MOVED EXC OP TO FPTEMP <2/8/91, JPO> * dst_fin: tst.b L_SCR1(a6) ;check for sign beq.b dst_exit or.l #neg_mask,USER_FPSR(a6) ;set N or.l #$8000,d1 dst_exit: ;;; movem.w d1,ETEMP_EX(a6) ; DELETED <2/8/91, JPO> ;;; movem.l d2,ETEMP_HI(a6) ; DELETED <2/8/91, JPO> ;;; movem.l d3,ETEMP_LO(a6) ; DELETED <2/8/91, JPO> movem.w d1,FPTEMP_EX(a6) ; result in FPTEMP <2/8/91, JPO> movem.l d2,FPTEMP_HI(a6) ; <2/8/91, JPO> movem.l d3,FPTEMP_LO(a6) ; <2/8/91, JPO> or.l #unfl_mask,USER_FPSR(a6) ;set unfl movem.l (a7)+,d2/d3 ;;; lea.l ETEMP(a6),a0 ; DELETED <2/8/91, JPO> lea.l FPTEMP(a6),a0 ; point to result <2/8/91, JPO> bra t_resdnrm * * Source is outside of 2^14 range. Test the sign and branch * to the appropriate exception handler. * src_out: tst.b L_SCR1(a6) beq.b scro_pos or.l #$8000,d1 scro_pos: move.l FPTEMP_HI(a6),ETEMP_HI(a6) move.l FPTEMP_LO(a6),ETEMP_LO(a6) tst.w ETEMP(a6) blt.b res_neg ;res_pos: ; label not referenced <1/7/91, JPO> move.w d1,ETEMP(a6) ;result in ETEMP bra t_ovfl2 res_neg: move.w d1,ETEMP(a6) ;result in ETEMP lea.l ETEMP(a6),a0 bra t_unfl