[BACK]Return to res_func.sa CVS log [TXT][DIR] Up to [local] / sys / arch / m68k / fpsp

File: [local] / sys / arch / m68k / fpsp / res_func.sa (download)

Revision 1.1, Tue Mar 4 16:07:06 2008 UTC (16 years, 2 months ago) by nbrk
Branch point for: MAIN

Initial revision

*	$OpenBSD: res_func.sa,v 1.5 2006/11/30 20:08:22 mk Exp $
*	$NetBSD: res_func.sa,v 1.3 1994/10/26 07:49:22 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.

*
*	res_func.sa 3.9 7/29/91
*
* Normalizes denormalized numbers if necessary and updates the
* stack frame.  The function is then restored back into the
* machine and the 040 completes the operation.  This routine
* is only used by the unsupported data type/format handler.
* (Exception vector 55).
*
* For packed move out (fmove.p fpm,<ea>) the operation is
* completed here; data is packed and moved to user memory. 
* The stack is restored to the 040 only in the case of a
* reportable exception in the conversion.
*

RES_FUNC    IDNT    2,1 Motorola 040 Floating Point Software Package

	section	8

	include	fpsp.h

sp_bnds:	dc.w	$3f81,$407e
		dc.w	$3f6a,$0000
dp_bnds:	dc.w	$3c01,$43fe
		dc.w	$3bcd,$0000

	xref	mem_write
	xref	bindec
	xref	get_fline
	xref	round
	xref	denorm
	xref	dest_ext
	xref	dest_dbl
	xref	dest_sgl
	xref	unf_sub
	xref	nrm_set
	xref	dnrm_lp
	xref	ovf_res
	xref	reg_dest
	xref	t_ovfl
	xref	t_unfl

	xdef	res_func
	xdef 	p_move

res_func:
	clr.b	DNRM_FLG(a6)
	clr.b	RES_FLG(a6)
	clr.b	CU_ONLY(a6)
	tst.b	DY_MO_FLG(a6)
	beq.b	monadic
dyadic:
	btst.b	#7,DTAG(a6)	;if dop = norm=000, zero=001,
*				;inf=010 or nan=011
	beq.b	monadic		;then branch
*				;else denorm
* HANDLE DESTINATION DENORM HERE
*				;set dtag to norm
*				;write the tag & fpte15 to the fstack
	lea.l	FPTEMP(a6),a0

	bclr.b	#sign_bit,LOCAL_EX(a0)
	sne	LOCAL_SGN(a0)

	bsr	nrm_set		;normalize number (exp will go negative)
	bclr.b	#sign_bit,LOCAL_EX(a0) ;get rid of false sign
	bfclr	LOCAL_SGN(a0){0:8}	;change back to IEEE ext format
	beq.b	dpos
	bset.b	#sign_bit,LOCAL_EX(a0)
dpos:
	bfclr	DTAG(a6){0:4}	;set tag to normalized, FPTE15 = 0
	bset.b	#4,DTAG(a6)	;set FPTE15
	or.b	#$0f,DNRM_FLG(a6)
monadic:
	lea.l	ETEMP(a6),a0
	btst.b	#direction_bit,CMDREG1B(a6)	;check direction
	bne.w	opclass3			;it is a mv out
*
* At this point, only oplcass 0 and 2 possible
*
	btst.b	#7,STAG(a6)	;if sop = norm=000, zero=001,
*				;inf=010 or nan=011
	bne.w	mon_dnrm	;else denorm
	tst.b	DY_MO_FLG(a6)	;all cases of dyadic instructions would
	bne.w	normal		;require normalization of denorm

* At this point:
*	monadic instructions:	fabs  = $18  fneg   = $1a  ftst   = $3a
*				fmove = $00  fsmove = $40  fdmove = $44
*				fsqrt = $05* fssqrt = $41  fdsqrt = $45
*				(*fsqrt reencoded to $05)
*
	move.w	CMDREG1B(a6),d0	;get command register
	andi.l	#$7f,d0			;strip to only command word
*
* At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and 
* fdsqrt are possible.
* For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize)
* For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize)
*
	btst.l	#0,d0
	bne.w	normal			;weed out fsqrt instructions
*
* cu_norm handles fmove in instructions with normalized inputs.
* The routine round is used to correctly round the input for the
* destination precision and mode.
*
cu_norm:
	st	CU_ONLY(a6)		;set cu-only inst flag
	move.w	CMDREG1B(a6),d0
	andi.b	#$3b,d0		;isolate bits to select inst
	tst.b	d0
	beq.l	cu_nmove	;if zero, it is an fmove
	cmpi.b	#$18,d0
	beq.l	cu_nabs		;if $18, it is fabs
	cmpi.b	#$1a,d0
	beq.l	cu_nneg		;if $1a, it is fneg
*
* Inst is ftst.  Check the source operand and set the cc's accordingly.
* No write is done, so simply rts.
*
cu_ntst:
	move.w	LOCAL_EX(a0),d0
	bclr.l	#15,d0
	sne	LOCAL_SGN(a0)
	beq.b	cu_ntpo
	or.l	#neg_mask,USER_FPSR(a6) ;set N
cu_ntpo:
	cmpi.w	#$7fff,d0	;test for inf/nan
	bne.b	cu_ntcz
	tst.l	LOCAL_HI(a0)
	bne.b	cu_ntn
	tst.l	LOCAL_LO(a0)
	bne.b	cu_ntn
	or.l	#inf_mask,USER_FPSR(a6)
	rts
cu_ntn:
	or.l	#nan_mask,USER_FPSR(a6)
	move.l	ETEMP_EX(a6),FPTEMP_EX(a6)	;set up fptemp sign for 
*						;snan handler

	rts
cu_ntcz:
	tst.l	LOCAL_HI(a0)
	bne.l	cu_ntsx
	tst.l	LOCAL_LO(a0)
	bne.l	cu_ntsx
	or.l	#z_mask,USER_FPSR(a6)
cu_ntsx:
	rts
*
* Inst is fabs.  Execute the absolute value function on the input.
* Branch to the fmove code.  If the operand is NaN, do nothing.
*
cu_nabs:
	move.b	STAG(a6),d0
	btst.l	#5,d0			;test for NaN or zero
	bne	wr_etemp		;if either, simply write it
	bclr.b	#7,LOCAL_EX(a0)		;do abs
	bra.b	cu_nmove		;fmove code will finish
*
* Inst is fneg.  Execute the negate value function on the input.
* Fall though to the fmove code.  If the operand is NaN, do nothing.
*
cu_nneg:
	move.b	STAG(a6),d0
	btst.l	#5,d0			;test for NaN or zero
	bne	wr_etemp		;if either, simply write it
	bchg.b	#7,LOCAL_EX(a0)		;do neg
*
* Inst is fmove.  This code also handles all result writes.
* If bit 2 is set, round is forced to double.  If it is clear,
* and bit 6 is set, round is forced to single.  If both are clear,
* the round precision is found in the fpcr.  If the rounding precision
* is double or single, round the result before the write.
*
cu_nmove:
	move.b	STAG(a6),d0
	andi.b	#$e0,d0			;isolate stag bits
	bne	wr_etemp		;if not norm, simply write it
	btst.b	#2,CMDREG1B+1(a6)	;check for rd
	bne	cu_nmrd
	btst.b	#6,CMDREG1B+1(a6)	;check for rs
	bne	cu_nmrs
*
* The move or operation is not with forced precision.  Test for
* nan or inf as the input; if so, simply write it to FPn.  Use the
* FPCR_MODE byte to get rounding on norms and zeros.
*
cu_nmnr:
	bfextu	FPCR_MODE(a6){0:2},d0
	tst.b	d0			;check for extended
	beq	cu_wrexn		;if so, just write result
	cmpi.b	#1,d0			;check for single
	beq	cu_nmrs			;fall through to double
*
* The move is fdmove or round precision is double.
*
cu_nmrd:
	move.l	#2,d0			;set up the size for denorm
	move.w	LOCAL_EX(a0),d1		;compare exponent to double threshold
	and.w	#$7fff,d1	
	cmp.w	#$3c01,d1
	bls	cu_nunfl
	bfextu	FPCR_MODE(a6){2:2},d1	;get rmode
	or.l	#$00020000,d1		;or in rprec (double)
	clr.l	d0			;clear g,r,s for round
	bclr.b	#sign_bit,LOCAL_EX(a0)	;convert to internal format
	sne	LOCAL_SGN(a0)
	bsr.l	round
	bfclr	LOCAL_SGN(a0){0:8}
	beq.b	cu_nmrdc
	bset.b	#sign_bit,LOCAL_EX(a0)
cu_nmrdc:
	move.w	LOCAL_EX(a0),d1		;check for overflow
	and.w	#$7fff,d1
	cmp.w	#$43ff,d1
	bge	cu_novfl		;take care of overflow case
	bra.w	cu_wrexn
*
* The move is fsmove or round precision is single.
*
cu_nmrs:
	move.l	#1,d0
	move.w	LOCAL_EX(a0),d1
	and.w	#$7fff,d1
	cmp.w	#$3f81,d1
	bls	cu_nunfl
	bfextu	FPCR_MODE(a6){2:2},d1
	or.l	#$00010000,d1
	clr.l	d0
	bclr.b	#sign_bit,LOCAL_EX(a0)
	sne	LOCAL_SGN(a0)
	bsr.l	round
	bfclr	LOCAL_SGN(a0){0:8}
	beq.b	cu_nmrsc
	bset.b	#sign_bit,LOCAL_EX(a0)
cu_nmrsc:
	move.w	LOCAL_EX(a0),d1
	and.w	#$7FFF,d1
	cmp.w	#$407f,d1
	blt	cu_wrexn
*
* The operand is above precision boundaries.  Use t_ovfl to
* generate the correct value.
*
cu_novfl:
	bsr	t_ovfl
	bra	cu_wrexn
*
* The operand is below precision boundaries.  Use denorm to
* generate the correct value.
*
cu_nunfl:
	bclr.b	#sign_bit,LOCAL_EX(a0)
	sne	LOCAL_SGN(a0)
	bsr	denorm
	bfclr	LOCAL_SGN(a0){0:8}	;change back to IEEE ext format
	beq.b	cu_nucont
	bset.b	#sign_bit,LOCAL_EX(a0)
