head     56.3;
access   ;
symbols  ;
locks    ; strict;
comment  @# @;


56.3
date     93.01.27.13.56.38;  author jwh;  state Exp;
branches ;
next     56.2;

56.2
date     93.01.27.12.28.19;  author jwh;  state Exp;
branches ;
next     56.1;

56.1
date     91.11.07.12.29.25;  author jwh;  state Exp;
branches ;
next     1.1;

1.1
date     91.03.13.08.48.02;  author jwh;  state Exp;
branches ;
next     ;


desc
@@


56.3
log
@
pws2rcs automatic delta on Wed Jan 27 13:14:25 MST 1993
@
text
@*
*       res_func.sa 3.1 12/10/90
*
* 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.
*
*
*               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.


* added to replace single-precision floating point immediates JWH 1/10/91

V46fffe00  DC.L  $46fffe00
V46ffff00  DC.L  $46ffff00
Vc7000080  DC.L  $c7000080
V42fe0000  DC.L  $42fe0000
Vc3000000  DC.L  $c3000000
V42ff0000  DC.L  $42ff0000
Vc3008000  DC.L  $c3008000
Vc7000000  DC.L  $c7000000
V41dfffffffc00000 DC.L  $41dfffff,$ffc00000
Vc1e0000000000000 DC.L  $c1e00000,$00000000
Vc1e0000000100000 DC.L  $c1e00000,$00100000
V41dfffffffe00000 DC.L  $41dfffff,$ffe00000

	include fpsp_h

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

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

	def     res_func
	def     p_move

res_func    equ    *
	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    equ    *
	btst    #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     FPTEMP(a6),a0

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

	bsr     nrm_set         ;normalize number (exp will go negative)
	bclr    #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    #sign_bit,LOCAL_EX(a0)
dpos    equ    *
	bfclr   DTAG(a6){0:4}   ;set tag to normalized, FPTE15 = 0
	bset    #4,DTAG(a6)     ;set FPTE15
	ori.b   #$0f,DNRM_FLG(a6)
monadic    equ    *
	lea     ETEMP(a6),a0
	btst    #direction_bit,CMDREG1B(a6)     ;check direction
	bne.w   opclass3                        ;it is a mv out
*
* At this point, only oplcass 0 and 2 possible
*
	btst    #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    #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    equ    *
	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    equ    *
	move.w  LOCAL_EX(a0),d0
	bclr    #15,d0
	sne     LOCAL_SGN(a0)
	beq.b   cu_ntpo
	ori.l   #neg_mask,USER_FPSTATUS(a6) ;set N
cu_ntpo    equ    *
	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
	ori.l   #inf_mask,USER_FPSTATUS(a6)
	rts
cu_ntn    equ    *
	ori.l   #nan_mask,USER_FPSTATUS(a6)
	move.l  ETEMP_EX(a6),FPTEMP_EX(a6)      ;set up fptemp sign for
*                                               ;snan handler

	rts
cu_ntcz    equ    *
	tst.l   LOCAL_HI(a0)
	bne.l   cu_ntsx
	tst.l   LOCAL_LO(a0)
	bne.l   cu_ntsx
	ori.l   #z_mask,USER_FPSTATUS(a6)
cu_ntsx    equ    *
	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    equ    *
	move.b  STAG(a6),d0
	btst    #5,d0                   ;test for NaN or zero
	bne     wr_etemp                ;if either, simply write it
	bclr    #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    equ    *
	move.b  STAG(a6),d0
	btst    #5,d0                   ;test for NaN or zero
	bne     wr_etemp                ;if either, simply write it
	bchg    #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 FPCONTROL.  If the rounding precision
* is double or single, round the result before the write.
*
cu_nmove    equ    *
	move.b  STAG(a6),d0
	andi.b  #$e0,d0                 ;isolate stag bits
	bne     wr_etemp                ;if not norm, simply write it
	btst    #2,CMDREG1B+1(a6)       ;check for rd
	bne     cu_nmrd
	btst    #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
* FPCONTROL_MODE byte to get rounding on norms and zeros.
*
cu_nmnr    equ    *
	bfextu  FPCONTROL_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    equ    *
	bfextu  FPCONTROL_MODE(a6){2:2},d1      ;get rmode
	or.l    #$00020000,d1           ;force double
	clr.l   d0                      ;clr grs for round
	bclr    #sign_bit,LOCAL_EX(a0)
	sne     LOCAL_SGN(a0)
	bsr.l   round                   ;perform the round
	bfclr   LOCAL_SGN(a0){0:8}
	beq.b   cu_nmrdc
	bset    #sign_bit,LOCAL_EX(a0)
cu_nmrdc    equ    *
	move.l  #2,d0                   ;set up size for denorm
	move.w  LOCAL_EX(a0),d1
	and.w   #$7FFF,d1
	cmp.w   #$3c01,d1
	bls     cu_nunfl
	cmp.w   #$43ff,d1
	bge     cu_novfl
	bra.w   cu_wrexn
*
* The move is fsmove or round precision is single.
*
cu_nmrs    equ    *
	bfextu  FPCONTROL_MODE(a6){2:2},d1      ;get rmode
	or.l    #$00010000,d1           ;force single
	clr.l   d0                      ;clr grs for round
	bclr    #sign_bit,LOCAL_EX(a0)
	sne     LOCAL_SGN(a0)
	bsr.l   round                   ;perform the round
	bfclr   LOCAL_SGN(a0){0:8}
	beq.b   cu_nmrsc
	bset    #sign_bit,LOCAL_EX(a0)
cu_nmrsc    equ    *
	move.l  #1,d0                   ;set up size for denorm
	move.w  LOCAL_EX(a0),d1
	and.w   #$7FFF,d1
	cmp.w   #$3f81,d1
	bls     cu_nunfl
	cmp.w   #$407f,d1
	blt     cu_wrexn
*
* The operand is above precision boundaries.  Use t_ovfl to
* generate the correct value.
*
cu_novfl    equ    *
	bsr     t_ovfl
	bra     cu_wrexn
*
* The operand is below precision boundaries.  Use denorm to
* generate the correct value.
*
cu_nunfl    equ    *
	bclr    #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_nuflp
	bset    #sign_bit,LOCAL_EX(a0)
cu_nuflp    equ    *
	btst    #inex2_bit,FPSTATUS_EXCEPT(a6)
	beq.b   cu_nuninx
	ori.l   #aunfl_mask,USER_FPSTATUS(a6) ;if the round was inex, set AUNFL
cu_nuninx    equ    *
	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 occured which would leave the lsb.
*
	move.l  USER_FPCONTROL(a6),d0
	andi.l  #$30,d0         ;isolate rmode
	cmpi.l  #$20,d0
	blt.b   cu_nzro
	bne.b   cu_nrp
cu_nrm    equ    *
	tst.w   LOCAL_EX(a0)    ;if positive, set lsb
	bge.b   cu_nzro
	btst    #7,FPCONTROL_MODE(a6) ;check for double
	beq.b   cu_nincs
	bra.b   cu_nincd
cu_nrp    equ    *
	tst.w   LOCAL_EX(a0)    ;if positive, set lsb
	blt.b   cu_nzro
	btst    #7,FPCONTROL_MODE(a6) ;check for double
	beq.b   cu_nincs
cu_nincd    equ    *
	ori.l   #$800,LOCAL_HI(a0) ;inc for double
	bra     cu_nunzro
cu_nincs    equ    *
	ori.l   #$100,LOCAL_HI(a0) ;inc for single
	bra     cu_nunzro
cu_nzro    equ    *
	ori.l   #z_mask,USER_FPSTATUS(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    equ    *
	ori.l   #unfl_mask,USER_FPSTATUS(a6) ;set unfl
cu_numv    equ    *
	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 FPSTATUS cc bits.  NaN and Inf
* bypass cu_wrexn.
*
cu_wrexn    equ    *
	tst.w   LOCAL_EX(a0)            ;test for zero
	beq.b   cu_wrzero
	cmpi.w  #$8000,LOCAL_EX(a0)     ;test for zero
	bne.b   cu_wreon
cu_wrzero    equ    *
	ori.l   #z_mask,USER_FPSTATUS(a6)       ;set Z bit
cu_wreon    equ    *
	tst.w   LOCAL_EX(a0)
	bpl     wr_etemp
	ori.l   #neg_mask,USER_FPSTATUS(a6)
	bra     wr_etemp

*
* HANDLE SOURCE DENORM HERE
*
*                               ;clear denorm stag to norm
*                               ;write the new tag & ete15 to the fstack
mon_dnrm    equ    *
*
* 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    #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    equ    *
	bclr    #sign_bit,LOCAL_EX(a0)
	sne     LOCAL_SGN(a0)
	bsr     nrm_set         ;normalize number (exponent will go
*                               ; negative)
	bclr    #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    #sign_bit,LOCAL_EX(a0)
spos    equ    *
	bfclr   STAG(a6){0:4}   ;set tag to normalized, FPTE15 = 0
	bset    #4,STAG(a6)     ;set ETE15
	ori.b   #$f0,DNRM_FLG(a6)
normal    equ    *
	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    equ    *
	move.b  #$fe,CU_SAVEPC(a6)
	bclr    #E1,E_BYTE(a6)

	clr.w   NMNEXC(a6)

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

