Training courses

Kernel and Embedded Linux

Bootlin training courses

Embedded Linux, kernel,
Yocto Project, Buildroot, real-time,
graphics, boot time, debugging...

Bootlin logo

Elixir Cross Referencer

*	$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