cu_nucont:
	bfextu	FPCR_MODE(a6){2:2},d1
	btst.b	#2,CMDREG1B+1(a6)	;check for rd
	bne	inst_d
	btst.b	#6,CMDREG1B+1(a6)	;check for rs
	bne	inst_s
	swap	d1
	move.b	FPCR_MODE(a6),d1
	lsr.b	#6,d1
	swap	d1
	bra	inst_sd
inst_d:
	or.l	#$00020000,d1
	bra	inst_sd
inst_s:
	or.l	#$00010000,d1
inst_sd:
	bclr.b	#sign_bit,LOCAL_EX(a0)
	sne	LOCAL_SGN(a0)
	bsr.l	round
	bfclr	LOCAL_SGN(a0){0:8}
	beq.b	cu_nuflp
	bset.b	#sign_bit,LOCAL_EX(a0)
cu_nuflp:
	btst.b	#inex2_bit,FPSR_EXCEPT(a6)
	beq.b	cu_nuninx
	or.l	#aunfl_mask,USER_FPSR(a6) ;if the round was inex, set AUNFL
cu_nuninx:
	tst.l	LOCAL_HI(a0)		;test for zero
	bne.b	cu_nunzro
	tst.l	LOCAL_LO(a0)
	bne.b	cu_nunzro
*
* The mantissa is zero from the denorm loop.  Check sign and rmode
* to see if rounding should have occurred which would leave the lsb.
*
	move.l	USER_FPCR(a6),d0
	andi.l	#$30,d0		;isolate rmode
	cmpi.l	#$20,d0
	blt.b	cu_nzro
	bne.b	cu_nrp
cu_nrm:
	tst.w	LOCAL_EX(a0)	;if positive, set lsb
	bge.b	cu_nzro
	btst.b	#7,FPCR_MODE(a6) ;check for double
	beq.b	cu_nincs
	bra.b	cu_nincd
cu_nrp:
	tst.w	LOCAL_EX(a0)	;if positive, set lsb
	blt.b	cu_nzro
	btst.b	#7,FPCR_MODE(a6) ;check for double
	beq.b	cu_nincs
cu_nincd:
	or.l	#$800,LOCAL_LO(a0) ;inc for double
	bra	cu_nunzro
cu_nincs:
	or.l	#$100,LOCAL_HI(a0) ;inc for single
	bra	cu_nunzro
cu_nzro:
	or.l	#z_mask,USER_FPSR(a6)
	move.b	STAG(a6),d0
	andi.b	#$e0,d0
	cmpi.b	#$40,d0		;check if input was tagged zero
	beq.b	cu_numv
cu_nunzro:
	or.l	#unfl_mask,USER_FPSR(a6) ;set unfl
cu_numv:
	move.l	(a0),ETEMP(a6)
	move.l	4(a0),ETEMP_HI(a6)
	move.l	8(a0),ETEMP_LO(a6)
*
* Write the result to memory, setting the fpsr cc bits.  NaN and Inf
* bypass cu_wrexn.
*
cu_wrexn:
	tst.w	LOCAL_EX(a0)		;test for zero
	beq.b	cu_wrzero
	cmp.w	#$8000,LOCAL_EX(a0)	;test for zero
	bne.b	cu_wreon
cu_wrzero:
	or.l	#z_mask,USER_FPSR(a6)	;set Z bit
cu_wreon:
	tst.w	LOCAL_EX(a0)
	bpl	wr_etemp
	or.l	#neg_mask,USER_FPSR(a6)
	bra	wr_etemp

*
* HANDLE SOURCE DENORM HERE
*
*				;clear denorm stag to norm
*				;write the new tag & ete15 to the fstack
mon_dnrm:
*
* At this point, check for the cases in which normalizing the 
* denorm produces incorrect results.
*
	tst.b	DY_MO_FLG(a6)	;all cases of dyadic instructions would
	bne.b	nrm_src		;require normalization of denorm

* At this point:
*	monadic instructions:	fabs  = $18  fneg   = $1a  ftst   = $3a
*				fmove = $00  fsmove = $40  fdmove = $44
*				fsqrt = $05* fssqrt = $41  fdsqrt = $45
*				(*fsqrt reencoded to $05)
*
	move.w	CMDREG1B(a6),d0	;get command register
	andi.l	#$7f,d0			;strip to only command word
*
* At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and 
* fdsqrt are possible.
* For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize)
* For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize)
*
	btst.l	#0,d0
	bne.b	nrm_src		;weed out fsqrt instructions
	st	CU_ONLY(a6)	;set cu-only inst flag
	bra	cu_dnrm		;fmove, fabs, fneg, ftst 
*				;cases go to cu_dnrm
nrm_src:
	bclr.b	#sign_bit,LOCAL_EX(a0)
	sne	LOCAL_SGN(a0)
	bsr	nrm_set		;normalize number (exponent will go 
*				; negative)
	bclr.b	#sign_bit,LOCAL_EX(a0) ;get rid of false sign

	bfclr	LOCAL_SGN(a0){0:8}	;change back to IEEE ext format
	beq.b	spos
	bset.b	#sign_bit,LOCAL_EX(a0)
spos:
	bfclr	STAG(a6){0:4}	;set tag to normalized, FPTE15 = 0
	bset.b	#4,STAG(a6)	;set ETE15
	or.b	#$f0,DNRM_FLG(a6)
normal:
	tst.b	DNRM_FLG(a6)	;check if any of the ops were denorms
	bne	ck_wrap		;if so, check if it is a potential
*				;wrap-around case
fix_stk:
	move.b	#$fe,CU_SAVEPC(a6)
	bclr.b	#E1,E_BYTE(a6)

	clr.w	NMNEXC(a6)

	st.b	RES_FLG(a6)	;indicate that a restore is needed
	rts

*
* cu_dnrm handles all cu-only instructions (fmove, fabs, fneg, and
* ftst) completely in software without an frestore to the 040. 
*
cu_dnrm:
	st.b	CU_ONLY(a6)
	move.w	CMDREG1B(a6),d0
	andi.b	#$3b,d0		;isolate bits to select inst
	tst.b	d0
	beq.l	cu_dmove	;if zero, it is an fmove
	cmpi.b	#$18,d0
	beq.l	cu_dabs		;if $18, it is fabs
	cmpi.b	#$1a,d0
	beq.l	cu_dneg		;if $1a, it is fneg
*
* Inst is ftst.  Check the source operand and set the cc's accordingly.
* No write is done, so simply rts.
*
cu_dtst:
	move.w	LOCAL_EX(a0),d0
	bclr.l	#15,d0
	sne	LOCAL_SGN(a0)
	beq.b	cu_dtpo
	or.l	#neg_mask,USER_FPSR(a6) ;set N
cu_dtpo:
	cmpi.w	#$7fff,d0	;test for inf/nan
	bne.b	cu_dtcz
	tst.l	LOCAL_HI(a0)
	bne.b	cu_dtn
	tst.l	LOCAL_LO(a0)
	bne.b	cu_dtn
	or.l	#inf_mask,USER_FPSR(a6)
	rts
cu_dtn:
	or.l	#nan_mask,USER_FPSR(a6)
	move.l	ETEMP_EX(a6),FPTEMP_EX(a6)	;set up fptemp sign for 
*						;snan handler
	rts
cu_dtcz:
	tst.l	LOCAL_HI(a0)
	bne.l	cu_dtsx
	tst.l	LOCAL_LO(a0)
	bne.l	cu_dtsx
	or.l	#z_mask,USER_FPSR(a6)
cu_dtsx:
	rts
*
* Inst is fabs.  Execute the absolute value function on the input.
* Branch to the fmove code.
*
cu_dabs:
	bclr.b	#7,LOCAL_EX(a0)		;do abs
	bra.b	cu_dmove		;fmove code will finish
*
* Inst is fneg.  Execute the negate value function on the input.
* Fall though to the fmove code.
*
cu_dneg:
	bchg.b	#7,LOCAL_EX(a0)		;do neg
*
* Inst is fmove.  This code also handles all result writes.
* If bit 2 is set, round is forced to double.  If it is clear,
* and bit 6 is set, round is forced to single.  If both are clear,
* the round precision is found in the fpcr.  If the rounding precision
* is double or single, the result is zero, and the mode is checked
* to determine if the lsb of the result should be set.
*
cu_dmove:
	btst.b	#2,CMDREG1B+1(a6)	;check for rd
	bne	cu_dmrd
	btst.b	#6,CMDREG1B+1(a6)	;check for rs
	bne	cu_dmrs
*
* The move or operation is not with forced precision.  Use the
* FPCR_MODE byte to get rounding.
*
cu_dmnr:
	bfextu	FPCR_MODE(a6){0:2},d0
	tst.b	d0			;check for extended
	beq	cu_wrexd		;if so, just write result
	cmpi.b	#1,d0			;check for single
	beq	cu_dmrs			;fall through to double
*
* The move is fdmove or round precision is double.  Result is zero.
* Check rmode for rp or rm and set lsb accordingly.
*
cu_dmrd:
	bfextu	FPCR_MODE(a6){2:2},d1	;get rmode
	tst.w	LOCAL_EX(a0)		;check sign
	blt.b	cu_dmdn
	cmpi.b	#3,d1			;check for rp
	bne	cu_dpd			;load double pos zero
	bra	cu_dpdr			;load double pos zero w/lsb
cu_dmdn:
	cmpi.b	#2,d1			;check for rm
	bne	cu_dnd			;load double neg zero
	bra	cu_dndr			;load double neg zero w/lsb
*
* The move is fsmove or round precision is single.  Result is zero.
* Check for rp or rm and set lsb accordingly.
*
cu_dmrs:
	bfextu	FPCR_MODE(a6){2:2},d1	;get rmode
	tst.w	LOCAL_EX(a0)		;check sign
	blt.b	cu_dmsn
	cmpi.b	#3,d1			;check for rp
	bne	cu_spd			;load single pos zero
	bra	cu_spdr			;load single pos zero w/lsb
