162306a36Sopenharmony_ci|
262306a36Sopenharmony_ci|	res_func.sa 3.9 7/29/91
362306a36Sopenharmony_ci|
462306a36Sopenharmony_ci| Normalizes denormalized numbers if necessary and updates the
562306a36Sopenharmony_ci| stack frame.  The function is then restored back into the
662306a36Sopenharmony_ci| machine and the 040 completes the operation.  This routine
762306a36Sopenharmony_ci| is only used by the unsupported data type/format handler.
862306a36Sopenharmony_ci| (Exception vector 55).
962306a36Sopenharmony_ci|
1062306a36Sopenharmony_ci| For packed move out (fmove.p fpm,<ea>) the operation is
1162306a36Sopenharmony_ci| completed here; data is packed and moved to user memory.
1262306a36Sopenharmony_ci| The stack is restored to the 040 only in the case of a
1362306a36Sopenharmony_ci| reportable exception in the conversion.
1462306a36Sopenharmony_ci|
1562306a36Sopenharmony_ci|
1662306a36Sopenharmony_ci|		Copyright (C) Motorola, Inc. 1990
1762306a36Sopenharmony_ci|			All Rights Reserved
1862306a36Sopenharmony_ci|
1962306a36Sopenharmony_ci|       For details on the license for this file, please see the
2062306a36Sopenharmony_ci|       file, README, in this same directory.
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ciRES_FUNC:    |idnt    2,1 | Motorola 040 Floating Point Software Package
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci	|section	8
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#include "fpsp.h"
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cisp_bnds:	.short	0x3f81,0x407e
2962306a36Sopenharmony_ci		.short	0x3f6a,0x0000
3062306a36Sopenharmony_cidp_bnds:	.short	0x3c01,0x43fe
3162306a36Sopenharmony_ci		.short	0x3bcd,0x0000
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	|xref	mem_write
3462306a36Sopenharmony_ci	|xref	bindec
3562306a36Sopenharmony_ci	|xref	get_fline
3662306a36Sopenharmony_ci	|xref	round
3762306a36Sopenharmony_ci	|xref	denorm
3862306a36Sopenharmony_ci	|xref	dest_ext
3962306a36Sopenharmony_ci	|xref	dest_dbl
4062306a36Sopenharmony_ci	|xref	dest_sgl
4162306a36Sopenharmony_ci	|xref	unf_sub
4262306a36Sopenharmony_ci	|xref	nrm_set
4362306a36Sopenharmony_ci	|xref	dnrm_lp
4462306a36Sopenharmony_ci	|xref	ovf_res
4562306a36Sopenharmony_ci	|xref	reg_dest
4662306a36Sopenharmony_ci	|xref	t_ovfl
4762306a36Sopenharmony_ci	|xref	t_unfl
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	.global	res_func
5062306a36Sopenharmony_ci	.global	p_move
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cires_func:
5362306a36Sopenharmony_ci	clrb	DNRM_FLG(%a6)
5462306a36Sopenharmony_ci	clrb	RES_FLG(%a6)
5562306a36Sopenharmony_ci	clrb	CU_ONLY(%a6)
5662306a36Sopenharmony_ci	tstb	DY_MO_FLG(%a6)
5762306a36Sopenharmony_ci	beqs	monadic
5862306a36Sopenharmony_cidyadic:
5962306a36Sopenharmony_ci	btstb	#7,DTAG(%a6)	|if dop = norm=000, zero=001,
6062306a36Sopenharmony_ci|				;inf=010 or nan=011
6162306a36Sopenharmony_ci	beqs	monadic		|then branch
6262306a36Sopenharmony_ci|				;else denorm
6362306a36Sopenharmony_ci| HANDLE DESTINATION DENORM HERE
6462306a36Sopenharmony_ci|				;set dtag to norm
6562306a36Sopenharmony_ci|				;write the tag & fpte15 to the fstack
6662306a36Sopenharmony_ci	leal	FPTEMP(%a6),%a0
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	bclrb	#sign_bit,LOCAL_EX(%a0)
6962306a36Sopenharmony_ci	sne	LOCAL_SGN(%a0)
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	bsr	nrm_set		|normalize number (exp will go negative)
7262306a36Sopenharmony_ci	bclrb	#sign_bit,LOCAL_EX(%a0) |get rid of false sign
7362306a36Sopenharmony_ci	bfclr	LOCAL_SGN(%a0){#0:#8}	|change back to IEEE ext format
7462306a36Sopenharmony_ci	beqs	dpos
7562306a36Sopenharmony_ci	bsetb	#sign_bit,LOCAL_EX(%a0)
7662306a36Sopenharmony_cidpos:
7762306a36Sopenharmony_ci	bfclr	DTAG(%a6){#0:#4}	|set tag to normalized, FPTE15 = 0
7862306a36Sopenharmony_ci	bsetb	#4,DTAG(%a6)	|set FPTE15
7962306a36Sopenharmony_ci	orb	#0x0f,DNRM_FLG(%a6)
8062306a36Sopenharmony_cimonadic:
8162306a36Sopenharmony_ci	leal	ETEMP(%a6),%a0
8262306a36Sopenharmony_ci	btstb	#direction_bit,CMDREG1B(%a6)	|check direction
8362306a36Sopenharmony_ci	bne	opclass3			|it is a mv out
8462306a36Sopenharmony_ci|
8562306a36Sopenharmony_ci| At this point, only opclass 0 and 2 possible
8662306a36Sopenharmony_ci|
8762306a36Sopenharmony_ci	btstb	#7,STAG(%a6)	|if sop = norm=000, zero=001,
8862306a36Sopenharmony_ci|				;inf=010 or nan=011
8962306a36Sopenharmony_ci	bne	mon_dnrm	|else denorm
9062306a36Sopenharmony_ci	tstb	DY_MO_FLG(%a6)	|all cases of dyadic instructions would
9162306a36Sopenharmony_ci	bne	normal		|require normalization of denorm
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci| At this point:
9462306a36Sopenharmony_ci|	monadic instructions:	fabs  = $18  fneg   = $1a  ftst   = $3a
9562306a36Sopenharmony_ci|				fmove = $00  fsmove = $40  fdmove = $44
9662306a36Sopenharmony_ci|				fsqrt = $05* fssqrt = $41  fdsqrt = $45
9762306a36Sopenharmony_ci|				(*fsqrt reencoded to $05)
9862306a36Sopenharmony_ci|
9962306a36Sopenharmony_ci	movew	CMDREG1B(%a6),%d0	|get command register
10062306a36Sopenharmony_ci	andil	#0x7f,%d0			|strip to only command word
10162306a36Sopenharmony_ci|
10262306a36Sopenharmony_ci| At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and
10362306a36Sopenharmony_ci| fdsqrt are possible.
10462306a36Sopenharmony_ci| For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize)
10562306a36Sopenharmony_ci| For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize)
10662306a36Sopenharmony_ci|
10762306a36Sopenharmony_ci	btstl	#0,%d0
10862306a36Sopenharmony_ci	bne	normal			|weed out fsqrt instructions
10962306a36Sopenharmony_ci|
11062306a36Sopenharmony_ci| cu_norm handles fmove in instructions with normalized inputs.
11162306a36Sopenharmony_ci| The routine round is used to correctly round the input for the
11262306a36Sopenharmony_ci| destination precision and mode.
11362306a36Sopenharmony_ci|
11462306a36Sopenharmony_cicu_norm:
11562306a36Sopenharmony_ci	st	CU_ONLY(%a6)		|set cu-only inst flag
11662306a36Sopenharmony_ci	movew	CMDREG1B(%a6),%d0
11762306a36Sopenharmony_ci	andib	#0x3b,%d0		|isolate bits to select inst
11862306a36Sopenharmony_ci	tstb	%d0
11962306a36Sopenharmony_ci	beql	cu_nmove	|if zero, it is an fmove
12062306a36Sopenharmony_ci	cmpib	#0x18,%d0
12162306a36Sopenharmony_ci	beql	cu_nabs		|if $18, it is fabs
12262306a36Sopenharmony_ci	cmpib	#0x1a,%d0
12362306a36Sopenharmony_ci	beql	cu_nneg		|if $1a, it is fneg
12462306a36Sopenharmony_ci|
12562306a36Sopenharmony_ci| Inst is ftst.  Check the source operand and set the cc's accordingly.
12662306a36Sopenharmony_ci| No write is done, so simply rts.
12762306a36Sopenharmony_ci|
12862306a36Sopenharmony_cicu_ntst:
12962306a36Sopenharmony_ci	movew	LOCAL_EX(%a0),%d0
13062306a36Sopenharmony_ci	bclrl	#15,%d0
13162306a36Sopenharmony_ci	sne	LOCAL_SGN(%a0)
13262306a36Sopenharmony_ci	beqs	cu_ntpo
13362306a36Sopenharmony_ci	orl	#neg_mask,USER_FPSR(%a6) |set N
13462306a36Sopenharmony_cicu_ntpo:
13562306a36Sopenharmony_ci	cmpiw	#0x7fff,%d0	|test for inf/nan
13662306a36Sopenharmony_ci	bnes	cu_ntcz
13762306a36Sopenharmony_ci	tstl	LOCAL_HI(%a0)
13862306a36Sopenharmony_ci	bnes	cu_ntn
13962306a36Sopenharmony_ci	tstl	LOCAL_LO(%a0)
14062306a36Sopenharmony_ci	bnes	cu_ntn
14162306a36Sopenharmony_ci	orl	#inf_mask,USER_FPSR(%a6)
14262306a36Sopenharmony_ci	rts
14362306a36Sopenharmony_cicu_ntn:
14462306a36Sopenharmony_ci	orl	#nan_mask,USER_FPSR(%a6)
14562306a36Sopenharmony_ci	movel	ETEMP_EX(%a6),FPTEMP_EX(%a6)	|set up fptemp sign for
14662306a36Sopenharmony_ci|						;snan handler
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	rts
14962306a36Sopenharmony_cicu_ntcz:
15062306a36Sopenharmony_ci	tstl	LOCAL_HI(%a0)
15162306a36Sopenharmony_ci	bnel	cu_ntsx
15262306a36Sopenharmony_ci	tstl	LOCAL_LO(%a0)
15362306a36Sopenharmony_ci	bnel	cu_ntsx
15462306a36Sopenharmony_ci	orl	#z_mask,USER_FPSR(%a6)
15562306a36Sopenharmony_cicu_ntsx:
15662306a36Sopenharmony_ci	rts
15762306a36Sopenharmony_ci|
15862306a36Sopenharmony_ci| Inst is fabs.  Execute the absolute value function on the input.
15962306a36Sopenharmony_ci| Branch to the fmove code.  If the operand is NaN, do nothing.
16062306a36Sopenharmony_ci|
16162306a36Sopenharmony_cicu_nabs:
16262306a36Sopenharmony_ci	moveb	STAG(%a6),%d0
16362306a36Sopenharmony_ci	btstl	#5,%d0			|test for NaN or zero
16462306a36Sopenharmony_ci	bne	wr_etemp		|if either, simply write it
16562306a36Sopenharmony_ci	bclrb	#7,LOCAL_EX(%a0)		|do abs
16662306a36Sopenharmony_ci	bras	cu_nmove		|fmove code will finish
16762306a36Sopenharmony_ci|
16862306a36Sopenharmony_ci| Inst is fneg.  Execute the negate value function on the input.
16962306a36Sopenharmony_ci| Fall though to the fmove code.  If the operand is NaN, do nothing.
17062306a36Sopenharmony_ci|
17162306a36Sopenharmony_cicu_nneg:
17262306a36Sopenharmony_ci	moveb	STAG(%a6),%d0
17362306a36Sopenharmony_ci	btstl	#5,%d0			|test for NaN or zero
17462306a36Sopenharmony_ci	bne	wr_etemp		|if either, simply write it
17562306a36Sopenharmony_ci	bchgb	#7,LOCAL_EX(%a0)		|do neg
17662306a36Sopenharmony_ci|
17762306a36Sopenharmony_ci| Inst is fmove.  This code also handles all result writes.
17862306a36Sopenharmony_ci| If bit 2 is set, round is forced to double.  If it is clear,
17962306a36Sopenharmony_ci| and bit 6 is set, round is forced to single.  If both are clear,
18062306a36Sopenharmony_ci| the round precision is found in the fpcr.  If the rounding precision
18162306a36Sopenharmony_ci| is double or single, round the result before the write.
18262306a36Sopenharmony_ci|
18362306a36Sopenharmony_cicu_nmove:
18462306a36Sopenharmony_ci	moveb	STAG(%a6),%d0
18562306a36Sopenharmony_ci	andib	#0xe0,%d0			|isolate stag bits
18662306a36Sopenharmony_ci	bne	wr_etemp		|if not norm, simply write it
18762306a36Sopenharmony_ci	btstb	#2,CMDREG1B+1(%a6)	|check for rd
18862306a36Sopenharmony_ci	bne	cu_nmrd
18962306a36Sopenharmony_ci	btstb	#6,CMDREG1B+1(%a6)	|check for rs
19062306a36Sopenharmony_ci	bne	cu_nmrs
19162306a36Sopenharmony_ci|
19262306a36Sopenharmony_ci| The move or operation is not with forced precision.  Test for
19362306a36Sopenharmony_ci| nan or inf as the input; if so, simply write it to FPn.  Use the
19462306a36Sopenharmony_ci| FPCR_MODE byte to get rounding on norms and zeros.
19562306a36Sopenharmony_ci|
19662306a36Sopenharmony_cicu_nmnr:
19762306a36Sopenharmony_ci	bfextu	FPCR_MODE(%a6){#0:#2},%d0
19862306a36Sopenharmony_ci	tstb	%d0			|check for extended
19962306a36Sopenharmony_ci	beq	cu_wrexn		|if so, just write result
20062306a36Sopenharmony_ci	cmpib	#1,%d0			|check for single
20162306a36Sopenharmony_ci	beq	cu_nmrs			|fall through to double
20262306a36Sopenharmony_ci|
20362306a36Sopenharmony_ci| The move is fdmove or round precision is double.
20462306a36Sopenharmony_ci|
20562306a36Sopenharmony_cicu_nmrd:
20662306a36Sopenharmony_ci	movel	#2,%d0			|set up the size for denorm
20762306a36Sopenharmony_ci	movew	LOCAL_EX(%a0),%d1		|compare exponent to double threshold
20862306a36Sopenharmony_ci	andw	#0x7fff,%d1
20962306a36Sopenharmony_ci	cmpw	#0x3c01,%d1
21062306a36Sopenharmony_ci	bls	cu_nunfl
21162306a36Sopenharmony_ci	bfextu	FPCR_MODE(%a6){#2:#2},%d1	|get rmode
21262306a36Sopenharmony_ci	orl	#0x00020000,%d1		|or in rprec (double)
21362306a36Sopenharmony_ci	clrl	%d0			|clear g,r,s for round
21462306a36Sopenharmony_ci	bclrb	#sign_bit,LOCAL_EX(%a0)	|convert to internal format
21562306a36Sopenharmony_ci	sne	LOCAL_SGN(%a0)
21662306a36Sopenharmony_ci	bsrl	round
21762306a36Sopenharmony_ci	bfclr	LOCAL_SGN(%a0){#0:#8}
21862306a36Sopenharmony_ci	beqs	cu_nmrdc
21962306a36Sopenharmony_ci	bsetb	#sign_bit,LOCAL_EX(%a0)
22062306a36Sopenharmony_cicu_nmrdc:
22162306a36Sopenharmony_ci	movew	LOCAL_EX(%a0),%d1		|check for overflow
22262306a36Sopenharmony_ci	andw	#0x7fff,%d1
22362306a36Sopenharmony_ci	cmpw	#0x43ff,%d1
22462306a36Sopenharmony_ci	bge	cu_novfl		|take care of overflow case
22562306a36Sopenharmony_ci	bra	cu_wrexn
22662306a36Sopenharmony_ci|
22762306a36Sopenharmony_ci| The move is fsmove or round precision is single.
22862306a36Sopenharmony_ci|
22962306a36Sopenharmony_cicu_nmrs:
23062306a36Sopenharmony_ci	movel	#1,%d0
23162306a36Sopenharmony_ci	movew	LOCAL_EX(%a0),%d1
23262306a36Sopenharmony_ci	andw	#0x7fff,%d1
23362306a36Sopenharmony_ci	cmpw	#0x3f81,%d1
23462306a36Sopenharmony_ci	bls	cu_nunfl
23562306a36Sopenharmony_ci	bfextu	FPCR_MODE(%a6){#2:#2},%d1
23662306a36Sopenharmony_ci	orl	#0x00010000,%d1
23762306a36Sopenharmony_ci	clrl	%d0
23862306a36Sopenharmony_ci	bclrb	#sign_bit,LOCAL_EX(%a0)
23962306a36Sopenharmony_ci	sne	LOCAL_SGN(%a0)
24062306a36Sopenharmony_ci	bsrl	round
24162306a36Sopenharmony_ci	bfclr	LOCAL_SGN(%a0){#0:#8}
24262306a36Sopenharmony_ci	beqs	cu_nmrsc
24362306a36Sopenharmony_ci	bsetb	#sign_bit,LOCAL_EX(%a0)
24462306a36Sopenharmony_cicu_nmrsc:
24562306a36Sopenharmony_ci	movew	LOCAL_EX(%a0),%d1
24662306a36Sopenharmony_ci	andw	#0x7FFF,%d1
24762306a36Sopenharmony_ci	cmpw	#0x407f,%d1
24862306a36Sopenharmony_ci	blt	cu_wrexn
24962306a36Sopenharmony_ci|
25062306a36Sopenharmony_ci| The operand is above precision boundaries.  Use t_ovfl to
25162306a36Sopenharmony_ci| generate the correct value.
25262306a36Sopenharmony_ci|
25362306a36Sopenharmony_cicu_novfl:
25462306a36Sopenharmony_ci	bsr	t_ovfl
25562306a36Sopenharmony_ci	bra	cu_wrexn
25662306a36Sopenharmony_ci|
25762306a36Sopenharmony_ci| The operand is below precision boundaries.  Use denorm to
25862306a36Sopenharmony_ci| generate the correct value.
25962306a36Sopenharmony_ci|
26062306a36Sopenharmony_cicu_nunfl:
26162306a36Sopenharmony_ci	bclrb	#sign_bit,LOCAL_EX(%a0)
26262306a36Sopenharmony_ci	sne	LOCAL_SGN(%a0)
26362306a36Sopenharmony_ci	bsr	denorm
26462306a36Sopenharmony_ci	bfclr	LOCAL_SGN(%a0){#0:#8}	|change back to IEEE ext format
26562306a36Sopenharmony_ci	beqs	cu_nucont
26662306a36Sopenharmony_ci	bsetb	#sign_bit,LOCAL_EX(%a0)
26762306a36Sopenharmony_cicu_nucont:
26862306a36Sopenharmony_ci	bfextu	FPCR_MODE(%a6){#2:#2},%d1
26962306a36Sopenharmony_ci	btstb	#2,CMDREG1B+1(%a6)	|check for rd
27062306a36Sopenharmony_ci	bne	inst_d
27162306a36Sopenharmony_ci	btstb	#6,CMDREG1B+1(%a6)	|check for rs
27262306a36Sopenharmony_ci	bne	inst_s
27362306a36Sopenharmony_ci	swap	%d1
27462306a36Sopenharmony_ci	moveb	FPCR_MODE(%a6),%d1
27562306a36Sopenharmony_ci	lsrb	#6,%d1
27662306a36Sopenharmony_ci	swap	%d1
27762306a36Sopenharmony_ci	bra	inst_sd
27862306a36Sopenharmony_ciinst_d:
27962306a36Sopenharmony_ci	orl	#0x00020000,%d1
28062306a36Sopenharmony_ci	bra	inst_sd
28162306a36Sopenharmony_ciinst_s:
28262306a36Sopenharmony_ci	orl	#0x00010000,%d1
28362306a36Sopenharmony_ciinst_sd:
28462306a36Sopenharmony_ci	bclrb	#sign_bit,LOCAL_EX(%a0)
28562306a36Sopenharmony_ci	sne	LOCAL_SGN(%a0)
28662306a36Sopenharmony_ci	bsrl	round
28762306a36Sopenharmony_ci	bfclr	LOCAL_SGN(%a0){#0:#8}
28862306a36Sopenharmony_ci	beqs	cu_nuflp
28962306a36Sopenharmony_ci	bsetb	#sign_bit,LOCAL_EX(%a0)
29062306a36Sopenharmony_cicu_nuflp:
29162306a36Sopenharmony_ci	btstb	#inex2_bit,FPSR_EXCEPT(%a6)
29262306a36Sopenharmony_ci	beqs	cu_nuninx
29362306a36Sopenharmony_ci	orl	#aunfl_mask,USER_FPSR(%a6) |if the round was inex, set AUNFL
29462306a36Sopenharmony_cicu_nuninx:
29562306a36Sopenharmony_ci	tstl	LOCAL_HI(%a0)		|test for zero
29662306a36Sopenharmony_ci	bnes	cu_nunzro
29762306a36Sopenharmony_ci	tstl	LOCAL_LO(%a0)
29862306a36Sopenharmony_ci	bnes	cu_nunzro
29962306a36Sopenharmony_ci|
30062306a36Sopenharmony_ci| The mantissa is zero from the denorm loop.  Check sign and rmode
30162306a36Sopenharmony_ci| to see if rounding should have occurred which would leave the lsb.
30262306a36Sopenharmony_ci|
30362306a36Sopenharmony_ci	movel	USER_FPCR(%a6),%d0
30462306a36Sopenharmony_ci	andil	#0x30,%d0		|isolate rmode
30562306a36Sopenharmony_ci	cmpil	#0x20,%d0
30662306a36Sopenharmony_ci	blts	cu_nzro
30762306a36Sopenharmony_ci	bnes	cu_nrp
30862306a36Sopenharmony_cicu_nrm:
30962306a36Sopenharmony_ci	tstw	LOCAL_EX(%a0)	|if positive, set lsb
31062306a36Sopenharmony_ci	bges	cu_nzro
31162306a36Sopenharmony_ci	btstb	#7,FPCR_MODE(%a6) |check for double
31262306a36Sopenharmony_ci	beqs	cu_nincs
31362306a36Sopenharmony_ci	bras	cu_nincd
31462306a36Sopenharmony_cicu_nrp:
31562306a36Sopenharmony_ci	tstw	LOCAL_EX(%a0)	|if positive, set lsb
31662306a36Sopenharmony_ci	blts	cu_nzro
31762306a36Sopenharmony_ci	btstb	#7,FPCR_MODE(%a6) |check for double
31862306a36Sopenharmony_ci	beqs	cu_nincs
31962306a36Sopenharmony_cicu_nincd:
32062306a36Sopenharmony_ci	orl	#0x800,LOCAL_LO(%a0) |inc for double
32162306a36Sopenharmony_ci	bra	cu_nunzro
32262306a36Sopenharmony_cicu_nincs:
32362306a36Sopenharmony_ci	orl	#0x100,LOCAL_HI(%a0) |inc for single
32462306a36Sopenharmony_ci	bra	cu_nunzro
32562306a36Sopenharmony_cicu_nzro:
32662306a36Sopenharmony_ci	orl	#z_mask,USER_FPSR(%a6)
32762306a36Sopenharmony_ci	moveb	STAG(%a6),%d0
32862306a36Sopenharmony_ci	andib	#0xe0,%d0
32962306a36Sopenharmony_ci	cmpib	#0x40,%d0		|check if input was tagged zero
33062306a36Sopenharmony_ci	beqs	cu_numv
33162306a36Sopenharmony_cicu_nunzro:
33262306a36Sopenharmony_ci	orl	#unfl_mask,USER_FPSR(%a6) |set unfl
33362306a36Sopenharmony_cicu_numv:
33462306a36Sopenharmony_ci	movel	(%a0),ETEMP(%a6)
33562306a36Sopenharmony_ci	movel	4(%a0),ETEMP_HI(%a6)
33662306a36Sopenharmony_ci	movel	8(%a0),ETEMP_LO(%a6)
33762306a36Sopenharmony_ci|
33862306a36Sopenharmony_ci| Write the result to memory, setting the fpsr cc bits.  NaN and Inf
33962306a36Sopenharmony_ci| bypass cu_wrexn.
34062306a36Sopenharmony_ci|
34162306a36Sopenharmony_cicu_wrexn:
34262306a36Sopenharmony_ci	tstw	LOCAL_EX(%a0)		|test for zero
34362306a36Sopenharmony_ci	beqs	cu_wrzero
34462306a36Sopenharmony_ci	cmpw	#0x8000,LOCAL_EX(%a0)	|test for zero
34562306a36Sopenharmony_ci	bnes	cu_wreon
34662306a36Sopenharmony_cicu_wrzero:
34762306a36Sopenharmony_ci	orl	#z_mask,USER_FPSR(%a6)	|set Z bit
34862306a36Sopenharmony_cicu_wreon:
34962306a36Sopenharmony_ci	tstw	LOCAL_EX(%a0)
35062306a36Sopenharmony_ci	bpl	wr_etemp
35162306a36Sopenharmony_ci	orl	#neg_mask,USER_FPSR(%a6)
35262306a36Sopenharmony_ci	bra	wr_etemp
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci|
35562306a36Sopenharmony_ci| HANDLE SOURCE DENORM HERE
35662306a36Sopenharmony_ci|
35762306a36Sopenharmony_ci|				;clear denorm stag to norm
35862306a36Sopenharmony_ci|				;write the new tag & ete15 to the fstack
35962306a36Sopenharmony_cimon_dnrm:
36062306a36Sopenharmony_ci|
36162306a36Sopenharmony_ci| At this point, check for the cases in which normalizing the
36262306a36Sopenharmony_ci| denorm produces incorrect results.
36362306a36Sopenharmony_ci|
36462306a36Sopenharmony_ci	tstb	DY_MO_FLG(%a6)	|all cases of dyadic instructions would
36562306a36Sopenharmony_ci	bnes	nrm_src		|require normalization of denorm
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci| At this point:
36862306a36Sopenharmony_ci|	monadic instructions:	fabs  = $18  fneg   = $1a  ftst   = $3a
36962306a36Sopenharmony_ci|				fmove = $00  fsmove = $40  fdmove = $44
37062306a36Sopenharmony_ci|				fsqrt = $05* fssqrt = $41  fdsqrt = $45
37162306a36Sopenharmony_ci|				(*fsqrt reencoded to $05)
37262306a36Sopenharmony_ci|
37362306a36Sopenharmony_ci	movew	CMDREG1B(%a6),%d0	|get command register
37462306a36Sopenharmony_ci	andil	#0x7f,%d0			|strip to only command word
37562306a36Sopenharmony_ci|
37662306a36Sopenharmony_ci| At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and
37762306a36Sopenharmony_ci| fdsqrt are possible.
37862306a36Sopenharmony_ci| For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize)
37962306a36Sopenharmony_ci| For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize)
38062306a36Sopenharmony_ci|
38162306a36Sopenharmony_ci	btstl	#0,%d0
38262306a36Sopenharmony_ci	bnes	nrm_src		|weed out fsqrt instructions
38362306a36Sopenharmony_ci	st	CU_ONLY(%a6)	|set cu-only inst flag
38462306a36Sopenharmony_ci	bra	cu_dnrm		|fmove, fabs, fneg, ftst
38562306a36Sopenharmony_ci|				;cases go to cu_dnrm
38662306a36Sopenharmony_cinrm_src:
38762306a36Sopenharmony_ci	bclrb	#sign_bit,LOCAL_EX(%a0)
38862306a36Sopenharmony_ci	sne	LOCAL_SGN(%a0)
38962306a36Sopenharmony_ci	bsr	nrm_set		|normalize number (exponent will go
39062306a36Sopenharmony_ci|				; negative)
39162306a36Sopenharmony_ci	bclrb	#sign_bit,LOCAL_EX(%a0) |get rid of false sign
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	bfclr	LOCAL_SGN(%a0){#0:#8}	|change back to IEEE ext format
39462306a36Sopenharmony_ci	beqs	spos
39562306a36Sopenharmony_ci	bsetb	#sign_bit,LOCAL_EX(%a0)
39662306a36Sopenharmony_cispos:
39762306a36Sopenharmony_ci	bfclr	STAG(%a6){#0:#4}	|set tag to normalized, FPTE15 = 0
39862306a36Sopenharmony_ci	bsetb	#4,STAG(%a6)	|set ETE15
39962306a36Sopenharmony_ci	orb	#0xf0,DNRM_FLG(%a6)
40062306a36Sopenharmony_cinormal:
40162306a36Sopenharmony_ci	tstb	DNRM_FLG(%a6)	|check if any of the ops were denorms
40262306a36Sopenharmony_ci	bne	ck_wrap		|if so, check if it is a potential
40362306a36Sopenharmony_ci|				;wrap-around case
40462306a36Sopenharmony_cifix_stk:
40562306a36Sopenharmony_ci	moveb	#0xfe,CU_SAVEPC(%a6)
40662306a36Sopenharmony_ci	bclrb	#E1,E_BYTE(%a6)
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	clrw	NMNEXC(%a6)
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	st	RES_FLG(%a6)	|indicate that a restore is needed
41162306a36Sopenharmony_ci	rts
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci|
41462306a36Sopenharmony_ci| cu_dnrm handles all cu-only instructions (fmove, fabs, fneg, and
41562306a36Sopenharmony_ci| ftst) completely in software without an frestore to the 040.
41662306a36Sopenharmony_ci|
41762306a36Sopenharmony_cicu_dnrm:
41862306a36Sopenharmony_ci	st	CU_ONLY(%a6)
41962306a36Sopenharmony_ci	movew	CMDREG1B(%a6),%d0
42062306a36Sopenharmony_ci	andib	#0x3b,%d0		|isolate bits to select inst
42162306a36Sopenharmony_ci	tstb	%d0
42262306a36Sopenharmony_ci	beql	cu_dmove	|if zero, it is an fmove
42362306a36Sopenharmony_ci	cmpib	#0x18,%d0
42462306a36Sopenharmony_ci	beql	cu_dabs		|if $18, it is fabs
42562306a36Sopenharmony_ci	cmpib	#0x1a,%d0
42662306a36Sopenharmony_ci	beql	cu_dneg		|if $1a, it is fneg
42762306a36Sopenharmony_ci|
42862306a36Sopenharmony_ci| Inst is ftst.  Check the source operand and set the cc's accordingly.
42962306a36Sopenharmony_ci| No write is done, so simply rts.
43062306a36Sopenharmony_ci|
43162306a36Sopenharmony_cicu_dtst:
43262306a36Sopenharmony_ci	movew	LOCAL_EX(%a0),%d0
43362306a36Sopenharmony_ci	bclrl	#15,%d0
43462306a36Sopenharmony_ci	sne	LOCAL_SGN(%a0)
43562306a36Sopenharmony_ci	beqs	cu_dtpo
43662306a36Sopenharmony_ci	orl	#neg_mask,USER_FPSR(%a6) |set N
43762306a36Sopenharmony_cicu_dtpo:
43862306a36Sopenharmony_ci	cmpiw	#0x7fff,%d0	|test for inf/nan
43962306a36Sopenharmony_ci	bnes	cu_dtcz
44062306a36Sopenharmony_ci	tstl	LOCAL_HI(%a0)
44162306a36Sopenharmony_ci	bnes	cu_dtn
44262306a36Sopenharmony_ci	tstl	LOCAL_LO(%a0)
44362306a36Sopenharmony_ci	bnes	cu_dtn
44462306a36Sopenharmony_ci	orl	#inf_mask,USER_FPSR(%a6)
44562306a36Sopenharmony_ci	rts
44662306a36Sopenharmony_cicu_dtn:
44762306a36Sopenharmony_ci	orl	#nan_mask,USER_FPSR(%a6)
44862306a36Sopenharmony_ci	movel	ETEMP_EX(%a6),FPTEMP_EX(%a6)	|set up fptemp sign for
44962306a36Sopenharmony_ci|						;snan handler
45062306a36Sopenharmony_ci	rts
45162306a36Sopenharmony_cicu_dtcz:
45262306a36Sopenharmony_ci	tstl	LOCAL_HI(%a0)
45362306a36Sopenharmony_ci	bnel	cu_dtsx
45462306a36Sopenharmony_ci	tstl	LOCAL_LO(%a0)
45562306a36Sopenharmony_ci	bnel	cu_dtsx
45662306a36Sopenharmony_ci	orl	#z_mask,USER_FPSR(%a6)
45762306a36Sopenharmony_cicu_dtsx:
45862306a36Sopenharmony_ci	rts
45962306a36Sopenharmony_ci|
46062306a36Sopenharmony_ci| Inst is fabs.  Execute the absolute value function on the input.
46162306a36Sopenharmony_ci| Branch to the fmove code.
46262306a36Sopenharmony_ci|
46362306a36Sopenharmony_cicu_dabs:
46462306a36Sopenharmony_ci	bclrb	#7,LOCAL_EX(%a0)		|do abs
46562306a36Sopenharmony_ci	bras	cu_dmove		|fmove code will finish
46662306a36Sopenharmony_ci|
46762306a36Sopenharmony_ci| Inst is fneg.  Execute the negate value function on the input.
46862306a36Sopenharmony_ci| Fall though to the fmove code.
46962306a36Sopenharmony_ci|
47062306a36Sopenharmony_cicu_dneg:
47162306a36Sopenharmony_ci	bchgb	#7,LOCAL_EX(%a0)		|do neg
47262306a36Sopenharmony_ci|
47362306a36Sopenharmony_ci| Inst is fmove.  This code also handles all result writes.
47462306a36Sopenharmony_ci| If bit 2 is set, round is forced to double.  If it is clear,
47562306a36Sopenharmony_ci| and bit 6 is set, round is forced to single.  If both are clear,
47662306a36Sopenharmony_ci| the round precision is found in the fpcr.  If the rounding precision
47762306a36Sopenharmony_ci| is double or single, the result is zero, and the mode is checked
47862306a36Sopenharmony_ci| to determine if the lsb of the result should be set.
47962306a36Sopenharmony_ci|
48062306a36Sopenharmony_cicu_dmove:
48162306a36Sopenharmony_ci	btstb	#2,CMDREG1B+1(%a6)	|check for rd
48262306a36Sopenharmony_ci	bne	cu_dmrd
48362306a36Sopenharmony_ci	btstb	#6,CMDREG1B+1(%a6)	|check for rs
48462306a36Sopenharmony_ci	bne	cu_dmrs
48562306a36Sopenharmony_ci|
48662306a36Sopenharmony_ci| The move or operation is not with forced precision.  Use the
48762306a36Sopenharmony_ci| FPCR_MODE byte to get rounding.
48862306a36Sopenharmony_ci|
48962306a36Sopenharmony_cicu_dmnr:
49062306a36Sopenharmony_ci	bfextu	FPCR_MODE(%a6){#0:#2},%d0
49162306a36Sopenharmony_ci	tstb	%d0			|check for extended
49262306a36Sopenharmony_ci	beq	cu_wrexd		|if so, just write result
49362306a36Sopenharmony_ci	cmpib	#1,%d0			|check for single
49462306a36Sopenharmony_ci	beq	cu_dmrs			|fall through to double
49562306a36Sopenharmony_ci|
49662306a36Sopenharmony_ci| The move is fdmove or round precision is double.  Result is zero.
49762306a36Sopenharmony_ci| Check rmode for rp or rm and set lsb accordingly.
49862306a36Sopenharmony_ci|
49962306a36Sopenharmony_cicu_dmrd:
50062306a36Sopenharmony_ci	bfextu	FPCR_MODE(%a6){#2:#2},%d1	|get rmode
50162306a36Sopenharmony_ci	tstw	LOCAL_EX(%a0)		|check sign
50262306a36Sopenharmony_ci	blts	cu_dmdn
50362306a36Sopenharmony_ci	cmpib	#3,%d1			|check for rp
50462306a36Sopenharmony_ci	bne	cu_dpd			|load double pos zero
50562306a36Sopenharmony_ci	bra	cu_dpdr			|load double pos zero w/lsb
50662306a36Sopenharmony_cicu_dmdn:
50762306a36Sopenharmony_ci	cmpib	#2,%d1			|check for rm
50862306a36Sopenharmony_ci	bne	cu_dnd			|load double neg zero
50962306a36Sopenharmony_ci	bra	cu_dndr			|load double neg zero w/lsb
51062306a36Sopenharmony_ci|
51162306a36Sopenharmony_ci| The move is fsmove or round precision is single.  Result is zero.
51262306a36Sopenharmony_ci| Check for rp or rm and set lsb accordingly.
51362306a36Sopenharmony_ci|
51462306a36Sopenharmony_cicu_dmrs:
51562306a36Sopenharmony_ci	bfextu	FPCR_MODE(%a6){#2:#2},%d1	|get rmode
51662306a36Sopenharmony_ci	tstw	LOCAL_EX(%a0)		|check sign
51762306a36Sopenharmony_ci	blts	cu_dmsn
51862306a36Sopenharmony_ci	cmpib	#3,%d1			|check for rp
51962306a36Sopenharmony_ci	bne	cu_spd			|load single pos zero
52062306a36Sopenharmony_ci	bra	cu_spdr			|load single pos zero w/lsb
52162306a36Sopenharmony_cicu_dmsn:
52262306a36Sopenharmony_ci	cmpib	#2,%d1			|check for rm
52362306a36Sopenharmony_ci	bne	cu_snd			|load single neg zero
52462306a36Sopenharmony_ci	bra	cu_sndr			|load single neg zero w/lsb
52562306a36Sopenharmony_ci|
52662306a36Sopenharmony_ci| The precision is extended, so the result in etemp is correct.
52762306a36Sopenharmony_ci| Simply set unfl (not inex2 or aunfl) and write the result to
52862306a36Sopenharmony_ci| the correct fp register.
52962306a36Sopenharmony_cicu_wrexd:
53062306a36Sopenharmony_ci	orl	#unfl_mask,USER_FPSR(%a6)
53162306a36Sopenharmony_ci	tstw	LOCAL_EX(%a0)
53262306a36Sopenharmony_ci	beq	wr_etemp
53362306a36Sopenharmony_ci	orl	#neg_mask,USER_FPSR(%a6)
53462306a36Sopenharmony_ci	bra	wr_etemp
53562306a36Sopenharmony_ci|
53662306a36Sopenharmony_ci| These routines write +/- zero in double format.  The routines
53762306a36Sopenharmony_ci| cu_dpdr and cu_dndr set the double lsb.
53862306a36Sopenharmony_ci|
53962306a36Sopenharmony_cicu_dpd:
54062306a36Sopenharmony_ci	movel	#0x3c010000,LOCAL_EX(%a0)	|force pos double zero
54162306a36Sopenharmony_ci	clrl	LOCAL_HI(%a0)
54262306a36Sopenharmony_ci	clrl	LOCAL_LO(%a0)
54362306a36Sopenharmony_ci	orl	#z_mask,USER_FPSR(%a6)
54462306a36Sopenharmony_ci	orl	#unfinx_mask,USER_FPSR(%a6)
54562306a36Sopenharmony_ci	bra	wr_etemp
54662306a36Sopenharmony_cicu_dpdr:
54762306a36Sopenharmony_ci	movel	#0x3c010000,LOCAL_EX(%a0)	|force pos double zero
54862306a36Sopenharmony_ci	clrl	LOCAL_HI(%a0)
54962306a36Sopenharmony_ci	movel	#0x800,LOCAL_LO(%a0)	|with lsb set
55062306a36Sopenharmony_ci	orl	#unfinx_mask,USER_FPSR(%a6)
55162306a36Sopenharmony_ci	bra	wr_etemp
55262306a36Sopenharmony_cicu_dnd:
55362306a36Sopenharmony_ci	movel	#0xbc010000,LOCAL_EX(%a0)	|force pos double zero
55462306a36Sopenharmony_ci	clrl	LOCAL_HI(%a0)
55562306a36Sopenharmony_ci	clrl	LOCAL_LO(%a0)
55662306a36Sopenharmony_ci	orl	#z_mask,USER_FPSR(%a6)
55762306a36Sopenharmony_ci	orl	#neg_mask,USER_FPSR(%a6)
55862306a36Sopenharmony_ci	orl	#unfinx_mask,USER_FPSR(%a6)
55962306a36Sopenharmony_ci	bra	wr_etemp
56062306a36Sopenharmony_cicu_dndr:
56162306a36Sopenharmony_ci	movel	#0xbc010000,LOCAL_EX(%a0)	|force pos double zero
56262306a36Sopenharmony_ci	clrl	LOCAL_HI(%a0)
56362306a36Sopenharmony_ci	movel	#0x800,LOCAL_LO(%a0)	|with lsb set
56462306a36Sopenharmony_ci	orl	#neg_mask,USER_FPSR(%a6)
56562306a36Sopenharmony_ci	orl	#unfinx_mask,USER_FPSR(%a6)
56662306a36Sopenharmony_ci	bra	wr_etemp
56762306a36Sopenharmony_ci|
56862306a36Sopenharmony_ci| These routines write +/- zero in single format.  The routines
56962306a36Sopenharmony_ci| cu_dpdr and cu_dndr set the single lsb.
57062306a36Sopenharmony_ci|
57162306a36Sopenharmony_cicu_spd:
57262306a36Sopenharmony_ci	movel	#0x3f810000,LOCAL_EX(%a0)	|force pos single zero
57362306a36Sopenharmony_ci	clrl	LOCAL_HI(%a0)
57462306a36Sopenharmony_ci	clrl	LOCAL_LO(%a0)
57562306a36Sopenharmony_ci	orl	#z_mask,USER_FPSR(%a6)
57662306a36Sopenharmony_ci	orl	#unfinx_mask,USER_FPSR(%a6)
57762306a36Sopenharmony_ci	bra	wr_etemp
57862306a36Sopenharmony_cicu_spdr:
57962306a36Sopenharmony_ci	movel	#0x3f810000,LOCAL_EX(%a0)	|force pos single zero
58062306a36Sopenharmony_ci	movel	#0x100,LOCAL_HI(%a0)	|with lsb set
58162306a36Sopenharmony_ci	clrl	LOCAL_LO(%a0)
58262306a36Sopenharmony_ci	orl	#unfinx_mask,USER_FPSR(%a6)
58362306a36Sopenharmony_ci	bra	wr_etemp
58462306a36Sopenharmony_cicu_snd:
58562306a36Sopenharmony_ci	movel	#0xbf810000,LOCAL_EX(%a0)	|force pos single zero
58662306a36Sopenharmony_ci	clrl	LOCAL_HI(%a0)
58762306a36Sopenharmony_ci	clrl	LOCAL_LO(%a0)
58862306a36Sopenharmony_ci	orl	#z_mask,USER_FPSR(%a6)
58962306a36Sopenharmony_ci	orl	#neg_mask,USER_FPSR(%a6)
59062306a36Sopenharmony_ci	orl	#unfinx_mask,USER_FPSR(%a6)
59162306a36Sopenharmony_ci	bra	wr_etemp
59262306a36Sopenharmony_cicu_sndr:
59362306a36Sopenharmony_ci	movel	#0xbf810000,LOCAL_EX(%a0)	|force pos single zero
59462306a36Sopenharmony_ci	movel	#0x100,LOCAL_HI(%a0)	|with lsb set
59562306a36Sopenharmony_ci	clrl	LOCAL_LO(%a0)
59662306a36Sopenharmony_ci	orl	#neg_mask,USER_FPSR(%a6)
59762306a36Sopenharmony_ci	orl	#unfinx_mask,USER_FPSR(%a6)
59862306a36Sopenharmony_ci	bra	wr_etemp
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci|
60162306a36Sopenharmony_ci| This code checks for 16-bit overflow conditions on dyadic
60262306a36Sopenharmony_ci| operations which are not restorable into the floating-point
60362306a36Sopenharmony_ci| unit and must be completed in software.  Basically, this
60462306a36Sopenharmony_ci| condition exists with a very large norm and a denorm.  One
60562306a36Sopenharmony_ci| of the operands must be denormalized to enter this code.
60662306a36Sopenharmony_ci|
60762306a36Sopenharmony_ci| Flags used:
60862306a36Sopenharmony_ci|	DY_MO_FLG contains 0 for monadic op, $ff for dyadic
60962306a36Sopenharmony_ci|	DNRM_FLG contains $00 for neither op denormalized
61062306a36Sopenharmony_ci|	                  $0f for the destination op denormalized
61162306a36Sopenharmony_ci|	                  $f0 for the source op denormalized
61262306a36Sopenharmony_ci|	                  $ff for both ops denormalized
61362306a36Sopenharmony_ci|
61462306a36Sopenharmony_ci| The wrap-around condition occurs for add, sub, div, and cmp
61562306a36Sopenharmony_ci| when
61662306a36Sopenharmony_ci|
61762306a36Sopenharmony_ci|	abs(dest_exp - src_exp) >= $8000
61862306a36Sopenharmony_ci|
61962306a36Sopenharmony_ci| and for mul when
62062306a36Sopenharmony_ci|
62162306a36Sopenharmony_ci|	(dest_exp + src_exp) < $0
62262306a36Sopenharmony_ci|
62362306a36Sopenharmony_ci| we must process the operation here if this case is true.
62462306a36Sopenharmony_ci|
62562306a36Sopenharmony_ci| The rts following the frcfpn routine is the exit from res_func
62662306a36Sopenharmony_ci| for this condition.  The restore flag (RES_FLG) is left clear.
62762306a36Sopenharmony_ci| No frestore is done unless an exception is to be reported.
62862306a36Sopenharmony_ci|
62962306a36Sopenharmony_ci| For fadd:
63062306a36Sopenharmony_ci|	if(sign_of(dest) != sign_of(src))
63162306a36Sopenharmony_ci|		replace exponent of src with $3fff (keep sign)
63262306a36Sopenharmony_ci|		use fpu to perform dest+new_src (user's rmode and X)
63362306a36Sopenharmony_ci|		clr sticky
63462306a36Sopenharmony_ci|	else
63562306a36Sopenharmony_ci|		set sticky
63662306a36Sopenharmony_ci|	call round with user's precision and mode
63762306a36Sopenharmony_ci|	move result to fpn and wbtemp
63862306a36Sopenharmony_ci|
63962306a36Sopenharmony_ci| For fsub:
64062306a36Sopenharmony_ci|	if(sign_of(dest) == sign_of(src))
64162306a36Sopenharmony_ci|		replace exponent of src with $3fff (keep sign)
64262306a36Sopenharmony_ci|		use fpu to perform dest+new_src (user's rmode and X)
64362306a36Sopenharmony_ci|		clr sticky
64462306a36Sopenharmony_ci|	else
64562306a36Sopenharmony_ci|		set sticky
64662306a36Sopenharmony_ci|	call round with user's precision and mode
64762306a36Sopenharmony_ci|	move result to fpn and wbtemp
64862306a36Sopenharmony_ci|
64962306a36Sopenharmony_ci| For fdiv/fsgldiv:
65062306a36Sopenharmony_ci|	if(both operands are denorm)
65162306a36Sopenharmony_ci|		restore_to_fpu;
65262306a36Sopenharmony_ci|	if(dest is norm)
65362306a36Sopenharmony_ci|		force_ovf;
65462306a36Sopenharmony_ci|	else(dest is denorm)
65562306a36Sopenharmony_ci|		force_unf:
65662306a36Sopenharmony_ci|
65762306a36Sopenharmony_ci| For fcmp:
65862306a36Sopenharmony_ci|	if(dest is norm)
65962306a36Sopenharmony_ci|		N = sign_of(dest);
66062306a36Sopenharmony_ci|	else(dest is denorm)
66162306a36Sopenharmony_ci|		N = sign_of(src);
66262306a36Sopenharmony_ci|
66362306a36Sopenharmony_ci| For fmul:
66462306a36Sopenharmony_ci|	if(both operands are denorm)
66562306a36Sopenharmony_ci|		force_unf;
66662306a36Sopenharmony_ci|	if((dest_exp + src_exp) < 0)
66762306a36Sopenharmony_ci|		force_unf:
66862306a36Sopenharmony_ci|	else
66962306a36Sopenharmony_ci|		restore_to_fpu;
67062306a36Sopenharmony_ci|
67162306a36Sopenharmony_ci| local equates:
67262306a36Sopenharmony_ci	.set	addcode,0x22
67362306a36Sopenharmony_ci	.set	subcode,0x28
67462306a36Sopenharmony_ci	.set	mulcode,0x23
67562306a36Sopenharmony_ci	.set	divcode,0x20
67662306a36Sopenharmony_ci	.set	cmpcode,0x38
67762306a36Sopenharmony_cick_wrap:
67862306a36Sopenharmony_ci	| tstb	DY_MO_FLG(%a6)	;check for fsqrt
67962306a36Sopenharmony_ci	beq	fix_stk		|if zero, it is fsqrt
68062306a36Sopenharmony_ci	movew	CMDREG1B(%a6),%d0
68162306a36Sopenharmony_ci	andiw	#0x3b,%d0		|strip to command bits
68262306a36Sopenharmony_ci	cmpiw	#addcode,%d0
68362306a36Sopenharmony_ci	beq	wrap_add
68462306a36Sopenharmony_ci	cmpiw	#subcode,%d0
68562306a36Sopenharmony_ci	beq	wrap_sub
68662306a36Sopenharmony_ci	cmpiw	#mulcode,%d0
68762306a36Sopenharmony_ci	beq	wrap_mul
68862306a36Sopenharmony_ci	cmpiw	#cmpcode,%d0
68962306a36Sopenharmony_ci	beq	wrap_cmp
69062306a36Sopenharmony_ci|
69162306a36Sopenharmony_ci| Inst is fdiv.
69262306a36Sopenharmony_ci|
69362306a36Sopenharmony_ciwrap_div:
69462306a36Sopenharmony_ci	cmpb	#0xff,DNRM_FLG(%a6) |if both ops denorm,
69562306a36Sopenharmony_ci	beq	fix_stk		 |restore to fpu
69662306a36Sopenharmony_ci|
69762306a36Sopenharmony_ci| One of the ops is denormalized.  Test for wrap condition
69862306a36Sopenharmony_ci| and force the result.
69962306a36Sopenharmony_ci|
70062306a36Sopenharmony_ci	cmpb	#0x0f,DNRM_FLG(%a6) |check for dest denorm
70162306a36Sopenharmony_ci	bnes	div_srcd
70262306a36Sopenharmony_cidiv_destd:
70362306a36Sopenharmony_ci	bsrl	ckinf_ns
70462306a36Sopenharmony_ci	bne	fix_stk
70562306a36Sopenharmony_ci	bfextu	ETEMP_EX(%a6){#1:#15},%d0	|get src exp (always pos)
70662306a36Sopenharmony_ci	bfexts	FPTEMP_EX(%a6){#1:#15},%d1	|get dest exp (always neg)
70762306a36Sopenharmony_ci	subl	%d1,%d0			|subtract dest from src
70862306a36Sopenharmony_ci	cmpl	#0x7fff,%d0
70962306a36Sopenharmony_ci	blt	fix_stk			|if less, not wrap case
71062306a36Sopenharmony_ci	clrb	WBTEMP_SGN(%a6)
71162306a36Sopenharmony_ci	movew	ETEMP_EX(%a6),%d0		|find the sign of the result
71262306a36Sopenharmony_ci	movew	FPTEMP_EX(%a6),%d1
71362306a36Sopenharmony_ci	eorw	%d1,%d0
71462306a36Sopenharmony_ci	andiw	#0x8000,%d0
71562306a36Sopenharmony_ci	beq	force_unf
71662306a36Sopenharmony_ci	st	WBTEMP_SGN(%a6)
71762306a36Sopenharmony_ci	bra	force_unf
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_cickinf_ns:
72062306a36Sopenharmony_ci	moveb	STAG(%a6),%d0		|check source tag for inf or nan
72162306a36Sopenharmony_ci	bra	ck_in_com
72262306a36Sopenharmony_cickinf_nd:
72362306a36Sopenharmony_ci	moveb	DTAG(%a6),%d0		|check destination tag for inf or nan
72462306a36Sopenharmony_cick_in_com:
72562306a36Sopenharmony_ci	andib	#0x60,%d0			|isolate tag bits
72662306a36Sopenharmony_ci	cmpb	#0x40,%d0			|is it inf?
72762306a36Sopenharmony_ci	beq	nan_or_inf		|not wrap case
72862306a36Sopenharmony_ci	cmpb	#0x60,%d0			|is it nan?
72962306a36Sopenharmony_ci	beq	nan_or_inf		|yes, not wrap case?
73062306a36Sopenharmony_ci	cmpb	#0x20,%d0			|is it a zero?
73162306a36Sopenharmony_ci	beq	nan_or_inf		|yes
73262306a36Sopenharmony_ci	clrl	%d0
73362306a36Sopenharmony_ci	rts				|then ; it is either a zero of norm,
73462306a36Sopenharmony_ci|					;check wrap case
73562306a36Sopenharmony_cinan_or_inf:
73662306a36Sopenharmony_ci	moveql	#-1,%d0
73762306a36Sopenharmony_ci	rts
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_cidiv_srcd:
74262306a36Sopenharmony_ci	bsrl	ckinf_nd
74362306a36Sopenharmony_ci	bne	fix_stk
74462306a36Sopenharmony_ci	bfextu	FPTEMP_EX(%a6){#1:#15},%d0	|get dest exp (always pos)
74562306a36Sopenharmony_ci	bfexts	ETEMP_EX(%a6){#1:#15},%d1	|get src exp (always neg)
74662306a36Sopenharmony_ci	subl	%d1,%d0			|subtract src from dest
74762306a36Sopenharmony_ci	cmpl	#0x8000,%d0
74862306a36Sopenharmony_ci	blt	fix_stk			|if less, not wrap case
74962306a36Sopenharmony_ci	clrb	WBTEMP_SGN(%a6)
75062306a36Sopenharmony_ci	movew	ETEMP_EX(%a6),%d0		|find the sign of the result
75162306a36Sopenharmony_ci	movew	FPTEMP_EX(%a6),%d1
75262306a36Sopenharmony_ci	eorw	%d1,%d0
75362306a36Sopenharmony_ci	andiw	#0x8000,%d0
75462306a36Sopenharmony_ci	beqs	force_ovf
75562306a36Sopenharmony_ci	st	WBTEMP_SGN(%a6)
75662306a36Sopenharmony_ci|
75762306a36Sopenharmony_ci| This code handles the case of the instruction resulting in
75862306a36Sopenharmony_ci| an overflow condition.
75962306a36Sopenharmony_ci|
76062306a36Sopenharmony_ciforce_ovf:
76162306a36Sopenharmony_ci	bclrb	#E1,E_BYTE(%a6)
76262306a36Sopenharmony_ci	orl	#ovfl_inx_mask,USER_FPSR(%a6)
76362306a36Sopenharmony_ci	clrw	NMNEXC(%a6)
76462306a36Sopenharmony_ci	leal	WBTEMP(%a6),%a0		|point a0 to memory location
76562306a36Sopenharmony_ci	movew	CMDREG1B(%a6),%d0
76662306a36Sopenharmony_ci	btstl	#6,%d0			|test for forced precision
76762306a36Sopenharmony_ci	beqs	frcovf_fpcr
76862306a36Sopenharmony_ci	btstl	#2,%d0			|check for double
76962306a36Sopenharmony_ci	bnes	frcovf_dbl
77062306a36Sopenharmony_ci	movel	#0x1,%d0			|inst is forced single
77162306a36Sopenharmony_ci	bras	frcovf_rnd
77262306a36Sopenharmony_cifrcovf_dbl:
77362306a36Sopenharmony_ci	movel	#0x2,%d0			|inst is forced double
77462306a36Sopenharmony_ci	bras	frcovf_rnd
77562306a36Sopenharmony_cifrcovf_fpcr:
77662306a36Sopenharmony_ci	bfextu	FPCR_MODE(%a6){#0:#2},%d0	|inst not forced - use fpcr prec
77762306a36Sopenharmony_cifrcovf_rnd:
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci| The 881/882 does not set inex2 for the following case, so the
78062306a36Sopenharmony_ci| line is commented out to be compatible with 881/882
78162306a36Sopenharmony_ci|	tst.b	%d0
78262306a36Sopenharmony_ci|	beq.b	frcovf_x
78362306a36Sopenharmony_ci|	or.l	#inex2_mask,USER_FPSR(%a6) ;if prec is s or d, set inex2
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci|frcovf_x:
78662306a36Sopenharmony_ci	bsrl	ovf_res			|get correct result based on
78762306a36Sopenharmony_ci|					;round precision/mode.  This
78862306a36Sopenharmony_ci|					;sets FPSR_CC correctly
78962306a36Sopenharmony_ci|					;returns in external format
79062306a36Sopenharmony_ci	bfclr	WBTEMP_SGN(%a6){#0:#8}
79162306a36Sopenharmony_ci	beq	frcfpn
79262306a36Sopenharmony_ci	bsetb	#sign_bit,WBTEMP_EX(%a6)
79362306a36Sopenharmony_ci	bra	frcfpn
79462306a36Sopenharmony_ci|
79562306a36Sopenharmony_ci| Inst is fadd.
79662306a36Sopenharmony_ci|
79762306a36Sopenharmony_ciwrap_add:
79862306a36Sopenharmony_ci	cmpb	#0xff,DNRM_FLG(%a6) |if both ops denorm,
79962306a36Sopenharmony_ci	beq	fix_stk		 |restore to fpu
80062306a36Sopenharmony_ci|
80162306a36Sopenharmony_ci| One of the ops is denormalized.  Test for wrap condition
80262306a36Sopenharmony_ci| and complete the instruction.
80362306a36Sopenharmony_ci|
80462306a36Sopenharmony_ci	cmpb	#0x0f,DNRM_FLG(%a6) |check for dest denorm
80562306a36Sopenharmony_ci	bnes	add_srcd
80662306a36Sopenharmony_ciadd_destd:
80762306a36Sopenharmony_ci	bsrl	ckinf_ns
80862306a36Sopenharmony_ci	bne	fix_stk
80962306a36Sopenharmony_ci	bfextu	ETEMP_EX(%a6){#1:#15},%d0	|get src exp (always pos)
81062306a36Sopenharmony_ci	bfexts	FPTEMP_EX(%a6){#1:#15},%d1	|get dest exp (always neg)
81162306a36Sopenharmony_ci	subl	%d1,%d0			|subtract dest from src
81262306a36Sopenharmony_ci	cmpl	#0x8000,%d0
81362306a36Sopenharmony_ci	blt	fix_stk			|if less, not wrap case
81462306a36Sopenharmony_ci	bra	add_wrap
81562306a36Sopenharmony_ciadd_srcd:
81662306a36Sopenharmony_ci	bsrl	ckinf_nd
81762306a36Sopenharmony_ci	bne	fix_stk
81862306a36Sopenharmony_ci	bfextu	FPTEMP_EX(%a6){#1:#15},%d0	|get dest exp (always pos)
81962306a36Sopenharmony_ci	bfexts	ETEMP_EX(%a6){#1:#15},%d1	|get src exp (always neg)
82062306a36Sopenharmony_ci	subl	%d1,%d0			|subtract src from dest
82162306a36Sopenharmony_ci	cmpl	#0x8000,%d0
82262306a36Sopenharmony_ci	blt	fix_stk			|if less, not wrap case
82362306a36Sopenharmony_ci|
82462306a36Sopenharmony_ci| Check the signs of the operands.  If they are unlike, the fpu
82562306a36Sopenharmony_ci| can be used to add the norm and 1.0 with the sign of the
82662306a36Sopenharmony_ci| denorm and it will correctly generate the result in extended
82762306a36Sopenharmony_ci| precision.  We can then call round with no sticky and the result
82862306a36Sopenharmony_ci| will be correct for the user's rounding mode and precision.  If
82962306a36Sopenharmony_ci| the signs are the same, we call round with the sticky bit set
83062306a36Sopenharmony_ci| and the result will be correct for the user's rounding mode and
83162306a36Sopenharmony_ci| precision.
83262306a36Sopenharmony_ci|
83362306a36Sopenharmony_ciadd_wrap:
83462306a36Sopenharmony_ci	movew	ETEMP_EX(%a6),%d0
83562306a36Sopenharmony_ci	movew	FPTEMP_EX(%a6),%d1
83662306a36Sopenharmony_ci	eorw	%d1,%d0
83762306a36Sopenharmony_ci	andiw	#0x8000,%d0
83862306a36Sopenharmony_ci	beq	add_same
83962306a36Sopenharmony_ci|
84062306a36Sopenharmony_ci| The signs are unlike.
84162306a36Sopenharmony_ci|
84262306a36Sopenharmony_ci	cmpb	#0x0f,DNRM_FLG(%a6) |is dest the denorm?
84362306a36Sopenharmony_ci	bnes	add_u_srcd
84462306a36Sopenharmony_ci	movew	FPTEMP_EX(%a6),%d0
84562306a36Sopenharmony_ci	andiw	#0x8000,%d0
84662306a36Sopenharmony_ci	orw	#0x3fff,%d0	|force the exponent to +/- 1
84762306a36Sopenharmony_ci	movew	%d0,FPTEMP_EX(%a6) |in the denorm
84862306a36Sopenharmony_ci	movel	USER_FPCR(%a6),%d0
84962306a36Sopenharmony_ci	andil	#0x30,%d0
85062306a36Sopenharmony_ci	fmovel	%d0,%fpcr		|set up users rmode and X
85162306a36Sopenharmony_ci	fmovex	ETEMP(%a6),%fp0
85262306a36Sopenharmony_ci	faddx	FPTEMP(%a6),%fp0
85362306a36Sopenharmony_ci	leal	WBTEMP(%a6),%a0	|point a0 to wbtemp in frame
85462306a36Sopenharmony_ci	fmovel	%fpsr,%d1
85562306a36Sopenharmony_ci	orl	%d1,USER_FPSR(%a6) |capture cc's and inex from fadd
85662306a36Sopenharmony_ci	fmovex	%fp0,WBTEMP(%a6)	|write result to memory
85762306a36Sopenharmony_ci	lsrl	#4,%d0		|put rmode in lower 2 bits
85862306a36Sopenharmony_ci	movel	USER_FPCR(%a6),%d1
85962306a36Sopenharmony_ci	andil	#0xc0,%d1
86062306a36Sopenharmony_ci	lsrl	#6,%d1		|put precision in upper word
86162306a36Sopenharmony_ci	swap	%d1
86262306a36Sopenharmony_ci	orl	%d0,%d1		|set up for round call
86362306a36Sopenharmony_ci	clrl	%d0		|force sticky to zero
86462306a36Sopenharmony_ci	bclrb	#sign_bit,WBTEMP_EX(%a6)
86562306a36Sopenharmony_ci	sne	WBTEMP_SGN(%a6)
86662306a36Sopenharmony_ci	bsrl	round		|round result to users rmode & prec
86762306a36Sopenharmony_ci	bfclr	WBTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
86862306a36Sopenharmony_ci	beq	frcfpnr
86962306a36Sopenharmony_ci	bsetb	#sign_bit,WBTEMP_EX(%a6)
87062306a36Sopenharmony_ci	bra	frcfpnr
87162306a36Sopenharmony_ciadd_u_srcd:
87262306a36Sopenharmony_ci	movew	ETEMP_EX(%a6),%d0
87362306a36Sopenharmony_ci	andiw	#0x8000,%d0
87462306a36Sopenharmony_ci	orw	#0x3fff,%d0	|force the exponent to +/- 1
87562306a36Sopenharmony_ci	movew	%d0,ETEMP_EX(%a6) |in the denorm
87662306a36Sopenharmony_ci	movel	USER_FPCR(%a6),%d0
87762306a36Sopenharmony_ci	andil	#0x30,%d0
87862306a36Sopenharmony_ci	fmovel	%d0,%fpcr		|set up users rmode and X
87962306a36Sopenharmony_ci	fmovex	ETEMP(%a6),%fp0
88062306a36Sopenharmony_ci	faddx	FPTEMP(%a6),%fp0
88162306a36Sopenharmony_ci	fmovel	%fpsr,%d1
88262306a36Sopenharmony_ci	orl	%d1,USER_FPSR(%a6) |capture cc's and inex from fadd
88362306a36Sopenharmony_ci	leal	WBTEMP(%a6),%a0	|point a0 to wbtemp in frame
88462306a36Sopenharmony_ci	fmovex	%fp0,WBTEMP(%a6)	|write result to memory
88562306a36Sopenharmony_ci	lsrl	#4,%d0		|put rmode in lower 2 bits
88662306a36Sopenharmony_ci	movel	USER_FPCR(%a6),%d1
88762306a36Sopenharmony_ci	andil	#0xc0,%d1
88862306a36Sopenharmony_ci	lsrl	#6,%d1		|put precision in upper word
88962306a36Sopenharmony_ci	swap	%d1
89062306a36Sopenharmony_ci	orl	%d0,%d1		|set up for round call
89162306a36Sopenharmony_ci	clrl	%d0		|force sticky to zero
89262306a36Sopenharmony_ci	bclrb	#sign_bit,WBTEMP_EX(%a6)
89362306a36Sopenharmony_ci	sne	WBTEMP_SGN(%a6)	|use internal format for round
89462306a36Sopenharmony_ci	bsrl	round		|round result to users rmode & prec
89562306a36Sopenharmony_ci	bfclr	WBTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
89662306a36Sopenharmony_ci	beq	frcfpnr
89762306a36Sopenharmony_ci	bsetb	#sign_bit,WBTEMP_EX(%a6)
89862306a36Sopenharmony_ci	bra	frcfpnr
89962306a36Sopenharmony_ci|
90062306a36Sopenharmony_ci| Signs are alike:
90162306a36Sopenharmony_ci|
90262306a36Sopenharmony_ciadd_same:
90362306a36Sopenharmony_ci	cmpb	#0x0f,DNRM_FLG(%a6) |is dest the denorm?
90462306a36Sopenharmony_ci	bnes	add_s_srcd
90562306a36Sopenharmony_ciadd_s_destd:
90662306a36Sopenharmony_ci	leal	ETEMP(%a6),%a0
90762306a36Sopenharmony_ci	movel	USER_FPCR(%a6),%d0
90862306a36Sopenharmony_ci	andil	#0x30,%d0
90962306a36Sopenharmony_ci	lsrl	#4,%d0		|put rmode in lower 2 bits
91062306a36Sopenharmony_ci	movel	USER_FPCR(%a6),%d1
91162306a36Sopenharmony_ci	andil	#0xc0,%d1
91262306a36Sopenharmony_ci	lsrl	#6,%d1		|put precision in upper word
91362306a36Sopenharmony_ci	swap	%d1
91462306a36Sopenharmony_ci	orl	%d0,%d1		|set up for round call
91562306a36Sopenharmony_ci	movel	#0x20000000,%d0	|set sticky for round
91662306a36Sopenharmony_ci	bclrb	#sign_bit,ETEMP_EX(%a6)
91762306a36Sopenharmony_ci	sne	ETEMP_SGN(%a6)
91862306a36Sopenharmony_ci	bsrl	round		|round result to users rmode & prec
91962306a36Sopenharmony_ci	bfclr	ETEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
92062306a36Sopenharmony_ci	beqs	add_s_dclr
92162306a36Sopenharmony_ci	bsetb	#sign_bit,ETEMP_EX(%a6)
92262306a36Sopenharmony_ciadd_s_dclr:
92362306a36Sopenharmony_ci	leal	WBTEMP(%a6),%a0
92462306a36Sopenharmony_ci	movel	ETEMP(%a6),(%a0)	|write result to wbtemp
92562306a36Sopenharmony_ci	movel	ETEMP_HI(%a6),4(%a0)
92662306a36Sopenharmony_ci	movel	ETEMP_LO(%a6),8(%a0)
92762306a36Sopenharmony_ci	tstw	ETEMP_EX(%a6)
92862306a36Sopenharmony_ci	bgt	add_ckovf
92962306a36Sopenharmony_ci	orl	#neg_mask,USER_FPSR(%a6)
93062306a36Sopenharmony_ci	bra	add_ckovf
93162306a36Sopenharmony_ciadd_s_srcd:
93262306a36Sopenharmony_ci	leal	FPTEMP(%a6),%a0
93362306a36Sopenharmony_ci	movel	USER_FPCR(%a6),%d0
93462306a36Sopenharmony_ci	andil	#0x30,%d0
93562306a36Sopenharmony_ci	lsrl	#4,%d0		|put rmode in lower 2 bits
93662306a36Sopenharmony_ci	movel	USER_FPCR(%a6),%d1
93762306a36Sopenharmony_ci	andil	#0xc0,%d1
93862306a36Sopenharmony_ci	lsrl	#6,%d1		|put precision in upper word
93962306a36Sopenharmony_ci	swap	%d1
94062306a36Sopenharmony_ci	orl	%d0,%d1		|set up for round call
94162306a36Sopenharmony_ci	movel	#0x20000000,%d0	|set sticky for round
94262306a36Sopenharmony_ci	bclrb	#sign_bit,FPTEMP_EX(%a6)
94362306a36Sopenharmony_ci	sne	FPTEMP_SGN(%a6)
94462306a36Sopenharmony_ci	bsrl	round		|round result to users rmode & prec
94562306a36Sopenharmony_ci	bfclr	FPTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
94662306a36Sopenharmony_ci	beqs	add_s_sclr
94762306a36Sopenharmony_ci	bsetb	#sign_bit,FPTEMP_EX(%a6)
94862306a36Sopenharmony_ciadd_s_sclr:
94962306a36Sopenharmony_ci	leal	WBTEMP(%a6),%a0
95062306a36Sopenharmony_ci	movel	FPTEMP(%a6),(%a0)	|write result to wbtemp
95162306a36Sopenharmony_ci	movel	FPTEMP_HI(%a6),4(%a0)
95262306a36Sopenharmony_ci	movel	FPTEMP_LO(%a6),8(%a0)
95362306a36Sopenharmony_ci	tstw	FPTEMP_EX(%a6)
95462306a36Sopenharmony_ci	bgt	add_ckovf
95562306a36Sopenharmony_ci	orl	#neg_mask,USER_FPSR(%a6)
95662306a36Sopenharmony_ciadd_ckovf:
95762306a36Sopenharmony_ci	movew	WBTEMP_EX(%a6),%d0
95862306a36Sopenharmony_ci	andiw	#0x7fff,%d0
95962306a36Sopenharmony_ci	cmpiw	#0x7fff,%d0
96062306a36Sopenharmony_ci	bne	frcfpnr
96162306a36Sopenharmony_ci|
96262306a36Sopenharmony_ci| The result has overflowed to $7fff exponent.  Set I, ovfl,
96362306a36Sopenharmony_ci| and aovfl, and clr the mantissa (incorrectly set by the
96462306a36Sopenharmony_ci| round routine.)
96562306a36Sopenharmony_ci|
96662306a36Sopenharmony_ci	orl	#inf_mask+ovfl_inx_mask,USER_FPSR(%a6)
96762306a36Sopenharmony_ci	clrl	4(%a0)
96862306a36Sopenharmony_ci	bra	frcfpnr
96962306a36Sopenharmony_ci|
97062306a36Sopenharmony_ci| Inst is fsub.
97162306a36Sopenharmony_ci|
97262306a36Sopenharmony_ciwrap_sub:
97362306a36Sopenharmony_ci	cmpb	#0xff,DNRM_FLG(%a6) |if both ops denorm,
97462306a36Sopenharmony_ci	beq	fix_stk		 |restore to fpu
97562306a36Sopenharmony_ci|
97662306a36Sopenharmony_ci| One of the ops is denormalized.  Test for wrap condition
97762306a36Sopenharmony_ci| and complete the instruction.
97862306a36Sopenharmony_ci|
97962306a36Sopenharmony_ci	cmpb	#0x0f,DNRM_FLG(%a6) |check for dest denorm
98062306a36Sopenharmony_ci	bnes	sub_srcd
98162306a36Sopenharmony_cisub_destd:
98262306a36Sopenharmony_ci	bsrl	ckinf_ns
98362306a36Sopenharmony_ci	bne	fix_stk
98462306a36Sopenharmony_ci	bfextu	ETEMP_EX(%a6){#1:#15},%d0	|get src exp (always pos)
98562306a36Sopenharmony_ci	bfexts	FPTEMP_EX(%a6){#1:#15},%d1	|get dest exp (always neg)
98662306a36Sopenharmony_ci	subl	%d1,%d0			|subtract src from dest
98762306a36Sopenharmony_ci	cmpl	#0x8000,%d0
98862306a36Sopenharmony_ci	blt	fix_stk			|if less, not wrap case
98962306a36Sopenharmony_ci	bra	sub_wrap
99062306a36Sopenharmony_cisub_srcd:
99162306a36Sopenharmony_ci	bsrl	ckinf_nd
99262306a36Sopenharmony_ci	bne	fix_stk
99362306a36Sopenharmony_ci	bfextu	FPTEMP_EX(%a6){#1:#15},%d0	|get dest exp (always pos)
99462306a36Sopenharmony_ci	bfexts	ETEMP_EX(%a6){#1:#15},%d1	|get src exp (always neg)
99562306a36Sopenharmony_ci	subl	%d1,%d0			|subtract dest from src
99662306a36Sopenharmony_ci	cmpl	#0x8000,%d0
99762306a36Sopenharmony_ci	blt	fix_stk			|if less, not wrap case
99862306a36Sopenharmony_ci|
99962306a36Sopenharmony_ci| Check the signs of the operands.  If they are alike, the fpu
100062306a36Sopenharmony_ci| can be used to subtract from the norm 1.0 with the sign of the
100162306a36Sopenharmony_ci| denorm and it will correctly generate the result in extended
100262306a36Sopenharmony_ci| precision.  We can then call round with no sticky and the result
100362306a36Sopenharmony_ci| will be correct for the user's rounding mode and precision.  If
100462306a36Sopenharmony_ci| the signs are unlike, we call round with the sticky bit set
100562306a36Sopenharmony_ci| and the result will be correct for the user's rounding mode and
100662306a36Sopenharmony_ci| precision.
100762306a36Sopenharmony_ci|
100862306a36Sopenharmony_cisub_wrap:
100962306a36Sopenharmony_ci	movew	ETEMP_EX(%a6),%d0
101062306a36Sopenharmony_ci	movew	FPTEMP_EX(%a6),%d1
101162306a36Sopenharmony_ci	eorw	%d1,%d0
101262306a36Sopenharmony_ci	andiw	#0x8000,%d0
101362306a36Sopenharmony_ci	bne	sub_diff
101462306a36Sopenharmony_ci|
101562306a36Sopenharmony_ci| The signs are alike.
101662306a36Sopenharmony_ci|
101762306a36Sopenharmony_ci	cmpb	#0x0f,DNRM_FLG(%a6) |is dest the denorm?
101862306a36Sopenharmony_ci	bnes	sub_u_srcd
101962306a36Sopenharmony_ci	movew	FPTEMP_EX(%a6),%d0
102062306a36Sopenharmony_ci	andiw	#0x8000,%d0
102162306a36Sopenharmony_ci	orw	#0x3fff,%d0	|force the exponent to +/- 1
102262306a36Sopenharmony_ci	movew	%d0,FPTEMP_EX(%a6) |in the denorm
102362306a36Sopenharmony_ci	movel	USER_FPCR(%a6),%d0
102462306a36Sopenharmony_ci	andil	#0x30,%d0
102562306a36Sopenharmony_ci	fmovel	%d0,%fpcr		|set up users rmode and X
102662306a36Sopenharmony_ci	fmovex	FPTEMP(%a6),%fp0
102762306a36Sopenharmony_ci	fsubx	ETEMP(%a6),%fp0
102862306a36Sopenharmony_ci	fmovel	%fpsr,%d1
102962306a36Sopenharmony_ci	orl	%d1,USER_FPSR(%a6) |capture cc's and inex from fadd
103062306a36Sopenharmony_ci	leal	WBTEMP(%a6),%a0	|point a0 to wbtemp in frame
103162306a36Sopenharmony_ci	fmovex	%fp0,WBTEMP(%a6)	|write result to memory
103262306a36Sopenharmony_ci	lsrl	#4,%d0		|put rmode in lower 2 bits
103362306a36Sopenharmony_ci	movel	USER_FPCR(%a6),%d1
103462306a36Sopenharmony_ci	andil	#0xc0,%d1
103562306a36Sopenharmony_ci	lsrl	#6,%d1		|put precision in upper word
103662306a36Sopenharmony_ci	swap	%d1
103762306a36Sopenharmony_ci	orl	%d0,%d1		|set up for round call
103862306a36Sopenharmony_ci	clrl	%d0		|force sticky to zero
103962306a36Sopenharmony_ci	bclrb	#sign_bit,WBTEMP_EX(%a6)
104062306a36Sopenharmony_ci	sne	WBTEMP_SGN(%a6)
104162306a36Sopenharmony_ci	bsrl	round		|round result to users rmode & prec
104262306a36Sopenharmony_ci	bfclr	WBTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
104362306a36Sopenharmony_ci	beq	frcfpnr
104462306a36Sopenharmony_ci	bsetb	#sign_bit,WBTEMP_EX(%a6)
104562306a36Sopenharmony_ci	bra	frcfpnr
104662306a36Sopenharmony_cisub_u_srcd:
104762306a36Sopenharmony_ci	movew	ETEMP_EX(%a6),%d0
104862306a36Sopenharmony_ci	andiw	#0x8000,%d0
104962306a36Sopenharmony_ci	orw	#0x3fff,%d0	|force the exponent to +/- 1
105062306a36Sopenharmony_ci	movew	%d0,ETEMP_EX(%a6) |in the denorm
105162306a36Sopenharmony_ci	movel	USER_FPCR(%a6),%d0
105262306a36Sopenharmony_ci	andil	#0x30,%d0
105362306a36Sopenharmony_ci	fmovel	%d0,%fpcr		|set up users rmode and X
105462306a36Sopenharmony_ci	fmovex	FPTEMP(%a6),%fp0
105562306a36Sopenharmony_ci	fsubx	ETEMP(%a6),%fp0
105662306a36Sopenharmony_ci	fmovel	%fpsr,%d1
105762306a36Sopenharmony_ci	orl	%d1,USER_FPSR(%a6) |capture cc's and inex from fadd
105862306a36Sopenharmony_ci	leal	WBTEMP(%a6),%a0	|point a0 to wbtemp in frame
105962306a36Sopenharmony_ci	fmovex	%fp0,WBTEMP(%a6)	|write result to memory
106062306a36Sopenharmony_ci	lsrl	#4,%d0		|put rmode in lower 2 bits
106162306a36Sopenharmony_ci	movel	USER_FPCR(%a6),%d1
106262306a36Sopenharmony_ci	andil	#0xc0,%d1
106362306a36Sopenharmony_ci	lsrl	#6,%d1		|put precision in upper word
106462306a36Sopenharmony_ci	swap	%d1
106562306a36Sopenharmony_ci	orl	%d0,%d1		|set up for round call
106662306a36Sopenharmony_ci	clrl	%d0		|force sticky to zero
106762306a36Sopenharmony_ci	bclrb	#sign_bit,WBTEMP_EX(%a6)
106862306a36Sopenharmony_ci	sne	WBTEMP_SGN(%a6)
106962306a36Sopenharmony_ci	bsrl	round		|round result to users rmode & prec
107062306a36Sopenharmony_ci	bfclr	WBTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
107162306a36Sopenharmony_ci	beq	frcfpnr
107262306a36Sopenharmony_ci	bsetb	#sign_bit,WBTEMP_EX(%a6)
107362306a36Sopenharmony_ci	bra	frcfpnr
107462306a36Sopenharmony_ci|
107562306a36Sopenharmony_ci| Signs are unlike:
107662306a36Sopenharmony_ci|
107762306a36Sopenharmony_cisub_diff:
107862306a36Sopenharmony_ci	cmpb	#0x0f,DNRM_FLG(%a6) |is dest the denorm?
107962306a36Sopenharmony_ci	bnes	sub_s_srcd
108062306a36Sopenharmony_cisub_s_destd:
108162306a36Sopenharmony_ci	leal	ETEMP(%a6),%a0
108262306a36Sopenharmony_ci	movel	USER_FPCR(%a6),%d0
108362306a36Sopenharmony_ci	andil	#0x30,%d0
108462306a36Sopenharmony_ci	lsrl	#4,%d0		|put rmode in lower 2 bits
108562306a36Sopenharmony_ci	movel	USER_FPCR(%a6),%d1
108662306a36Sopenharmony_ci	andil	#0xc0,%d1
108762306a36Sopenharmony_ci	lsrl	#6,%d1		|put precision in upper word
108862306a36Sopenharmony_ci	swap	%d1
108962306a36Sopenharmony_ci	orl	%d0,%d1		|set up for round call
109062306a36Sopenharmony_ci	movel	#0x20000000,%d0	|set sticky for round
109162306a36Sopenharmony_ci|
109262306a36Sopenharmony_ci| Since the dest is the denorm, the sign is the opposite of the
109362306a36Sopenharmony_ci| norm sign.
109462306a36Sopenharmony_ci|
109562306a36Sopenharmony_ci	eoriw	#0x8000,ETEMP_EX(%a6)	|flip sign on result
109662306a36Sopenharmony_ci	tstw	ETEMP_EX(%a6)
109762306a36Sopenharmony_ci	bgts	sub_s_dwr
109862306a36Sopenharmony_ci	orl	#neg_mask,USER_FPSR(%a6)
109962306a36Sopenharmony_cisub_s_dwr:
110062306a36Sopenharmony_ci	bclrb	#sign_bit,ETEMP_EX(%a6)
110162306a36Sopenharmony_ci	sne	ETEMP_SGN(%a6)
110262306a36Sopenharmony_ci	bsrl	round		|round result to users rmode & prec
110362306a36Sopenharmony_ci	bfclr	ETEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
110462306a36Sopenharmony_ci	beqs	sub_s_dclr
110562306a36Sopenharmony_ci	bsetb	#sign_bit,ETEMP_EX(%a6)
110662306a36Sopenharmony_cisub_s_dclr:
110762306a36Sopenharmony_ci	leal	WBTEMP(%a6),%a0
110862306a36Sopenharmony_ci	movel	ETEMP(%a6),(%a0)	|write result to wbtemp
110962306a36Sopenharmony_ci	movel	ETEMP_HI(%a6),4(%a0)
111062306a36Sopenharmony_ci	movel	ETEMP_LO(%a6),8(%a0)
111162306a36Sopenharmony_ci	bra	sub_ckovf
111262306a36Sopenharmony_cisub_s_srcd:
111362306a36Sopenharmony_ci	leal	FPTEMP(%a6),%a0
111462306a36Sopenharmony_ci	movel	USER_FPCR(%a6),%d0
111562306a36Sopenharmony_ci	andil	#0x30,%d0
111662306a36Sopenharmony_ci	lsrl	#4,%d0		|put rmode in lower 2 bits
111762306a36Sopenharmony_ci	movel	USER_FPCR(%a6),%d1
111862306a36Sopenharmony_ci	andil	#0xc0,%d1
111962306a36Sopenharmony_ci	lsrl	#6,%d1		|put precision in upper word
112062306a36Sopenharmony_ci	swap	%d1
112162306a36Sopenharmony_ci	orl	%d0,%d1		|set up for round call
112262306a36Sopenharmony_ci	movel	#0x20000000,%d0	|set sticky for round
112362306a36Sopenharmony_ci	bclrb	#sign_bit,FPTEMP_EX(%a6)
112462306a36Sopenharmony_ci	sne	FPTEMP_SGN(%a6)
112562306a36Sopenharmony_ci	bsrl	round		|round result to users rmode & prec
112662306a36Sopenharmony_ci	bfclr	FPTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
112762306a36Sopenharmony_ci	beqs	sub_s_sclr
112862306a36Sopenharmony_ci	bsetb	#sign_bit,FPTEMP_EX(%a6)
112962306a36Sopenharmony_cisub_s_sclr:
113062306a36Sopenharmony_ci	leal	WBTEMP(%a6),%a0
113162306a36Sopenharmony_ci	movel	FPTEMP(%a6),(%a0)	|write result to wbtemp
113262306a36Sopenharmony_ci	movel	FPTEMP_HI(%a6),4(%a0)
113362306a36Sopenharmony_ci	movel	FPTEMP_LO(%a6),8(%a0)
113462306a36Sopenharmony_ci	tstw	FPTEMP_EX(%a6)
113562306a36Sopenharmony_ci	bgt	sub_ckovf
113662306a36Sopenharmony_ci	orl	#neg_mask,USER_FPSR(%a6)
113762306a36Sopenharmony_cisub_ckovf:
113862306a36Sopenharmony_ci	movew	WBTEMP_EX(%a6),%d0
113962306a36Sopenharmony_ci	andiw	#0x7fff,%d0
114062306a36Sopenharmony_ci	cmpiw	#0x7fff,%d0
114162306a36Sopenharmony_ci	bne	frcfpnr
114262306a36Sopenharmony_ci|
114362306a36Sopenharmony_ci| The result has overflowed to $7fff exponent.  Set I, ovfl,
114462306a36Sopenharmony_ci| and aovfl, and clr the mantissa (incorrectly set by the
114562306a36Sopenharmony_ci| round routine.)
114662306a36Sopenharmony_ci|
114762306a36Sopenharmony_ci	orl	#inf_mask+ovfl_inx_mask,USER_FPSR(%a6)
114862306a36Sopenharmony_ci	clrl	4(%a0)
114962306a36Sopenharmony_ci	bra	frcfpnr
115062306a36Sopenharmony_ci|
115162306a36Sopenharmony_ci| Inst is fcmp.
115262306a36Sopenharmony_ci|
115362306a36Sopenharmony_ciwrap_cmp:
115462306a36Sopenharmony_ci	cmpb	#0xff,DNRM_FLG(%a6) |if both ops denorm,
115562306a36Sopenharmony_ci	beq	fix_stk		 |restore to fpu
115662306a36Sopenharmony_ci|
115762306a36Sopenharmony_ci| One of the ops is denormalized.  Test for wrap condition
115862306a36Sopenharmony_ci| and complete the instruction.
115962306a36Sopenharmony_ci|
116062306a36Sopenharmony_ci	cmpb	#0x0f,DNRM_FLG(%a6) |check for dest denorm
116162306a36Sopenharmony_ci	bnes	cmp_srcd
116262306a36Sopenharmony_cicmp_destd:
116362306a36Sopenharmony_ci	bsrl	ckinf_ns
116462306a36Sopenharmony_ci	bne	fix_stk
116562306a36Sopenharmony_ci	bfextu	ETEMP_EX(%a6){#1:#15},%d0	|get src exp (always pos)
116662306a36Sopenharmony_ci	bfexts	FPTEMP_EX(%a6){#1:#15},%d1	|get dest exp (always neg)
116762306a36Sopenharmony_ci	subl	%d1,%d0			|subtract dest from src
116862306a36Sopenharmony_ci	cmpl	#0x8000,%d0
116962306a36Sopenharmony_ci	blt	fix_stk			|if less, not wrap case
117062306a36Sopenharmony_ci	tstw	ETEMP_EX(%a6)		|set N to ~sign_of(src)
117162306a36Sopenharmony_ci	bge	cmp_setn
117262306a36Sopenharmony_ci	rts
117362306a36Sopenharmony_cicmp_srcd:
117462306a36Sopenharmony_ci	bsrl	ckinf_nd
117562306a36Sopenharmony_ci	bne	fix_stk
117662306a36Sopenharmony_ci	bfextu	FPTEMP_EX(%a6){#1:#15},%d0	|get dest exp (always pos)
117762306a36Sopenharmony_ci	bfexts	ETEMP_EX(%a6){#1:#15},%d1	|get src exp (always neg)
117862306a36Sopenharmony_ci	subl	%d1,%d0			|subtract src from dest
117962306a36Sopenharmony_ci	cmpl	#0x8000,%d0
118062306a36Sopenharmony_ci	blt	fix_stk			|if less, not wrap case
118162306a36Sopenharmony_ci	tstw	FPTEMP_EX(%a6)		|set N to sign_of(dest)
118262306a36Sopenharmony_ci	blt	cmp_setn
118362306a36Sopenharmony_ci	rts
118462306a36Sopenharmony_cicmp_setn:
118562306a36Sopenharmony_ci	orl	#neg_mask,USER_FPSR(%a6)
118662306a36Sopenharmony_ci	rts
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci|
118962306a36Sopenharmony_ci| Inst is fmul.
119062306a36Sopenharmony_ci|
119162306a36Sopenharmony_ciwrap_mul:
119262306a36Sopenharmony_ci	cmpb	#0xff,DNRM_FLG(%a6) |if both ops denorm,
119362306a36Sopenharmony_ci	beq	force_unf	|force an underflow (really!)
119462306a36Sopenharmony_ci|
119562306a36Sopenharmony_ci| One of the ops is denormalized.  Test for wrap condition
119662306a36Sopenharmony_ci| and complete the instruction.
119762306a36Sopenharmony_ci|
119862306a36Sopenharmony_ci	cmpb	#0x0f,DNRM_FLG(%a6) |check for dest denorm
119962306a36Sopenharmony_ci	bnes	mul_srcd
120062306a36Sopenharmony_cimul_destd:
120162306a36Sopenharmony_ci	bsrl	ckinf_ns
120262306a36Sopenharmony_ci	bne	fix_stk
120362306a36Sopenharmony_ci	bfextu	ETEMP_EX(%a6){#1:#15},%d0	|get src exp (always pos)
120462306a36Sopenharmony_ci	bfexts	FPTEMP_EX(%a6){#1:#15},%d1	|get dest exp (always neg)
120562306a36Sopenharmony_ci	addl	%d1,%d0			|subtract dest from src
120662306a36Sopenharmony_ci	bgt	fix_stk
120762306a36Sopenharmony_ci	bra	force_unf
120862306a36Sopenharmony_cimul_srcd:
120962306a36Sopenharmony_ci	bsrl	ckinf_nd
121062306a36Sopenharmony_ci	bne	fix_stk
121162306a36Sopenharmony_ci	bfextu	FPTEMP_EX(%a6){#1:#15},%d0	|get dest exp (always pos)
121262306a36Sopenharmony_ci	bfexts	ETEMP_EX(%a6){#1:#15},%d1	|get src exp (always neg)
121362306a36Sopenharmony_ci	addl	%d1,%d0			|subtract src from dest
121462306a36Sopenharmony_ci	bgt	fix_stk
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ci|
121762306a36Sopenharmony_ci| This code handles the case of the instruction resulting in
121862306a36Sopenharmony_ci| an underflow condition.
121962306a36Sopenharmony_ci|
122062306a36Sopenharmony_ciforce_unf:
122162306a36Sopenharmony_ci	bclrb	#E1,E_BYTE(%a6)
122262306a36Sopenharmony_ci	orl	#unfinx_mask,USER_FPSR(%a6)
122362306a36Sopenharmony_ci	clrw	NMNEXC(%a6)
122462306a36Sopenharmony_ci	clrb	WBTEMP_SGN(%a6)
122562306a36Sopenharmony_ci	movew	ETEMP_EX(%a6),%d0		|find the sign of the result
122662306a36Sopenharmony_ci	movew	FPTEMP_EX(%a6),%d1
122762306a36Sopenharmony_ci	eorw	%d1,%d0
122862306a36Sopenharmony_ci	andiw	#0x8000,%d0
122962306a36Sopenharmony_ci	beqs	frcunfcont
123062306a36Sopenharmony_ci	st	WBTEMP_SGN(%a6)
123162306a36Sopenharmony_cifrcunfcont:
123262306a36Sopenharmony_ci	lea	WBTEMP(%a6),%a0		|point a0 to memory location
123362306a36Sopenharmony_ci	movew	CMDREG1B(%a6),%d0
123462306a36Sopenharmony_ci	btstl	#6,%d0			|test for forced precision
123562306a36Sopenharmony_ci	beqs	frcunf_fpcr
123662306a36Sopenharmony_ci	btstl	#2,%d0			|check for double
123762306a36Sopenharmony_ci	bnes	frcunf_dbl
123862306a36Sopenharmony_ci	movel	#0x1,%d0			|inst is forced single
123962306a36Sopenharmony_ci	bras	frcunf_rnd
124062306a36Sopenharmony_cifrcunf_dbl:
124162306a36Sopenharmony_ci	movel	#0x2,%d0			|inst is forced double
124262306a36Sopenharmony_ci	bras	frcunf_rnd
124362306a36Sopenharmony_cifrcunf_fpcr:
124462306a36Sopenharmony_ci	bfextu	FPCR_MODE(%a6){#0:#2},%d0	|inst not forced - use fpcr prec
124562306a36Sopenharmony_cifrcunf_rnd:
124662306a36Sopenharmony_ci	bsrl	unf_sub			|get correct result based on
124762306a36Sopenharmony_ci|					;round precision/mode.  This
124862306a36Sopenharmony_ci|					;sets FPSR_CC correctly
124962306a36Sopenharmony_ci	bfclr	WBTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
125062306a36Sopenharmony_ci	beqs	frcfpn
125162306a36Sopenharmony_ci	bsetb	#sign_bit,WBTEMP_EX(%a6)
125262306a36Sopenharmony_ci	bra	frcfpn
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_ci|
125562306a36Sopenharmony_ci| Write the result to the user's fpn.  All results must be HUGE to be
125662306a36Sopenharmony_ci| written; otherwise the results would have overflowed or underflowed.
125762306a36Sopenharmony_ci| If the rounding precision is single or double, the ovf_res routine
125862306a36Sopenharmony_ci| is needed to correctly supply the max value.
125962306a36Sopenharmony_ci|
126062306a36Sopenharmony_cifrcfpnr:
126162306a36Sopenharmony_ci	movew	CMDREG1B(%a6),%d0
126262306a36Sopenharmony_ci	btstl	#6,%d0			|test for forced precision
126362306a36Sopenharmony_ci	beqs	frcfpn_fpcr
126462306a36Sopenharmony_ci	btstl	#2,%d0			|check for double
126562306a36Sopenharmony_ci	bnes	frcfpn_dbl
126662306a36Sopenharmony_ci	movel	#0x1,%d0			|inst is forced single
126762306a36Sopenharmony_ci	bras	frcfpn_rnd
126862306a36Sopenharmony_cifrcfpn_dbl:
126962306a36Sopenharmony_ci	movel	#0x2,%d0			|inst is forced double
127062306a36Sopenharmony_ci	bras	frcfpn_rnd
127162306a36Sopenharmony_cifrcfpn_fpcr:
127262306a36Sopenharmony_ci	bfextu	FPCR_MODE(%a6){#0:#2},%d0	|inst not forced - use fpcr prec
127362306a36Sopenharmony_ci	tstb	%d0
127462306a36Sopenharmony_ci	beqs	frcfpn			|if extended, write what you got
127562306a36Sopenharmony_cifrcfpn_rnd:
127662306a36Sopenharmony_ci	bclrb	#sign_bit,WBTEMP_EX(%a6)
127762306a36Sopenharmony_ci	sne	WBTEMP_SGN(%a6)
127862306a36Sopenharmony_ci	bsrl	ovf_res			|get correct result based on
127962306a36Sopenharmony_ci|					;round precision/mode.  This
128062306a36Sopenharmony_ci|					;sets FPSR_CC correctly
128162306a36Sopenharmony_ci	bfclr	WBTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
128262306a36Sopenharmony_ci	beqs	frcfpn_clr
128362306a36Sopenharmony_ci	bsetb	#sign_bit,WBTEMP_EX(%a6)
128462306a36Sopenharmony_cifrcfpn_clr:
128562306a36Sopenharmony_ci	orl	#ovfinx_mask,USER_FPSR(%a6)
128662306a36Sopenharmony_ci|
128762306a36Sopenharmony_ci| Perform the write.
128862306a36Sopenharmony_ci|
128962306a36Sopenharmony_cifrcfpn:
129062306a36Sopenharmony_ci	bfextu	CMDREG1B(%a6){#6:#3},%d0	|extract fp destination register
129162306a36Sopenharmony_ci	cmpib	#3,%d0
129262306a36Sopenharmony_ci	bles	frc0123			|check if dest is fp0-fp3
129362306a36Sopenharmony_ci	movel	#7,%d1
129462306a36Sopenharmony_ci	subl	%d0,%d1
129562306a36Sopenharmony_ci	clrl	%d0
129662306a36Sopenharmony_ci	bsetl	%d1,%d0
129762306a36Sopenharmony_ci	fmovemx WBTEMP(%a6),%d0
129862306a36Sopenharmony_ci	rts
129962306a36Sopenharmony_cifrc0123:
130062306a36Sopenharmony_ci	cmpib	#0,%d0
130162306a36Sopenharmony_ci	beqs	frc0_dst
130262306a36Sopenharmony_ci	cmpib	#1,%d0
130362306a36Sopenharmony_ci	beqs	frc1_dst
130462306a36Sopenharmony_ci	cmpib	#2,%d0
130562306a36Sopenharmony_ci	beqs	frc2_dst
130662306a36Sopenharmony_cifrc3_dst:
130762306a36Sopenharmony_ci	movel	WBTEMP_EX(%a6),USER_FP3(%a6)
130862306a36Sopenharmony_ci	movel	WBTEMP_HI(%a6),USER_FP3+4(%a6)
130962306a36Sopenharmony_ci	movel	WBTEMP_LO(%a6),USER_FP3+8(%a6)
131062306a36Sopenharmony_ci	rts
131162306a36Sopenharmony_cifrc2_dst:
131262306a36Sopenharmony_ci	movel	WBTEMP_EX(%a6),USER_FP2(%a6)
131362306a36Sopenharmony_ci	movel	WBTEMP_HI(%a6),USER_FP2+4(%a6)
131462306a36Sopenharmony_ci	movel	WBTEMP_LO(%a6),USER_FP2+8(%a6)
131562306a36Sopenharmony_ci	rts
131662306a36Sopenharmony_cifrc1_dst:
131762306a36Sopenharmony_ci	movel	WBTEMP_EX(%a6),USER_FP1(%a6)
131862306a36Sopenharmony_ci	movel	WBTEMP_HI(%a6),USER_FP1+4(%a6)
131962306a36Sopenharmony_ci	movel	WBTEMP_LO(%a6),USER_FP1+8(%a6)
132062306a36Sopenharmony_ci	rts
132162306a36Sopenharmony_cifrc0_dst:
132262306a36Sopenharmony_ci	movel	WBTEMP_EX(%a6),USER_FP0(%a6)
132362306a36Sopenharmony_ci	movel	WBTEMP_HI(%a6),USER_FP0+4(%a6)
132462306a36Sopenharmony_ci	movel	WBTEMP_LO(%a6),USER_FP0+8(%a6)
132562306a36Sopenharmony_ci	rts
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci|
132862306a36Sopenharmony_ci| Write etemp to fpn.
132962306a36Sopenharmony_ci| A check is made on enabled and signalled snan exceptions,
133062306a36Sopenharmony_ci| and the destination is not overwritten if this condition exists.
133162306a36Sopenharmony_ci| This code is designed to make fmoveins of unsupported data types
133262306a36Sopenharmony_ci| faster.
133362306a36Sopenharmony_ci|
133462306a36Sopenharmony_ciwr_etemp:
133562306a36Sopenharmony_ci	btstb	#snan_bit,FPSR_EXCEPT(%a6)	|if snan is set, and
133662306a36Sopenharmony_ci	beqs	fmoveinc		|enabled, force restore
133762306a36Sopenharmony_ci	btstb	#snan_bit,FPCR_ENABLE(%a6) |and don't overwrite
133862306a36Sopenharmony_ci	beqs	fmoveinc		|the dest
133962306a36Sopenharmony_ci	movel	ETEMP_EX(%a6),FPTEMP_EX(%a6)	|set up fptemp sign for
134062306a36Sopenharmony_ci|						;snan handler
134162306a36Sopenharmony_ci	tstb	ETEMP(%a6)		|check for negative
134262306a36Sopenharmony_ci	blts	snan_neg
134362306a36Sopenharmony_ci	rts
134462306a36Sopenharmony_cisnan_neg:
134562306a36Sopenharmony_ci	orl	#neg_bit,USER_FPSR(%a6)	|snan is negative; set N
134662306a36Sopenharmony_ci	rts
134762306a36Sopenharmony_cifmoveinc:
134862306a36Sopenharmony_ci	clrw	NMNEXC(%a6)
134962306a36Sopenharmony_ci	bclrb	#E1,E_BYTE(%a6)
135062306a36Sopenharmony_ci	moveb	STAG(%a6),%d0		|check if stag is inf
135162306a36Sopenharmony_ci	andib	#0xe0,%d0
135262306a36Sopenharmony_ci	cmpib	#0x40,%d0
135362306a36Sopenharmony_ci	bnes	fminc_cnan
135462306a36Sopenharmony_ci	orl	#inf_mask,USER_FPSR(%a6) |if inf, nothing yet has set I
135562306a36Sopenharmony_ci	tstw	LOCAL_EX(%a0)		|check sign
135662306a36Sopenharmony_ci	bges	fminc_con
135762306a36Sopenharmony_ci	orl	#neg_mask,USER_FPSR(%a6)
135862306a36Sopenharmony_ci	bra	fminc_con
135962306a36Sopenharmony_cifminc_cnan:
136062306a36Sopenharmony_ci	cmpib	#0x60,%d0			|check if stag is NaN
136162306a36Sopenharmony_ci	bnes	fminc_czero
136262306a36Sopenharmony_ci	orl	#nan_mask,USER_FPSR(%a6) |if nan, nothing yet has set NaN
136362306a36Sopenharmony_ci	movel	ETEMP_EX(%a6),FPTEMP_EX(%a6)	|set up fptemp sign for
136462306a36Sopenharmony_ci|						;snan handler
136562306a36Sopenharmony_ci	tstw	LOCAL_EX(%a0)		|check sign
136662306a36Sopenharmony_ci	bges	fminc_con
136762306a36Sopenharmony_ci	orl	#neg_mask,USER_FPSR(%a6)
136862306a36Sopenharmony_ci	bra	fminc_con
136962306a36Sopenharmony_cifminc_czero:
137062306a36Sopenharmony_ci	cmpib	#0x20,%d0			|check if zero
137162306a36Sopenharmony_ci	bnes	fminc_con
137262306a36Sopenharmony_ci	orl	#z_mask,USER_FPSR(%a6)	|if zero, set Z
137362306a36Sopenharmony_ci	tstw	LOCAL_EX(%a0)		|check sign
137462306a36Sopenharmony_ci	bges	fminc_con
137562306a36Sopenharmony_ci	orl	#neg_mask,USER_FPSR(%a6)
137662306a36Sopenharmony_cifminc_con:
137762306a36Sopenharmony_ci	bfextu	CMDREG1B(%a6){#6:#3},%d0	|extract fp destination register
137862306a36Sopenharmony_ci	cmpib	#3,%d0
137962306a36Sopenharmony_ci	bles	fp0123			|check if dest is fp0-fp3
138062306a36Sopenharmony_ci	movel	#7,%d1
138162306a36Sopenharmony_ci	subl	%d0,%d1
138262306a36Sopenharmony_ci	clrl	%d0
138362306a36Sopenharmony_ci	bsetl	%d1,%d0
138462306a36Sopenharmony_ci	fmovemx ETEMP(%a6),%d0
138562306a36Sopenharmony_ci	rts
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_cifp0123:
138862306a36Sopenharmony_ci	cmpib	#0,%d0
138962306a36Sopenharmony_ci	beqs	fp0_dst
139062306a36Sopenharmony_ci	cmpib	#1,%d0
139162306a36Sopenharmony_ci	beqs	fp1_dst
139262306a36Sopenharmony_ci	cmpib	#2,%d0
139362306a36Sopenharmony_ci	beqs	fp2_dst
139462306a36Sopenharmony_cifp3_dst:
139562306a36Sopenharmony_ci	movel	ETEMP_EX(%a6),USER_FP3(%a6)
139662306a36Sopenharmony_ci	movel	ETEMP_HI(%a6),USER_FP3+4(%a6)
139762306a36Sopenharmony_ci	movel	ETEMP_LO(%a6),USER_FP3+8(%a6)
139862306a36Sopenharmony_ci	rts
139962306a36Sopenharmony_cifp2_dst:
140062306a36Sopenharmony_ci	movel	ETEMP_EX(%a6),USER_FP2(%a6)
140162306a36Sopenharmony_ci	movel	ETEMP_HI(%a6),USER_FP2+4(%a6)
140262306a36Sopenharmony_ci	movel	ETEMP_LO(%a6),USER_FP2+8(%a6)
140362306a36Sopenharmony_ci	rts
140462306a36Sopenharmony_cifp1_dst:
140562306a36Sopenharmony_ci	movel	ETEMP_EX(%a6),USER_FP1(%a6)
140662306a36Sopenharmony_ci	movel	ETEMP_HI(%a6),USER_FP1+4(%a6)
140762306a36Sopenharmony_ci	movel	ETEMP_LO(%a6),USER_FP1+8(%a6)
140862306a36Sopenharmony_ci	rts
140962306a36Sopenharmony_cifp0_dst:
141062306a36Sopenharmony_ci	movel	ETEMP_EX(%a6),USER_FP0(%a6)
141162306a36Sopenharmony_ci	movel	ETEMP_HI(%a6),USER_FP0+4(%a6)
141262306a36Sopenharmony_ci	movel	ETEMP_LO(%a6),USER_FP0+8(%a6)
141362306a36Sopenharmony_ci	rts
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ciopclass3:
141662306a36Sopenharmony_ci	st	CU_ONLY(%a6)
141762306a36Sopenharmony_ci	movew	CMDREG1B(%a6),%d0	|check if packed moveout
141862306a36Sopenharmony_ci	andiw	#0x0c00,%d0	|isolate last 2 bits of size field
141962306a36Sopenharmony_ci	cmpiw	#0x0c00,%d0	|if size is 011 or 111, it is packed
142062306a36Sopenharmony_ci	beq	pack_out	|else it is norm or denorm
142162306a36Sopenharmony_ci	bra	mv_out
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_ci|
142562306a36Sopenharmony_ci|	MOVE OUT
142662306a36Sopenharmony_ci|
142762306a36Sopenharmony_ci
142862306a36Sopenharmony_cimv_tbl:
142962306a36Sopenharmony_ci	.long	li
143062306a36Sopenharmony_ci	.long	sgp
143162306a36Sopenharmony_ci	.long	xp
143262306a36Sopenharmony_ci	.long	mvout_end	|should never be taken
143362306a36Sopenharmony_ci	.long	wi
143462306a36Sopenharmony_ci	.long	dp
143562306a36Sopenharmony_ci	.long	bi
143662306a36Sopenharmony_ci	.long	mvout_end	|should never be taken
143762306a36Sopenharmony_cimv_out:
143862306a36Sopenharmony_ci	bfextu	CMDREG1B(%a6){#3:#3},%d1	|put source specifier in d1
143962306a36Sopenharmony_ci	leal	mv_tbl,%a0
144062306a36Sopenharmony_ci	movel	%a0@(%d1:l:4),%a0
144162306a36Sopenharmony_ci	jmp	(%a0)
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_ci|
144462306a36Sopenharmony_ci| This exit is for move-out to memory.  The aunfl bit is
144562306a36Sopenharmony_ci| set if the result is inex and unfl is signalled.
144662306a36Sopenharmony_ci|
144762306a36Sopenharmony_cimvout_end:
144862306a36Sopenharmony_ci	btstb	#inex2_bit,FPSR_EXCEPT(%a6)
144962306a36Sopenharmony_ci	beqs	no_aufl
145062306a36Sopenharmony_ci	btstb	#unfl_bit,FPSR_EXCEPT(%a6)
145162306a36Sopenharmony_ci	beqs	no_aufl
145262306a36Sopenharmony_ci	bsetb	#aunfl_bit,FPSR_AEXCEPT(%a6)
145362306a36Sopenharmony_cino_aufl:
145462306a36Sopenharmony_ci	clrw	NMNEXC(%a6)
145562306a36Sopenharmony_ci	bclrb	#E1,E_BYTE(%a6)
145662306a36Sopenharmony_ci	fmovel	#0,%FPSR			|clear any cc bits from res_func
145762306a36Sopenharmony_ci|
145862306a36Sopenharmony_ci| Return ETEMP to extended format from internal extended format so
145962306a36Sopenharmony_ci| that gen_except will have a correctly signed value for ovfl/unfl
146062306a36Sopenharmony_ci| handlers.
146162306a36Sopenharmony_ci|
146262306a36Sopenharmony_ci	bfclr	ETEMP_SGN(%a6){#0:#8}
146362306a36Sopenharmony_ci	beqs	mvout_con
146462306a36Sopenharmony_ci	bsetb	#sign_bit,ETEMP_EX(%a6)
146562306a36Sopenharmony_cimvout_con:
146662306a36Sopenharmony_ci	rts
146762306a36Sopenharmony_ci|
146862306a36Sopenharmony_ci| This exit is for move-out to int register.  The aunfl bit is
146962306a36Sopenharmony_ci| not set in any case for this move.
147062306a36Sopenharmony_ci|
147162306a36Sopenharmony_cimvouti_end:
147262306a36Sopenharmony_ci	clrw	NMNEXC(%a6)
147362306a36Sopenharmony_ci	bclrb	#E1,E_BYTE(%a6)
147462306a36Sopenharmony_ci	fmovel	#0,%FPSR			|clear any cc bits from res_func
147562306a36Sopenharmony_ci|
147662306a36Sopenharmony_ci| Return ETEMP to extended format from internal extended format so
147762306a36Sopenharmony_ci| that gen_except will have a correctly signed value for ovfl/unfl
147862306a36Sopenharmony_ci| handlers.
147962306a36Sopenharmony_ci|
148062306a36Sopenharmony_ci	bfclr	ETEMP_SGN(%a6){#0:#8}
148162306a36Sopenharmony_ci	beqs	mvouti_con
148262306a36Sopenharmony_ci	bsetb	#sign_bit,ETEMP_EX(%a6)
148362306a36Sopenharmony_cimvouti_con:
148462306a36Sopenharmony_ci	rts
148562306a36Sopenharmony_ci|
148662306a36Sopenharmony_ci| li is used to handle a long integer source specifier
148762306a36Sopenharmony_ci|
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_cili:
149062306a36Sopenharmony_ci	moveql	#4,%d0		|set byte count
149162306a36Sopenharmony_ci
149262306a36Sopenharmony_ci	btstb	#7,STAG(%a6)	|check for extended denorm
149362306a36Sopenharmony_ci	bne	int_dnrm	|if so, branch
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_ci	fmovemx ETEMP(%a6),%fp0-%fp0
149662306a36Sopenharmony_ci	fcmpd	#0x41dfffffffc00000,%fp0
149762306a36Sopenharmony_ci| 41dfffffffc00000 in dbl prec = 401d0000fffffffe00000000 in ext prec
149862306a36Sopenharmony_ci	fbge	lo_plrg
149962306a36Sopenharmony_ci	fcmpd	#0xc1e0000000000000,%fp0
150062306a36Sopenharmony_ci| c1e0000000000000 in dbl prec = c01e00008000000000000000 in ext prec
150162306a36Sopenharmony_ci	fble	lo_nlrg
150262306a36Sopenharmony_ci|
150362306a36Sopenharmony_ci| at this point, the answer is between the largest pos and neg values
150462306a36Sopenharmony_ci|
150562306a36Sopenharmony_ci	movel	USER_FPCR(%a6),%d1	|use user's rounding mode
150662306a36Sopenharmony_ci	andil	#0x30,%d1
150762306a36Sopenharmony_ci	fmovel	%d1,%fpcr
150862306a36Sopenharmony_ci	fmovel	%fp0,L_SCR1(%a6)	|let the 040 perform conversion
150962306a36Sopenharmony_ci	fmovel %fpsr,%d1
151062306a36Sopenharmony_ci	orl	%d1,USER_FPSR(%a6)	|capture inex2/ainex if set
151162306a36Sopenharmony_ci	bra	int_wrt
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_cilo_plrg:
151562306a36Sopenharmony_ci	movel	#0x7fffffff,L_SCR1(%a6)	|answer is largest positive int
151662306a36Sopenharmony_ci	fbeq	int_wrt			|exact answer
151762306a36Sopenharmony_ci	fcmpd	#0x41dfffffffe00000,%fp0
151862306a36Sopenharmony_ci| 41dfffffffe00000 in dbl prec = 401d0000ffffffff00000000 in ext prec
151962306a36Sopenharmony_ci	fbge	int_operr		|set operr
152062306a36Sopenharmony_ci	bra	int_inx			|set inexact
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_cilo_nlrg:
152362306a36Sopenharmony_ci	movel	#0x80000000,L_SCR1(%a6)
152462306a36Sopenharmony_ci	fbeq	int_wrt			|exact answer
152562306a36Sopenharmony_ci	fcmpd	#0xc1e0000000100000,%fp0
152662306a36Sopenharmony_ci| c1e0000000100000 in dbl prec = c01e00008000000080000000 in ext prec
152762306a36Sopenharmony_ci	fblt	int_operr		|set operr
152862306a36Sopenharmony_ci	bra	int_inx			|set inexact
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_ci|
153162306a36Sopenharmony_ci| wi is used to handle a word integer source specifier
153262306a36Sopenharmony_ci|
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ciwi:
153562306a36Sopenharmony_ci	moveql	#2,%d0		|set byte count
153662306a36Sopenharmony_ci
153762306a36Sopenharmony_ci	btstb	#7,STAG(%a6)	|check for extended denorm
153862306a36Sopenharmony_ci	bne	int_dnrm	|branch if so
153962306a36Sopenharmony_ci
154062306a36Sopenharmony_ci	fmovemx ETEMP(%a6),%fp0-%fp0
154162306a36Sopenharmony_ci	fcmps	#0x46fffe00,%fp0
154262306a36Sopenharmony_ci| 46fffe00 in sgl prec = 400d0000fffe000000000000 in ext prec
154362306a36Sopenharmony_ci	fbge	wo_plrg
154462306a36Sopenharmony_ci	fcmps	#0xc7000000,%fp0
154562306a36Sopenharmony_ci| c7000000 in sgl prec = c00e00008000000000000000 in ext prec
154662306a36Sopenharmony_ci	fble	wo_nlrg
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_ci|
154962306a36Sopenharmony_ci| at this point, the answer is between the largest pos and neg values
155062306a36Sopenharmony_ci|
155162306a36Sopenharmony_ci	movel	USER_FPCR(%a6),%d1	|use user's rounding mode
155262306a36Sopenharmony_ci	andil	#0x30,%d1
155362306a36Sopenharmony_ci	fmovel	%d1,%fpcr
155462306a36Sopenharmony_ci	fmovew	%fp0,L_SCR1(%a6)	|let the 040 perform conversion
155562306a36Sopenharmony_ci	fmovel %fpsr,%d1
155662306a36Sopenharmony_ci	orl	%d1,USER_FPSR(%a6)	|capture inex2/ainex if set
155762306a36Sopenharmony_ci	bra	int_wrt
155862306a36Sopenharmony_ci
155962306a36Sopenharmony_ciwo_plrg:
156062306a36Sopenharmony_ci	movew	#0x7fff,L_SCR1(%a6)	|answer is largest positive int
156162306a36Sopenharmony_ci	fbeq	int_wrt			|exact answer
156262306a36Sopenharmony_ci	fcmps	#0x46ffff00,%fp0
156362306a36Sopenharmony_ci| 46ffff00 in sgl prec = 400d0000ffff000000000000 in ext prec
156462306a36Sopenharmony_ci	fbge	int_operr		|set operr
156562306a36Sopenharmony_ci	bra	int_inx			|set inexact
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_ciwo_nlrg:
156862306a36Sopenharmony_ci	movew	#0x8000,L_SCR1(%a6)
156962306a36Sopenharmony_ci	fbeq	int_wrt			|exact answer
157062306a36Sopenharmony_ci	fcmps	#0xc7000080,%fp0
157162306a36Sopenharmony_ci| c7000080 in sgl prec = c00e00008000800000000000 in ext prec
157262306a36Sopenharmony_ci	fblt	int_operr		|set operr
157362306a36Sopenharmony_ci	bra	int_inx			|set inexact
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_ci|
157662306a36Sopenharmony_ci| bi is used to handle a byte integer source specifier
157762306a36Sopenharmony_ci|
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_cibi:
158062306a36Sopenharmony_ci	moveql	#1,%d0		|set byte count
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_ci	btstb	#7,STAG(%a6)	|check for extended denorm
158362306a36Sopenharmony_ci	bne	int_dnrm	|branch if so
158462306a36Sopenharmony_ci
158562306a36Sopenharmony_ci	fmovemx ETEMP(%a6),%fp0-%fp0
158662306a36Sopenharmony_ci	fcmps	#0x42fe0000,%fp0
158762306a36Sopenharmony_ci| 42fe0000 in sgl prec = 40050000fe00000000000000 in ext prec
158862306a36Sopenharmony_ci	fbge	by_plrg
158962306a36Sopenharmony_ci	fcmps	#0xc3000000,%fp0
159062306a36Sopenharmony_ci| c3000000 in sgl prec = c00600008000000000000000 in ext prec
159162306a36Sopenharmony_ci	fble	by_nlrg
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ci|
159462306a36Sopenharmony_ci| at this point, the answer is between the largest pos and neg values
159562306a36Sopenharmony_ci|
159662306a36Sopenharmony_ci	movel	USER_FPCR(%a6),%d1	|use user's rounding mode
159762306a36Sopenharmony_ci	andil	#0x30,%d1
159862306a36Sopenharmony_ci	fmovel	%d1,%fpcr
159962306a36Sopenharmony_ci	fmoveb	%fp0,L_SCR1(%a6)	|let the 040 perform conversion
160062306a36Sopenharmony_ci	fmovel %fpsr,%d1
160162306a36Sopenharmony_ci	orl	%d1,USER_FPSR(%a6)	|capture inex2/ainex if set
160262306a36Sopenharmony_ci	bra	int_wrt
160362306a36Sopenharmony_ci
160462306a36Sopenharmony_ciby_plrg:
160562306a36Sopenharmony_ci	moveb	#0x7f,L_SCR1(%a6)		|answer is largest positive int
160662306a36Sopenharmony_ci	fbeq	int_wrt			|exact answer
160762306a36Sopenharmony_ci	fcmps	#0x42ff0000,%fp0
160862306a36Sopenharmony_ci| 42ff0000 in sgl prec = 40050000ff00000000000000 in ext prec
160962306a36Sopenharmony_ci	fbge	int_operr		|set operr
161062306a36Sopenharmony_ci	bra	int_inx			|set inexact
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_ciby_nlrg:
161362306a36Sopenharmony_ci	moveb	#0x80,L_SCR1(%a6)
161462306a36Sopenharmony_ci	fbeq	int_wrt			|exact answer
161562306a36Sopenharmony_ci	fcmps	#0xc3008000,%fp0
161662306a36Sopenharmony_ci| c3008000 in sgl prec = c00600008080000000000000 in ext prec
161762306a36Sopenharmony_ci	fblt	int_operr		|set operr
161862306a36Sopenharmony_ci	bra	int_inx			|set inexact
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_ci|
162162306a36Sopenharmony_ci| Common integer routines
162262306a36Sopenharmony_ci|
162362306a36Sopenharmony_ci| int_drnrm---account for possible nonzero result for round up with positive
162462306a36Sopenharmony_ci| operand and round down for negative answer.  In the first case (result = 1)
162562306a36Sopenharmony_ci| byte-width (store in d0) of result must be honored.  In the second case,
162662306a36Sopenharmony_ci| -1 in L_SCR1(a6) will cover all contingencies (FMOVE.B/W/L out).
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ciint_dnrm:
162962306a36Sopenharmony_ci	movel	#0,L_SCR1(%a6)	| initialize result to 0
163062306a36Sopenharmony_ci	bfextu	FPCR_MODE(%a6){#2:#2},%d1	| d1 is the rounding mode
163162306a36Sopenharmony_ci	cmpb	#2,%d1
163262306a36Sopenharmony_ci	bmis	int_inx		| if RN or RZ, done
163362306a36Sopenharmony_ci	bnes	int_rp		| if RP, continue below
163462306a36Sopenharmony_ci	tstw	ETEMP(%a6)	| RM: store -1 in L_SCR1 if src is negative
163562306a36Sopenharmony_ci	bpls	int_inx		| otherwise result is 0
163662306a36Sopenharmony_ci	movel	#-1,L_SCR1(%a6)
163762306a36Sopenharmony_ci	bras	int_inx
163862306a36Sopenharmony_ciint_rp:
163962306a36Sopenharmony_ci	tstw	ETEMP(%a6)	| RP: store +1 of proper width in L_SCR1 if
164062306a36Sopenharmony_ci|				; source is greater than 0
164162306a36Sopenharmony_ci	bmis	int_inx		| otherwise, result is 0
164262306a36Sopenharmony_ci	lea	L_SCR1(%a6),%a1	| a1 is address of L_SCR1
164362306a36Sopenharmony_ci	addal	%d0,%a1		| offset by destination width -1
164462306a36Sopenharmony_ci	subal	#1,%a1
164562306a36Sopenharmony_ci	bsetb	#0,(%a1)		| set low bit at a1 address
164662306a36Sopenharmony_ciint_inx:
164762306a36Sopenharmony_ci	oril	#inx2a_mask,USER_FPSR(%a6)
164862306a36Sopenharmony_ci	bras	int_wrt
164962306a36Sopenharmony_ciint_operr:
165062306a36Sopenharmony_ci	fmovemx %fp0-%fp0,FPTEMP(%a6)	|FPTEMP must contain the extended
165162306a36Sopenharmony_ci|				;precision source that needs to be
165262306a36Sopenharmony_ci|				;converted to integer this is required
165362306a36Sopenharmony_ci|				;if the operr exception is enabled.
165462306a36Sopenharmony_ci|				;set operr/aiop (no inex2 on int ovfl)
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_ci	oril	#opaop_mask,USER_FPSR(%a6)
165762306a36Sopenharmony_ci|				;fall through to perform int_wrt
165862306a36Sopenharmony_ciint_wrt:
165962306a36Sopenharmony_ci	movel	EXC_EA(%a6),%a1	|load destination address
166062306a36Sopenharmony_ci	tstl	%a1		|check to see if it is a dest register
166162306a36Sopenharmony_ci	beqs	wrt_dn		|write data register
166262306a36Sopenharmony_ci	lea	L_SCR1(%a6),%a0	|point to supervisor source address
166362306a36Sopenharmony_ci	bsrl	mem_write
166462306a36Sopenharmony_ci	bra	mvouti_end
166562306a36Sopenharmony_ci
166662306a36Sopenharmony_ciwrt_dn:
166762306a36Sopenharmony_ci	movel	%d0,-(%sp)	|d0 currently contains the size to write
166862306a36Sopenharmony_ci	bsrl	get_fline	|get_fline returns Dn in d0
166962306a36Sopenharmony_ci	andiw	#0x7,%d0		|isolate register
167062306a36Sopenharmony_ci	movel	(%sp)+,%d1	|get size
167162306a36Sopenharmony_ci	cmpil	#4,%d1		|most frequent case
167262306a36Sopenharmony_ci	beqs	sz_long
167362306a36Sopenharmony_ci	cmpil	#2,%d1
167462306a36Sopenharmony_ci	bnes	sz_con
167562306a36Sopenharmony_ci	orl	#8,%d0		|add 'word' size to register#
167662306a36Sopenharmony_ci	bras	sz_con
167762306a36Sopenharmony_cisz_long:
167862306a36Sopenharmony_ci	orl	#0x10,%d0		|add 'long' size to register#
167962306a36Sopenharmony_cisz_con:
168062306a36Sopenharmony_ci	movel	%d0,%d1		|reg_dest expects size:reg in d1
168162306a36Sopenharmony_ci	bsrl	reg_dest	|load proper data register
168262306a36Sopenharmony_ci	bra	mvouti_end
168362306a36Sopenharmony_cixp:
168462306a36Sopenharmony_ci	lea	ETEMP(%a6),%a0
168562306a36Sopenharmony_ci	bclrb	#sign_bit,LOCAL_EX(%a0)
168662306a36Sopenharmony_ci	sne	LOCAL_SGN(%a0)
168762306a36Sopenharmony_ci	btstb	#7,STAG(%a6)	|check for extended denorm
168862306a36Sopenharmony_ci	bne	xdnrm
168962306a36Sopenharmony_ci	clrl	%d0
169062306a36Sopenharmony_ci	bras	do_fp		|do normal case
169162306a36Sopenharmony_cisgp:
169262306a36Sopenharmony_ci	lea	ETEMP(%a6),%a0
169362306a36Sopenharmony_ci	bclrb	#sign_bit,LOCAL_EX(%a0)
169462306a36Sopenharmony_ci	sne	LOCAL_SGN(%a0)
169562306a36Sopenharmony_ci	btstb	#7,STAG(%a6)	|check for extended denorm
169662306a36Sopenharmony_ci	bne	sp_catas	|branch if so
169762306a36Sopenharmony_ci	movew	LOCAL_EX(%a0),%d0
169862306a36Sopenharmony_ci	lea	sp_bnds,%a1
169962306a36Sopenharmony_ci	cmpw	(%a1),%d0
170062306a36Sopenharmony_ci	blt	sp_under
170162306a36Sopenharmony_ci	cmpw	2(%a1),%d0
170262306a36Sopenharmony_ci	bgt	sp_over
170362306a36Sopenharmony_ci	movel	#1,%d0		|set destination format to single
170462306a36Sopenharmony_ci	bras	do_fp		|do normal case
170562306a36Sopenharmony_cidp:
170662306a36Sopenharmony_ci	lea	ETEMP(%a6),%a0
170762306a36Sopenharmony_ci	bclrb	#sign_bit,LOCAL_EX(%a0)
170862306a36Sopenharmony_ci	sne	LOCAL_SGN(%a0)
170962306a36Sopenharmony_ci
171062306a36Sopenharmony_ci	btstb	#7,STAG(%a6)	|check for extended denorm
171162306a36Sopenharmony_ci	bne	dp_catas	|branch if so
171262306a36Sopenharmony_ci
171362306a36Sopenharmony_ci	movew	LOCAL_EX(%a0),%d0
171462306a36Sopenharmony_ci	lea	dp_bnds,%a1
171562306a36Sopenharmony_ci
171662306a36Sopenharmony_ci	cmpw	(%a1),%d0
171762306a36Sopenharmony_ci	blt	dp_under
171862306a36Sopenharmony_ci	cmpw	2(%a1),%d0
171962306a36Sopenharmony_ci	bgt	dp_over
172062306a36Sopenharmony_ci
172162306a36Sopenharmony_ci	movel	#2,%d0		|set destination format to double
172262306a36Sopenharmony_ci|				;fall through to do_fp
172362306a36Sopenharmony_ci|
172462306a36Sopenharmony_cido_fp:
172562306a36Sopenharmony_ci	bfextu	FPCR_MODE(%a6){#2:#2},%d1	|rnd mode in d1
172662306a36Sopenharmony_ci	swap	%d0			|rnd prec in upper word
172762306a36Sopenharmony_ci	addl	%d0,%d1			|d1 has PREC/MODE info
172862306a36Sopenharmony_ci
172962306a36Sopenharmony_ci	clrl	%d0			|clear g,r,s
173062306a36Sopenharmony_ci
173162306a36Sopenharmony_ci	bsrl	round			|round
173262306a36Sopenharmony_ci
173362306a36Sopenharmony_ci	movel	%a0,%a1
173462306a36Sopenharmony_ci	movel	EXC_EA(%a6),%a0
173562306a36Sopenharmony_ci
173662306a36Sopenharmony_ci	bfextu	CMDREG1B(%a6){#3:#3},%d1	|extract destination format
173762306a36Sopenharmony_ci|					;at this point only the dest
173862306a36Sopenharmony_ci|					;formats sgl, dbl, ext are
173962306a36Sopenharmony_ci|					;possible
174062306a36Sopenharmony_ci	cmpb	#2,%d1
174162306a36Sopenharmony_ci	bgts	ddbl			|double=5, extended=2, single=1
174262306a36Sopenharmony_ci	bnes	dsgl
174362306a36Sopenharmony_ci|					;fall through to dext
174462306a36Sopenharmony_cidext:
174562306a36Sopenharmony_ci	bsrl	dest_ext
174662306a36Sopenharmony_ci	bra	mvout_end
174762306a36Sopenharmony_cidsgl:
174862306a36Sopenharmony_ci	bsrl	dest_sgl
174962306a36Sopenharmony_ci	bra	mvout_end
175062306a36Sopenharmony_ciddbl:
175162306a36Sopenharmony_ci	bsrl	dest_dbl
175262306a36Sopenharmony_ci	bra	mvout_end
175362306a36Sopenharmony_ci
175462306a36Sopenharmony_ci|
175562306a36Sopenharmony_ci| Handle possible denorm or catastrophic underflow cases here
175662306a36Sopenharmony_ci|
175762306a36Sopenharmony_cixdnrm:
175862306a36Sopenharmony_ci	bsr	set_xop		|initialize WBTEMP
175962306a36Sopenharmony_ci	bsetb	#wbtemp15_bit,WB_BYTE(%a6) |set wbtemp15
176062306a36Sopenharmony_ci
176162306a36Sopenharmony_ci	movel	%a0,%a1
176262306a36Sopenharmony_ci	movel	EXC_EA(%a6),%a0	|a0 has the destination pointer
176362306a36Sopenharmony_ci	bsrl	dest_ext	|store to memory
176462306a36Sopenharmony_ci	bsetb	#unfl_bit,FPSR_EXCEPT(%a6)
176562306a36Sopenharmony_ci	bra	mvout_end
176662306a36Sopenharmony_ci
176762306a36Sopenharmony_cisp_under:
176862306a36Sopenharmony_ci	bsetb	#etemp15_bit,STAG(%a6)
176962306a36Sopenharmony_ci
177062306a36Sopenharmony_ci	cmpw	4(%a1),%d0
177162306a36Sopenharmony_ci	blts	sp_catas	|catastrophic underflow case
177262306a36Sopenharmony_ci
177362306a36Sopenharmony_ci	movel	#1,%d0		|load in round precision
177462306a36Sopenharmony_ci	movel	#sgl_thresh,%d1	|load in single denorm threshold
177562306a36Sopenharmony_ci	bsrl	dpspdnrm	|expects d1 to have the proper
177662306a36Sopenharmony_ci|				;denorm threshold
177762306a36Sopenharmony_ci	bsrl	dest_sgl	|stores value to destination
177862306a36Sopenharmony_ci	bsetb	#unfl_bit,FPSR_EXCEPT(%a6)
177962306a36Sopenharmony_ci	bra	mvout_end	|exit
178062306a36Sopenharmony_ci
178162306a36Sopenharmony_cidp_under:
178262306a36Sopenharmony_ci	bsetb	#etemp15_bit,STAG(%a6)
178362306a36Sopenharmony_ci
178462306a36Sopenharmony_ci	cmpw	4(%a1),%d0
178562306a36Sopenharmony_ci	blts	dp_catas	|catastrophic underflow case
178662306a36Sopenharmony_ci
178762306a36Sopenharmony_ci	movel	#dbl_thresh,%d1	|load in double precision threshold
178862306a36Sopenharmony_ci	movel	#2,%d0
178962306a36Sopenharmony_ci	bsrl	dpspdnrm	|expects d1 to have proper
179062306a36Sopenharmony_ci|				;denorm threshold
179162306a36Sopenharmony_ci|				;expects d0 to have round precision
179262306a36Sopenharmony_ci	bsrl	dest_dbl	|store value to destination
179362306a36Sopenharmony_ci	bsetb	#unfl_bit,FPSR_EXCEPT(%a6)
179462306a36Sopenharmony_ci	bra	mvout_end	|exit
179562306a36Sopenharmony_ci
179662306a36Sopenharmony_ci|
179762306a36Sopenharmony_ci| Handle catastrophic underflow cases here
179862306a36Sopenharmony_ci|
179962306a36Sopenharmony_cisp_catas:
180062306a36Sopenharmony_ci| Temp fix for z bit set in unf_sub
180162306a36Sopenharmony_ci	movel	USER_FPSR(%a6),-(%a7)
180262306a36Sopenharmony_ci
180362306a36Sopenharmony_ci	movel	#1,%d0		|set round precision to sgl
180462306a36Sopenharmony_ci
180562306a36Sopenharmony_ci	bsrl	unf_sub		|a0 points to result
180662306a36Sopenharmony_ci
180762306a36Sopenharmony_ci	movel	(%a7)+,USER_FPSR(%a6)
180862306a36Sopenharmony_ci
180962306a36Sopenharmony_ci	movel	#1,%d0
181062306a36Sopenharmony_ci	subw	%d0,LOCAL_EX(%a0) |account for difference between
181162306a36Sopenharmony_ci|				;denorm/norm bias
181262306a36Sopenharmony_ci
181362306a36Sopenharmony_ci	movel	%a0,%a1		|a1 has the operand input
181462306a36Sopenharmony_ci	movel	EXC_EA(%a6),%a0	|a0 has the destination pointer
181562306a36Sopenharmony_ci
181662306a36Sopenharmony_ci	bsrl	dest_sgl	|store the result
181762306a36Sopenharmony_ci	oril	#unfinx_mask,USER_FPSR(%a6)
181862306a36Sopenharmony_ci	bra	mvout_end
181962306a36Sopenharmony_ci
182062306a36Sopenharmony_cidp_catas:
182162306a36Sopenharmony_ci| Temp fix for z bit set in unf_sub
182262306a36Sopenharmony_ci	movel	USER_FPSR(%a6),-(%a7)
182362306a36Sopenharmony_ci
182462306a36Sopenharmony_ci	movel	#2,%d0		|set round precision to dbl
182562306a36Sopenharmony_ci	bsrl	unf_sub		|a0 points to result
182662306a36Sopenharmony_ci
182762306a36Sopenharmony_ci	movel	(%a7)+,USER_FPSR(%a6)
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_ci	movel	#1,%d0
183062306a36Sopenharmony_ci	subw	%d0,LOCAL_EX(%a0) |account for difference between
183162306a36Sopenharmony_ci|				;denorm/norm bias
183262306a36Sopenharmony_ci
183362306a36Sopenharmony_ci	movel	%a0,%a1		|a1 has the operand input
183462306a36Sopenharmony_ci	movel	EXC_EA(%a6),%a0	|a0 has the destination pointer
183562306a36Sopenharmony_ci
183662306a36Sopenharmony_ci	bsrl	dest_dbl	|store the result
183762306a36Sopenharmony_ci	oril	#unfinx_mask,USER_FPSR(%a6)
183862306a36Sopenharmony_ci	bra	mvout_end
183962306a36Sopenharmony_ci
184062306a36Sopenharmony_ci|
184162306a36Sopenharmony_ci| Handle catastrophic overflow cases here
184262306a36Sopenharmony_ci|
184362306a36Sopenharmony_cisp_over:
184462306a36Sopenharmony_ci| Temp fix for z bit set in unf_sub
184562306a36Sopenharmony_ci	movel	USER_FPSR(%a6),-(%a7)
184662306a36Sopenharmony_ci
184762306a36Sopenharmony_ci	movel	#1,%d0
184862306a36Sopenharmony_ci	leal	FP_SCR1(%a6),%a0	|use FP_SCR1 for creating result
184962306a36Sopenharmony_ci	movel	ETEMP_EX(%a6),(%a0)
185062306a36Sopenharmony_ci	movel	ETEMP_HI(%a6),4(%a0)
185162306a36Sopenharmony_ci	movel	ETEMP_LO(%a6),8(%a0)
185262306a36Sopenharmony_ci	bsrl	ovf_res
185362306a36Sopenharmony_ci
185462306a36Sopenharmony_ci	movel	(%a7)+,USER_FPSR(%a6)
185562306a36Sopenharmony_ci
185662306a36Sopenharmony_ci	movel	%a0,%a1
185762306a36Sopenharmony_ci	movel	EXC_EA(%a6),%a0
185862306a36Sopenharmony_ci	bsrl	dest_sgl
185962306a36Sopenharmony_ci	orl	#ovfinx_mask,USER_FPSR(%a6)
186062306a36Sopenharmony_ci	bra	mvout_end
186162306a36Sopenharmony_ci
186262306a36Sopenharmony_cidp_over:
186362306a36Sopenharmony_ci| Temp fix for z bit set in ovf_res
186462306a36Sopenharmony_ci	movel	USER_FPSR(%a6),-(%a7)
186562306a36Sopenharmony_ci
186662306a36Sopenharmony_ci	movel	#2,%d0
186762306a36Sopenharmony_ci	leal	FP_SCR1(%a6),%a0	|use FP_SCR1 for creating result
186862306a36Sopenharmony_ci	movel	ETEMP_EX(%a6),(%a0)
186962306a36Sopenharmony_ci	movel	ETEMP_HI(%a6),4(%a0)
187062306a36Sopenharmony_ci	movel	ETEMP_LO(%a6),8(%a0)
187162306a36Sopenharmony_ci	bsrl	ovf_res
187262306a36Sopenharmony_ci
187362306a36Sopenharmony_ci	movel	(%a7)+,USER_FPSR(%a6)
187462306a36Sopenharmony_ci
187562306a36Sopenharmony_ci	movel	%a0,%a1
187662306a36Sopenharmony_ci	movel	EXC_EA(%a6),%a0
187762306a36Sopenharmony_ci	bsrl	dest_dbl
187862306a36Sopenharmony_ci	orl	#ovfinx_mask,USER_FPSR(%a6)
187962306a36Sopenharmony_ci	bra	mvout_end
188062306a36Sopenharmony_ci
188162306a36Sopenharmony_ci|
188262306a36Sopenharmony_ci|	DPSPDNRM
188362306a36Sopenharmony_ci|
188462306a36Sopenharmony_ci| This subroutine takes an extended normalized number and denormalizes
188562306a36Sopenharmony_ci| it to the given round precision. This subroutine also decrements
188662306a36Sopenharmony_ci| the input operand's exponent by 1 to account for the fact that
188762306a36Sopenharmony_ci| dest_sgl or dest_dbl expects a normalized number's bias.
188862306a36Sopenharmony_ci|
188962306a36Sopenharmony_ci| Input: a0  points to a normalized number in internal extended format
189062306a36Sopenharmony_ci|	 d0  is the round precision (=1 for sgl; =2 for dbl)
189162306a36Sopenharmony_ci|	 d1  is the single precision or double precision
189262306a36Sopenharmony_ci|	     denorm threshold
189362306a36Sopenharmony_ci|
189462306a36Sopenharmony_ci| Output: (In the format for dest_sgl or dest_dbl)
189562306a36Sopenharmony_ci|	 a0   points to the destination
189662306a36Sopenharmony_ci|	 a1   points to the operand
189762306a36Sopenharmony_ci|
189862306a36Sopenharmony_ci| Exceptions: Reports inexact 2 exception by setting USER_FPSR bits
189962306a36Sopenharmony_ci|
190062306a36Sopenharmony_cidpspdnrm:
190162306a36Sopenharmony_ci	movel	%d0,-(%a7)	|save round precision
190262306a36Sopenharmony_ci	clrl	%d0		|clear initial g,r,s
190362306a36Sopenharmony_ci	bsrl	dnrm_lp		|careful with d0, it's needed by round
190462306a36Sopenharmony_ci
190562306a36Sopenharmony_ci	bfextu	FPCR_MODE(%a6){#2:#2},%d1 |get rounding mode
190662306a36Sopenharmony_ci	swap	%d1
190762306a36Sopenharmony_ci	movew	2(%a7),%d1	|set rounding precision
190862306a36Sopenharmony_ci	swap	%d1		|at this point d1 has PREC/MODE info
190962306a36Sopenharmony_ci	bsrl	round		|round result, sets the inex bit in
191062306a36Sopenharmony_ci|				;USER_FPSR if needed
191162306a36Sopenharmony_ci
191262306a36Sopenharmony_ci	movew	#1,%d0
191362306a36Sopenharmony_ci	subw	%d0,LOCAL_EX(%a0) |account for difference in denorm
191462306a36Sopenharmony_ci|				;vs norm bias
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_ci	movel	%a0,%a1		|a1 has the operand input
191762306a36Sopenharmony_ci	movel	EXC_EA(%a6),%a0	|a0 has the destination pointer
191862306a36Sopenharmony_ci	addw	#4,%a7		|pop stack
191962306a36Sopenharmony_ci	rts
192062306a36Sopenharmony_ci|
192162306a36Sopenharmony_ci| SET_XOP initialized WBTEMP with the value pointed to by a0
192262306a36Sopenharmony_ci| input: a0 points to input operand in the internal extended format
192362306a36Sopenharmony_ci|
192462306a36Sopenharmony_ciset_xop:
192562306a36Sopenharmony_ci	movel	LOCAL_EX(%a0),WBTEMP_EX(%a6)
192662306a36Sopenharmony_ci	movel	LOCAL_HI(%a0),WBTEMP_HI(%a6)
192762306a36Sopenharmony_ci	movel	LOCAL_LO(%a0),WBTEMP_LO(%a6)
192862306a36Sopenharmony_ci	bfclr	WBTEMP_SGN(%a6){#0:#8}
192962306a36Sopenharmony_ci	beqs	sxop
193062306a36Sopenharmony_ci	bsetb	#sign_bit,WBTEMP_EX(%a6)
193162306a36Sopenharmony_cisxop:
193262306a36Sopenharmony_ci	bfclr	STAG(%a6){#5:#4}	|clear wbtm66,wbtm1,wbtm0,sbit
193362306a36Sopenharmony_ci	rts
193462306a36Sopenharmony_ci|
193562306a36Sopenharmony_ci|	P_MOVE
193662306a36Sopenharmony_ci|
193762306a36Sopenharmony_cip_movet:
193862306a36Sopenharmony_ci	.long	p_move
193962306a36Sopenharmony_ci	.long	p_movez
194062306a36Sopenharmony_ci	.long	p_movei
194162306a36Sopenharmony_ci	.long	p_moven
194262306a36Sopenharmony_ci	.long	p_move
194362306a36Sopenharmony_cip_regd:
194462306a36Sopenharmony_ci	.long	p_dyd0
194562306a36Sopenharmony_ci	.long	p_dyd1
194662306a36Sopenharmony_ci	.long	p_dyd2
194762306a36Sopenharmony_ci	.long	p_dyd3
194862306a36Sopenharmony_ci	.long	p_dyd4
194962306a36Sopenharmony_ci	.long	p_dyd5
195062306a36Sopenharmony_ci	.long	p_dyd6
195162306a36Sopenharmony_ci	.long	p_dyd7
195262306a36Sopenharmony_ci
195362306a36Sopenharmony_cipack_out:
195462306a36Sopenharmony_ci	leal	p_movet,%a0	|load jmp table address
195562306a36Sopenharmony_ci	movew	STAG(%a6),%d0	|get source tag
195662306a36Sopenharmony_ci	bfextu	%d0{#16:#3},%d0	|isolate source bits
195762306a36Sopenharmony_ci	movel	(%a0,%d0.w*4),%a0	|load a0 with routine label for tag
195862306a36Sopenharmony_ci	jmp	(%a0)		|go to the routine
195962306a36Sopenharmony_ci
196062306a36Sopenharmony_cip_write:
196162306a36Sopenharmony_ci	movel	#0x0c,%d0	|get byte count
196262306a36Sopenharmony_ci	movel	EXC_EA(%a6),%a1	|get the destination address
196362306a36Sopenharmony_ci	bsr	mem_write	|write the user's destination
196462306a36Sopenharmony_ci	moveb	#0,CU_SAVEPC(%a6) |set the cu save pc to all 0's
196562306a36Sopenharmony_ci
196662306a36Sopenharmony_ci|
196762306a36Sopenharmony_ci| Also note that the dtag must be set to norm here - this is because
196862306a36Sopenharmony_ci| the 040 uses the dtag to execute the correct microcode.
196962306a36Sopenharmony_ci|
197062306a36Sopenharmony_ci        bfclr    DTAG(%a6){#0:#3}  |set dtag to norm
197162306a36Sopenharmony_ci
197262306a36Sopenharmony_ci	rts
197362306a36Sopenharmony_ci
197462306a36Sopenharmony_ci| Notes on handling of special case (zero, inf, and nan) inputs:
197562306a36Sopenharmony_ci|	1. Operr is not signalled if the k-factor is greater than 18.
197662306a36Sopenharmony_ci|	2. Per the manual, status bits are not set.
197762306a36Sopenharmony_ci|
197862306a36Sopenharmony_ci
197962306a36Sopenharmony_cip_move:
198062306a36Sopenharmony_ci	movew	CMDREG1B(%a6),%d0
198162306a36Sopenharmony_ci	btstl	#kfact_bit,%d0	|test for dynamic k-factor
198262306a36Sopenharmony_ci	beqs	statick		|if clear, k-factor is static
198362306a36Sopenharmony_cidynamick:
198462306a36Sopenharmony_ci	bfextu	%d0{#25:#3},%d0	|isolate register for dynamic k-factor
198562306a36Sopenharmony_ci	lea	p_regd,%a0
198662306a36Sopenharmony_ci	movel	%a0@(%d0:l:4),%a0
198762306a36Sopenharmony_ci	jmp	(%a0)
198862306a36Sopenharmony_cistatick:
198962306a36Sopenharmony_ci	andiw	#0x007f,%d0	|get k-factor
199062306a36Sopenharmony_ci	bfexts	%d0{#25:#7},%d0	|sign extend d0 for bindec
199162306a36Sopenharmony_ci	leal	ETEMP(%a6),%a0	|a0 will point to the packed decimal
199262306a36Sopenharmony_ci	bsrl	bindec		|perform the convert; data at a6
199362306a36Sopenharmony_ci	leal	FP_SCR1(%a6),%a0	|load a0 with result address
199462306a36Sopenharmony_ci	bral	p_write
199562306a36Sopenharmony_cip_movez:
199662306a36Sopenharmony_ci	leal	ETEMP(%a6),%a0	|a0 will point to the packed decimal
199762306a36Sopenharmony_ci	clrw	2(%a0)		|clear lower word of exp
199862306a36Sopenharmony_ci	clrl	4(%a0)		|load second lword of ZERO
199962306a36Sopenharmony_ci	clrl	8(%a0)		|load third lword of ZERO
200062306a36Sopenharmony_ci	bra	p_write		|go write results
200162306a36Sopenharmony_cip_movei:
200262306a36Sopenharmony_ci	fmovel	#0,%FPSR		|clear aiop
200362306a36Sopenharmony_ci	leal	ETEMP(%a6),%a0	|a0 will point to the packed decimal
200462306a36Sopenharmony_ci	clrw	2(%a0)		|clear lower word of exp
200562306a36Sopenharmony_ci	bra	p_write		|go write the result
200662306a36Sopenharmony_cip_moven:
200762306a36Sopenharmony_ci	leal	ETEMP(%a6),%a0	|a0 will point to the packed decimal
200862306a36Sopenharmony_ci	clrw	2(%a0)		|clear lower word of exp
200962306a36Sopenharmony_ci	bra	p_write		|go write the result
201062306a36Sopenharmony_ci
201162306a36Sopenharmony_ci|
201262306a36Sopenharmony_ci| Routines to read the dynamic k-factor from Dn.
201362306a36Sopenharmony_ci|
201462306a36Sopenharmony_cip_dyd0:
201562306a36Sopenharmony_ci	movel	USER_D0(%a6),%d0
201662306a36Sopenharmony_ci	bras	statick
201762306a36Sopenharmony_cip_dyd1:
201862306a36Sopenharmony_ci	movel	USER_D1(%a6),%d0
201962306a36Sopenharmony_ci	bras	statick
202062306a36Sopenharmony_cip_dyd2:
202162306a36Sopenharmony_ci	movel	%d2,%d0
202262306a36Sopenharmony_ci	bras	statick
202362306a36Sopenharmony_cip_dyd3:
202462306a36Sopenharmony_ci	movel	%d3,%d0
202562306a36Sopenharmony_ci	bras	statick
202662306a36Sopenharmony_cip_dyd4:
202762306a36Sopenharmony_ci	movel	%d4,%d0
202862306a36Sopenharmony_ci	bras	statick
202962306a36Sopenharmony_cip_dyd5:
203062306a36Sopenharmony_ci	movel	%d5,%d0
203162306a36Sopenharmony_ci	bras	statick
203262306a36Sopenharmony_cip_dyd6:
203362306a36Sopenharmony_ci	movel	%d6,%d0
203462306a36Sopenharmony_ci	bra	statick
203562306a36Sopenharmony_cip_dyd7:
203662306a36Sopenharmony_ci	movel	%d7,%d0
203762306a36Sopenharmony_ci	bra	statick
203862306a36Sopenharmony_ci
203962306a36Sopenharmony_ci	|end
2040