NetBSD/sys/arch/m68k/fpsp/scale.sa

398 lines
10 KiB
Plaintext

* $NetBSD: scale.sa,v 1.3 1994/10/26 07:49:34 cgd Exp $
* MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP
* M68000 Hi-Performance Microprocessor Division
* M68040 Software Package
*
* M68040 Software Package Copyright (c) 1993, 1994 Motorola Inc.
* All rights reserved.
*
* THE SOFTWARE is provided on an "AS IS" basis and without warranty.
* To the maximum extent permitted by applicable law,
* MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED,
* INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A
* PARTICULAR PURPOSE and any warranty against infringement with
* regard to the SOFTWARE (INCLUDING ANY MODIFIED VERSIONS THEREOF)
* and any accompanying written materials.
*
* To the maximum extent permitted by applicable law,
* IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER
* (INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS
* PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR
* OTHER PECUNIARY LOSS) ARISING OF THE USE OR INABILITY TO USE THE
* SOFTWARE. Motorola assumes no responsibility for the maintenance
* and support of the SOFTWARE.
*
* You are hereby granted a copyright license to use, modify, and
* distribute the SOFTWARE so long as this entire notice is retained
* without alteration in any modified and/or redistributed versions,
* and that such modified versions are clearly identified as such.
* No licenses are granted by implication, estoppel or otherwise
* under any patents or trademarks of Motorola, Inc.
*
* scale.sa 3.3 7/30/91
*
* The entry point sSCALE computes the destination operand
* scaled by the source operand. If the absoulute 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:
*
SCALE IDNT 2,1 Motorola 040 Floating Point Software Package
section 8
include fpsp.h
xref t_ovfl2
xref t_unfl
xref round
xref t_resdnrm
SRC_BNDS dc.w $3fff,$400c
*
* This entry point is used by the unimplemented instruction exception
* handler.
*
*
*
* FSCALE
*
xdef sscale
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:
move.b DTAG(a6),d0
andi.b #$e0,d0
tst.b d0
beq.b no_denorm
st STORE_FLG(a6) ;dest already contains result
or.l #unfl_mask,USER_FPSR(a6) ;set UNFL
den_done:
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:
tst.w d1 ;check for denorm
beq.w dst_dnrm
add.l d0,d1 ;add src to dest exp
beq.b denorm ;if zero, result is denorm
cmpi.l #$7fff,d1 ;test for overflow
bge.b ovfl
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
ovfl:
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
denorm:
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
move.l FPTEMP_HI(a6),ETEMP_HI(a6)
move.l FPTEMP_LO(a6),ETEMP_LO(a6)
or.l #unfl_bit,USER_FPSR(a6) ;set unfl
lea.l ETEMP(a6),a0
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 denorm ;if zero, result is denorm
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
blt.w fix_unfl ;if lower, catastrophic unfl
move.w d1,d0 ;use d0 for exp
move.l d2,-(a7) ;free d2 for norm
move.l FPTEMP_HI(a6),d1
move.l FPTEMP_LO(a6),d2
clr.l L_SCR2(a6)
fix_loop:
add.w #1,d0 ;drive d0 to 0
lsr.l #1,d1 ;while shifting the
roxr.l #1,d2 ;mantissa to the right
bcc.b no_carry
st L_SCR2(a6) ;use L_SCR2 to capture inex
no_carry:
tst.w d0 ;it is finished when
blt.b fix_loop ;d0 is zero or the mantissa
tst.b L_SCR2(a6)
beq.b tst_zero
or.l #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:
clr.w FPTEMP_EX(a6)
tst.b L_SCR1(a6) ;test for sign
beq.b tst_con
or.w #$8000,FPTEMP_EX(a6) ;set sign bit
tst_con:
move.l d1,FPTEMP_HI(a6)
move.l d2,FPTEMP_LO(a6)
move.l (a7)+,d2
tst.l d1
bne.b not_zero
tst.l FPTEMP_LO(a6)
bne.b 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.
*
btst.b #5,FPCR_MODE(a6) ;test if rm or rp
beq.b no_dir
btst.b #4,FPCR_MODE(a6) ;check which one
beq.b zer_rm
zer_rp:
tst.b L_SCR1(a6) ;check sign
bne.b no_dir ;if set, neg op, no inc
move.l #1,FPTEMP_LO(a6) ;set lsb
bra.b sm_dnrm
zer_rm:
tst.b L_SCR1(a6) ;check sign
beq.b no_dir ;if clr, neg op, no inc
move.l #1,FPTEMP_LO(a6) ;set lsb
or.l #neg_mask,USER_FPSR(a6) ;set N
bra.b sm_dnrm
no_dir:
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:
move.l FPTEMP_EX(a6),ETEMP_EX(a6)
move.l FPTEMP_HI(a6),ETEMP_HI(a6)
move.l FPTEMP_LO(a6),ETEMP_LO(a6)
lea.l ETEMP(a6),a0
bra t_resdnrm
*
* Result is still denormalized.
*
not_zero:
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
*
* The result has underflowed to zero. Return zero and set
* unfl, aunfl, and ainex.
*
fix_unfl:
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:
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 pos_zero
neg_zero:
clr.l FP_SCR1(a6) ;clear the exceptional operand
clr.l FP_SCR1+4(a6) ;for gen_except.
clr.l FP_SCR1+8(a6)
fmove.s #:80000000,fp0
rts
pos_zero:
clr.l FP_SCR1(a6) ;clear the exceptional operand
clr.l FP_SCR1+4(a6) ;for gen_except.
clr.l FP_SCR1+8(a6)
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 d2 ;test for normalized result
blt.b dst_norm ;exit loop if so
tst.l d0 ;otherwise, test shift count
beq.b dst_fin ;if zero, shifting is done
subq.l #1,d0 ;dec src
add.l d3,d3
addx.l d2,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.w #$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.
*
dst_fin:
tst.b L_SCR1(a6) ;check for sign
beq.b dst_exit
or.l #neg_mask,USER_FPSR(a6) ;set N
or.w #$8000,d1
dst_exit:
movem.w d1,ETEMP_EX(a6)
movem.l d2,ETEMP_HI(a6)
movem.l d3,ETEMP_LO(a6)
or.l #unfl_mask,USER_FPSR(a6) ;set unfl
movem.l (a7)+,d2/d3
lea.l 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:
tst.b L_SCR1(a6)
beq.b scro_pos
or.w #$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:
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
end