cu_dmsn:
	cmpi.b	#2,d1			;check for rm
	bne	cu_snd			;load single neg zero
	bra	cu_sndr			;load single neg zero w/lsb
*
* The precision is extended, so the result in etemp is correct.
* Simply set unfl (not inex2 or aunfl) and write the result to 
* the correct fp register.
cu_wrexd:
	or.l	#unfl_mask,USER_FPSR(a6)
	tst.w	LOCAL_EX(a0)
	beq	wr_etemp
	or.l	#neg_mask,USER_FPSR(a6)
	bra	wr_etemp
*
* These routines write +/- zero in double format.  The routines
* cu_dpdr and cu_dndr set the double lsb.
*
cu_dpd:
	move.l	#$3c010000,LOCAL_EX(a0)	;force pos double zero
	clr.l	LOCAL_HI(a0)
	clr.l	LOCAL_LO(a0)
	or.l	#z_mask,USER_FPSR(a6)
	or.l	#unfinx_mask,USER_FPSR(a6)
	bra	wr_etemp
cu_dpdr:
	move.l	#$3c010000,LOCAL_EX(a0)	;force pos double zero
	clr.l	LOCAL_HI(a0)
	move.l	#$800,LOCAL_LO(a0)	;with lsb set
	or.l	#unfinx_mask,USER_FPSR(a6)
	bra	wr_etemp
cu_dnd:
	move.l	#$bc010000,LOCAL_EX(a0)	;force pos double zero
	clr.l	LOCAL_HI(a0)
	clr.l	LOCAL_LO(a0)
	or.l	#z_mask,USER_FPSR(a6)
	or.l	#neg_mask,USER_FPSR(a6)
	or.l	#unfinx_mask,USER_FPSR(a6)
	bra	wr_etemp
cu_dndr:
	move.l	#$bc010000,LOCAL_EX(a0)	;force pos double zero
	clr.l	LOCAL_HI(a0)
	move.l	#$800,LOCAL_LO(a0)	;with lsb set
	or.l	#neg_mask,USER_FPSR(a6)
	or.l	#unfinx_mask,USER_FPSR(a6)
	bra	wr_etemp
*
* These routines write +/- zero in single format.  The routines
* cu_dpdr and cu_dndr set the single lsb.
*
cu_spd:
	move.l	#$3f810000,LOCAL_EX(a0)	;force pos single zero
	clr.l	LOCAL_HI(a0)
	clr.l	LOCAL_LO(a0)
	or.l	#z_mask,USER_FPSR(a6)
	or.l	#unfinx_mask,USER_FPSR(a6)
	bra	wr_etemp
cu_spdr:
	move.l	#$3f810000,LOCAL_EX(a0)	;force pos single zero
	move.l	#$100,LOCAL_HI(a0)	;with lsb set
	clr.l	LOCAL_LO(a0)
	or.l	#unfinx_mask,USER_FPSR(a6)
	bra	wr_etemp
cu_snd:
	move.l	#$bf810000,LOCAL_EX(a0)	;force pos single zero
	clr.l	LOCAL_HI(a0)
	clr.l	LOCAL_LO(a0)
	or.l	#z_mask,USER_FPSR(a6)
	or.l	#neg_mask,USER_FPSR(a6)
	or.l	#unfinx_mask,USER_FPSR(a6)
	bra	wr_etemp
cu_sndr:
	move.l	#$bf810000,LOCAL_EX(a0)	;force pos single zero
	move.l	#$100,LOCAL_HI(a0)	;with lsb set
	clr.l	LOCAL_LO(a0)
	or.l	#neg_mask,USER_FPSR(a6)
	or.l	#unfinx_mask,USER_FPSR(a6)
	bra	wr_etemp
	