*
* cu_dnrm handles all cu-only instructions (fmove, fabs, fneg, and
* ftst) completly in software without an frestore to the 040.
*
cu_dnrm    equ    *
	st      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    equ    *
	move.w  LOCAL_EX(a0),d0
	bclr    #15,d0
	sne     LOCAL_SGN(a0)
	beq.b   cu_dtpo
	ori.l   #neg_mask,USER_FPSTATUS(a6) ;set N
cu_dtpo    equ    *
	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
	ori.l   #inf_mask,USER_FPSTATUS(a6)
	rts
cu_dtn    equ    *
	ori.l   #nan_mask,USER_FPSTATUS(a6)
	move.l  ETEMP_EX(a6),FPTEMP_EX(a6)      ;set up fptemp sign for
*                                               ;snan handler
	rts
cu_dtcz    equ    *
	tst.l   LOCAL_HI(a0)
	bne.l   cu_dtsx
	tst.l   LOCAL_LO(a0)
	bne.l   cu_dtsx
	ori.l   #z_mask,USER_FPSTATUS(a6)
cu_dtsx    equ    *
	rts
*
* Inst is fabs.  Execute the absolute value function on the input.
* Branch to the fmove code.
*
cu_dabs    equ    *
	bclr    #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    equ    *
	bchg    #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 FPCONTROL.  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    equ    *
	btst    #2,CMDREG1B+1(a6)       ;check for rd
	bne     cu_dmrd
	btst    #6,CMDREG1B+1(a6)       ;check for rs
	bne     cu_dmrs
*
* The move or operation is not with forced precision.  Use the
* FPCONTROL_MODE byte to get rounding.
*
cu_dmnr    equ    *
	bfextu  FPCONTROL_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    equ    *
	bfextu  FPCONTROL_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    equ    *
	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    equ    *
	bfextu  FPCONTROL_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    equ    *
	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    equ    *
	ori.l   #unfl_mask,USER_FPSTATUS(a6)
	tst.w   LOCAL_EX(a0)
	beq     wr_etemp
	ori.l   #neg_mask,USER_FPSTATUS(a6)
	bra     wr_etemp
*
* These routines write +/- zero in double format.  The routines
* cu_dpdr and cu_dndr set the double lsb.
*
cu_dpd    equ    *
	move.l  #$3c010000,LOCAL_EX(a0) ;force pos double zero
	clr.l   LOCAL_HI(a0)
	clr.l   LOCAL_LO(a0)
	ori.l   #z_mask,USER_FPSTATUS(a6)
	ori.l   #unfinx_mask,USER_FPSTATUS(a6)
	bra     wr_etemp
cu_dpdr    equ    *
	move.l  #$3c010000,LOCAL_EX(a0) ;force pos double zero
	clr.l   LOCAL_HI(a0)
	move.l  #$800,LOCAL_LO(a0)      ;with lsb set
	ori.l   #unfinx_mask,USER_FPSTATUS(a6)
	bra     wr_etemp
cu_dnd    equ    *
	move.l  #$bc010000,LOCAL_EX(a0) ;force pos double zero
	clr.l   LOCAL_HI(a0)
	clr.l   LOCAL_LO(a0)
	ori.l   #z_mask,USER_FPSTATUS(a6)
	ori.l   #neg_mask,USER_FPSTATUS(a6)
	ori.l   #unfinx_mask,USER_FPSTATUS(a6)
	bra     wr_etemp
cu_dndr    equ    *
	move.l  #$bc010000,LOCAL_EX(a0) ;force pos double zero
	clr.l   LOCAL_HI(a0)
	move.l  #$800,LOCAL_LO(a0)      ;with lsb set
	ori.l   #neg_mask,USER_FPSTATUS(a6)
	ori.l   #unfinx_mask,USER_FPSTATUS(a6)
	bra     wr_etemp
*
* These routines write +/- zero in single format.  The routines
* cu_dpdr and cu_dndr set the single lsb.
*
cu_spd    equ    *
	move.l  #$3f810000,LOCAL_EX(a0) ;force pos single zero
	clr.l   LOCAL_HI(a0)
	clr.l   LOCAL_LO(a0)
	ori.l   #z_mask,USER_FPSTATUS(a6)
	ori.l   #unfinx_mask,USER_FPSTATUS(a6)
	bra     wr_etemp
cu_spdr    equ    *
	move.l  #$3f810000,LOCAL_EX(a0) ;force pos single zero
	move.l  #$100,LOCAL_HI(a0)      ;with lsb set
	clr.l   LOCAL_LO(a0)
	ori.l   #unfinx_mask,USER_FPSTATUS(a6)
	bra     wr_etemp
cu_snd    equ    *
	move.l  #$bf810000,LOCAL_EX(a0) ;force pos single zero
	clr.l   LOCAL_HI(a0)
	clr.l   LOCAL_LO(a0)
	ori.l   #z_mask,USER_FPSTATUS(a6)
	ori.l   #neg_mask,USER_FPSTATUS(a6)
	ori.l   #unfinx_mask,USER_FPSTATUS(a6)
	bra     wr_etemp
cu_sndr    equ    *
	move.l  #$bf810000,LOCAL_EX(a0) ;force pos single zero
	move.l  #$100,LOCAL_HI(a0)      ;with lsb set
	clr.l   LOCAL_LO(a0)
	ori.l   #neg_mask,USER_FPSTATUS(a6)
	ori.l   #unfinx_mask,USER_FPSTATUS(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    equ    *
	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    equ    *
	cmpi.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.
*
	cmpi.b  #$0f,DNRM_FLG(a6) ;check for dest denorm
	bne.b   div_srcd
div_destd    equ    *
	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
	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      WBTEMP_SGN(a6)
	bra     force_unf
div_srcd    equ    *
	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      WBTEMP_SGN(a6)
*
* This code handles the case of the instruction resulting in
* an overflow condition.
*
force_ovf    equ    *
	bclr    #E1,E_BYTE(a6)
	ori.l   #ovfl_inx_mask,USER_FPSTATUS(a6)
	clr.w   NMNEXC(a6)
	lea     WBTEMP(a6),a0           ;point a0 to memory location
	move.w  CMDREG1B(a6),d0
	btst    #6,d0                   ;test for forced precision
	beq.b   frcovf_FPCONTROL
	btst    #2,d0                   ;check for double
	bne.b   frcovf_dbl
	move.l  #$1,d0                  ;inst is forced single
	bra.b   frcovf_rnd
frcovf_dbl    equ    *
	move.l  #$2,d0                  ;inst is forced double
	bra.b   frcovf_rnd
frcovf_FPCONTROL    equ    *
	bfextu  FPCONTROL_MODE(a6){0:2},d0      ;inst not forced - use FPCONTROL prec
frcovf_rnd    equ    *
	tst.b   d0
	beq.b   frcovf_x
	ori.l   #inex2_mask,USER_FPSTATUS(a6) ;if prec is s or d, set inex2
frcovf_x    equ    *
	bsr.l   ovf_res                 ;get correct result based on
*                                       ;round precision/mode.  This
*                                       ;sets FPSTATUS_CC correctly
*                                       ;returns in external format
	bfclr   WBTEMP_SGN(a6){0:8}
	beq     frcfpn
	bset    #sign_bit,WBTEMP_EX(a6)
	bra     frcfpn
*
* Inst is fadd.
*
wrap_add    equ    *
	cmpi.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.
*
	cmpi.b  #$0f,DNRM_FLG(a6) ;check for dest denorm
	bne.b   add_srcd
add_destd    equ    *
	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    equ    *
	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    equ    *
	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.
