396 lines
9.9 KiB
Plaintext
396 lines
9.9 KiB
Plaintext
* 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
|