*
* This code checks for 16-bit overflow conditions on dyadic
* operations which are not restorable into the floating-point
* unit and must be completed in software.  Basically, this
* condition exists with a very large norm and a denorm.  One
* of the operands must be denormalized to enter this code.
*
* Flags used:
*	DY_MO_FLG contains 0 for monadic op, $ff for dyadic
*	DNRM_FLG contains $00 for neither op denormalized
*	                  $0f for the destination op denormalized
*	                  $f0 for the source op denormalized
*	                  $ff for both ops denormalzed
*
* The wrap-around condition occurs for add, sub, div, and cmp
* when 
*
*	abs(dest_exp - src_exp) >= $8000
*
* and for mul when
*
*	(dest_exp + src_exp) < $0
*
* we must process the operation here if this case is true.
*
* The rts following the frcfpn routine is the exit from res_func
* for this condition.  The restore flag (RES_FLG) is left clear.
* No frestore is done unless an exception is to be reported.
*
* For fadd: 
*	if(sign_of(dest) != sign_of(src))
*		replace exponent of src with $3fff (keep sign)
*		use fpu to perform dest+new_src (user's rmode and X)
*		clr sticky
*	else
*		set sticky
*	call round with user's precision and mode
*	move result to fpn and wbtemp
*
* For fsub:
*	if(sign_of(dest) == sign_of(src))
*		replace exponent of src with $3fff (keep sign)
*		use fpu to perform dest+new_src (user's rmode and X)
*		clr sticky
*	else
*		set sticky
*	call round with user's precision and mode
*	move result to fpn and wbtemp
*
* For fdiv/fsgldiv:
*	if(both operands are denorm)
*		restore_to_fpu;
*	if(dest is norm)
*		force_ovf;
*	else(dest is denorm)
*		force_unf:
*
* For fcmp:
*	if(dest is norm)
*		N = sign_of(dest);
*	else(dest is denorm)
*		N = sign_of(src);
*
* For fmul:
*	if(both operands are denorm)
*		force_unf;
*	if((dest_exp + src_exp) < 0)
*		force_unf:
*	else
*		restore_to_fpu;
*
* local equates:
addcode	equ	$22
subcode	equ	$28
mulcode	equ	$23
divcode	equ	$20
cmpcode	equ	$38
ck_wrap:
	tst.b	DY_MO_FLG(a6)	;check for fsqrt
	beq	fix_stk		;if zero, it is fsqrt
	move.w	CMDREG1B(a6),d0
	andi.w	#$3b,d0		;strip to command bits
	cmpi.w	#addcode,d0
	beq	wrap_add
	cmpi.w	#subcode,d0
	beq	wrap_sub
	cmpi.w	#mulcode,d0
	beq	wrap_mul
	cmpi.w	#cmpcode,d0
	beq	wrap_cmp
*
* Inst is fdiv.  
*
wrap_div:
	cmp.b	#$ff,DNRM_FLG(a6) ;if both ops denorm, 
	beq	fix_stk		 ;restore to fpu
*
* One of the ops is denormalized.  Test for wrap condition
* and force the result.
*
	cmp.b	#$0f,DNRM_FLG(a6) ;check for dest denorm
	bne.b	div_srcd
div_destd:
	bsr.l	ckinf_ns
	bne	fix_stk
	bfextu	ETEMP_EX(a6){1:15},d0	;get src exp (always pos)
	bfexts	FPTEMP_EX(a6){1:15},d1	;get dest exp (always neg)
	sub.l	d1,d0			;subtract dest from src
	cmp.l	#$7fff,d0
	blt	fix_stk			;if less, not wrap case
	clr.b	WBTEMP_SGN(a6)
	move.w	ETEMP_EX(a6),d0		;find the sign of the result
	move.w	FPTEMP_EX(a6),d1
	eor.w	d1,d0
	andi.w	#$8000,d0
	beq	force_unf
	st.b	WBTEMP_SGN(a6)
	bra	force_unf

ckinf_ns:
	move.b	STAG(a6),d0		;check source tag for inf or nan
	bra	ck_in_com
ckinf_nd:
	move.b	DTAG(a6),d0		;check destination tag for inf or nan
ck_in_com:	
	andi.b	#$60,d0			;isolate tag bits
	cmp.b	#$40,d0			;is it inf?
	beq	nan_or_inf		;not wrap case
	cmp.b	#$60,d0			;is it nan?
	beq	nan_or_inf		;yes, not wrap case?
	cmp.b	#$20,d0			;is it a zero?
	beq	nan_or_inf		;yes
	clr.l	d0
	rts				;then it is either a zero of norm,
*					;check wrap case
nan_or_inf:
	moveq.l	#-1,d0
	rts



div_srcd:
	bsr.l	ckinf_nd
	bne	fix_stk
	bfextu	FPTEMP_EX(a6){1:15},d0	;get dest exp (always pos)
	bfexts	ETEMP_EX(a6){1:15},d1	;get src exp (always neg)
	sub.l	d1,d0			;subtract src from dest
	cmp.l	#$8000,d0
	blt	fix_stk			;if less, not wrap case
	clr.b	WBTEMP_SGN(a6)
	move.w	ETEMP_EX(a6),d0		;find the sign of the result
	move.w	FPTEMP_EX(a6),d1
	eor.w	d1,d0
	andi.w	#$8000,d0
	beq.b	force_ovf
	st.b	WBTEMP_SGN(a6)
*
* This code handles the case of the instruction resulting in 
* an overflow condition.
*
force_ovf:
	bclr.b	#E1,E_BYTE(a6)
	or.l	#ovfl_inx_mask,USER_FPSR(a6)
	clr.w	NMNEXC(a6)
	lea.l	WBTEMP(a6),a0		;point a0 to memory location
	move.w	CMDREG1B(a6),d0
	btst.l	#6,d0			;test for forced precision
	beq.b	frcovf_fpcr
	btst.l	#2,d0			;check for double
	bne.b	frcovf_dbl
	move.l	#$1,d0			;inst is forced single
	bra.b	frcovf_rnd
frcovf_dbl:
	move.l	#$2,d0			;inst is forced double
	bra.b	frcovf_rnd
frcovf_fpcr:
	bfextu	FPCR_MODE(a6){0:2},d0	;inst not forced - use fpcr prec
frcovf_rnd:

* The 881/882 does not set inex2 for the following case, so the 
* line is commented out to be compatible with 881/882
*	tst.b	d0
*	beq.b	frcovf_x
*	or.l	#inex2_mask,USER_FPSR(a6) ;if prec is s or d, set inex2

*frcovf_x:
	bsr.l	ovf_res			;get correct result based on
*					;round precision/mode.  This 
*					;sets FPSR_CC correctly
*					;returns in external format
	bfclr	WBTEMP_SGN(a6){0:8}
	beq	frcfpn
	bset.b	#sign_bit,WBTEMP_EX(a6)
	bra	frcfpn
*
* Inst is fadd.
*
wrap_add:
	cmp.b	#$ff,DNRM_FLG(a6) ;if both ops denorm, 
	beq	fix_stk		 ;restore to fpu
*
* One of the ops is denormalized.  Test for wrap condition
* and complete the instruction.
*
	cmp.b	#$0f,DNRM_FLG(a6) ;check for dest denorm
	bne.b	add_srcd
add_destd:
	bsr.l	ckinf_ns
	bne	fix_stk
	bfextu	ETEMP_EX(a6){1:15},d0	;get src exp (always pos)
	bfexts	FPTEMP_EX(a6){1:15},d1	;get dest exp (always neg)
	sub.l	d1,d0			;subtract dest from src
	cmp.l	#$8000,d0
	blt	fix_stk			;if less, not wrap case
	bra	add_wrap
add_srcd:
	bsr.l	ckinf_nd
	bne	fix_stk
	bfextu	FPTEMP_EX(a6){1:15},d0	;get dest exp (always pos)
	bfexts	ETEMP_EX(a6){1:15},d1	;get src exp (always neg)
	sub.l	d1,d0			;subtract src from dest
	cmp.l	#$8000,d0
	blt	fix_stk			;if less, not wrap case
*
* Check the signs of the operands.  If they are unlike, the fpu
* can be used to add the norm and 1.0 with the sign of the
* denorm and it will correctly generate the result in extended
* precision.  We can then call round with no sticky and the result
* will be correct for the user's rounding mode and precision.  If
* the signs are the same, we call round with the sticky bit set
* and the result will be correctfor the user's rounding mode and
* precision.
*
add_wrap:
	move.w	ETEMP_EX(a6),d0
	move.w	FPTEMP_EX(a6),d1
	eor.w	d1,d0
	andi.w	#$8000,d0
	beq	add_same
*
* The signs are unlike.
*
	cmp.b	#$0f,DNRM_FLG(a6) ;is dest the denorm?
	bne.b	add_u_srcd
	move.w	FPTEMP_EX(a6),d0
	andi.w	#$8000,d0
	or.w	#$3fff,d0	;force the exponent to +/- 1
	move.w	d0,FPTEMP_EX(a6) ;in the denorm
	move.l	USER_FPCR(a6),d0
	andi.l	#$30,d0
	fmove.l	d0,fpcr		;set up users rmode and X
	fmove.x	ETEMP(a6),fp0
	fadd.x	FPTEMP(a6),fp0
	lea.l	WBTEMP(a6),a0	;point a0 to wbtemp in frame
	fmove.l	fpsr,d1
	or.l	d1,USER_FPSR(a6) ;capture cc's and inex from fadd
	fmove.x	fp0,WBTEMP(a6)	;write result to memory
	lsr.l	#4,d0		;put rmode in lower 2 bits
	move.l	USER_FPCR(a6),d1
	andi.l	#$c0,d1
	lsr.l	#6,d1		;put precision in upper word
	swap	d1
	or.l	d0,d1		;set up for round call
	clr.l	d0		;force sticky to zero
	bclr.b	#sign_bit,WBTEMP_EX(a6)
	sne	WBTEMP_SGN(a6)
	bsr.l	round		;round result to users rmode & prec
	bfclr	WBTEMP_SGN(a6){0:8}	;convert back to IEEE ext format
	beq	frcfpnr
	bset.b	#sign_bit,WBTEMP_EX(a6)
	bra	frcfpnr
add_u_srcd:
	move.w	ETEMP_EX(a6),d0
	andi.w	#$8000,d0
	or.w	#$3fff,d0	;force the exponent to +/- 1
	move.w	d0,ETEMP_EX(a6) ;in the denorm
	move.l	USER_FPCR(a6),d0
	andi.l	#$30,d0
	fmove.l	d0,fpcr		;set up users rmode and X
	fmove.x	ETEMP(a6),fp0
	fadd.x	FPTEMP(a6),fp0
	fmove.l	fpsr,d1
	or.l	d1,USER_FPSR(a6) ;capture cc's and inex from fadd
	lea.l	WBTEMP(a6),a0	;point a0 to wbtemp in frame
	fmove.x	fp0,WBTEMP(a6)	;write result to memory
	lsr.l	#4,d0		;put rmode in lower 2 bits
	move.l	USER_FPCR(a6),d1
	andi.l	#$c0,d1
	lsr.l	#6,d1		;put precision in upper word
	swap	d1
	or.l	d0,d1		;set up for round call
	clr.l	d0		;force sticky to zero
	bclr.b	#sign_bit,WBTEMP_EX(a6)
	sne	WBTEMP_SGN(a6)	;use internal format for round
	bsr.l	round		;round result to users rmode & prec
	bfclr	WBTEMP_SGN(a6){0:8}	;convert back to IEEE ext format
	beq	frcfpnr
	bset.b	#sign_bit,WBTEMP_EX(a6)
	bra	frcfpnr
*
* Signs are alike:
*
add_same:
	cmp.b	#$0f,DNRM_FLG(a6) ;is dest the denorm?
	bne.b	add_s_srcd
add_s_destd:
	lea.l	ETEMP(a6),a0
	move.l	USER_FPCR(a6),d0
	andi.l	#$30,d0
	lsr.l	#4,d0		;put rmode in lower 2 bits
	move.l	USER_FPCR(a6),d1
	andi.l	#$c0,d1
	lsr.l	#6,d1		;put precision in upper word
	swap	d1
	or.l	d0,d1		;set up for round call
	move.l	#$20000000,d0	;set sticky for round
	bclr.b	#sign_bit,ETEMP_EX(a6)
	sne	ETEMP_SGN(a6)
	bsr.l	round		;round result to users rmode & prec
	bfclr	ETEMP_SGN(a6){0:8}	;convert back to IEEE ext format
	beq.b	add_s_dclr
	bset.b	#sign_bit,ETEMP_EX(a6)
add_s_dclr:
	lea.l	WBTEMP(a6),a0
	move.l	ETEMP(a6),(a0)	;write result to wbtemp
	move.l	ETEMP_HI(a6),4(a0)
	move.l	ETEMP_LO(a6),8(a0)
	tst.w	ETEMP_EX(a6)
	bgt	add_ckovf
	or.l	#neg_mask,USER_FPSR(a6)
	bra	add_ckovf
add_s_srcd:
	lea.l	FPTEMP(a6),a0
	move.l	USER_FPCR(a6),d0
	andi.l	#$30,d0
	lsr.l	#4,d0		;put rmode in lower 2 bits
	move.l	USER_FPCR(a6),d1
	andi.l	#$c0,d1
	lsr.l	#6,d1		;put precision in upper word
	swap	d1
	or.l	d0,d1		;set up for round call
	move.l	#$20000000,d0	;set sticky for round
	bclr.b	#sign_bit,FPTEMP_EX(a6)
	sne	FPTEMP_SGN(a6)
	bsr.l	round		;round result to users rmode & prec
	bfclr	FPTEMP_SGN(a6){0:8}	;convert back to IEEE ext format
	beq.b	add_s_sclr
	bset.b	#sign_bit,FPTEMP_EX(a6)
add_s_sclr:
	lea.l	WBTEMP(a6),a0
	move.l	FPTEMP(a6),(a0)	;write result to wbtemp
	move.l	FPTEMP_HI(a6),4(a0)
	move.l	FPTEMP_LO(a6),8(a0)
	tst.w	FPTEMP_EX(a6)
	bgt	add_ckovf
	or.l	#neg_mask,USER_FPSR(a6)
add_ckovf:
	move.w	WBTEMP_EX(a6),d0
	andi.w	#$7fff,d0
	cmpi.w	#$7fff,d0
	bne	frcfpnr
*
* The result has overflowed to $7fff exponent.  Set I, ovfl,
* and aovfl, and clr the mantissa (incorrectly set by the
* round routine.)
*
	or.l	#inf_mask+ovfl_inx_mask,USER_FPSR(a6)	
	clr.l	4(a0)
	bra	frcfpnr
*
* Inst is fsub.
*
wrap_sub:
	cmp.b	#$ff,DNRM_FLG(a6) ;if both ops denorm, 
	beq	fix_stk		 ;restore to fpu
*
* One of the ops is denormalized.  Test for wrap condition
* and complete the instruction.
*
	cmp.b	#$0f,DNRM_FLG(a6) ;check for dest denorm
	bne.b	sub_srcd
sub_destd:
	bsr.l	ckinf_ns
	bne	fix_stk
	bfextu	ETEMP_EX(a6){1:15},d0	;get src exp (always pos)
	bfexts	FPTEMP_EX(a6){1:15},d1	;get dest exp (always neg)
	sub.l	d1,d0			;subtract src from dest
	cmp.l	#$8000,d0
	blt	fix_stk			;if less, not wrap case
	bra	sub_wrap
sub_srcd:
	bsr.l	ckinf_nd
	bne	fix_stk
	bfextu	FPTEMP_EX(a6){1:15},d0	;get dest exp (always pos)
	bfexts	ETEMP_EX(a6){1:15},d1	;get src exp (always neg)
	sub.l	d1,d0			;subtract dest from src
	cmp.l	#$8000,d0
	blt	fix_stk			;if less, not wrap case
*
* Check the signs of the operands.  If they are alike, the fpu
* can be used to subtract from the norm 1.0 with the sign of the
* denorm and it will correctly generate the result in extended
* precision.  We can then call round with no sticky and the result
* will be correct for the user's rounding mode and precision.  If
* the signs are unlike, we call round with the sticky bit set
* and the result will be correctfor the user's rounding mode and
* precision.
*
sub_wrap:
	move.w	ETEMP_EX(a6),d0
	move.w	FPTEMP_EX(a6),d1
	eor.w	d1,d0
	andi.w	#$8000,d0
	bne	sub_diff
*
* The signs are alike.
*
	cmp.b	#$0f,DNRM_FLG(a6) ;is dest the denorm?
	bne.b	sub_u_srcd
	move.w	FPTEMP_EX(a6),d0
	andi.w	#$8000,d0
	or.w	#$3fff,d0	;force the exponent to +/- 1
	move.w	d0,FPTEMP_EX(a6) ;in the denorm
	move.l	USER_FPCR(a6),d0
	andi.l	#$30,d0
	fmove.l	d0,fpcr		;set up users rmode and X
	fmove.x	FPTEMP(a6),fp0
	fsub.x	ETEMP(a6),fp0
	fmove.l	fpsr,d1
	or.l	d1,USER_FPSR(a6) ;capture cc's and inex from fadd
	lea.l	WBTEMP(a6),a0	;point a0 to wbtemp in frame
	fmove.x	fp0,WBTEMP(a6)	;write result to memory
	lsr.l	#4,d0		;put rmode in lower 2 bits
	move.l	USER_FPCR(a6),d1
	andi.l	#$c0,d1
	lsr.l	#6,d1		;put precision in upper word
	swap	d1
	or.l	d0,d1		;set up for round call
	clr.l	d0		;force sticky to zero
	bclr.b	#sign_bit,WBTEMP_EX(a6)
	sne	WBTEMP_SGN(a6)
	bsr.l	round		;round result to users rmode & prec
	bfclr	WBTEMP_SGN(a6){0:8}	;convert back to IEEE ext format
	beq	frcfpnr
	bset.b	#sign_bit,WBTEMP_EX(a6)
	bra	frcfpnr
sub_u_srcd:
	move.w	ETEMP_EX(a6),d0
	andi.w	#$8000,d0
	or.w	#$3fff,d0	;force the exponent to +/- 1
	move.w	d0,ETEMP_EX(a6) ;in the denorm
	move.l	USER_FPCR(a6),d0
	andi.l	#$30,d0
	fmove.l	d0,fpcr		;set up users rmode and X
	fmove.x	FPTEMP(a6),fp0
	fsub.x	ETEMP(a6),fp0
	fmove.l	fpsr,d1
	or.l	d1,USER_FPSR(a6) ;capture cc's and inex from fadd
	lea.l	WBTEMP(a6),a0	;point a0 to wbtemp in frame
	fmove.x	fp0,WBTEMP(a6)	;write result to memory
	lsr.l	#4,d0		;put rmode in lower 2 bits
	move.l	USER_FPCR(a6),d1
	andi.l	#$c0,d1
	lsr.l	#6,d1		;put precision in upper word
	swap	d1
	or.l	d0,d1		;set up for round call
	clr.l	d0		;force sticky to zero
	bclr.b	#sign_bit,WBTEMP_EX(a6)
	sne	WBTEMP_SGN(a6)
	bsr.l	round		;round result to users rmode & prec
	bfclr	WBTEMP_SGN(a6){0:8}	;convert back to IEEE ext format
	beq	frcfpnr
	bset.b	#sign_bit,WBTEMP_EX(a6)
	bra	frcfpnr
*
* Signs are unlike:
*
sub_diff:
	cmp.b	#$0f,DNRM_FLG(a6) ;is dest the denorm?
	bne.b	sub_s_srcd
sub_s_destd:
	lea.l	ETEMP(a6),a0
	move.l	USER_FPCR(a6),d0
	andi.l	#$30,d0
	lsr.l	#4,d0		;put rmode in lower 2 bits
	move.l	USER_FPCR(a6),d1
	andi.l	#$c0,d1
	lsr.l	#6,d1		;put precision in upper word
	swap	d1
	or.l	d0,d1		;set up for round call
	move.l	#$20000000,d0	;set sticky for round
*
* Since the dest is the denorm, the sign is the opposite of the
* norm sign.
*
	eori.w	#$8000,ETEMP_EX(a6)	;flip sign on result
	tst.w	ETEMP_EX(a6)
	bgt.b	sub_s_dwr
	or.l	#neg_mask,USER_FPSR(a6)
sub_s_dwr:
	bclr.b	#sign_bit,ETEMP_EX(a6)
	sne	ETEMP_SGN(a6)
	bsr.l	round		;round result to users rmode & prec
	bfclr	ETEMP_SGN(a6){0:8}	;convert back to IEEE ext format
	beq.b	sub_s_dclr
	bset.b	#sign_bit,ETEMP_EX(a6)
sub_s_dclr:
	lea.l	WBTEMP(a6),a0
	move.l	ETEMP(a6),(a0)	;write result to wbtemp
	move.l	ETEMP_HI(a6),4(a0)
	move.l	ETEMP_LO(a6),8(a0)
	bra	sub_ckovf
sub_s_srcd:
	lea.l	FPTEMP(a6),a0
	move.l	USER_FPCR(a6),d0
	andi.l	#$30,d0
	lsr.l	#4,d0		;put rmode in lower 2 bits
	move.l	USER_FPCR(a6),d1
	andi.l	#$c0,d1
	lsr.l	#6,d1		;put precision in upper word
	swap	d1
	or.l	d0,d1		;set up for round call
	move.l	#$20000000,d0	;set sticky for round
	bclr.b	#sign_bit,FPTEMP_EX(a6)
	sne	FPTEMP_SGN(a6)
	bsr.l	round		;round result to users rmode & prec
	bfclr	FPTEMP_SGN(a6){0:8}	;convert back to IEEE ext format
	beq.b	sub_s_sclr
	bset.b	#sign_bit,FPTEMP_EX(a6)
sub_s_sclr:
	lea.l	WBTEMP(a6),a0
	move.l	FPTEMP(a6),(a0)	;write result to wbtemp
	move.l	FPTEMP_HI(a6),4(a0)
	move.l	FPTEMP_LO(a6),8(a0)
	tst.w	FPTEMP_EX(a6)
	bgt	sub_ckovf
	or.l	#neg_mask,USER_FPSR(a6)
sub_ckovf:
	move.w	WBTEMP_EX(a6),d0
	andi.w	#$7fff,d0
	cmpi.w	#$7fff,d0
	bne	frcfpnr
*
* The result has overflowed to $7fff exponent.  Set I, ovfl,
* and aovfl, and clr the mantissa (incorrectly set by the
* round routine.)
*
	or.l	#inf_mask+ovfl_inx_mask,USER_FPSR(a6)	
	clr.l	4(a0)
	bra	frcfpnr
*
* Inst is fcmp.
*
wrap_cmp:
	cmp.b	#$ff,DNRM_FLG(a6) ;if both ops denorm, 
	beq	fix_stk		 ;restore to fpu
*
* One of the ops is denormalized.  Test for wrap condition
* and complete the instruction.
*
	cmp.b	#$0f,DNRM_FLG(a6) ;check for dest denorm
	bne.b	cmp_srcd
cmp_destd:
	bsr.l	ckinf_ns
	bne	fix_stk
	bfextu	ETEMP_EX(a6){1:15},d0	;get src exp (always pos)
	bfexts	FPTEMP_EX(a6){1:15},d1	;get dest exp (always neg)
	sub.l	d1,d0			;subtract dest from src
	cmp.l	#$8000,d0
	blt	fix_stk			;if less, not wrap case
	tst.w	ETEMP_EX(a6)		;set N to ~sign_of(src)
	bge	cmp_setn
	rts
cmp_srcd:
	bsr.l	ckinf_nd
	bne	fix_stk
	bfextu	FPTEMP_EX(a6){1:15},d0	;get dest exp (always pos)
	bfexts	ETEMP_EX(a6){1:15},d1	;get src exp (always neg)
	sub.l	d1,d0			;subtract src from dest
	cmp.l	#$8000,d0
	blt	fix_stk			;if less, not wrap case
	tst.w	FPTEMP_EX(a6)		;set N to sign_of(dest)
	blt	cmp_setn
	rts
cmp_setn:
	or.l	#neg_mask,USER_FPSR(a6)
	rts

*
* Inst is fmul.
*
wrap_mul:
	cmp.b	#$ff,DNRM_FLG(a6) ;if both ops denorm, 
	beq	force_unf	;force an underflow (really!)
*
* One of the ops is denormalized.  Test for wrap condition
* and complete the instruction.
*
	cmp.b	#$0f,DNRM_FLG(a6) ;check for dest denorm
	bne.b	mul_srcd
mul_destd:
	bsr.l	ckinf_ns
	bne	fix_stk
	bfextu	ETEMP_EX(a6){1:15},d0	;get src exp (always pos)
	bfexts	FPTEMP_EX(a6){1:15},d1	;get dest exp (always neg)
	add.l	d1,d0			;subtract dest from src
	bgt	fix_stk
	bra	force_unf
mul_srcd:
	bsr.l	ckinf_nd
	bne	fix_stk
	bfextu	FPTEMP_EX(a6){1:15},d0	;get dest exp (always pos)
	bfexts	ETEMP_EX(a6){1:15},d1	;get src exp (always neg)
	add.l	d1,d0			;subtract src from dest
	bgt	fix_stk
	
*
* This code handles the case of the instruction resulting in 
* an underflow condition.
*
force_unf:
	bclr.b	#E1,E_BYTE(a6)
	or.l	#unfinx_mask,USER_FPSR(a6)
	clr.w	NMNEXC(a6)
	clr.b	WBTEMP_SGN(a6)
	move.w	ETEMP_EX(a6),d0		;find the sign of the result
	move.w	FPTEMP_EX(a6),d1
	eor.w	d1,d0
	andi.w	#$8000,d0
	beq.b	frcunfcont
	st.b	WBTEMP_SGN(a6)
frcunfcont:
	lea	WBTEMP(a6),a0		;point a0 to memory location
	move.w	CMDREG1B(a6),d0
	btst.l	#6,d0			;test for forced precision
	beq.b	frcunf_fpcr
	btst.l	#2,d0			;check for double
	bne.b	frcunf_dbl
	move.l	#$1,d0			;inst is forced single
	bra.b	frcunf_rnd
frcunf_dbl:
	move.l	#$2,d0			;inst is forced double
	bra.b	frcunf_rnd
frcunf_fpcr:
	bfextu	FPCR_MODE(a6){0:2},d0	;inst not forced - use fpcr prec
frcunf_rnd:
	bsr.l	unf_sub			;get correct result based on
*					;round precision/mode.  This 
*					;sets FPSR_CC correctly
	bfclr	WBTEMP_SGN(a6){0:8}	;convert back to IEEE ext format
	beq.b	frcfpn
	bset.b	#sign_bit,WBTEMP_EX(a6)
	bra	frcfpn

*
* Write the result to the user's fpn.  All results must be HUGE to be
* written; otherwise the results would have overflowed or underflowed.
* If the rounding precision is single or double, the ovf_res routine
* is needed to correctly supply the max value.
*
frcfpnr:
	move.w	CMDREG1B(a6),d0
	btst.l	#6,d0			;test for forced precision
	beq.b	frcfpn_fpcr
	btst.l	#2,d0			;check for double
	bne.b	frcfpn_dbl
	move.l	#$1,d0			;inst is forced single
	bra.b	frcfpn_rnd
frcfpn_dbl:
	move.l	#$2,d0			;inst is forced double
	bra.b	frcfpn_rnd
frcfpn_fpcr:
	bfextu	FPCR_MODE(a6){0:2},d0	;inst not forced - use fpcr prec
	tst.b	d0
	beq.b	frcfpn			;if extended, write what you got
frcfpn_rnd:
	bclr.b	#sign_bit,WBTEMP_EX(a6)
	sne	WBTEMP_SGN(a6)
	bsr.l	ovf_res			;get correct result based on
*					;round precision/mode.  This 
*					;sets FPSR_CC correctly
	bfclr	WBTEMP_SGN(a6){0:8}	;convert back to IEEE ext format
	beq.b	frcfpn_clr
	bset.b	#sign_bit,WBTEMP_EX(a6)
frcfpn_clr:
	or.l	#ovfinx_mask,USER_FPSR(a6)
* 
* Perform the write.
*
frcfpn:
	bfextu	CMDREG1B(a6){6:3},d0	;extract fp destination register
	cmpi.b	#3,d0
	ble.b	frc0123			;check if dest is fp0-fp3
	move.l	#7,d1
	sub.l	d0,d1
	clr.l	d0
	bset.l	d1,d0
	fmovem.x WBTEMP(a6),d0
	rts
frc0123:
	tst.b	d0
	beq.b	frc0_dst
	cmpi.b	#1,d0
	beq.b	frc1_dst 
	cmpi.b	#2,d0
	beq.b	frc2_dst 
frc3_dst:
	move.l	WBTEMP_EX(a6),USER_FP3(a6)
	move.l	WBTEMP_HI(a6),USER_FP3+4(a6)
	move.l	WBTEMP_LO(a6),USER_FP3+8(a6)
	rts
frc2_dst:
	move.l	WBTEMP_EX(a6),USER_FP2(a6)
	move.l	WBTEMP_HI(a6),USER_FP2+4(a6)
	move.l	WBTEMP_LO(a6),USER_FP2+8(a6)
	rts
frc1_dst:
	move.l	WBTEMP_EX(a6),USER_FP1(a6)
	move.l	WBTEMP_HI(a6),USER_FP1+4(a6)
	move.l	WBTEMP_LO(a6),USER_FP1+8(a6)
	rts
frc0_dst:
	move.l	WBTEMP_EX(a6),USER_FP0(a6)
	move.l	WBTEMP_HI(a6),USER_FP0+4(a6)
	move.l	WBTEMP_LO(a6),USER_FP0+8(a6)
	rts

*
* Write etemp to fpn.
* A check is made on enabled and signalled snan exceptions,
* and the destination is not overwritten if this condition exists.
* This code is designed to make fmoveins of unsupported data types
* faster.
*
wr_etemp:
	btst.b	#snan_bit,FPSR_EXCEPT(a6)	;if snan is set, and
	beq.b	fmoveinc		;enabled, force restore
	btst.b	#snan_bit,FPCR_ENABLE(a6) ;and don't overwrite
	beq.b	fmoveinc		;the dest
	move.l	ETEMP_EX(a6),FPTEMP_EX(a6)	;set up fptemp sign for 
*						;snan handler
	tst.b	ETEMP(a6)		;check for negative
	blt.b	snan_neg
	rts
snan_neg:
	or.l	#neg_bit,USER_FPSR(a6)	;snan is negative; set N
	rts
fmoveinc:
	clr.w	NMNEXC(a6)
	bclr.b	#E1,E_BYTE(a6)
	move.b	STAG(a6),d0		;check if stag is inf
	andi.b	#$e0,d0
	cmpi.b	#$40,d0
	bne.b	fminc_cnan
	or.l	#inf_mask,USER_FPSR(a6) ;if inf, nothing yet has set I
	tst.w	LOCAL_EX(a0)		;check sign
	bge.b	fminc_con
	or.l	#neg_mask,USER_FPSR(a6)
	bra	fminc_con
fminc_cnan:
	cmpi.b	#$60,d0			;check if stag is NaN
	bne.b	fminc_czero
	or.l	#nan_mask,USER_FPSR(a6) ;if nan, nothing yet has set NaN
	move.l	ETEMP_EX(a6),FPTEMP_EX(a6)	;set up fptemp sign for 
*						;snan handler
	tst.w	LOCAL_EX(a0)		;check sign
	bge.b	fminc_con
	or.l	#neg_mask,USER_FPSR(a6)
	bra	fminc_con
fminc_czero:
	cmpi.b	#$20,d0			;check if zero
	bne.b	fminc_con
	or.l	#z_mask,USER_FPSR(a6)	;if zero, set Z
	tst.w	LOCAL_EX(a0)		;check sign
	bge.b	fminc_con
	or.l	#neg_mask,USER_FPSR(a6)
fminc_con:
	bfextu	CMDREG1B(a6){6:3},d0	;extract fp destination register
	cmpi.b	#3,d0
	ble.b	fp0123			;check if dest is fp0-fp3
	move.l	#7,d1
	sub.l	d0,d1
	clr.l	d0
	bset.l	d1,d0
	fmovem.x ETEMP(a6),d0
	rts

fp0123:
	tst.b	d0
	beq.b	fp0_dst
	cmpi.b	#1,d0
	beq.b	fp1_dst 
	cmpi.b	#2,d0
	beq.b	fp2_dst 
fp3_dst:
	move.l	ETEMP_EX(a6),USER_FP3(a6)
	move.l	ETEMP_HI(a6),USER_FP3+4(a6)
	move.l	ETEMP_LO(a6),USER_FP3+8(a6)
	rts
fp2_dst:
	move.l	ETEMP_EX(a6),USER_FP2(a6)
	move.l	ETEMP_HI(a6),USER_FP2+4(a6)
	move.l	ETEMP_LO(a6),USER_FP2+8(a6)
	rts
fp1_dst:
	move.l	ETEMP_EX(a6),USER_FP1(a6)
	move.l	ETEMP_HI(a6),USER_FP1+4(a6)
	move.l	ETEMP_LO(a6),USER_FP1+8(a6)
	rts
fp0_dst:
	move.l	ETEMP_EX(a6),USER_FP0(a6)
	move.l	ETEMP_HI(a6),USER_FP0+4(a6)
	move.l	ETEMP_LO(a6),USER_FP0+8(a6)
	rts

opclass3:
	st.b	CU_ONLY(a6)
	move.w	CMDREG1B(a6),d0	;check if packed moveout
	andi.w	#$0c00,d0	;isolate last 2 bits of size field
	cmpi.w	#$0c00,d0	;if size is 011 or 111, it is packed
	beq.w	pack_out	;else it is norm or denorm
	bra.w	mv_out

	
*
*	MOVE OUT
*

mv_tbl:
	dc.l	li
	dc.l 	sgp
	dc.l 	xp
	dc.l 	mvout_end	;should never be taken
	dc.l 	wi
	dc.l 	dp
	dc.l 	bi
	dc.l 	mvout_end	;should never be taken
mv_out:
	bfextu	CMDREG1B(a6){3:3},d1	;put source specifier in d1
	lea.l	mv_tbl,a0
	move.l	(a0,d1*4),a0
	jmp	(a0)

*
* This exit is for move-out to memory.  The aunfl bit is 
* set if the result is inex and unfl is signalled.
*
mvout_end:
	btst.b	#inex2_bit,FPSR_EXCEPT(a6)
	beq.b	no_aufl
	btst.b	#unfl_bit,FPSR_EXCEPT(a6)
	beq.b	no_aufl
	bset.b	#aunfl_bit,FPSR_AEXCEPT(a6)
no_aufl:
	clr.w	NMNEXC(a6)
	bclr.b	#E1,E_BYTE(a6)
	fmove.l	#0,FPSR			;clear any cc bits from res_func
*
* Return ETEMP to extended format from internal extended format so
* that gen_except will have a correctly signed value for ovfl/unfl
* handlers.
*
	bfclr	ETEMP_SGN(a6){0:8}
	beq.b	mvout_con
	bset.b	#sign_bit,ETEMP_EX(a6)
mvout_con:
	rts
*
* This exit is for move-out to int register.  The aunfl bit is 
* not set in any case for this move.
*
mvouti_end:
	clr.w	NMNEXC(a6)
	bclr.b	#E1,E_BYTE(a6)
	fmove.l	#0,FPSR			;clear any cc bits from res_func
*
* Return ETEMP to extended format from internal extended format so
* that gen_except will have a correctly signed value for ovfl/unfl
* handlers.
*
	bfclr	ETEMP_SGN(a6){0:8}
	beq.b	mvouti_con
	bset.b	#sign_bit,ETEMP_EX(a6)
mvouti_con:
	rts
*
* li is used to handle a long integer source specifier
*

li:
	moveq.l	#4,d0		;set byte count

	btst.b	#7,STAG(a6)	;check for extended denorm
	bne.w	int_dnrm	;if so, branch

	fmovem.x ETEMP(a6),fp0
	fcmp.d	#:41dfffffffc00000,fp0
* 41dfffffffc00000 in dbl prec = 401d0000fffffffe00000000 in ext prec
	fbge.w	lo_plrg	
	fcmp.d	#:c1e0000000000000,fp0
* c1e0000000000000 in dbl prec = c01e00008000000000000000 in ext prec
	fble.w	lo_nlrg
*
* at this point, the answer is between the largest pos and neg values
*
	move.l	USER_FPCR(a6),d1	;use user's rounding mode
	andi.l	#$30,d1
	fmove.l	d1,fpcr
	fmove.l	fp0,L_SCR1(a6)	;let the 040 perform conversion
	fmove.l fpsr,d1
	or.l	d1,USER_FPSR(a6)	;capture inex2/ainex if set
	bra.w	int_wrt


lo_plrg:
	move.l	#$7fffffff,L_SCR1(a6)	;answer is largest positive int
	fbeq.w	int_wrt			;exact answer
	fcmp.d	#:41dfffffffe00000,fp0
* 41dfffffffe00000 in dbl prec = 401d0000ffffffff00000000 in ext prec
	fbge.w	int_operr		;set operr
	bra.w	int_inx			;set inexact

lo_nlrg:
	move.l	#$80000000,L_SCR1(a6)
	fbeq.w	int_wrt			;exact answer
	fcmp.d	#:c1e0000000100000,fp0
* c1e0000000100000 in dbl prec = c01e00008000000080000000 in ext prec
	fblt.w	int_operr		;set operr
	bra.w	int_inx			;set inexact

*
* wi is used to handle a word integer source specifier
*

wi:
	moveq.l	#2,d0		;set byte count

	btst.b	#7,STAG(a6)	;check for extended denorm
	bne.w	int_dnrm	;branch if so

	fmovem.x ETEMP(a6),fp0
	fcmp.s	#:46fffe00,fp0
* 46fffe00 in sgl prec = 400d0000fffe000000000000 in ext prec
	fbge.w	wo_plrg	
	fcmp.s	#:c7000000,fp0
* c7000000 in sgl prec = c00e00008000000000000000 in ext prec
	fble.w	wo_nlrg

*
* at this point, the answer is between the largest pos and neg values
*
	move.l	USER_FPCR(a6),d1	;use user's rounding mode
	andi.l	#$30,d1
	fmove.l	d1,fpcr
	fmove.w	fp0,L_SCR1(a6)	;let the 040 perform conversion
	fmove.l fpsr,d1
	or.l	d1,USER_FPSR(a6)	;capture inex2/ainex if set
	bra.w	int_wrt

wo_plrg:
	move.w	#$7fff,L_SCR1(a6)	;answer is largest positive int
	fbeq.w	int_wrt			;exact answer
	fcmp.s	#:46ffff00,fp0
* 46ffff00 in sgl prec = 400d0000ffff000000000000 in ext prec
	fbge.w	int_operr		;set operr
	bra.w	int_inx			;set inexact

wo_nlrg:
	move.w	#$8000,L_SCR1(a6)
	fbeq.w	int_wrt			;exact answer
	fcmp.s	#:c7000080,fp0
* c7000080 in sgl prec = c00e00008000800000000000 in ext prec
	fblt.w	int_operr		;set operr
	bra.w	int_inx			;set inexact

*
* bi is used to handle a byte integer source specifier
*

bi:
	moveq.l	#1,d0		;set byte count

	btst.b	#7,STAG(a6)	;check for extended denorm
	bne.w	int_dnrm	;branch if so

	fmovem.x ETEMP(a6),fp0
	fcmp.s	#:42fe0000,fp0
* 42fe0000 in sgl prec = 40050000fe00000000000000 in ext prec
	fbge.w	by_plrg	
	fcmp.s	#:c3000000,fp0
* c3000000 in sgl prec = c00600008000000000000000 in ext prec
	fble.w	by_nlrg

*
* at this point, the answer is between the largest pos and neg values
*
	move.l	USER_FPCR(a6),d1	;use user's rounding mode
	andi.l	#$30,d1
	fmove.l	d1,fpcr
	fmove.b	fp0,L_SCR1(a6)	;let the 040 perform conversion
	fmove.l fpsr,d1
	or.l	d1,USER_FPSR(a6)	;capture inex2/ainex if set
	bra.w	int_wrt

by_plrg:
	move.b	#$7f,L_SCR1(a6)		;answer is largest positive int
	fbeq.w	int_wrt			;exact answer
	fcmp.s	#:42ff0000,fp0
* 42ff0000 in sgl prec = 40050000ff00000000000000 in ext prec
	fbge.w	int_operr		;set operr
	bra.w	int_inx			;set inexact

by_nlrg:
	move.b	#$80,L_SCR1(a6)
	fbeq.w	int_wrt			;exact answer
	fcmp.s	#:c3008000,fp0
* c3008000 in sgl prec = c00600008080000000000000 in ext prec
	fblt.w	int_operr		;set operr
	bra.w	int_inx			;set inexact

*
* Common integer routines
*
* int_drnrm---account for possible nonzero result for round up with positive
* operand and round down for negative answer.  In the first case (result = 1)
* byte-width (store in d0) of result must be honored.  In the second case,
* -1 in L_SCR1(a6) will cover all contingencies (FMOVE.B/W/L out).

int_dnrm:
	clr.l	L_SCR1(a6)	; initialize result to 0
	bfextu	FPCR_MODE(a6){2:2},d1	; d1 is the rounding mode
	cmp.b	#2,d1		
	bmi.b	int_inx		; if RN or RZ, done
	bne.b	int_rp		; if RP, continue below
	tst.w	ETEMP(a6)	; RM: store -1 in L_SCR1 if src is negative
	bpl.b	int_inx		; otherwise result is 0
	move.l	#-1,L_SCR1(a6)
	bra.b	int_inx
int_rp:
	tst.w	ETEMP(a6)	; RP: store +1 of proper width in L_SCR1 if
*				; source is greater than 0
	bmi.b	int_inx		; otherwise, result is 0
	lea	L_SCR1(a6),a1	; a1 is address of L_SCR1
	adda.l	d0,a1		; offset by destination width -1
	suba.l	#1,a1		
	bset.b	#0,(a1)		; set low bit at a1 address
int_inx:
	ori.l	#inx2a_mask,USER_FPSR(a6)
	bra.b	int_wrt
int_operr:
	fmovem.x fp0,FPTEMP(a6)	;FPTEMP must contain the extended
*				;precision source that needs to be
*				;converted to integer this is required
*				;if the operr exception is enabled.
*				;set operr/aiop (no inex2 on int ovfl)

	ori.l	#opaop_mask,USER_FPSR(a6)
*				;fall through to perform int_wrt
int_wrt: 
	move.l	EXC_EA(a6),a1	;load destination address
	tst.l	a1		;check to see if it is a dest register
	beq.b	wrt_dn		;write data register 
	lea	L_SCR1(a6),a0	;point to supervisor source address
	bsr.l	mem_write
	bra.w	mvouti_end

wrt_dn:
	move.l	d0,-(sp)	;d0 currently contains the size to write
	bsr.l	get_fline	;get_fline returns Dn in d0
	andi.w	#$7,d0		;isolate register
	move.l	(sp)+,d1	;get size
	cmpi.l	#4,d1		;most frequent case
	beq.b	sz_long
	cmpi.l	#2,d1
	bne.b	sz_con
	or.l	#8,d0		;add 'word' size to register#
	bra.b	sz_con
sz_long:
	or.l	#$10,d0		;add 'long' size to register#
sz_con:
	move.l	d0,d1		;reg_dest expects size:reg in d1
	bsr.l	reg_dest	;load proper data register
	bra.w	mvouti_end 
xp:
	lea	ETEMP(a6),a0
	bclr.b	#sign_bit,LOCAL_EX(a0)
	sne	LOCAL_SGN(a0)
	btst.b	#7,STAG(a6)	;check for extended denorm
	bne.w	xdnrm
	clr.l	d0
	bra.b	do_fp		;do normal case
sgp:
	lea	ETEMP(a6),a0
	bclr.b	#sign_bit,LOCAL_EX(a0)
	sne	LOCAL_SGN(a0)
	btst.b	#7,STAG(a6)	;check for extended denorm
	bne.w	sp_catas	;branch if so
	move.w	LOCAL_EX(a0),d0
	lea	sp_bnds,a1
	cmp.w	(a1),d0
	blt.w	sp_under
	cmp.w	2(a1),d0
	bgt.w	sp_over
	move.l	#1,d0		;set destination format to single
	bra.b	do_fp		;do normal case
dp:
	lea	ETEMP(a6),a0
	bclr.b	#sign_bit,LOCAL_EX(a0)
	sne	LOCAL_SGN(a0)

	btst.b	#7,STAG(a6)	;check for extended denorm
	bne.w	dp_catas	;branch if so

	move.w	LOCAL_EX(a0),d0
	lea	dp_bnds,a1

	cmp.w	(a1),d0
	blt.w	dp_under
	cmp.w	2(a1),d0
	bgt.w	dp_over
	
	move.l	#2,d0		;set destination format to double
*				;fall through to do_fp
*
do_fp:
	bfextu	FPCR_MODE(a6){2:2},d1	;rnd mode in d1
	swap	d0			;rnd prec in upper word
	add.l	d0,d1			;d1 has PREC/MODE info
	
	clr.l	d0			;clear g,r,s 

	bsr.l	round			;round 

	move.l	a0,a1
	move.l	EXC_EA(a6),a0

	bfextu	CMDREG1B(a6){3:3},d1	;extract destination format
*					;at this point only the dest
*					;formats sgl, dbl, ext are
*					;possible
	cmp.b	#2,d1
	bgt.b	ddbl			;double=5, extended=2, single=1
	bne.b	dsgl
*					;fall through to dext
dext:
	bsr.l	dest_ext
	bra.w	mvout_end
dsgl:
	bsr.l	dest_sgl
	bra.w	mvout_end
ddbl:
	bsr.l	dest_dbl
	bra.w	mvout_end

*
* Handle possible denorm or catastrophic underflow cases here
*
xdnrm:
	bsr.w	set_xop		;initialize WBTEMP
	bset.b	#wbtemp15_bit,WB_BYTE(a6) ;set wbtemp15

	move.l	a0,a1
	move.l	EXC_EA(a6),a0	;a0 has the destination pointer
	bsr.l	dest_ext	;store to memory
	bset.b	#unfl_bit,FPSR_EXCEPT(a6)
	bra.w	mvout_end
	
sp_under:
	bset.b	#etemp15_bit,STAG(a6)

	cmp.w	4(a1),d0
	blt.b	sp_catas	;catastrophic underflow case	

	move.l	#1,d0		;load in round precision
	move.l	#sgl_thresh,d1	;load in single denorm threshold
	bsr.l	dpspdnrm	;expects d1 to have the proper
*				;denorm threshold
	bsr.l	dest_sgl	;stores value to destination
	bset.b	#unfl_bit,FPSR_EXCEPT(a6)
	bra.w	mvout_end	;exit

dp_under:
	bset.b	#etemp15_bit,STAG(a6)

	cmp.w	4(a1),d0
	blt.b	dp_catas	;catastrophic underflow case
		
	move.l	#dbl_thresh,d1	;load in double precision threshold
	move.l	#2,d0		
	bsr.l	dpspdnrm	;expects d1 to have proper
*				;denorm threshold
*				;expects d0 to have round precision
	bsr.l	dest_dbl	;store value to destination
	bset.b	#unfl_bit,FPSR_EXCEPT(a6)
	bra.w	mvout_end	;exit

*
* Handle catastrophic underflow cases here
*
sp_catas:
* Temp fix for z bit set in unf_sub
	move.l	USER_FPSR(a6),-(a7)

	move.l	#1,d0		;set round precision to sgl

	bsr.l	unf_sub		;a0 points to result

	move.l	(a7)+,USER_FPSR(a6)

	move.l	#1,d0
	sub.w	d0,LOCAL_EX(a0) ;account for difference between
*				;denorm/norm bias

	move.l	a0,a1		;a1 has the operand input
	move.l	EXC_EA(a6),a0	;a0 has the destination pointer
	
	bsr.l	dest_sgl	;store the result
	ori.l	#unfinx_mask,USER_FPSR(a6)
	bra.w	mvout_end
	
dp_catas:
* Temp fix for z bit set in unf_sub
	move.l	USER_FPSR(a6),-(a7)

	move.l	#2,d0		;set round precision to dbl
	bsr.l	unf_sub		;a0 points to result

	move.l	(a7)+,USER_FPSR(a6)

	move.l	#1,d0
	sub.w	d0,LOCAL_EX(a0) ;account for difference between 
*				;denorm/norm bias

	move.l	a0,a1		;a1 has the operand input
	move.l	EXC_EA(a6),a0	;a0 has the destination pointer
	
	bsr.l	dest_dbl	;store the result
	ori.l	#unfinx_mask,USER_FPSR(a6)
	bra.w	mvout_end

*
* Handle catastrophic overflow cases here
*
sp_over:
* Temp fix for z bit set in unf_sub
	move.l	USER_FPSR(a6),-(a7)

	move.l	#1,d0
	lea.l	FP_SCR1(a6),a0	;use FP_SCR1 for creating result
	move.l	ETEMP_EX(a6),(a0)
	move.l	ETEMP_HI(a6),4(a0)
	move.l	ETEMP_LO(a6),8(a0)
	bsr.l	ovf_res

	move.l	(a7)+,USER_FPSR(a6)

	move.l	a0,a1
	move.l	EXC_EA(a6),a0
	bsr.l	dest_sgl
	or.l	#ovfinx_mask,USER_FPSR(a6)
	bra.w	mvout_end

dp_over:
* Temp fix for z bit set in ovf_res
	move.l	USER_FPSR(a6),-(a7)

	move.l	#2,d0
	lea.l	FP_SCR1(a6),a0	;use FP_SCR1 for creating result
	move.l	ETEMP_EX(a6),(a0)
	move.l	ETEMP_HI(a6),4(a0)
	move.l	ETEMP_LO(a6),8(a0)
	bsr.l	ovf_res

	move.l	(a7)+,USER_FPSR(a6)

	move.l	a0,a1
	move.l	EXC_EA(a6),a0
	bsr.l	dest_dbl
	or.l	#ovfinx_mask,USER_FPSR(a6)
	bra.w	mvout_end

*
* 	DPSPDNRM
*
* This subroutine takes an extended normalized number and denormalizes
* it to the given round precision. This subroutine also decrements
* the input operand's exponent by 1 to account for the fact that
* dest_sgl or dest_dbl expects a normalized number's bias.
*
* Input: a0  points to a normalized number in internal extended format
*	 d0  is the round precision (=1 for sgl; =2 for dbl)
*	 d1  is the single precision or double precision
*	     denorm threshold
*
* Output: (In the format for dest_sgl or dest_dbl)
*	 a0   points to the destination
*   	 a1   points to the operand
*
* Exceptions: Reports inexact 2 exception by setting USER_FPSR bits
*
dpspdnrm:
	move.l	d0,-(a7)	;save round precision
	clr.l	d0		;clear initial g,r,s
	bsr.l	dnrm_lp		;careful with d0, it's needed by round

	bfextu	FPCR_MODE(a6){2:2},d1 ;get rounding mode
	swap	d1
	move.w	2(a7),d1	;set rounding precision 
	swap	d1		;at this point d1 has PREC/MODE info
	bsr.l	round		;round result, sets the inex bit in
*				;USER_FPSR if needed

	move.w	#1,d0
	sub.w	d0,LOCAL_EX(a0) ;account for difference in denorm
*				;vs norm bias

	move.l	a0,a1		;a1 has the operand input
	move.l	EXC_EA(a6),a0	;a0 has the destination pointer
	addq.l	#4,a7		;pop stack
	rts
*
* SET_XOP initialized WBTEMP with the value pointed to by a0
* input: a0 points to input operand in the internal extended format
*
set_xop:
	move.l	LOCAL_EX(a0),WBTEMP_EX(a6)
	move.l	LOCAL_HI(a0),WBTEMP_HI(a6)
	move.l	LOCAL_LO(a0),WBTEMP_LO(a6)
	bfclr	WBTEMP_SGN(a6){0:8}
	beq.b	sxop
	bset.b	#sign_bit,WBTEMP_EX(a6)
sxop:
	bfclr	STAG(a6){5:4}	;clear wbtm66,wbtm1,wbtm0,sbit
	rts
*
*	P_MOVE
*
p_movet:
	dc.l	p_move
	dc.l	p_movez
	dc.l	p_movei
	dc.l	p_moven
	dc.l	p_move
p_regd:
	dc.l	p_dyd0
	dc.l	p_dyd1
	dc.l	p_dyd2
	dc.l	p_dyd3
	dc.l	p_dyd4
	dc.l	p_dyd5
	dc.l	p_dyd6
	dc.l	p_dyd7

pack_out:
 	lea.l	p_movet,a0	;load jmp table address
	move.w	STAG(a6),d0	;get source tag
	bfextu	d0{16:3},d0	;isolate source bits
	move.l	(a0,d0.w*4),a0	;load a0 with routine label for tag
	jmp	(a0)		;go to the routine

p_write:
	move.l	#$0c,d0 	;get byte count
	move.l	EXC_EA(a6),a1	;get the destination address
	bsr 	mem_write	;write the user's destination
	clr.b	CU_SAVEPC(a6) ;set the cu save pc to all 0's

*
* Also note that the dtag must be set to norm here - this is because 
* the 040 uses the dtag to execute the correct microcode.
*
        bfclr    DTAG(a6){0:3}  ;set dtag to norm

	rts

* Notes on handling of special case (zero, inf, and nan) inputs:
*	1. Operr is not signalled if the k-factor is greater than 18.
*	2. Per the manual, status bits are not set.
*

p_move:
	move.w	CMDREG1B(a6),d0
	btst.l	#kfact_bit,d0	;test for dynamic k-factor
	beq.b	statick		;if clear, k-factor is static
dynamick:
	bfextu	d0{25:3},d0	;isolate register for dynamic k-factor
	lea	p_regd,a0
	move.l	(a0,d0*4),a0
	jmp	(a0)
statick:
	andi.w	#$007f,d0	;get k-factor
	bfexts	d0{25:7},d0	;sign extend d0 for bindec
	lea.l	ETEMP(a6),a0	;a0 will point to the packed decimal
	bsr.l	bindec		;perform the convert; data at a6
	lea.l	FP_SCR1(a6),a0	;load a0 with result address
	bra.l	p_write
p_movez:
	lea.l	ETEMP(a6),a0	;a0 will point to the packed decimal
	clr.w	2(a0)		;clear lower word of exp
	clr.l	4(a0)		;load second lword of ZERO
	clr.l	8(a0)		;load third lword of ZERO
	bra.w	p_write		;go write results
p_movei:
	fmove.l	#0,FPSR		;clear aiop
	lea.l	ETEMP(a6),a0	;a0 will point to the packed decimal
	clr.w	2(a0)		;clear lower word of exp
	bra.w	p_write		;go write the result
p_moven:
	lea.l	ETEMP(a6),a0	;a0 will point to the packed decimal
	clr.w	2(a0)		;clear lower word of exp
	bra.w	p_write		;go write the result

*
* Routines to read the dynamic k-factor from Dn.
*
p_dyd0:
	move.l	USER_D0(a6),d0
	bra.b	statick
p_dyd1:
	move.l	USER_D1(a6),d0
	bra.b	statick
p_dyd2:
	move.l	d2,d0
	bra.b	statick
p_dyd3:
	move.l	d3,d0
	bra.b	statick
p_dyd4:
	move.l	d4,d0
	bra.b	statick
p_dyd5:
	move.l	d5,d0
	bra.b	statick
p_dyd6:
	move.l	d6,d0
	bra.w	statick
p_dyd7:
	move.l	d7,d0
	bra.w	statick

	end