*
	cmpi.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_FPCONTROL(a6),d0
	andi.l  #$30,d0
	fmove.l d0,FPCONTROL            ;set up users rmode and X
	fmove.x ETEMP(a6),fp0
	fadd.x  FPTEMP(a6),fp0
	lea     WBTEMP(a6),a0   ;point a0 to wbtemp in frame
	fmove.l FPSTATUS,d1
	or.l    d1,USER_FPSTATUS(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_FPCONTROL(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    #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    #sign_bit,WBTEMP_EX(a6)
	bra     frcfpnr
add_u_srcd    equ    *
	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_FPCONTROL(a6),d0
	andi.l  #$30,d0
	fmove.l d0,FPCONTROL            ;set up users rmode and X
	fmove.x ETEMP(a6),fp0
	fadd.x  FPTEMP(a6),fp0
	fmove.l FPSTATUS,d1
	or.l    d1,USER_FPSTATUS(a6) ;capture cc's and inex from fadd
	lea     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_FPCONTROL(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    #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    #sign_bit,WBTEMP_EX(a6)
	bra     frcfpnr
*
* Signs are alike:
*
add_same    equ    *
	cmpi.b  #$0f,DNRM_FLG(a6) ;is dest the denorm?
	bne.b   add_s_srcd
add_s_destd    equ    *
	lea     ETEMP(a6),a0
	move.l  USER_FPCONTROL(a6),d0
	andi.l  #$30,d0
	lsr.l   #4,d0           ;put rmode in lower 2 bits
	move.l  USER_FPCONTROL(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    #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    #sign_bit,ETEMP_EX(a6)
add_s_dclr    equ    *
	lea     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
	ori.l   #neg_mask,USER_FPSTATUS(a6)
	bra     add_ckovf
add_s_srcd    equ    *
	lea     FPTEMP(a6),a0
	move.l  USER_FPCONTROL(a6),d0
	andi.l  #$30,d0
	lsr.l   #4,d0           ;put rmode in lower 2 bits
	move.l  USER_FPCONTROL(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    #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    #sign_bit,FPTEMP_EX(a6)
add_s_sclr    equ    *
	lea     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
	ori.l   #neg_mask,USER_FPSTATUS(a6)
add_ckovf    equ    *
	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.)
*
	ori.l   #inf_mask+ovfl_inx_mask,USER_FPSTATUS(a6)
	clr.l   4(a0)
	bra     frcfpnr
*
* Inst is fsub.
*
wrap_sub    equ    *
	cmpi.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.
*
	cmpi.b  #$0f,DNRM_FLG(a6) ;check for dest denorm
	bne.b   sub_srcd
sub_destd    equ    *
	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    equ    *
	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    equ    *
	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.
*
	cmpi.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_FPCONTROL(a6),d0
	andi.l  #$30,d0
	fmove.l d0,FPCONTROL            ;set up users rmode and X
	fmove.x FPTEMP(a6),fp0
	fsub.x  ETEMP(a6),fp0
	fmove.l FPSTATUS,d1
	or.l    d1,USER_FPSTATUS(a6) ;capture cc's and inex from fadd
	lea     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_FPCONTROL(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    #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    #sign_bit,WBTEMP_EX(a6)
	bra     frcfpnr
sub_u_srcd    equ    *
	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_FPCONTROL(a6),d0
	andi.l  #$30,d0
	fmove.l d0,FPCONTROL            ;set up users rmode and X
	fmove.x FPTEMP(a6),fp0
	fsub.x  ETEMP(a6),fp0
	fmove.l FPSTATUS,d1
	or.l    d1,USER_FPSTATUS(a6) ;capture cc's and inex from fadd
	lea     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_FPCONTROL(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    #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    #sign_bit,WBTEMP_EX(a6)
	bra     frcfpnr
*
* Signs are unlike:
*
sub_diff    equ    *
	cmpi.b  #$0f,DNRM_FLG(a6) ;is dest the denorm?
	bne.b   sub_s_srcd
sub_s_destd    equ    *
	lea     ETEMP(a6),a0
	move.l  USER_FPCONTROL(a6),d0
	andi.l  #$30,d0
	lsr.l   #4,d0           ;put rmode in lower 2 bits
	move.l  USER_FPCONTROL(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
	ori.l   #neg_mask,USER_FPSTATUS(a6)
sub_s_dwr    equ    *
	bclr    #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    #sign_bit,ETEMP_EX(a6)
sub_s_dclr    equ    *
	lea     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    equ    *
	lea     FPTEMP(a6),a0
	move.l  USER_FPCONTROL(a6),d0
	andi.l  #$30,d0
	lsr.l   #4,d0           ;put rmode in lower 2 bits
	move.l  USER_FPCONTROL(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    #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    #sign_bit,FPTEMP_EX(a6)
sub_s_sclr    equ    *
	lea     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
	ori.l   #neg_mask,USER_FPSTATUS(a6)
sub_ckovf    equ    *
	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.)
*
	ori.l   #inf_mask+ovfl_inx_mask,USER_FPSTATUS(a6)
	clr.l   4(a0)
	bra     frcfpnr
*
* Inst is fcmp.
*
wrap_cmp    equ    *
	cmpi.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.
*
	cmpi.b  #$0f,DNRM_FLG(a6) ;check for dest denorm
	bne.b   cmp_srcd
cmp_destd    equ    *
	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    equ    *
	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    equ    *
	ori.l   #neg_mask,USER_FPSTATUS(a6)
	rts

*
* Inst is fmul.
*
wrap_mul    equ    *
	cmpi.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.
*
	cmpi.b  #$0f,DNRM_FLG(a6) ;check for dest denorm
	bne.b   mul_srcd
mul_destd    equ    *
	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    equ    *
	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    equ    *
	bclr    #E1,E_BYTE(a6)
	ori.l   #unfinx_mask,USER_FPSTATUS(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      WBTEMP_SGN(a6)
frcunfcont    equ    *
	lea     WBTEMP(a6),a0           ;point a0 to memory location
	btst    #6,d0                   ;test for forced precision
	beq.b   frcunf_FPCONTROL
	btst    #2,d0                   ;check for double
	bne.b   frcunf_dbl
	move.l  #$1,d0                  ;inst is forced single
	bra.b   frcunf_rnd
frcunf_dbl    equ    *
	move.l  #$2,d0                  ;inst is forced double
	bra.b   frcunf_rnd
frcunf_FPCONTROL    equ    *
	bfextu  FPCONTROL_MODE(a6){0:2},d0      ;inst not forced - use FPCONTROL prec
frcunf_rnd    equ    *
	bsr.l   unf_sub                 ;get correct result based on
*                                       ;round precision/mode.  This
*                                       ;sets FPSTATUS_CC correctly
	bfclr   WBTEMP_SGN(a6){0:8}     ;convert back to IEEE ext format
	beq.b   frcfpn
	bset    #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    equ    *
	move.w  CMDREG1B(a6),d0
	btst    #6,d0                   ;test for forced precision
	beq.b   frcfpn_FPCONTROL
	btst    #2,d0                   ;check for double
	bne.b   frcfpn_dbl
	move.l  #$1,d0                  ;inst is forced single
	bra.b   frcfpn_rnd
frcfpn_dbl    equ    *
	move.l  #$2,d0                  ;inst is forced double
	bra.b   frcfpn_rnd
frcfpn_FPCONTROL    equ    *
	bfextu  FPCONTROL_MODE(a6){0:2},d0      ;inst not forced - use FPCONTROL prec
	tst.b   d0
	beq.b   frcfpn                  ;if extended, write what you got
frcfpn_rnd    equ    *
	bclr    #sign_bit,WBTEMP_EX(a6)
	sne     WBTEMP_SGN(a6)
	bsr.l   ovf_res                 ;get correct result based on
*                                       ;round precision/mode.  This
*                                       ;sets FPSTATUS_CC correctly
	bfclr   WBTEMP_SGN(a6){0:8}     ;convert back to IEEE ext format
	beq.b   frcfpn_clr
	bset    #sign_bit,WBTEMP_EX(a6)
frcfpn_clr    equ    *
	ori.l   #ovfinx_mask,USER_FPSTATUS(a6)
*
* Perform the write.
*
frcfpn    equ    *
	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    d1,d0
	fmovem.x WBTEMP(a6),d0
	rts
frc0123    equ    *
	cmpi.b  #0,d0
	beq.b   frc0_dst
	cmpi.b  #1,d0
	beq.b   frc1_dst
	cmpi.b  #2,d0
	beq.b   frc2_dst
frc3_dst    equ    *
	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    equ    *
	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    equ    *
	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    equ    *
	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    equ    *
	btst    #snan_bit,FPSTATUS_EXCEPT(a6)   ;if snan is set, and
	beq.b   fmoveinc                ;enabled, force restore
	btst    #snan_bit,FPCONTROL_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    equ    *
	ori.l   #neg_bit,USER_FPSTATUS(a6)      ;snan is negative; set N
	rts
fmoveinc    equ    *
	clr.w   NMNEXC(a6)
	bclr    #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
	ori.l   #inf_mask,USER_FPSTATUS(a6) ;if inf, nothing yet has set I
	tst.w   LOCAL_EX(a0)            ;check sign
	bge.b   fminc_con
	ori.l   #neg_mask,USER_FPSTATUS(a6)
	bra     fminc_con
fminc_cnan    equ    *
	cmpi.b  #$60,d0                 ;check if stag is NaN
	bne.b   fminc_czero
	ori.l   #nan_mask,USER_FPSTATUS(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
	ori.l   #neg_mask,USER_FPSTATUS(a6)
	bra     fminc_con
fminc_czero    equ    *
	cmpi.b  #$20,d0                 ;check if zero
	bne.b   fminc_con
	ori.l   #z_mask,USER_FPSTATUS(a6)       ;if zero, set Z
	tst.w   LOCAL_EX(a0)            ;check sign
	bge.b   fminc_con
	ori.l   #neg_mask,USER_FPSTATUS(a6)
fminc_con    equ    *
	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    d1,d0
	fmovem.x ETEMP(a6),d0
	rts

fp0123    equ    *
	cmpi.b  #0,d0
	beq.b   fp0_dst
	cmpi.b  #1,d0
	beq.b   fp1_dst
	cmpi.b  #2,d0
	beq.b   fp2_dst
fp3_dst    equ    *
	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    equ    *
	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    equ    *
	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    equ    *
	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    equ    *
	st      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    equ    *
	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    equ    *
	bfextu  CMDREG1B(a6){3:3},d1    ;put source specifier in d1
	lea     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    equ    *
	btst    #inex2_bit,FPSTATUS_EXCEPT(a6)
	beq.b   no_aufl
	btst    #unfl_bit,FPSTATUS_EXCEPT(a6)
	beq.b   no_aufl
	bset    #aunfl_bit,FPSTATUS_AEXCEPT(a6)
no_aufl    equ    *
	clr.w   NMNEXC(a6)
	bclr    #E1,E_BYTE(a6)
	fmove.l #0,FPSTATUS                     ;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    #sign_bit,ETEMP_EX(a6)
mvout_con    equ    *
	rts
*
* This exit is for move-out to int register.  The aunfl bit is
* not set in any case for this move.
*
mvouti_end    equ    *
	clr.w   NMNEXC(a6)
	bclr    #E1,E_BYTE(a6)
	fmove.l #0,FPSTATUS                     ;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    #sign_bit,ETEMP_EX(a6)
mvouti_con    equ    *
	rts
*
* li is used to handle a long integer source specifier
*

li    equ    *
	moveq   #4,d0           ;set byte count

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

	fmovem.x ETEMP(a6),fp0
*       fcmp.d  #:41dfffffffc00000,fp0
	fcmp.d  V41dfffffffc00000,fp0
* 41dfffffffc00000 in dbl prec = 401d0000fffffffe00000000 in ext prec
	fbge.w  lo_plrg
*       fcmp.d  #:c1e0000000000000,fp0
	fcmp.d  Vc1e0000000000000,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_FPCONTROL(a6),d1   ;use user's rounding mode
	andi.l  #$30,d1
	fmove.l d1,FPCONTROL
	fmove.l fp0,L_SCR1(a6)  ;let the 040 perform conversion
	fmove.l FPSTATUS,d1
	or.l    d1,USER_FPSTATUS(a6)    ;capture inex2/ainex if set
	bra.w   int_wrt


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

lo_nlrg    equ    *
	move.l  #$80000000,L_SCR1(a6)
	fbeq.w  int_wrt                 ;exact answer
*       fcmp.d  #:c1e0000000100000,fp0
	fcmp.d  Vc1e0000000100000,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    equ    *
	moveq   #2,d0           ;set byte count

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

	fmovem.x ETEMP(a6),fp0
*       fcmp.s  #:46fffe00,fp0
	fcmp.s  V46fffe00,fp0
* 46fffe00 in sgl prec = 400d0000fffe000000000000 in ext prec
	fbge.w  wo_plrg
*       fcmp.s  #:c7000000,fp0
	fcmp.s  Vc7000000,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_FPCONTROL(a6),d1   ;use user's rounding mode
	andi.l  #$30,d1
	fmove.l d1,FPCONTROL
	fmove.w fp0,L_SCR1(a6)  ;let the 040 perform conversion
	fmove.l FPSTATUS,d1
	or.l    d1,USER_FPSTATUS(a6)    ;capture inex2/ainex if set
	bra.w   int_wrt

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

wo_nlrg    equ    *
	move.w  #$8000,L_SCR1(a6)
	fbeq.w  int_wrt                 ;exact answer
*       fcmp.s  #:c7000080,fp0
	fcmp.s  Vc7000080,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    equ    *
	moveq   #1,d0           ;set byte count

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

	fmovem.x ETEMP(a6),fp0
*       fcmp.s  #:42fe0000,fp0
	fcmp.s  V42fe0000,fp0
* 42fe0000 in sgl prec = 40050000fe00000000000000 in ext prec
	fbge.w  by_plrg
*       fcmp.s  #:c3000000,fp0
	fcmp.s  Vc3000000,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_FPCONTROL(a6),d1   ;use user's rounding mode
	andi.l  #$30,d1
	fmove.l d1,FPCONTROL
	fmove.b fp0,L_SCR1(a6)  ;let the 040 perform conversion
	fmove.l FPSTATUS,d1
	or.l    d1,USER_FPSTATUS(a6)    ;capture inex2/ainex if set
	bra.w   int_wrt

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

by_nlrg    equ    *
	move.b  #$80,L_SCR1(a6)
	fbeq.w  int_wrt                 ;exact answer
*       fcmp.s  #:c3008000,fp0
	fcmp.s  Vc3008000,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_dnrm    equ    *
	move.l  #0,L_SCR1(a6)   ;if extended denorm, answer is zero
*                               ;fall through to  int_inx
int_inx    equ    *
	ori.l   #inx2a_mask,USER_FPSTATUS(a6)
	bra.b   int_wrt
int_operr    equ    *
	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_FPSTATUS(a6)
*                               ;fall through to perform int_wrt
int_wrt     equ    *
	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    equ    *
	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    equ    *
	or.l    #$10,d0         ;add 'long' size to register#
sz_con    equ    *
	move.l  d0,d1           ;reg_dest expects size:reg in d1
	bsr.l   reg_dest        ;load proper data register
	bra.w   mvouti_end
xp    equ    *
	lea     ETEMP(a6),a0
	bclr    #sign_bit,LOCAL_EX(a0)
	sne     LOCAL_SGN(a0)
	btst    #7,STAG(a6)     ;check for extended denorm
	bne.w   xdnrm
	clr.l   d0
	bra.b   do_fp           ;do normal case
sgp    equ    *
	lea     ETEMP(a6),a0
	bclr    #sign_bit,LOCAL_EX(a0)
	sne     LOCAL_SGN(a0)
	btst    #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    equ    *
	lea     ETEMP(a6),a0
	bclr    #sign_bit,LOCAL_EX(a0)
	sne     LOCAL_SGN(a0)

	btst    #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    equ    *
	bfextu  FPCONTROL_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    equ    *
	bsr.l   dest_ext
	bra.w   mvout_end
dsgl    equ    *
	bsr.l   dest_sgl
	bra.w   mvout_end
ddbl    equ    *
	bsr.l   dest_dbl
	bra.w   mvout_end

*
* Handle possible denorm or catastrophic underflow cases here
*
xdnrm    equ    *
	bsr.w   set_xop         ;initialize WBTEMP
	bset    #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    #unfl_bit,FPSTATUS_EXCEPT(a6)
	bra.w   mvout_end

sp_under    equ    *
	bset    #etemp15_bit,STAG(a6)

	cmp.w   4(a1),d0
	ble.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    #unfl_bit,FPSTATUS_EXCEPT(a6)
	bra.w   mvout_end       ;exit

dp_under    equ    *
	bset    #etemp15_bit,STAG(a6)

	cmp.w   4(a1),d0
	ble.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    #unfl_bit,FPSTATUS_EXCEPT(a6)
	bra.w   mvout_end       ;exit

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

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

	bsr.l   unf_sub         ;a0 points to result

	move.l  (a7)+,USER_FPSTATUS(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_FPSTATUS(a6)
	bra.w   mvout_end

dp_catas    equ    *
* Temp fix for z bit set in unf_sub
	move.l  USER_FPSTATUS(a6),-(a7)

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

	move.l  (a7)+,USER_FPSTATUS(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_FPSTATUS(a6)
	bra.w   mvout_end

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

	move.l  #1,d0
	lea     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_FPSTATUS(a6)

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

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

	move.l  #2,d0
	lea     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_FPSTATUS(a6)

	move.l  a0,a1
	move.l  EXC_EA(a6),a0
	bsr.l   dest_dbl
	ori.l   #ovfinx_mask,USER_FPSTATUS(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 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_FPSTATUS bits
*
dpspdnrm    equ    *
	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  FPCONTROL_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_FPSTATUS 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
	add.w   #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    equ    *
	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    #sign_bit,WBTEMP_EX(a6)
sxop    equ    *
	bfclr   STAG(a6){5:4}   ;clear wbtm66,wbtm1,wbtm0,sbit
	rts
*
*       P_MOVE
*
p_movet    equ    *
	dc.l    p_move
	dc.l    p_movez
	dc.l    p_movei
	dc.l    p_moven
	dc.l    p_move
p_regd    equ    *
	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    equ    *
	lea     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    equ    *
	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
	move.b  #0,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    equ    *
	move.w  CMDREG1B(a6),d0
	btst    #kfact_bit,d0   ;test for dynamic k-factor
	beq.b   statick         ;if clear, k-factor is static
dynamick    equ    *
	bfextu  d0{25:3},d0     ;isolate register for dynamic k-factor
	lea     p_regd,a0
	move.l  (a0,d0*4),a0
	jmp     (a0)
statick    equ    *
	andi.w  #$007f,d0       ;get k-factor
	bfexts  d0{25:7},d0     ;sign extend d0 for bindec
	lea     ETEMP(a6),a0    ;a0 will point to the packed decimal
	bsr.l   bindec          ;perform the convert; data at a6
	lea     FP_SCR1(a6),a0  ;load a0 with result address
	bra.l   p_write
p_movez    equ    *
	lea     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    equ    *
	fmove.l #0,FPSTATUS             ;clear aiop
	lea     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    equ    *
	lea     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    equ    *
	move.l  USER_D0(a6),d0
	bra.b   statick
p_dyd1    equ    *
	move.l  USER_D1(a6),d0
	bra.b   statick
p_dyd2    equ    *
	move.l  d2,d0
	bra.b   statick
p_dyd3    equ    *
	move.l  d3,d0
	bra.b   statick
p_dyd4    equ    *
	move.l  d4,d0
	bra.b   statick
p_dyd5    equ    *
	move.l  d5,d0
	bra.b   statick
p_dyd6    equ    *
	move.l  d6,d0
	bra.w   statick
p_dyd7    equ    *
	move.l  d7,d0
	bra.w   statick

	end
@


56.2
log
@
pws2rcs automatic delta on Wed Jan 27 11:57:27 MST 1993
@
text
@d1 1970
@


56.1
log
@Automatic bump of revision number for PWS version 3.25
@
text
@a0 1970
*
*       res_func.sa 3.1 12/10/90
*
* 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.
*
*
*               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.


* added to replace single-precision floating point immediates JWH 1/10/91

V46fffe00  DC.L  $46fffe00
V46ffff00  DC.L  $46ffff00
Vc7000080  DC.L  $c7000080
V42fe0000  DC.L  $42fe0000
Vc3000000  DC.L  $c3000000
V42ff0000  DC.L  $42ff0000
Vc3008000  DC.L  $c3008000
Vc7000000  DC.L  $c7000000
V41dfffffffc00000 DC.L  $41dfffff,$ffc00000
Vc1e0000000000000 DC.L  $c1e00000,$00000000
Vc1e0000000100000 DC.L  $c1e00000,$00100000
V41dfffffffe00000 DC.L  $41dfffff,$ffe00000

	include fpsp_h

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

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

	def     res_func
	def     p_move

res_func    equ    *
	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    equ    *
	btst    #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     FPTEMP(a6),a0

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

	bsr     nrm_set         ;normalize number (exp will go negative)
	bclr    #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    #sign_bit,LOCAL_EX(a0)
dpos    equ    *
	bfclr   DTAG(a6){0:4}   ;set tag to normalized, FPTE15 = 0
	bset    #4,DTAG(a6)     ;set FPTE15
	ori.b   #$0f,DNRM_FLG(a6)
monadic    equ    *
	lea     ETEMP(a6),a0
	btst    #direction_bit,CMDREG1B(a6)     ;check direction
	bne.w   opclass3                        ;it is a mv out
*
* At this point, only oplcass 0 and 2 possible
*
	btst    #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    #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    equ    *
	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    equ    *
	move.w  LOCAL_EX(a0),d0
	bclr    #15,d0
	sne     LOCAL_SGN(a0)
	beq.b   cu_ntpo
	ori.l   #neg_mask,USER_FPSTATUS(a6) ;set N
cu_ntpo    equ    *
	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
	ori.l   #inf_mask,USER_FPSTATUS(a6)
	rts
cu_ntn    equ    *
	ori.l   #nan_mask,USER_FPSTATUS(a6)
	move.l  ETEMP_EX(a6),FPTEMP_EX(a6)      ;set up fptemp sign for
*                                               ;snan handler

	rts
cu_ntcz    equ    *
	tst.l   LOCAL_HI(a0)
	bne.l   cu_ntsx
	tst.l   LOCAL_LO(a0)
	bne.l   cu_ntsx
	ori.l   #z_mask,USER_FPSTATUS(a6)
cu_ntsx    equ    *
	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    equ    *
	move.b  STAG(a6),d0
	btst    #5,d0                   ;test for NaN or zero
	bne     wr_etemp                ;if either, simply write it
	bclr    #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    equ    *
	move.b  STAG(a6),d0
	btst    #5,d0                   ;test for NaN or zero
	bne     wr_etemp                ;if either, simply write it
	bchg    #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 FPCONTROL.  If the rounding precision
* is double or single, round the result before the write.
*
cu_nmove    equ    *
	move.b  STAG(a6),d0
	andi.b  #$e0,d0                 ;isolate stag bits
	bne     wr_etemp                ;if not norm, simply write it
	btst    #2,CMDREG1B+1(a6)       ;check for rd
	bne     cu_nmrd
	btst    #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
* FPCONTROL_MODE byte to get rounding on norms and zeros.
*
cu_nmnr    equ    *
	bfextu  FPCONTROL_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    equ    *
	bfextu  FPCONTROL_MODE(a6){2:2},d1      ;get rmode
	or.l    #$00020000,d1           ;force double
	clr.l   d0                      ;clr grs for round
	bclr    #sign_bit,LOCAL_EX(a0)
	sne     LOCAL_SGN(a0)
	bsr.l   round                   ;perform the round
	bfclr   LOCAL_SGN(a0){0:8}
	beq.b   cu_nmrdc
	bset    #sign_bit,LOCAL_EX(a0)
cu_nmrdc    equ    *
	move.l  #2,d0                   ;set up size for denorm
	move.w  LOCAL_EX(a0),d1
	and.w   #$7FFF,d1
	cmp.w   #$3c01,d1
	bls     cu_nunfl
	cmp.w   #$43ff,d1
	bge     cu_novfl
	bra.w   cu_wrexn
*
* The move is fsmove or round precision is single.
*
cu_nmrs    equ    *
	bfextu  FPCONTROL_MODE(a6){2:2},d1      ;get rmode
	or.l    #$00010000,d1           ;force single
	clr.l   d0                      ;clr grs for round
	bclr    #sign_bit,LOCAL_EX(a0)
	sne     LOCAL_SGN(a0)
	bsr.l   round                   ;perform the round
	bfclr   LOCAL_SGN(a0){0:8}
	beq.b   cu_nmrsc
	bset    #sign_bit,LOCAL_EX(a0)
cu_nmrsc    equ    *
	move.l  #1,d0                   ;set up size for denorm
	move.w  LOCAL_EX(a0),d1
	and.w   #$7FFF,d1
	cmp.w   #$3f81,d1
	bls     cu_nunfl
	cmp.w   #$407f,d1
	blt     cu_wrexn
*
* The operand is above precision boundaries.  Use t_ovfl to
* generate the correct value.
*
cu_novfl    equ    *
	bsr     t_ovfl
	bra     cu_wrexn
*
* The operand is below precision boundaries.  Use denorm to
* generate the correct value.
*
cu_nunfl    equ    *
	bclr    #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_nuflp
	bset    #sign_bit,LOCAL_EX(a0)
cu_nuflp    equ    *
	btst    #inex2_bit,FPSTATUS_EXCEPT(a6)
	beq.b   cu_nuninx
	ori.l   #aunfl_mask,USER_FPSTATUS(a6) ;if the round was inex, set AUNFL
cu_nuninx    equ    *
	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 occured which would leave the lsb.
*
	move.l  USER_FPCONTROL(a6),d0
	andi.l  #$30,d0         ;isolate rmode
	cmpi.l  #$20,d0
	blt.b   cu_nzro
	bne.b   cu_nrp
cu_nrm    equ    *
	tst.w   LOCAL_EX(a0)    ;if positive, set lsb
	bge.b   cu_nzro
	btst    #7,FPCONTROL_MODE(a6) ;check for double
	beq.b   cu_nincs
	bra.b   cu_nincd
cu_nrp    equ    *
	tst.w   LOCAL_EX(a0)    ;if positive, set lsb
	blt.b   cu_nzro
	btst    #7,FPCONTROL_MODE(a6) ;check for double
	beq.b   cu_nincs
cu_nincd    equ    *
	ori.l   #$800,LOCAL_HI(a0) ;inc for double
	bra     cu_nunzro
cu_nincs    equ    *
	ori.l   #$100,LOCAL_HI(a0) ;inc for single
	bra     cu_nunzro
cu_nzro    equ    *
	ori.l   #z_mask,USER_FPSTATUS(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    equ    *
	ori.l   #unfl_mask,USER_FPSTATUS(a6) ;set unfl
cu_numv    equ    *
	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 FPSTATUS cc bits.  NaN and Inf
* bypass cu_wrexn.
*
cu_wrexn    equ    *
	tst.w   LOCAL_EX(a0)            ;test for zero
	beq.b   cu_wrzero
	cmpi.w  #$8000,LOCAL_EX(a0)     ;test for zero
	bne.b   cu_wreon
cu_wrzero    equ    *
	ori.l   #z_mask,USER_FPSTATUS(a6)       ;set Z bit
cu_wreon    equ    *
	tst.w   LOCAL_EX(a0)
	bpl     wr_etemp
	ori.l   #neg_mask,USER_FPSTATUS(a6)
	bra     wr_etemp

*
* HANDLE SOURCE DENORM HERE
*
*                               ;clear denorm stag to norm
*                               ;write the new tag & ete15 to the fstack
mon_dnrm    equ    *
*
* 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    #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    equ    *
	bclr    #sign_bit,LOCAL_EX(a0)
	sne     LOCAL_SGN(a0)
	bsr     nrm_set         ;normalize number (exponent will go
*                               ; negative)
	bclr    #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    #sign_bit,LOCAL_EX(a0)
spos    equ    *
	bfclr   STAG(a6){0:4}   ;set tag to normalized, FPTE15 = 0
	bset    #4,STAG(a6)     ;set ETE15
	ori.b   #$f0,DNRM_FLG(a6)
normal    equ    *
	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    equ    *
	move.b  #$fe,CU_SAVEPC(a6)
	bclr    #E1,E_BYTE(a6)

	clr.w   NMNEXC(a6)

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

*
* cu_dnrm handles all cu-only instructions (fmove, fabs, fneg, and
* ftst) completly in software without an frestore to the 040.
*
cu_dnrm    equ    *
	st      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    equ    *
	move.w  LOCAL_EX(a0),d0
	bclr    #15,d0
	sne     LOCAL_SGN(a0)
	beq.b   cu_dtpo
	ori.l   #neg_mask,USER_FPSTATUS(a6) ;set N
cu_dtpo    equ    *
	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
	ori.l   #inf_mask,USER_FPSTATUS(a6)
	rts
cu_dtn    equ    *
	ori.l   #nan_mask,USER_FPSTATUS(a6)
	move.l  ETEMP_EX(a6),FPTEMP_EX(a6)      ;set up fptemp sign for
*                                               ;snan handler
	rts
cu_dtcz    equ    *
	tst.l   LOCAL_HI(a0)
	bne.l   cu_dtsx
	tst.l   LOCAL_LO(a0)
	bne.l   cu_dtsx
	ori.l   #z_mask,USER_FPSTATUS(a6)
cu_dtsx    equ    *
	rts
*
* Inst is fabs.  Execute the absolute value function on the input.
* Branch to the fmove code.
*
cu_dabs    equ    *
	bclr    #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    equ    *
	bchg    #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 FPCONTROL.  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    equ    *
	btst    #2,CMDREG1B+1(a6)       ;check for rd
	bne     cu_dmrd
	btst    #6,CMDREG1B+1(a6)       ;check for rs
	bne     cu_dmrs
*
* The move or operation is not with forced precision.  Use the
* FPCONTROL_MODE byte to get rounding.
*
cu_dmnr    equ    *
	bfextu  FPCONTROL_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    equ    *
	bfextu  FPCONTROL_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    equ    *
	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    equ    *
	bfextu  FPCONTROL_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    equ    *
	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    equ    *
	ori.l   #unfl_mask,USER_FPSTATUS(a6)
	tst.w   LOCAL_EX(a0)
	beq     wr_etemp
	ori.l   #neg_mask,USER_FPSTATUS(a6)
	bra     wr_etemp
*
* These routines write +/- zero in double format.  The routines
* cu_dpdr and cu_dndr set the double lsb.
*
cu_dpd    equ    *
	move.l  #$3c010000,LOCAL_EX(a0) ;force pos double zero
	clr.l   LOCAL_HI(a0)
	clr.l   LOCAL_LO(a0)
	ori.l   #z_mask,USER_FPSTATUS(a6)
	ori.l   #unfinx_mask,USER_FPSTATUS(a6)
	bra     wr_etemp
cu_dpdr    equ    *
	move.l  #$3c010000,LOCAL_EX(a0) ;force pos double zero
	clr.l   LOCAL_HI(a0)
	move.l  #$800,LOCAL_LO(a0)      ;with lsb set
	ori.l   #unfinx_mask,USER_FPSTATUS(a6)
	bra     wr_etemp
cu_dnd    equ    *
	move.l  #$bc010000,LOCAL_EX(a0) ;force pos double zero
	clr.l   LOCAL_HI(a0)
	clr.l   LOCAL_LO(a0)
	ori.l   #z_mask,USER_FPSTATUS(a6)
	ori.l   #neg_mask,USER_FPSTATUS(a6)
	ori.l   #unfinx_mask,USER_FPSTATUS(a6)
	bra     wr_etemp
cu_dndr    equ    *
	move.l  #$bc010000,LOCAL_EX(a0) ;force pos double zero
	clr.l   LOCAL_HI(a0)
	move.l  #$800,LOCAL_LO(a0)      ;with lsb set
	ori.l   #neg_mask,USER_FPSTATUS(a6)
	ori.l   #unfinx_mask,USER_FPSTATUS(a6)
	bra     wr_etemp
*
* These routines write +/- zero in single format.  The routines
* cu_dpdr and cu_dndr set the single lsb.
*
cu_spd    equ    *
	move.l  #$3f810000,LOCAL_EX(a0) ;force pos single zero
	clr.l   LOCAL_HI(a0)
	clr.l   LOCAL_LO(a0)
	ori.l   #z_mask,USER_FPSTATUS(a6)
	ori.l   #unfinx_mask,USER_FPSTATUS(a6)
	bra     wr_etemp
cu_spdr    equ    *
	move.l  #$3f810000,LOCAL_EX(a0) ;force pos single zero
	move.l  #$100,LOCAL_HI(a0)      ;with lsb set
	clr.l   LOCAL_LO(a0)
	ori.l   #unfinx_mask,USER_FPSTATUS(a6)
	bra     wr_etemp
cu_snd    equ    *
	move.l  #$bf810000,LOCAL_EX(a0) ;force pos single zero
	clr.l   LOCAL_HI(a0)
	clr.l   LOCAL_LO(a0)
	ori.l   #z_mask,USER_FPSTATUS(a6)
	ori.l   #neg_mask,USER_FPSTATUS(a6)
	ori.l   #unfinx_mask,USER_FPSTATUS(a6)
	bra     wr_etemp
cu_sndr    equ    *
	move.l  #$bf810000,LOCAL_EX(a0) ;force pos single zero
	move.l  #$100,LOCAL_HI(a0)      ;with lsb set
	clr.l   LOCAL_LO(a0)
	ori.l   #neg_mask,USER_FPSTATUS(a6)
	ori.l   #unfinx_mask,USER_FPSTATUS(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    equ    *
	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    equ    *
	cmpi.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.
*
	cmpi.b  #$0f,DNRM_FLG(a6) ;check for dest denorm
	bne.b   div_srcd
div_destd    equ    *
	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
	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      WBTEMP_SGN(a6)
	bra     force_unf
div_srcd    equ    *
	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      WBTEMP_SGN(a6)
*
* This code handles the case of the instruction resulting in
* an overflow condition.
*
force_ovf    equ    *
	bclr    #E1,E_BYTE(a6)
	ori.l   #ovfl_inx_mask,USER_FPSTATUS(a6)
	clr.w   NMNEXC(a6)
	lea     WBTEMP(a6),a0           ;point a0 to memory location
	move.w  CMDREG1B(a6),d0
	btst    #6,d0                   ;test for forced precision
	beq.b   frcovf_FPCONTROL
	btst    #2,d0                   ;check for double
	bne.b   frcovf_dbl
	move.l  #$1,d0                  ;inst is forced single
	bra.b   frcovf_rnd
frcovf_dbl    equ    *
	move.l  #$2,d0                  ;inst is forced double
	bra.b   frcovf_rnd
frcovf_FPCONTROL    equ    *
	bfextu  FPCONTROL_MODE(a6){0:2},d0      ;inst not forced - use FPCONTROL prec
frcovf_rnd    equ    *
	tst.b   d0
	beq.b   frcovf_x
	ori.l   #inex2_mask,USER_FPSTATUS(a6) ;if prec is s or d, set inex2
frcovf_x    equ    *
	bsr.l   ovf_res                 ;get correct result based on
*                                       ;round precision/mode.  This
*                                       ;sets FPSTATUS_CC correctly
*                                       ;returns in external format
	bfclr   WBTEMP_SGN(a6){0:8}
	beq     frcfpn
	bset    #sign_bit,WBTEMP_EX(a6)
	bra     frcfpn
*
* Inst is fadd.
*
wrap_add    equ    *
	cmpi.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.
*
	cmpi.b  #$0f,DNRM_FLG(a6) ;check for dest denorm
	bne.b   add_srcd
add_destd    equ    *
	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    equ    *
	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    equ    *
	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.
*
	cmpi.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_FPCONTROL(a6),d0
	andi.l  #$30,d0
	fmove.l d0,FPCONTROL            ;set up users rmode and X
	fmove.x ETEMP(a6),fp0
	fadd.x  FPTEMP(a6),fp0
	lea     WBTEMP(a6),a0   ;point a0 to wbtemp in frame
	fmove.l FPSTATUS,d1
	or.l    d1,USER_FPSTATUS(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_FPCONTROL(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    #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    #sign_bit,WBTEMP_EX(a6)
	bra     frcfpnr
add_u_srcd    equ    *
	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_FPCONTROL(a6),d0
	andi.l  #$30,d0
	fmove.l d0,FPCONTROL            ;set up users rmode and X
	fmove.x ETEMP(a6),fp0
	fadd.x  FPTEMP(a6),fp0
	fmove.l FPSTATUS,d1
	or.l    d1,USER_FPSTATUS(a6) ;capture cc's and inex from fadd
	lea     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_FPCONTROL(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    #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    #sign_bit,WBTEMP_EX(a6)
	bra     frcfpnr
*
* Signs are alike:
*
add_same    equ    *
	cmpi.b  #$0f,DNRM_FLG(a6) ;is dest the denorm?
	bne.b   add_s_srcd
add_s_destd    equ    *
	lea     ETEMP(a6),a0
	move.l  USER_FPCONTROL(a6),d0
	andi.l  #$30,d0
	lsr.l   #4,d0           ;put rmode in lower 2 bits
	move.l  USER_FPCONTROL(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    #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    #sign_bit,ETEMP_EX(a6)
add_s_dclr    equ    *
	lea     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
	ori.l   #neg_mask,USER_FPSTATUS(a6)
	bra     add_ckovf
add_s_srcd    equ    *
	lea     FPTEMP(a6),a0
	move.l  USER_FPCONTROL(a6),d0
	andi.l  #$30,d0
	lsr.l   #4,d0           ;put rmode in lower 2 bits
	move.l  USER_FPCONTROL(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    #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    #sign_bit,FPTEMP_EX(a6)
add_s_sclr    equ    *
	lea     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
	ori.l   #neg_mask,USER_FPSTATUS(a6)
add_ckovf    equ    *
	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.)
*
	ori.l   #inf_mask+ovfl_inx_mask,USER_FPSTATUS(a6)
	clr.l   4(a0)
	bra     frcfpnr
*
* Inst is fsub.
*
wrap_sub    equ    *
	cmpi.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.
*
	cmpi.b  #$0f,DNRM_FLG(a6) ;check for dest denorm
	bne.b   sub_srcd
sub_destd    equ    *
	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    equ    *
	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    equ    *
	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.
*
	cmpi.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_FPCONTROL(a6),d0
	andi.l  #$30,d0
	fmove.l d0,FPCONTROL            ;set up users rmode and X
	fmove.x FPTEMP(a6),fp0
	fsub.x  ETEMP(a6),fp0
	fmove.l FPSTATUS,d1
	or.l    d1,USER_FPSTATUS(a6) ;capture cc's and inex from fadd
	lea     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_FPCONTROL(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    #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    #sign_bit,WBTEMP_EX(a6)
	bra     frcfpnr
sub_u_srcd    equ    *
	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_FPCONTROL(a6),d0
	andi.l  #$30,d0
	fmove.l d0,FPCONTROL            ;set up users rmode and X
	fmove.x FPTEMP(a6),fp0
	fsub.x  ETEMP(a6),fp0
	fmove.l FPSTATUS,d1
	or.l    d1,USER_FPSTATUS(a6) ;capture cc's and inex from fadd
	lea     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_FPCONTROL(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    #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    #sign_bit,WBTEMP_EX(a6)
	bra     frcfpnr
*
* Signs are unlike:
*
sub_diff    equ    *
	cmpi.b  #$0f,DNRM_FLG(a6) ;is dest the denorm?
	bne.b   sub_s_srcd
sub_s_destd    equ    *
	lea     ETEMP(a6),a0
	move.l  USER_FPCONTROL(a6),d0
	andi.l  #$30,d0
	lsr.l   #4,d0           ;put rmode in lower 2 bits
	move.l  USER_FPCONTROL(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
	ori.l   #neg_mask,USER_FPSTATUS(a6)
sub_s_dwr    equ    *
	bclr    #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    #sign_bit,ETEMP_EX(a6)
sub_s_dclr    equ    *
	lea     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    equ    *
	lea     FPTEMP(a6),a0
	move.l  USER_FPCONTROL(a6),d0
	andi.l  #$30,d0
	lsr.l   #4,d0           ;put rmode in lower 2 bits
	move.l  USER_FPCONTROL(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    #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    #sign_bit,FPTEMP_EX(a6)
sub_s_sclr    equ    *
	lea     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
	ori.l   #neg_mask,USER_FPSTATUS(a6)
sub_ckovf    equ    *
	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.)
*
	ori.l   #inf_mask+ovfl_inx_mask,USER_FPSTATUS(a6)
	clr.l   4(a0)
	bra     frcfpnr
*
* Inst is fcmp.
*
wrap_cmp    equ    *
	cmpi.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.
*
	cmpi.b  #$0f,DNRM_FLG(a6) ;check for dest denorm
	bne.b   cmp_srcd
cmp_destd    equ    *
	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    equ    *
	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    equ    *
	ori.l   #neg_mask,USER_FPSTATUS(a6)
	rts

*
* Inst is fmul.
*
wrap_mul    equ    *
	cmpi.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.
*
	cmpi.b  #$0f,DNRM_FLG(a6) ;check for dest denorm
	bne.b   mul_srcd
mul_destd    equ    *
	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    equ    *
	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    equ    *
	bclr    #E1,E_BYTE(a6)
	ori.l   #unfinx_mask,USER_FPSTATUS(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      WBTEMP_SGN(a6)
frcunfcont    equ    *
	lea     WBTEMP(a6),a0           ;point a0 to memory location
	btst    #6,d0                   ;test for forced precision
	beq.b   frcunf_FPCONTROL
	btst    #2,d0                   ;check for double
	bne.b   frcunf_dbl
	move.l  #$1,d0                  ;inst is forced single
	bra.b   frcunf_rnd
frcunf_dbl    equ    *
	move.l  #$2,d0                  ;inst is forced double
	bra.b   frcunf_rnd
frcunf_FPCONTROL    equ    *
	bfextu  FPCONTROL_MODE(a6){0:2},d0      ;inst not forced - use FPCONTROL prec
frcunf_rnd    equ    *
	bsr.l   unf_sub                 ;get correct result based on
*                                       ;round precision/mode.  This
*                                       ;sets FPSTATUS_CC correctly
	bfclr   WBTEMP_SGN(a6){0:8}     ;convert back to IEEE ext format
	beq.b   frcfpn
	bset    #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    equ    *
	move.w  CMDREG1B(a6),d0
	btst    #6,d0                   ;test for forced precision
	beq.b   frcfpn_FPCONTROL
	btst    #2,d0                   ;check for double
	bne.b   frcfpn_dbl
	move.l  #$1,d0                  ;inst is forced single
	bra.b   frcfpn_rnd
frcfpn_dbl    equ    *
	move.l  #$2,d0                  ;inst is forced double
	bra.b   frcfpn_rnd
frcfpn_FPCONTROL    equ    *
	bfextu  FPCONTROL_MODE(a6){0:2},d0      ;inst not forced - use FPCONTROL prec
	tst.b   d0
	beq.b   frcfpn                  ;if extended, write what you got
frcfpn_rnd    equ    *
	bclr    #sign_bit,WBTEMP_EX(a6)
	sne     WBTEMP_SGN(a6)
	bsr.l   ovf_res                 ;get correct result based on
*                                       ;round precision/mode.  This
*                                       ;sets FPSTATUS_CC correctly
	bfclr   WBTEMP_SGN(a6){0:8}     ;convert back to IEEE ext format
	beq.b   frcfpn_clr
	bset    #sign_bit,WBTEMP_EX(a6)
frcfpn_clr    equ    *
	ori.l   #ovfinx_mask,USER_FPSTATUS(a6)
*
* Perform the write.
*
frcfpn    equ    *
	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    d1,d0
	fmovem.x WBTEMP(a6),d0
	rts
frc0123    equ    *
	cmpi.b  #0,d0
	beq.b   frc0_dst
	cmpi.b  #1,d0
	beq.b   frc1_dst
	cmpi.b  #2,d0
	beq.b   frc2_dst
frc3_dst    equ    *
	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    equ    *
	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    equ    *
	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    equ    *
	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    equ    *
	btst    #snan_bit,FPSTATUS_EXCEPT(a6)   ;if snan is set, and
	beq.b   fmoveinc                ;enabled, force restore
	btst    #snan_bit,FPCONTROL_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    equ    *
	ori.l   #neg_bit,USER_FPSTATUS(a6)      ;snan is negative; set N
	rts
fmoveinc    equ    *
	clr.w   NMNEXC(a6)
	bclr    #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
	ori.l   #inf_mask,USER_FPSTATUS(a6) ;if inf, nothing yet has set I
	tst.w   LOCAL_EX(a0)            ;check sign
	bge.b   fminc_con
	ori.l   #neg_mask,USER_FPSTATUS(a6)
	bra     fminc_con
fminc_cnan    equ    *
	cmpi.b  #$60,d0                 ;check if stag is NaN
	bne.b   fminc_czero
	ori.l   #nan_mask,USER_FPSTATUS(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
	ori.l   #neg_mask,USER_FPSTATUS(a6)
	bra     fminc_con
fminc_czero    equ    *
	cmpi.b  #$20,d0                 ;check if zero
	bne.b   fminc_con
	ori.l   #z_mask,USER_FPSTATUS(a6)       ;if zero, set Z
	tst.w   LOCAL_EX(a0)            ;check sign
	bge.b   fminc_con
	ori.l   #neg_mask,USER_FPSTATUS(a6)
fminc_con    equ    *
	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    d1,d0
	fmovem.x ETEMP(a6),d0
	rts

fp0123    equ    *
	cmpi.b  #0,d0
	beq.b   fp0_dst
	cmpi.b  #1,d0
	beq.b   fp1_dst
	cmpi.b  #2,d0
	beq.b   fp2_dst
fp3_dst    equ    *
	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    equ    *
	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    equ    *
	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    equ    *
	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    equ    *
	st      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    equ    *
	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    equ    *
	bfextu  CMDREG1B(a6){3:3},d1    ;put source specifier in d1
	lea     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    equ    *
	btst    #inex2_bit,FPSTATUS_EXCEPT(a6)
	beq.b   no_aufl
	btst    #unfl_bit,FPSTATUS_EXCEPT(a6)
	beq.b   no_aufl
	bset    #aunfl_bit,FPSTATUS_AEXCEPT(a6)
no_aufl    equ    *
	clr.w   NMNEXC(a6)
	bclr    #E1,E_BYTE(a6)
	fmove.l #0,FPSTATUS                     ;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    #sign_bit,ETEMP_EX(a6)
mvout_con    equ    *
	rts
*
* This exit is for move-out to int register.  The aunfl bit is
* not set in any case for this move.
*
mvouti_end    equ    *
	clr.w   NMNEXC(a6)
	bclr    #E1,E_BYTE(a6)
	fmove.l #0,FPSTATUS                     ;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    #sign_bit,ETEMP_EX(a6)
mvouti_con    equ    *
	rts
*
* li is used to handle a long integer source specifier
*

li    equ    *
	moveq   #4,d0           ;set byte count

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

	fmovem.x ETEMP(a6),fp0
*       fcmp.d  #:41dfffffffc00000,fp0
	fcmp.d  V41dfffffffc00000,fp0
* 41dfffffffc00000 in dbl prec = 401d0000fffffffe00000000 in ext prec
	fbge.w  lo_plrg
*       fcmp.d  #:c1e0000000000000,fp0
	fcmp.d  Vc1e0000000000000,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_FPCONTROL(a6),d1   ;use user's rounding mode
	andi.l  #$30,d1
	fmove.l d1,FPCONTROL
	fmove.l fp0,L_SCR1(a6)  ;let the 040 perform conversion
	fmove.l FPSTATUS,d1
	or.l    d1,USER_FPSTATUS(a6)    ;capture inex2/ainex if set
	bra.w   int_wrt


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

lo_nlrg    equ    *
	move.l  #$80000000,L_SCR1(a6)
	fbeq.w  int_wrt                 ;exact answer
*       fcmp.d  #:c1e0000000100000,fp0
	fcmp.d  Vc1e0000000100000,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    equ    *
	moveq   #2,d0           ;set byte count

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

	fmovem.x ETEMP(a6),fp0
*       fcmp.s  #:46fffe00,fp0
	fcmp.s  V46fffe00,fp0
* 46fffe00 in sgl prec = 400d0000fffe000000000000 in ext prec
	fbge.w  wo_plrg
*       fcmp.s  #:c7000000,fp0
	fcmp.s  Vc7000000,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_FPCONTROL(a6),d1   ;use user's rounding mode
	andi.l  #$30,d1
	fmove.l d1,FPCONTROL
	fmove.w fp0,L_SCR1(a6)  ;let the 040 perform conversion
	fmove.l FPSTATUS,d1
	or.l    d1,USER_FPSTATUS(a6)    ;capture inex2/ainex if set
	bra.w   int_wrt

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

wo_nlrg    equ    *
	move.w  #$8000,L_SCR1(a6)
	fbeq.w  int_wrt                 ;exact answer
*       fcmp.s  #:c7000080,fp0
	fcmp.s  Vc7000080,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    equ    *
	moveq   #1,d0           ;set byte count

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

	fmovem.x ETEMP(a6),fp0
*       fcmp.s  #:42fe0000,fp0
	fcmp.s  V42fe0000,fp0
* 42fe0000 in sgl prec = 40050000fe00000000000000 in ext prec
	fbge.w  by_plrg
*       fcmp.s  #:c3000000,fp0
	fcmp.s  Vc3000000,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_FPCONTROL(a6),d1   ;use user's rounding mode
	andi.l  #$30,d1
	fmove.l d1,FPCONTROL
	fmove.b fp0,L_SCR1(a6)  ;let the 040 perform conversion
	fmove.l FPSTATUS,d1
	or.l    d1,USER_FPSTATUS(a6)    ;capture inex2/ainex if set
	bra.w   int_wrt

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

by_nlrg    equ    *
	move.b  #$80,L_SCR1(a6)
	fbeq.w  int_wrt                 ;exact answer
*       fcmp.s  #:c3008000,fp0
	fcmp.s  Vc3008000,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_dnrm    equ    *
	move.l  #0,L_SCR1(a6)   ;if extended denorm, answer is zero
*                               ;fall through to  int_inx
int_inx    equ    *
	ori.l   #inx2a_mask,USER_FPSTATUS(a6)
	bra.b   int_wrt
int_operr    equ    *
	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_FPSTATUS(a6)
*                               ;fall through to perform int_wrt
int_wrt     equ    *
	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    equ    *
	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    equ    *
	or.l    #$10,d0         ;add 'long' size to register#
sz_con    equ    *
	move.l  d0,d1           ;reg_dest expects size:reg in d1
	bsr.l   reg_dest        ;load proper data register
	bra.w   mvouti_end
xp    equ    *
	lea     ETEMP(a6),a0
	bclr    #sign_bit,LOCAL_EX(a0)
	sne     LOCAL_SGN(a0)
	btst    #7,STAG(a6)     ;check for extended denorm
	bne.w   xdnrm
	clr.l   d0
	bra.b   do_fp           ;do normal case
sgp    equ    *
	lea     ETEMP(a6),a0
	bclr    #sign_bit,LOCAL_EX(a0)
	sne     LOCAL_SGN(a0)
	btst    #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    equ    *
	lea     ETEMP(a6),a0
	bclr    #sign_bit,LOCAL_EX(a0)
	sne     LOCAL_SGN(a0)

	btst    #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    equ    *
	bfextu  FPCONTROL_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    equ    *
	bsr.l   dest_ext
	bra.w   mvout_end
dsgl    equ    *
	bsr.l   dest_sgl
	bra.w   mvout_end
ddbl    equ    *
	bsr.l   dest_dbl
	bra.w   mvout_end

*
* Handle possible denorm or catastrophic underflow cases here
*
xdnrm    equ    *
	bsr.w   set_xop         ;initialize WBTEMP
	bset    #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    #unfl_bit,FPSTATUS_EXCEPT(a6)
	bra.w   mvout_end

sp_under    equ    *
	bset    #etemp15_bit,STAG(a6)

	cmp.w   4(a1),d0
	ble.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    #unfl_bit,FPSTATUS_EXCEPT(a6)
	bra.w   mvout_end       ;exit

dp_under    equ    *
	bset    #etemp15_bit,STAG(a6)

	cmp.w   4(a1),d0
	ble.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    #unfl_bit,FPSTATUS_EXCEPT(a6)
	bra.w   mvout_end       ;exit

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

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

	bsr.l   unf_sub         ;a0 points to result

	move.l  (a7)+,USER_FPSTATUS(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_FPSTATUS(a6)
	bra.w   mvout_end

dp_catas    equ    *
* Temp fix for z bit set in unf_sub
	move.l  USER_FPSTATUS(a6),-(a7)

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

	move.l  (a7)+,USER_FPSTATUS(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_FPSTATUS(a6)
	bra.w   mvout_end

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

	move.l  #1,d0
	lea     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_FPSTATUS(a6)

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

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

	move.l  #2,d0
	lea     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_FPSTATUS(a6)

	move.l  a0,a1
	move.l  EXC_EA(a6),a0
	bsr.l   dest_dbl
	ori.l   #ovfinx_mask,USER_FPSTATUS(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 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_FPSTATUS bits
*
dpspdnrm    equ    *
	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  FPCONTROL_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_FPSTATUS 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
	add.w   #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    equ    *
	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    #sign_bit,WBTEMP_EX(a6)
sxop    equ    *
	bfclr   STAG(a6){5:4}   ;clear wbtm66,wbtm1,wbtm0,sbit
	rts
*
*       P_MOVE
*
p_movet    equ    *
	dc.l    p_move
	dc.l    p_movez
	dc.l    p_movei
	dc.l    p_moven
	dc.l    p_move
p_regd    equ    *
	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    equ    *
	lea     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    equ    *
	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
	move.b  #0,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    equ    *
	move.w  CMDREG1B(a6),d0
	btst    #kfact_bit,d0   ;test for dynamic k-factor
	beq.b   statick         ;if clear, k-factor is static
dynamick    equ    *
	bfextu  d0{25:3},d0     ;isolate register for dynamic k-factor
	lea     p_regd,a0
	move.l  (a0,d0*4),a0
	jmp     (a0)
statick    equ    *
	andi.w  #$007f,d0       ;get k-factor
	bfexts  d0{25:7},d0     ;sign extend d0 for bindec
	lea     ETEMP(a6),a0    ;a0 will point to the packed decimal
	bsr.l   bindec          ;perform the convert; data at a6
	lea     FP_SCR1(a6),a0  ;load a0 with result address
	bra.l   p_write
p_movez    equ    *
	lea     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    equ    *
	fmove.l #0,FPSTATUS             ;clear aiop
	lea     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    equ    *
	lea     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    equ    *
	move.l  USER_D0(a6),d0
	bra.b   statick
p_dyd1    equ    *
	move.l  USER_D1(a6),d0
	bra.b   statick
p_dyd2    equ    *
	move.l  d2,d0
	bra.b   statick
p_dyd3    equ    *
	move.l  d3,d0
	bra.b   statick
p_dyd4    equ    *
	move.l  d4,d0
	bra.b   statick
p_dyd5    equ    *
	move.l  d5,d0
	bra.b   statick
p_dyd6    equ    *
	move.l  d6,d0
	bra.w   statick
p_dyd7    equ    *
	move.l  d7,d0
	bra.w   statick

	end
@


1.1
log
@Initial revision
@
text
@@
