18c2ecf20Sopenharmony_ci|
28c2ecf20Sopenharmony_ci|	res_func.sa 3.9 7/29/91
38c2ecf20Sopenharmony_ci|
48c2ecf20Sopenharmony_ci| Normalizes denormalized numbers if necessary and updates the
58c2ecf20Sopenharmony_ci| stack frame.  The function is then restored back into the
68c2ecf20Sopenharmony_ci| machine and the 040 completes the operation.  This routine
78c2ecf20Sopenharmony_ci| is only used by the unsupported data type/format handler.
88c2ecf20Sopenharmony_ci| (Exception vector 55).
98c2ecf20Sopenharmony_ci|
108c2ecf20Sopenharmony_ci| For packed move out (fmove.p fpm,<ea>) the operation is
118c2ecf20Sopenharmony_ci| completed here; data is packed and moved to user memory.
128c2ecf20Sopenharmony_ci| The stack is restored to the 040 only in the case of a
138c2ecf20Sopenharmony_ci| reportable exception in the conversion.
148c2ecf20Sopenharmony_ci|
158c2ecf20Sopenharmony_ci|
168c2ecf20Sopenharmony_ci|		Copyright (C) Motorola, Inc. 1990
178c2ecf20Sopenharmony_ci|			All Rights Reserved
188c2ecf20Sopenharmony_ci|
198c2ecf20Sopenharmony_ci|       For details on the license for this file, please see the
208c2ecf20Sopenharmony_ci|       file, README, in this same directory.
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ciRES_FUNC:    |idnt    2,1 | Motorola 040 Floating Point Software Package
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci	|section	8
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#include "fpsp.h"
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cisp_bnds:	.short	0x3f81,0x407e
298c2ecf20Sopenharmony_ci		.short	0x3f6a,0x0000
308c2ecf20Sopenharmony_cidp_bnds:	.short	0x3c01,0x43fe
318c2ecf20Sopenharmony_ci		.short	0x3bcd,0x0000
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	|xref	mem_write
348c2ecf20Sopenharmony_ci	|xref	bindec
358c2ecf20Sopenharmony_ci	|xref	get_fline
368c2ecf20Sopenharmony_ci	|xref	round
378c2ecf20Sopenharmony_ci	|xref	denorm
388c2ecf20Sopenharmony_ci	|xref	dest_ext
398c2ecf20Sopenharmony_ci	|xref	dest_dbl
408c2ecf20Sopenharmony_ci	|xref	dest_sgl
418c2ecf20Sopenharmony_ci	|xref	unf_sub
428c2ecf20Sopenharmony_ci	|xref	nrm_set
438c2ecf20Sopenharmony_ci	|xref	dnrm_lp
448c2ecf20Sopenharmony_ci	|xref	ovf_res
458c2ecf20Sopenharmony_ci	|xref	reg_dest
468c2ecf20Sopenharmony_ci	|xref	t_ovfl
478c2ecf20Sopenharmony_ci	|xref	t_unfl
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	.global	res_func
508c2ecf20Sopenharmony_ci	.global	p_move
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cires_func:
538c2ecf20Sopenharmony_ci	clrb	DNRM_FLG(%a6)
548c2ecf20Sopenharmony_ci	clrb	RES_FLG(%a6)
558c2ecf20Sopenharmony_ci	clrb	CU_ONLY(%a6)
568c2ecf20Sopenharmony_ci	tstb	DY_MO_FLG(%a6)
578c2ecf20Sopenharmony_ci	beqs	monadic
588c2ecf20Sopenharmony_cidyadic:
598c2ecf20Sopenharmony_ci	btstb	#7,DTAG(%a6)	|if dop = norm=000, zero=001,
608c2ecf20Sopenharmony_ci|				;inf=010 or nan=011
618c2ecf20Sopenharmony_ci	beqs	monadic		|then branch
628c2ecf20Sopenharmony_ci|				;else denorm
638c2ecf20Sopenharmony_ci| HANDLE DESTINATION DENORM HERE
648c2ecf20Sopenharmony_ci|				;set dtag to norm
658c2ecf20Sopenharmony_ci|				;write the tag & fpte15 to the fstack
668c2ecf20Sopenharmony_ci	leal	FPTEMP(%a6),%a0
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	bclrb	#sign_bit,LOCAL_EX(%a0)
698c2ecf20Sopenharmony_ci	sne	LOCAL_SGN(%a0)
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	bsr	nrm_set		|normalize number (exp will go negative)
728c2ecf20Sopenharmony_ci	bclrb	#sign_bit,LOCAL_EX(%a0) |get rid of false sign
738c2ecf20Sopenharmony_ci	bfclr	LOCAL_SGN(%a0){#0:#8}	|change back to IEEE ext format
748c2ecf20Sopenharmony_ci	beqs	dpos
758c2ecf20Sopenharmony_ci	bsetb	#sign_bit,LOCAL_EX(%a0)
768c2ecf20Sopenharmony_cidpos:
778c2ecf20Sopenharmony_ci	bfclr	DTAG(%a6){#0:#4}	|set tag to normalized, FPTE15 = 0
788c2ecf20Sopenharmony_ci	bsetb	#4,DTAG(%a6)	|set FPTE15
798c2ecf20Sopenharmony_ci	orb	#0x0f,DNRM_FLG(%a6)
808c2ecf20Sopenharmony_cimonadic:
818c2ecf20Sopenharmony_ci	leal	ETEMP(%a6),%a0
828c2ecf20Sopenharmony_ci	btstb	#direction_bit,CMDREG1B(%a6)	|check direction
838c2ecf20Sopenharmony_ci	bne	opclass3			|it is a mv out
848c2ecf20Sopenharmony_ci|
858c2ecf20Sopenharmony_ci| At this point, only opclass 0 and 2 possible
868c2ecf20Sopenharmony_ci|
878c2ecf20Sopenharmony_ci	btstb	#7,STAG(%a6)	|if sop = norm=000, zero=001,
888c2ecf20Sopenharmony_ci|				;inf=010 or nan=011
898c2ecf20Sopenharmony_ci	bne	mon_dnrm	|else denorm
908c2ecf20Sopenharmony_ci	tstb	DY_MO_FLG(%a6)	|all cases of dyadic instructions would
918c2ecf20Sopenharmony_ci	bne	normal		|require normalization of denorm
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci| At this point:
948c2ecf20Sopenharmony_ci|	monadic instructions:	fabs  = $18  fneg   = $1a  ftst   = $3a
958c2ecf20Sopenharmony_ci|				fmove = $00  fsmove = $40  fdmove = $44
968c2ecf20Sopenharmony_ci|				fsqrt = $05* fssqrt = $41  fdsqrt = $45
978c2ecf20Sopenharmony_ci|				(*fsqrt reencoded to $05)
988c2ecf20Sopenharmony_ci|
998c2ecf20Sopenharmony_ci	movew	CMDREG1B(%a6),%d0	|get command register
1008c2ecf20Sopenharmony_ci	andil	#0x7f,%d0			|strip to only command word
1018c2ecf20Sopenharmony_ci|
1028c2ecf20Sopenharmony_ci| At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and
1038c2ecf20Sopenharmony_ci| fdsqrt are possible.
1048c2ecf20Sopenharmony_ci| For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize)
1058c2ecf20Sopenharmony_ci| For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize)
1068c2ecf20Sopenharmony_ci|
1078c2ecf20Sopenharmony_ci	btstl	#0,%d0
1088c2ecf20Sopenharmony_ci	bne	normal			|weed out fsqrt instructions
1098c2ecf20Sopenharmony_ci|
1108c2ecf20Sopenharmony_ci| cu_norm handles fmove in instructions with normalized inputs.
1118c2ecf20Sopenharmony_ci| The routine round is used to correctly round the input for the
1128c2ecf20Sopenharmony_ci| destination precision and mode.
1138c2ecf20Sopenharmony_ci|
1148c2ecf20Sopenharmony_cicu_norm:
1158c2ecf20Sopenharmony_ci	st	CU_ONLY(%a6)		|set cu-only inst flag
1168c2ecf20Sopenharmony_ci	movew	CMDREG1B(%a6),%d0
1178c2ecf20Sopenharmony_ci	andib	#0x3b,%d0		|isolate bits to select inst
1188c2ecf20Sopenharmony_ci	tstb	%d0
1198c2ecf20Sopenharmony_ci	beql	cu_nmove	|if zero, it is an fmove
1208c2ecf20Sopenharmony_ci	cmpib	#0x18,%d0
1218c2ecf20Sopenharmony_ci	beql	cu_nabs		|if $18, it is fabs
1228c2ecf20Sopenharmony_ci	cmpib	#0x1a,%d0
1238c2ecf20Sopenharmony_ci	beql	cu_nneg		|if $1a, it is fneg
1248c2ecf20Sopenharmony_ci|
1258c2ecf20Sopenharmony_ci| Inst is ftst.  Check the source operand and set the cc's accordingly.
1268c2ecf20Sopenharmony_ci| No write is done, so simply rts.
1278c2ecf20Sopenharmony_ci|
1288c2ecf20Sopenharmony_cicu_ntst:
1298c2ecf20Sopenharmony_ci	movew	LOCAL_EX(%a0),%d0
1308c2ecf20Sopenharmony_ci	bclrl	#15,%d0
1318c2ecf20Sopenharmony_ci	sne	LOCAL_SGN(%a0)
1328c2ecf20Sopenharmony_ci	beqs	cu_ntpo
1338c2ecf20Sopenharmony_ci	orl	#neg_mask,USER_FPSR(%a6) |set N
1348c2ecf20Sopenharmony_cicu_ntpo:
1358c2ecf20Sopenharmony_ci	cmpiw	#0x7fff,%d0	|test for inf/nan
1368c2ecf20Sopenharmony_ci	bnes	cu_ntcz
1378c2ecf20Sopenharmony_ci	tstl	LOCAL_HI(%a0)
1388c2ecf20Sopenharmony_ci	bnes	cu_ntn
1398c2ecf20Sopenharmony_ci	tstl	LOCAL_LO(%a0)
1408c2ecf20Sopenharmony_ci	bnes	cu_ntn
1418c2ecf20Sopenharmony_ci	orl	#inf_mask,USER_FPSR(%a6)
1428c2ecf20Sopenharmony_ci	rts
1438c2ecf20Sopenharmony_cicu_ntn:
1448c2ecf20Sopenharmony_ci	orl	#nan_mask,USER_FPSR(%a6)
1458c2ecf20Sopenharmony_ci	movel	ETEMP_EX(%a6),FPTEMP_EX(%a6)	|set up fptemp sign for
1468c2ecf20Sopenharmony_ci|						;snan handler
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	rts
1498c2ecf20Sopenharmony_cicu_ntcz:
1508c2ecf20Sopenharmony_ci	tstl	LOCAL_HI(%a0)
1518c2ecf20Sopenharmony_ci	bnel	cu_ntsx
1528c2ecf20Sopenharmony_ci	tstl	LOCAL_LO(%a0)
1538c2ecf20Sopenharmony_ci	bnel	cu_ntsx
1548c2ecf20Sopenharmony_ci	orl	#z_mask,USER_FPSR(%a6)
1558c2ecf20Sopenharmony_cicu_ntsx:
1568c2ecf20Sopenharmony_ci	rts
1578c2ecf20Sopenharmony_ci|
1588c2ecf20Sopenharmony_ci| Inst is fabs.  Execute the absolute value function on the input.
1598c2ecf20Sopenharmony_ci| Branch to the fmove code.  If the operand is NaN, do nothing.
1608c2ecf20Sopenharmony_ci|
1618c2ecf20Sopenharmony_cicu_nabs:
1628c2ecf20Sopenharmony_ci	moveb	STAG(%a6),%d0
1638c2ecf20Sopenharmony_ci	btstl	#5,%d0			|test for NaN or zero
1648c2ecf20Sopenharmony_ci	bne	wr_etemp		|if either, simply write it
1658c2ecf20Sopenharmony_ci	bclrb	#7,LOCAL_EX(%a0)		|do abs
1668c2ecf20Sopenharmony_ci	bras	cu_nmove		|fmove code will finish
1678c2ecf20Sopenharmony_ci|
1688c2ecf20Sopenharmony_ci| Inst is fneg.  Execute the negate value function on the input.
1698c2ecf20Sopenharmony_ci| Fall though to the fmove code.  If the operand is NaN, do nothing.
1708c2ecf20Sopenharmony_ci|
1718c2ecf20Sopenharmony_cicu_nneg:
1728c2ecf20Sopenharmony_ci	moveb	STAG(%a6),%d0
1738c2ecf20Sopenharmony_ci	btstl	#5,%d0			|test for NaN or zero
1748c2ecf20Sopenharmony_ci	bne	wr_etemp		|if either, simply write it
1758c2ecf20Sopenharmony_ci	bchgb	#7,LOCAL_EX(%a0)		|do neg
1768c2ecf20Sopenharmony_ci|
1778c2ecf20Sopenharmony_ci| Inst is fmove.  This code also handles all result writes.
1788c2ecf20Sopenharmony_ci| If bit 2 is set, round is forced to double.  If it is clear,
1798c2ecf20Sopenharmony_ci| and bit 6 is set, round is forced to single.  If both are clear,
1808c2ecf20Sopenharmony_ci| the round precision is found in the fpcr.  If the rounding precision
1818c2ecf20Sopenharmony_ci| is double or single, round the result before the write.
1828c2ecf20Sopenharmony_ci|
1838c2ecf20Sopenharmony_cicu_nmove:
1848c2ecf20Sopenharmony_ci	moveb	STAG(%a6),%d0
1858c2ecf20Sopenharmony_ci	andib	#0xe0,%d0			|isolate stag bits
1868c2ecf20Sopenharmony_ci	bne	wr_etemp		|if not norm, simply write it
1878c2ecf20Sopenharmony_ci	btstb	#2,CMDREG1B+1(%a6)	|check for rd
1888c2ecf20Sopenharmony_ci	bne	cu_nmrd
1898c2ecf20Sopenharmony_ci	btstb	#6,CMDREG1B+1(%a6)	|check for rs
1908c2ecf20Sopenharmony_ci	bne	cu_nmrs
1918c2ecf20Sopenharmony_ci|
1928c2ecf20Sopenharmony_ci| The move or operation is not with forced precision.  Test for
1938c2ecf20Sopenharmony_ci| nan or inf as the input; if so, simply write it to FPn.  Use the
1948c2ecf20Sopenharmony_ci| FPCR_MODE byte to get rounding on norms and zeros.
1958c2ecf20Sopenharmony_ci|
1968c2ecf20Sopenharmony_cicu_nmnr:
1978c2ecf20Sopenharmony_ci	bfextu	FPCR_MODE(%a6){#0:#2},%d0
1988c2ecf20Sopenharmony_ci	tstb	%d0			|check for extended
1998c2ecf20Sopenharmony_ci	beq	cu_wrexn		|if so, just write result
2008c2ecf20Sopenharmony_ci	cmpib	#1,%d0			|check for single
2018c2ecf20Sopenharmony_ci	beq	cu_nmrs			|fall through to double
2028c2ecf20Sopenharmony_ci|
2038c2ecf20Sopenharmony_ci| The move is fdmove or round precision is double.
2048c2ecf20Sopenharmony_ci|
2058c2ecf20Sopenharmony_cicu_nmrd:
2068c2ecf20Sopenharmony_ci	movel	#2,%d0			|set up the size for denorm
2078c2ecf20Sopenharmony_ci	movew	LOCAL_EX(%a0),%d1		|compare exponent to double threshold
2088c2ecf20Sopenharmony_ci	andw	#0x7fff,%d1
2098c2ecf20Sopenharmony_ci	cmpw	#0x3c01,%d1
2108c2ecf20Sopenharmony_ci	bls	cu_nunfl
2118c2ecf20Sopenharmony_ci	bfextu	FPCR_MODE(%a6){#2:#2},%d1	|get rmode
2128c2ecf20Sopenharmony_ci	orl	#0x00020000,%d1		|or in rprec (double)
2138c2ecf20Sopenharmony_ci	clrl	%d0			|clear g,r,s for round
2148c2ecf20Sopenharmony_ci	bclrb	#sign_bit,LOCAL_EX(%a0)	|convert to internal format
2158c2ecf20Sopenharmony_ci	sne	LOCAL_SGN(%a0)
2168c2ecf20Sopenharmony_ci	bsrl	round
2178c2ecf20Sopenharmony_ci	bfclr	LOCAL_SGN(%a0){#0:#8}
2188c2ecf20Sopenharmony_ci	beqs	cu_nmrdc
2198c2ecf20Sopenharmony_ci	bsetb	#sign_bit,LOCAL_EX(%a0)
2208c2ecf20Sopenharmony_cicu_nmrdc:
2218c2ecf20Sopenharmony_ci	movew	LOCAL_EX(%a0),%d1		|check for overflow
2228c2ecf20Sopenharmony_ci	andw	#0x7fff,%d1
2238c2ecf20Sopenharmony_ci	cmpw	#0x43ff,%d1
2248c2ecf20Sopenharmony_ci	bge	cu_novfl		|take care of overflow case
2258c2ecf20Sopenharmony_ci	bra	cu_wrexn
2268c2ecf20Sopenharmony_ci|
2278c2ecf20Sopenharmony_ci| The move is fsmove or round precision is single.
2288c2ecf20Sopenharmony_ci|
2298c2ecf20Sopenharmony_cicu_nmrs:
2308c2ecf20Sopenharmony_ci	movel	#1,%d0
2318c2ecf20Sopenharmony_ci	movew	LOCAL_EX(%a0),%d1
2328c2ecf20Sopenharmony_ci	andw	#0x7fff,%d1
2338c2ecf20Sopenharmony_ci	cmpw	#0x3f81,%d1
2348c2ecf20Sopenharmony_ci	bls	cu_nunfl
2358c2ecf20Sopenharmony_ci	bfextu	FPCR_MODE(%a6){#2:#2},%d1
2368c2ecf20Sopenharmony_ci	orl	#0x00010000,%d1
2378c2ecf20Sopenharmony_ci	clrl	%d0
2388c2ecf20Sopenharmony_ci	bclrb	#sign_bit,LOCAL_EX(%a0)
2398c2ecf20Sopenharmony_ci	sne	LOCAL_SGN(%a0)
2408c2ecf20Sopenharmony_ci	bsrl	round
2418c2ecf20Sopenharmony_ci	bfclr	LOCAL_SGN(%a0){#0:#8}
2428c2ecf20Sopenharmony_ci	beqs	cu_nmrsc
2438c2ecf20Sopenharmony_ci	bsetb	#sign_bit,LOCAL_EX(%a0)
2448c2ecf20Sopenharmony_cicu_nmrsc:
2458c2ecf20Sopenharmony_ci	movew	LOCAL_EX(%a0),%d1
2468c2ecf20Sopenharmony_ci	andw	#0x7FFF,%d1
2478c2ecf20Sopenharmony_ci	cmpw	#0x407f,%d1
2488c2ecf20Sopenharmony_ci	blt	cu_wrexn
2498c2ecf20Sopenharmony_ci|
2508c2ecf20Sopenharmony_ci| The operand is above precision boundaries.  Use t_ovfl to
2518c2ecf20Sopenharmony_ci| generate the correct value.
2528c2ecf20Sopenharmony_ci|
2538c2ecf20Sopenharmony_cicu_novfl:
2548c2ecf20Sopenharmony_ci	bsr	t_ovfl
2558c2ecf20Sopenharmony_ci	bra	cu_wrexn
2568c2ecf20Sopenharmony_ci|
2578c2ecf20Sopenharmony_ci| The operand is below precision boundaries.  Use denorm to
2588c2ecf20Sopenharmony_ci| generate the correct value.
2598c2ecf20Sopenharmony_ci|
2608c2ecf20Sopenharmony_cicu_nunfl:
2618c2ecf20Sopenharmony_ci	bclrb	#sign_bit,LOCAL_EX(%a0)
2628c2ecf20Sopenharmony_ci	sne	LOCAL_SGN(%a0)
2638c2ecf20Sopenharmony_ci	bsr	denorm
2648c2ecf20Sopenharmony_ci	bfclr	LOCAL_SGN(%a0){#0:#8}	|change back to IEEE ext format
2658c2ecf20Sopenharmony_ci	beqs	cu_nucont
2668c2ecf20Sopenharmony_ci	bsetb	#sign_bit,LOCAL_EX(%a0)
2678c2ecf20Sopenharmony_cicu_nucont:
2688c2ecf20Sopenharmony_ci	bfextu	FPCR_MODE(%a6){#2:#2},%d1
2698c2ecf20Sopenharmony_ci	btstb	#2,CMDREG1B+1(%a6)	|check for rd
2708c2ecf20Sopenharmony_ci	bne	inst_d
2718c2ecf20Sopenharmony_ci	btstb	#6,CMDREG1B+1(%a6)	|check for rs
2728c2ecf20Sopenharmony_ci	bne	inst_s
2738c2ecf20Sopenharmony_ci	swap	%d1
2748c2ecf20Sopenharmony_ci	moveb	FPCR_MODE(%a6),%d1
2758c2ecf20Sopenharmony_ci	lsrb	#6,%d1
2768c2ecf20Sopenharmony_ci	swap	%d1
2778c2ecf20Sopenharmony_ci	bra	inst_sd
2788c2ecf20Sopenharmony_ciinst_d:
2798c2ecf20Sopenharmony_ci	orl	#0x00020000,%d1
2808c2ecf20Sopenharmony_ci	bra	inst_sd
2818c2ecf20Sopenharmony_ciinst_s:
2828c2ecf20Sopenharmony_ci	orl	#0x00010000,%d1
2838c2ecf20Sopenharmony_ciinst_sd:
2848c2ecf20Sopenharmony_ci	bclrb	#sign_bit,LOCAL_EX(%a0)
2858c2ecf20Sopenharmony_ci	sne	LOCAL_SGN(%a0)
2868c2ecf20Sopenharmony_ci	bsrl	round
2878c2ecf20Sopenharmony_ci	bfclr	LOCAL_SGN(%a0){#0:#8}
2888c2ecf20Sopenharmony_ci	beqs	cu_nuflp
2898c2ecf20Sopenharmony_ci	bsetb	#sign_bit,LOCAL_EX(%a0)
2908c2ecf20Sopenharmony_cicu_nuflp:
2918c2ecf20Sopenharmony_ci	btstb	#inex2_bit,FPSR_EXCEPT(%a6)
2928c2ecf20Sopenharmony_ci	beqs	cu_nuninx
2938c2ecf20Sopenharmony_ci	orl	#aunfl_mask,USER_FPSR(%a6) |if the round was inex, set AUNFL
2948c2ecf20Sopenharmony_cicu_nuninx:
2958c2ecf20Sopenharmony_ci	tstl	LOCAL_HI(%a0)		|test for zero
2968c2ecf20Sopenharmony_ci	bnes	cu_nunzro
2978c2ecf20Sopenharmony_ci	tstl	LOCAL_LO(%a0)
2988c2ecf20Sopenharmony_ci	bnes	cu_nunzro
2998c2ecf20Sopenharmony_ci|
3008c2ecf20Sopenharmony_ci| The mantissa is zero from the denorm loop.  Check sign and rmode
3018c2ecf20Sopenharmony_ci| to see if rounding should have occurred which would leave the lsb.
3028c2ecf20Sopenharmony_ci|
3038c2ecf20Sopenharmony_ci	movel	USER_FPCR(%a6),%d0
3048c2ecf20Sopenharmony_ci	andil	#0x30,%d0		|isolate rmode
3058c2ecf20Sopenharmony_ci	cmpil	#0x20,%d0
3068c2ecf20Sopenharmony_ci	blts	cu_nzro
3078c2ecf20Sopenharmony_ci	bnes	cu_nrp
3088c2ecf20Sopenharmony_cicu_nrm:
3098c2ecf20Sopenharmony_ci	tstw	LOCAL_EX(%a0)	|if positive, set lsb
3108c2ecf20Sopenharmony_ci	bges	cu_nzro
3118c2ecf20Sopenharmony_ci	btstb	#7,FPCR_MODE(%a6) |check for double
3128c2ecf20Sopenharmony_ci	beqs	cu_nincs
3138c2ecf20Sopenharmony_ci	bras	cu_nincd
3148c2ecf20Sopenharmony_cicu_nrp:
3158c2ecf20Sopenharmony_ci	tstw	LOCAL_EX(%a0)	|if positive, set lsb
3168c2ecf20Sopenharmony_ci	blts	cu_nzro
3178c2ecf20Sopenharmony_ci	btstb	#7,FPCR_MODE(%a6) |check for double
3188c2ecf20Sopenharmony_ci	beqs	cu_nincs
3198c2ecf20Sopenharmony_cicu_nincd:
3208c2ecf20Sopenharmony_ci	orl	#0x800,LOCAL_LO(%a0) |inc for double
3218c2ecf20Sopenharmony_ci	bra	cu_nunzro
3228c2ecf20Sopenharmony_cicu_nincs:
3238c2ecf20Sopenharmony_ci	orl	#0x100,LOCAL_HI(%a0) |inc for single
3248c2ecf20Sopenharmony_ci	bra	cu_nunzro
3258c2ecf20Sopenharmony_cicu_nzro:
3268c2ecf20Sopenharmony_ci	orl	#z_mask,USER_FPSR(%a6)
3278c2ecf20Sopenharmony_ci	moveb	STAG(%a6),%d0
3288c2ecf20Sopenharmony_ci	andib	#0xe0,%d0
3298c2ecf20Sopenharmony_ci	cmpib	#0x40,%d0		|check if input was tagged zero
3308c2ecf20Sopenharmony_ci	beqs	cu_numv
3318c2ecf20Sopenharmony_cicu_nunzro:
3328c2ecf20Sopenharmony_ci	orl	#unfl_mask,USER_FPSR(%a6) |set unfl
3338c2ecf20Sopenharmony_cicu_numv:
3348c2ecf20Sopenharmony_ci	movel	(%a0),ETEMP(%a6)
3358c2ecf20Sopenharmony_ci	movel	4(%a0),ETEMP_HI(%a6)
3368c2ecf20Sopenharmony_ci	movel	8(%a0),ETEMP_LO(%a6)
3378c2ecf20Sopenharmony_ci|
3388c2ecf20Sopenharmony_ci| Write the result to memory, setting the fpsr cc bits.  NaN and Inf
3398c2ecf20Sopenharmony_ci| bypass cu_wrexn.
3408c2ecf20Sopenharmony_ci|
3418c2ecf20Sopenharmony_cicu_wrexn:
3428c2ecf20Sopenharmony_ci	tstw	LOCAL_EX(%a0)		|test for zero
3438c2ecf20Sopenharmony_ci	beqs	cu_wrzero
3448c2ecf20Sopenharmony_ci	cmpw	#0x8000,LOCAL_EX(%a0)	|test for zero
3458c2ecf20Sopenharmony_ci	bnes	cu_wreon
3468c2ecf20Sopenharmony_cicu_wrzero:
3478c2ecf20Sopenharmony_ci	orl	#z_mask,USER_FPSR(%a6)	|set Z bit
3488c2ecf20Sopenharmony_cicu_wreon:
3498c2ecf20Sopenharmony_ci	tstw	LOCAL_EX(%a0)
3508c2ecf20Sopenharmony_ci	bpl	wr_etemp
3518c2ecf20Sopenharmony_ci	orl	#neg_mask,USER_FPSR(%a6)
3528c2ecf20Sopenharmony_ci	bra	wr_etemp
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci|
3558c2ecf20Sopenharmony_ci| HANDLE SOURCE DENORM HERE
3568c2ecf20Sopenharmony_ci|
3578c2ecf20Sopenharmony_ci|				;clear denorm stag to norm
3588c2ecf20Sopenharmony_ci|				;write the new tag & ete15 to the fstack
3598c2ecf20Sopenharmony_cimon_dnrm:
3608c2ecf20Sopenharmony_ci|
3618c2ecf20Sopenharmony_ci| At this point, check for the cases in which normalizing the
3628c2ecf20Sopenharmony_ci| denorm produces incorrect results.
3638c2ecf20Sopenharmony_ci|
3648c2ecf20Sopenharmony_ci	tstb	DY_MO_FLG(%a6)	|all cases of dyadic instructions would
3658c2ecf20Sopenharmony_ci	bnes	nrm_src		|require normalization of denorm
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci| At this point:
3688c2ecf20Sopenharmony_ci|	monadic instructions:	fabs  = $18  fneg   = $1a  ftst   = $3a
3698c2ecf20Sopenharmony_ci|				fmove = $00  fsmove = $40  fdmove = $44
3708c2ecf20Sopenharmony_ci|				fsqrt = $05* fssqrt = $41  fdsqrt = $45
3718c2ecf20Sopenharmony_ci|				(*fsqrt reencoded to $05)
3728c2ecf20Sopenharmony_ci|
3738c2ecf20Sopenharmony_ci	movew	CMDREG1B(%a6),%d0	|get command register
3748c2ecf20Sopenharmony_ci	andil	#0x7f,%d0			|strip to only command word
3758c2ecf20Sopenharmony_ci|
3768c2ecf20Sopenharmony_ci| At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and
3778c2ecf20Sopenharmony_ci| fdsqrt are possible.
3788c2ecf20Sopenharmony_ci| For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize)
3798c2ecf20Sopenharmony_ci| For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize)
3808c2ecf20Sopenharmony_ci|
3818c2ecf20Sopenharmony_ci	btstl	#0,%d0
3828c2ecf20Sopenharmony_ci	bnes	nrm_src		|weed out fsqrt instructions
3838c2ecf20Sopenharmony_ci	st	CU_ONLY(%a6)	|set cu-only inst flag
3848c2ecf20Sopenharmony_ci	bra	cu_dnrm		|fmove, fabs, fneg, ftst
3858c2ecf20Sopenharmony_ci|				;cases go to cu_dnrm
3868c2ecf20Sopenharmony_cinrm_src:
3878c2ecf20Sopenharmony_ci	bclrb	#sign_bit,LOCAL_EX(%a0)
3888c2ecf20Sopenharmony_ci	sne	LOCAL_SGN(%a0)
3898c2ecf20Sopenharmony_ci	bsr	nrm_set		|normalize number (exponent will go
3908c2ecf20Sopenharmony_ci|				; negative)
3918c2ecf20Sopenharmony_ci	bclrb	#sign_bit,LOCAL_EX(%a0) |get rid of false sign
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	bfclr	LOCAL_SGN(%a0){#0:#8}	|change back to IEEE ext format
3948c2ecf20Sopenharmony_ci	beqs	spos
3958c2ecf20Sopenharmony_ci	bsetb	#sign_bit,LOCAL_EX(%a0)
3968c2ecf20Sopenharmony_cispos:
3978c2ecf20Sopenharmony_ci	bfclr	STAG(%a6){#0:#4}	|set tag to normalized, FPTE15 = 0
3988c2ecf20Sopenharmony_ci	bsetb	#4,STAG(%a6)	|set ETE15
3998c2ecf20Sopenharmony_ci	orb	#0xf0,DNRM_FLG(%a6)
4008c2ecf20Sopenharmony_cinormal:
4018c2ecf20Sopenharmony_ci	tstb	DNRM_FLG(%a6)	|check if any of the ops were denorms
4028c2ecf20Sopenharmony_ci	bne	ck_wrap		|if so, check if it is a potential
4038c2ecf20Sopenharmony_ci|				;wrap-around case
4048c2ecf20Sopenharmony_cifix_stk:
4058c2ecf20Sopenharmony_ci	moveb	#0xfe,CU_SAVEPC(%a6)
4068c2ecf20Sopenharmony_ci	bclrb	#E1,E_BYTE(%a6)
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	clrw	NMNEXC(%a6)
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	st	RES_FLG(%a6)	|indicate that a restore is needed
4118c2ecf20Sopenharmony_ci	rts
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci|
4148c2ecf20Sopenharmony_ci| cu_dnrm handles all cu-only instructions (fmove, fabs, fneg, and
4158c2ecf20Sopenharmony_ci| ftst) completely in software without an frestore to the 040.
4168c2ecf20Sopenharmony_ci|
4178c2ecf20Sopenharmony_cicu_dnrm:
4188c2ecf20Sopenharmony_ci	st	CU_ONLY(%a6)
4198c2ecf20Sopenharmony_ci	movew	CMDREG1B(%a6),%d0
4208c2ecf20Sopenharmony_ci	andib	#0x3b,%d0		|isolate bits to select inst
4218c2ecf20Sopenharmony_ci	tstb	%d0
4228c2ecf20Sopenharmony_ci	beql	cu_dmove	|if zero, it is an fmove
4238c2ecf20Sopenharmony_ci	cmpib	#0x18,%d0
4248c2ecf20Sopenharmony_ci	beql	cu_dabs		|if $18, it is fabs
4258c2ecf20Sopenharmony_ci	cmpib	#0x1a,%d0
4268c2ecf20Sopenharmony_ci	beql	cu_dneg		|if $1a, it is fneg
4278c2ecf20Sopenharmony_ci|
4288c2ecf20Sopenharmony_ci| Inst is ftst.  Check the source operand and set the cc's accordingly.
4298c2ecf20Sopenharmony_ci| No write is done, so simply rts.
4308c2ecf20Sopenharmony_ci|
4318c2ecf20Sopenharmony_cicu_dtst:
4328c2ecf20Sopenharmony_ci	movew	LOCAL_EX(%a0),%d0
4338c2ecf20Sopenharmony_ci	bclrl	#15,%d0
4348c2ecf20Sopenharmony_ci	sne	LOCAL_SGN(%a0)
4358c2ecf20Sopenharmony_ci	beqs	cu_dtpo
4368c2ecf20Sopenharmony_ci	orl	#neg_mask,USER_FPSR(%a6) |set N
4378c2ecf20Sopenharmony_cicu_dtpo:
4388c2ecf20Sopenharmony_ci	cmpiw	#0x7fff,%d0	|test for inf/nan
4398c2ecf20Sopenharmony_ci	bnes	cu_dtcz
4408c2ecf20Sopenharmony_ci	tstl	LOCAL_HI(%a0)
4418c2ecf20Sopenharmony_ci	bnes	cu_dtn
4428c2ecf20Sopenharmony_ci	tstl	LOCAL_LO(%a0)
4438c2ecf20Sopenharmony_ci	bnes	cu_dtn
4448c2ecf20Sopenharmony_ci	orl	#inf_mask,USER_FPSR(%a6)
4458c2ecf20Sopenharmony_ci	rts
4468c2ecf20Sopenharmony_cicu_dtn:
4478c2ecf20Sopenharmony_ci	orl	#nan_mask,USER_FPSR(%a6)
4488c2ecf20Sopenharmony_ci	movel	ETEMP_EX(%a6),FPTEMP_EX(%a6)	|set up fptemp sign for
4498c2ecf20Sopenharmony_ci|						;snan handler
4508c2ecf20Sopenharmony_ci	rts
4518c2ecf20Sopenharmony_cicu_dtcz:
4528c2ecf20Sopenharmony_ci	tstl	LOCAL_HI(%a0)
4538c2ecf20Sopenharmony_ci	bnel	cu_dtsx
4548c2ecf20Sopenharmony_ci	tstl	LOCAL_LO(%a0)
4558c2ecf20Sopenharmony_ci	bnel	cu_dtsx
4568c2ecf20Sopenharmony_ci	orl	#z_mask,USER_FPSR(%a6)
4578c2ecf20Sopenharmony_cicu_dtsx:
4588c2ecf20Sopenharmony_ci	rts
4598c2ecf20Sopenharmony_ci|
4608c2ecf20Sopenharmony_ci| Inst is fabs.  Execute the absolute value function on the input.
4618c2ecf20Sopenharmony_ci| Branch to the fmove code.
4628c2ecf20Sopenharmony_ci|
4638c2ecf20Sopenharmony_cicu_dabs:
4648c2ecf20Sopenharmony_ci	bclrb	#7,LOCAL_EX(%a0)		|do abs
4658c2ecf20Sopenharmony_ci	bras	cu_dmove		|fmove code will finish
4668c2ecf20Sopenharmony_ci|
4678c2ecf20Sopenharmony_ci| Inst is fneg.  Execute the negate value function on the input.
4688c2ecf20Sopenharmony_ci| Fall though to the fmove code.
4698c2ecf20Sopenharmony_ci|
4708c2ecf20Sopenharmony_cicu_dneg:
4718c2ecf20Sopenharmony_ci	bchgb	#7,LOCAL_EX(%a0)		|do neg
4728c2ecf20Sopenharmony_ci|
4738c2ecf20Sopenharmony_ci| Inst is fmove.  This code also handles all result writes.
4748c2ecf20Sopenharmony_ci| If bit 2 is set, round is forced to double.  If it is clear,
4758c2ecf20Sopenharmony_ci| and bit 6 is set, round is forced to single.  If both are clear,
4768c2ecf20Sopenharmony_ci| the round precision is found in the fpcr.  If the rounding precision
4778c2ecf20Sopenharmony_ci| is double or single, the result is zero, and the mode is checked
4788c2ecf20Sopenharmony_ci| to determine if the lsb of the result should be set.
4798c2ecf20Sopenharmony_ci|
4808c2ecf20Sopenharmony_cicu_dmove:
4818c2ecf20Sopenharmony_ci	btstb	#2,CMDREG1B+1(%a6)	|check for rd
4828c2ecf20Sopenharmony_ci	bne	cu_dmrd
4838c2ecf20Sopenharmony_ci	btstb	#6,CMDREG1B+1(%a6)	|check for rs
4848c2ecf20Sopenharmony_ci	bne	cu_dmrs
4858c2ecf20Sopenharmony_ci|
4868c2ecf20Sopenharmony_ci| The move or operation is not with forced precision.  Use the
4878c2ecf20Sopenharmony_ci| FPCR_MODE byte to get rounding.
4888c2ecf20Sopenharmony_ci|
4898c2ecf20Sopenharmony_cicu_dmnr:
4908c2ecf20Sopenharmony_ci	bfextu	FPCR_MODE(%a6){#0:#2},%d0
4918c2ecf20Sopenharmony_ci	tstb	%d0			|check for extended
4928c2ecf20Sopenharmony_ci	beq	cu_wrexd		|if so, just write result
4938c2ecf20Sopenharmony_ci	cmpib	#1,%d0			|check for single
4948c2ecf20Sopenharmony_ci	beq	cu_dmrs			|fall through to double
4958c2ecf20Sopenharmony_ci|
4968c2ecf20Sopenharmony_ci| The move is fdmove or round precision is double.  Result is zero.
4978c2ecf20Sopenharmony_ci| Check rmode for rp or rm and set lsb accordingly.
4988c2ecf20Sopenharmony_ci|
4998c2ecf20Sopenharmony_cicu_dmrd:
5008c2ecf20Sopenharmony_ci	bfextu	FPCR_MODE(%a6){#2:#2},%d1	|get rmode
5018c2ecf20Sopenharmony_ci	tstw	LOCAL_EX(%a0)		|check sign
5028c2ecf20Sopenharmony_ci	blts	cu_dmdn
5038c2ecf20Sopenharmony_ci	cmpib	#3,%d1			|check for rp
5048c2ecf20Sopenharmony_ci	bne	cu_dpd			|load double pos zero
5058c2ecf20Sopenharmony_ci	bra	cu_dpdr			|load double pos zero w/lsb
5068c2ecf20Sopenharmony_cicu_dmdn:
5078c2ecf20Sopenharmony_ci	cmpib	#2,%d1			|check for rm
5088c2ecf20Sopenharmony_ci	bne	cu_dnd			|load double neg zero
5098c2ecf20Sopenharmony_ci	bra	cu_dndr			|load double neg zero w/lsb
5108c2ecf20Sopenharmony_ci|
5118c2ecf20Sopenharmony_ci| The move is fsmove or round precision is single.  Result is zero.
5128c2ecf20Sopenharmony_ci| Check for rp or rm and set lsb accordingly.
5138c2ecf20Sopenharmony_ci|
5148c2ecf20Sopenharmony_cicu_dmrs:
5158c2ecf20Sopenharmony_ci	bfextu	FPCR_MODE(%a6){#2:#2},%d1	|get rmode
5168c2ecf20Sopenharmony_ci	tstw	LOCAL_EX(%a0)		|check sign
5178c2ecf20Sopenharmony_ci	blts	cu_dmsn
5188c2ecf20Sopenharmony_ci	cmpib	#3,%d1			|check for rp
5198c2ecf20Sopenharmony_ci	bne	cu_spd			|load single pos zero
5208c2ecf20Sopenharmony_ci	bra	cu_spdr			|load single pos zero w/lsb
5218c2ecf20Sopenharmony_cicu_dmsn:
5228c2ecf20Sopenharmony_ci	cmpib	#2,%d1			|check for rm
5238c2ecf20Sopenharmony_ci	bne	cu_snd			|load single neg zero
5248c2ecf20Sopenharmony_ci	bra	cu_sndr			|load single neg zero w/lsb
5258c2ecf20Sopenharmony_ci|
5268c2ecf20Sopenharmony_ci| The precision is extended, so the result in etemp is correct.
5278c2ecf20Sopenharmony_ci| Simply set unfl (not inex2 or aunfl) and write the result to
5288c2ecf20Sopenharmony_ci| the correct fp register.
5298c2ecf20Sopenharmony_cicu_wrexd:
5308c2ecf20Sopenharmony_ci	orl	#unfl_mask,USER_FPSR(%a6)
5318c2ecf20Sopenharmony_ci	tstw	LOCAL_EX(%a0)
5328c2ecf20Sopenharmony_ci	beq	wr_etemp
5338c2ecf20Sopenharmony_ci	orl	#neg_mask,USER_FPSR(%a6)
5348c2ecf20Sopenharmony_ci	bra	wr_etemp
5358c2ecf20Sopenharmony_ci|
5368c2ecf20Sopenharmony_ci| These routines write +/- zero in double format.  The routines
5378c2ecf20Sopenharmony_ci| cu_dpdr and cu_dndr set the double lsb.
5388c2ecf20Sopenharmony_ci|
5398c2ecf20Sopenharmony_cicu_dpd:
5408c2ecf20Sopenharmony_ci	movel	#0x3c010000,LOCAL_EX(%a0)	|force pos double zero
5418c2ecf20Sopenharmony_ci	clrl	LOCAL_HI(%a0)
5428c2ecf20Sopenharmony_ci	clrl	LOCAL_LO(%a0)
5438c2ecf20Sopenharmony_ci	orl	#z_mask,USER_FPSR(%a6)
5448c2ecf20Sopenharmony_ci	orl	#unfinx_mask,USER_FPSR(%a6)
5458c2ecf20Sopenharmony_ci	bra	wr_etemp
5468c2ecf20Sopenharmony_cicu_dpdr:
5478c2ecf20Sopenharmony_ci	movel	#0x3c010000,LOCAL_EX(%a0)	|force pos double zero
5488c2ecf20Sopenharmony_ci	clrl	LOCAL_HI(%a0)
5498c2ecf20Sopenharmony_ci	movel	#0x800,LOCAL_LO(%a0)	|with lsb set
5508c2ecf20Sopenharmony_ci	orl	#unfinx_mask,USER_FPSR(%a6)
5518c2ecf20Sopenharmony_ci	bra	wr_etemp
5528c2ecf20Sopenharmony_cicu_dnd:
5538c2ecf20Sopenharmony_ci	movel	#0xbc010000,LOCAL_EX(%a0)	|force pos double zero
5548c2ecf20Sopenharmony_ci	clrl	LOCAL_HI(%a0)
5558c2ecf20Sopenharmony_ci	clrl	LOCAL_LO(%a0)
5568c2ecf20Sopenharmony_ci	orl	#z_mask,USER_FPSR(%a6)
5578c2ecf20Sopenharmony_ci	orl	#neg_mask,USER_FPSR(%a6)
5588c2ecf20Sopenharmony_ci	orl	#unfinx_mask,USER_FPSR(%a6)
5598c2ecf20Sopenharmony_ci	bra	wr_etemp
5608c2ecf20Sopenharmony_cicu_dndr:
5618c2ecf20Sopenharmony_ci	movel	#0xbc010000,LOCAL_EX(%a0)	|force pos double zero
5628c2ecf20Sopenharmony_ci	clrl	LOCAL_HI(%a0)
5638c2ecf20Sopenharmony_ci	movel	#0x800,LOCAL_LO(%a0)	|with lsb set
5648c2ecf20Sopenharmony_ci	orl	#neg_mask,USER_FPSR(%a6)
5658c2ecf20Sopenharmony_ci	orl	#unfinx_mask,USER_FPSR(%a6)
5668c2ecf20Sopenharmony_ci	bra	wr_etemp
5678c2ecf20Sopenharmony_ci|
5688c2ecf20Sopenharmony_ci| These routines write +/- zero in single format.  The routines
5698c2ecf20Sopenharmony_ci| cu_dpdr and cu_dndr set the single lsb.
5708c2ecf20Sopenharmony_ci|
5718c2ecf20Sopenharmony_cicu_spd:
5728c2ecf20Sopenharmony_ci	movel	#0x3f810000,LOCAL_EX(%a0)	|force pos single zero
5738c2ecf20Sopenharmony_ci	clrl	LOCAL_HI(%a0)
5748c2ecf20Sopenharmony_ci	clrl	LOCAL_LO(%a0)
5758c2ecf20Sopenharmony_ci	orl	#z_mask,USER_FPSR(%a6)
5768c2ecf20Sopenharmony_ci	orl	#unfinx_mask,USER_FPSR(%a6)
5778c2ecf20Sopenharmony_ci	bra	wr_etemp
5788c2ecf20Sopenharmony_cicu_spdr:
5798c2ecf20Sopenharmony_ci	movel	#0x3f810000,LOCAL_EX(%a0)	|force pos single zero
5808c2ecf20Sopenharmony_ci	movel	#0x100,LOCAL_HI(%a0)	|with lsb set
5818c2ecf20Sopenharmony_ci	clrl	LOCAL_LO(%a0)
5828c2ecf20Sopenharmony_ci	orl	#unfinx_mask,USER_FPSR(%a6)
5838c2ecf20Sopenharmony_ci	bra	wr_etemp
5848c2ecf20Sopenharmony_cicu_snd:
5858c2ecf20Sopenharmony_ci	movel	#0xbf810000,LOCAL_EX(%a0)	|force pos single zero
5868c2ecf20Sopenharmony_ci	clrl	LOCAL_HI(%a0)
5878c2ecf20Sopenharmony_ci	clrl	LOCAL_LO(%a0)
5888c2ecf20Sopenharmony_ci	orl	#z_mask,USER_FPSR(%a6)
5898c2ecf20Sopenharmony_ci	orl	#neg_mask,USER_FPSR(%a6)
5908c2ecf20Sopenharmony_ci	orl	#unfinx_mask,USER_FPSR(%a6)
5918c2ecf20Sopenharmony_ci	bra	wr_etemp
5928c2ecf20Sopenharmony_cicu_sndr:
5938c2ecf20Sopenharmony_ci	movel	#0xbf810000,LOCAL_EX(%a0)	|force pos single zero
5948c2ecf20Sopenharmony_ci	movel	#0x100,LOCAL_HI(%a0)	|with lsb set
5958c2ecf20Sopenharmony_ci	clrl	LOCAL_LO(%a0)
5968c2ecf20Sopenharmony_ci	orl	#neg_mask,USER_FPSR(%a6)
5978c2ecf20Sopenharmony_ci	orl	#unfinx_mask,USER_FPSR(%a6)
5988c2ecf20Sopenharmony_ci	bra	wr_etemp
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci|
6018c2ecf20Sopenharmony_ci| This code checks for 16-bit overflow conditions on dyadic
6028c2ecf20Sopenharmony_ci| operations which are not restorable into the floating-point
6038c2ecf20Sopenharmony_ci| unit and must be completed in software.  Basically, this
6048c2ecf20Sopenharmony_ci| condition exists with a very large norm and a denorm.  One
6058c2ecf20Sopenharmony_ci| of the operands must be denormalized to enter this code.
6068c2ecf20Sopenharmony_ci|
6078c2ecf20Sopenharmony_ci| Flags used:
6088c2ecf20Sopenharmony_ci|	DY_MO_FLG contains 0 for monadic op, $ff for dyadic
6098c2ecf20Sopenharmony_ci|	DNRM_FLG contains $00 for neither op denormalized
6108c2ecf20Sopenharmony_ci|	                  $0f for the destination op denormalized
6118c2ecf20Sopenharmony_ci|	                  $f0 for the source op denormalized
6128c2ecf20Sopenharmony_ci|	                  $ff for both ops denormalized
6138c2ecf20Sopenharmony_ci|
6148c2ecf20Sopenharmony_ci| The wrap-around condition occurs for add, sub, div, and cmp
6158c2ecf20Sopenharmony_ci| when
6168c2ecf20Sopenharmony_ci|
6178c2ecf20Sopenharmony_ci|	abs(dest_exp - src_exp) >= $8000
6188c2ecf20Sopenharmony_ci|
6198c2ecf20Sopenharmony_ci| and for mul when
6208c2ecf20Sopenharmony_ci|
6218c2ecf20Sopenharmony_ci|	(dest_exp + src_exp) < $0
6228c2ecf20Sopenharmony_ci|
6238c2ecf20Sopenharmony_ci| we must process the operation here if this case is true.
6248c2ecf20Sopenharmony_ci|
6258c2ecf20Sopenharmony_ci| The rts following the frcfpn routine is the exit from res_func
6268c2ecf20Sopenharmony_ci| for this condition.  The restore flag (RES_FLG) is left clear.
6278c2ecf20Sopenharmony_ci| No frestore is done unless an exception is to be reported.
6288c2ecf20Sopenharmony_ci|
6298c2ecf20Sopenharmony_ci| For fadd:
6308c2ecf20Sopenharmony_ci|	if(sign_of(dest) != sign_of(src))
6318c2ecf20Sopenharmony_ci|		replace exponent of src with $3fff (keep sign)
6328c2ecf20Sopenharmony_ci|		use fpu to perform dest+new_src (user's rmode and X)
6338c2ecf20Sopenharmony_ci|		clr sticky
6348c2ecf20Sopenharmony_ci|	else
6358c2ecf20Sopenharmony_ci|		set sticky
6368c2ecf20Sopenharmony_ci|	call round with user's precision and mode
6378c2ecf20Sopenharmony_ci|	move result to fpn and wbtemp
6388c2ecf20Sopenharmony_ci|
6398c2ecf20Sopenharmony_ci| For fsub:
6408c2ecf20Sopenharmony_ci|	if(sign_of(dest) == sign_of(src))
6418c2ecf20Sopenharmony_ci|		replace exponent of src with $3fff (keep sign)
6428c2ecf20Sopenharmony_ci|		use fpu to perform dest+new_src (user's rmode and X)
6438c2ecf20Sopenharmony_ci|		clr sticky
6448c2ecf20Sopenharmony_ci|	else
6458c2ecf20Sopenharmony_ci|		set sticky
6468c2ecf20Sopenharmony_ci|	call round with user's precision and mode
6478c2ecf20Sopenharmony_ci|	move result to fpn and wbtemp
6488c2ecf20Sopenharmony_ci|
6498c2ecf20Sopenharmony_ci| For fdiv/fsgldiv:
6508c2ecf20Sopenharmony_ci|	if(both operands are denorm)
6518c2ecf20Sopenharmony_ci|		restore_to_fpu;
6528c2ecf20Sopenharmony_ci|	if(dest is norm)
6538c2ecf20Sopenharmony_ci|		force_ovf;
6548c2ecf20Sopenharmony_ci|	else(dest is denorm)
6558c2ecf20Sopenharmony_ci|		force_unf:
6568c2ecf20Sopenharmony_ci|
6578c2ecf20Sopenharmony_ci| For fcmp:
6588c2ecf20Sopenharmony_ci|	if(dest is norm)
6598c2ecf20Sopenharmony_ci|		N = sign_of(dest);
6608c2ecf20Sopenharmony_ci|	else(dest is denorm)
6618c2ecf20Sopenharmony_ci|		N = sign_of(src);
6628c2ecf20Sopenharmony_ci|
6638c2ecf20Sopenharmony_ci| For fmul:
6648c2ecf20Sopenharmony_ci|	if(both operands are denorm)
6658c2ecf20Sopenharmony_ci|		force_unf;
6668c2ecf20Sopenharmony_ci|	if((dest_exp + src_exp) < 0)
6678c2ecf20Sopenharmony_ci|		force_unf:
6688c2ecf20Sopenharmony_ci|	else
6698c2ecf20Sopenharmony_ci|		restore_to_fpu;
6708c2ecf20Sopenharmony_ci|
6718c2ecf20Sopenharmony_ci| local equates:
6728c2ecf20Sopenharmony_ci	.set	addcode,0x22
6738c2ecf20Sopenharmony_ci	.set	subcode,0x28
6748c2ecf20Sopenharmony_ci	.set	mulcode,0x23
6758c2ecf20Sopenharmony_ci	.set	divcode,0x20
6768c2ecf20Sopenharmony_ci	.set	cmpcode,0x38
6778c2ecf20Sopenharmony_cick_wrap:
6788c2ecf20Sopenharmony_ci	| tstb	DY_MO_FLG(%a6)	;check for fsqrt
6798c2ecf20Sopenharmony_ci	beq	fix_stk		|if zero, it is fsqrt
6808c2ecf20Sopenharmony_ci	movew	CMDREG1B(%a6),%d0
6818c2ecf20Sopenharmony_ci	andiw	#0x3b,%d0		|strip to command bits
6828c2ecf20Sopenharmony_ci	cmpiw	#addcode,%d0
6838c2ecf20Sopenharmony_ci	beq	wrap_add
6848c2ecf20Sopenharmony_ci	cmpiw	#subcode,%d0
6858c2ecf20Sopenharmony_ci	beq	wrap_sub
6868c2ecf20Sopenharmony_ci	cmpiw	#mulcode,%d0
6878c2ecf20Sopenharmony_ci	beq	wrap_mul
6888c2ecf20Sopenharmony_ci	cmpiw	#cmpcode,%d0
6898c2ecf20Sopenharmony_ci	beq	wrap_cmp
6908c2ecf20Sopenharmony_ci|
6918c2ecf20Sopenharmony_ci| Inst is fdiv.
6928c2ecf20Sopenharmony_ci|
6938c2ecf20Sopenharmony_ciwrap_div:
6948c2ecf20Sopenharmony_ci	cmpb	#0xff,DNRM_FLG(%a6) |if both ops denorm,
6958c2ecf20Sopenharmony_ci	beq	fix_stk		 |restore to fpu
6968c2ecf20Sopenharmony_ci|
6978c2ecf20Sopenharmony_ci| One of the ops is denormalized.  Test for wrap condition
6988c2ecf20Sopenharmony_ci| and force the result.
6998c2ecf20Sopenharmony_ci|
7008c2ecf20Sopenharmony_ci	cmpb	#0x0f,DNRM_FLG(%a6) |check for dest denorm
7018c2ecf20Sopenharmony_ci	bnes	div_srcd
7028c2ecf20Sopenharmony_cidiv_destd:
7038c2ecf20Sopenharmony_ci	bsrl	ckinf_ns
7048c2ecf20Sopenharmony_ci	bne	fix_stk
7058c2ecf20Sopenharmony_ci	bfextu	ETEMP_EX(%a6){#1:#15},%d0	|get src exp (always pos)
7068c2ecf20Sopenharmony_ci	bfexts	FPTEMP_EX(%a6){#1:#15},%d1	|get dest exp (always neg)
7078c2ecf20Sopenharmony_ci	subl	%d1,%d0			|subtract dest from src
7088c2ecf20Sopenharmony_ci	cmpl	#0x7fff,%d0
7098c2ecf20Sopenharmony_ci	blt	fix_stk			|if less, not wrap case
7108c2ecf20Sopenharmony_ci	clrb	WBTEMP_SGN(%a6)
7118c2ecf20Sopenharmony_ci	movew	ETEMP_EX(%a6),%d0		|find the sign of the result
7128c2ecf20Sopenharmony_ci	movew	FPTEMP_EX(%a6),%d1
7138c2ecf20Sopenharmony_ci	eorw	%d1,%d0
7148c2ecf20Sopenharmony_ci	andiw	#0x8000,%d0
7158c2ecf20Sopenharmony_ci	beq	force_unf
7168c2ecf20Sopenharmony_ci	st	WBTEMP_SGN(%a6)
7178c2ecf20Sopenharmony_ci	bra	force_unf
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_cickinf_ns:
7208c2ecf20Sopenharmony_ci	moveb	STAG(%a6),%d0		|check source tag for inf or nan
7218c2ecf20Sopenharmony_ci	bra	ck_in_com
7228c2ecf20Sopenharmony_cickinf_nd:
7238c2ecf20Sopenharmony_ci	moveb	DTAG(%a6),%d0		|check destination tag for inf or nan
7248c2ecf20Sopenharmony_cick_in_com:
7258c2ecf20Sopenharmony_ci	andib	#0x60,%d0			|isolate tag bits
7268c2ecf20Sopenharmony_ci	cmpb	#0x40,%d0			|is it inf?
7278c2ecf20Sopenharmony_ci	beq	nan_or_inf		|not wrap case
7288c2ecf20Sopenharmony_ci	cmpb	#0x60,%d0			|is it nan?
7298c2ecf20Sopenharmony_ci	beq	nan_or_inf		|yes, not wrap case?
7308c2ecf20Sopenharmony_ci	cmpb	#0x20,%d0			|is it a zero?
7318c2ecf20Sopenharmony_ci	beq	nan_or_inf		|yes
7328c2ecf20Sopenharmony_ci	clrl	%d0
7338c2ecf20Sopenharmony_ci	rts				|then ; it is either a zero of norm,
7348c2ecf20Sopenharmony_ci|					;check wrap case
7358c2ecf20Sopenharmony_cinan_or_inf:
7368c2ecf20Sopenharmony_ci	moveql	#-1,%d0
7378c2ecf20Sopenharmony_ci	rts
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_cidiv_srcd:
7428c2ecf20Sopenharmony_ci	bsrl	ckinf_nd
7438c2ecf20Sopenharmony_ci	bne	fix_stk
7448c2ecf20Sopenharmony_ci	bfextu	FPTEMP_EX(%a6){#1:#15},%d0	|get dest exp (always pos)
7458c2ecf20Sopenharmony_ci	bfexts	ETEMP_EX(%a6){#1:#15},%d1	|get src exp (always neg)
7468c2ecf20Sopenharmony_ci	subl	%d1,%d0			|subtract src from dest
7478c2ecf20Sopenharmony_ci	cmpl	#0x8000,%d0
7488c2ecf20Sopenharmony_ci	blt	fix_stk			|if less, not wrap case
7498c2ecf20Sopenharmony_ci	clrb	WBTEMP_SGN(%a6)
7508c2ecf20Sopenharmony_ci	movew	ETEMP_EX(%a6),%d0		|find the sign of the result
7518c2ecf20Sopenharmony_ci	movew	FPTEMP_EX(%a6),%d1
7528c2ecf20Sopenharmony_ci	eorw	%d1,%d0
7538c2ecf20Sopenharmony_ci	andiw	#0x8000,%d0
7548c2ecf20Sopenharmony_ci	beqs	force_ovf
7558c2ecf20Sopenharmony_ci	st	WBTEMP_SGN(%a6)
7568c2ecf20Sopenharmony_ci|
7578c2ecf20Sopenharmony_ci| This code handles the case of the instruction resulting in
7588c2ecf20Sopenharmony_ci| an overflow condition.
7598c2ecf20Sopenharmony_ci|
7608c2ecf20Sopenharmony_ciforce_ovf:
7618c2ecf20Sopenharmony_ci	bclrb	#E1,E_BYTE(%a6)
7628c2ecf20Sopenharmony_ci	orl	#ovfl_inx_mask,USER_FPSR(%a6)
7638c2ecf20Sopenharmony_ci	clrw	NMNEXC(%a6)
7648c2ecf20Sopenharmony_ci	leal	WBTEMP(%a6),%a0		|point a0 to memory location
7658c2ecf20Sopenharmony_ci	movew	CMDREG1B(%a6),%d0
7668c2ecf20Sopenharmony_ci	btstl	#6,%d0			|test for forced precision
7678c2ecf20Sopenharmony_ci	beqs	frcovf_fpcr
7688c2ecf20Sopenharmony_ci	btstl	#2,%d0			|check for double
7698c2ecf20Sopenharmony_ci	bnes	frcovf_dbl
7708c2ecf20Sopenharmony_ci	movel	#0x1,%d0			|inst is forced single
7718c2ecf20Sopenharmony_ci	bras	frcovf_rnd
7728c2ecf20Sopenharmony_cifrcovf_dbl:
7738c2ecf20Sopenharmony_ci	movel	#0x2,%d0			|inst is forced double
7748c2ecf20Sopenharmony_ci	bras	frcovf_rnd
7758c2ecf20Sopenharmony_cifrcovf_fpcr:
7768c2ecf20Sopenharmony_ci	bfextu	FPCR_MODE(%a6){#0:#2},%d0	|inst not forced - use fpcr prec
7778c2ecf20Sopenharmony_cifrcovf_rnd:
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci| The 881/882 does not set inex2 for the following case, so the
7808c2ecf20Sopenharmony_ci| line is commented out to be compatible with 881/882
7818c2ecf20Sopenharmony_ci|	tst.b	%d0
7828c2ecf20Sopenharmony_ci|	beq.b	frcovf_x
7838c2ecf20Sopenharmony_ci|	or.l	#inex2_mask,USER_FPSR(%a6) ;if prec is s or d, set inex2
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_ci|frcovf_x:
7868c2ecf20Sopenharmony_ci	bsrl	ovf_res			|get correct result based on
7878c2ecf20Sopenharmony_ci|					;round precision/mode.  This
7888c2ecf20Sopenharmony_ci|					;sets FPSR_CC correctly
7898c2ecf20Sopenharmony_ci|					;returns in external format
7908c2ecf20Sopenharmony_ci	bfclr	WBTEMP_SGN(%a6){#0:#8}
7918c2ecf20Sopenharmony_ci	beq	frcfpn
7928c2ecf20Sopenharmony_ci	bsetb	#sign_bit,WBTEMP_EX(%a6)
7938c2ecf20Sopenharmony_ci	bra	frcfpn
7948c2ecf20Sopenharmony_ci|
7958c2ecf20Sopenharmony_ci| Inst is fadd.
7968c2ecf20Sopenharmony_ci|
7978c2ecf20Sopenharmony_ciwrap_add:
7988c2ecf20Sopenharmony_ci	cmpb	#0xff,DNRM_FLG(%a6) |if both ops denorm,
7998c2ecf20Sopenharmony_ci	beq	fix_stk		 |restore to fpu
8008c2ecf20Sopenharmony_ci|
8018c2ecf20Sopenharmony_ci| One of the ops is denormalized.  Test for wrap condition
8028c2ecf20Sopenharmony_ci| and complete the instruction.
8038c2ecf20Sopenharmony_ci|
8048c2ecf20Sopenharmony_ci	cmpb	#0x0f,DNRM_FLG(%a6) |check for dest denorm
8058c2ecf20Sopenharmony_ci	bnes	add_srcd
8068c2ecf20Sopenharmony_ciadd_destd:
8078c2ecf20Sopenharmony_ci	bsrl	ckinf_ns
8088c2ecf20Sopenharmony_ci	bne	fix_stk
8098c2ecf20Sopenharmony_ci	bfextu	ETEMP_EX(%a6){#1:#15},%d0	|get src exp (always pos)
8108c2ecf20Sopenharmony_ci	bfexts	FPTEMP_EX(%a6){#1:#15},%d1	|get dest exp (always neg)
8118c2ecf20Sopenharmony_ci	subl	%d1,%d0			|subtract dest from src
8128c2ecf20Sopenharmony_ci	cmpl	#0x8000,%d0
8138c2ecf20Sopenharmony_ci	blt	fix_stk			|if less, not wrap case
8148c2ecf20Sopenharmony_ci	bra	add_wrap
8158c2ecf20Sopenharmony_ciadd_srcd:
8168c2ecf20Sopenharmony_ci	bsrl	ckinf_nd
8178c2ecf20Sopenharmony_ci	bne	fix_stk
8188c2ecf20Sopenharmony_ci	bfextu	FPTEMP_EX(%a6){#1:#15},%d0	|get dest exp (always pos)
8198c2ecf20Sopenharmony_ci	bfexts	ETEMP_EX(%a6){#1:#15},%d1	|get src exp (always neg)
8208c2ecf20Sopenharmony_ci	subl	%d1,%d0			|subtract src from dest
8218c2ecf20Sopenharmony_ci	cmpl	#0x8000,%d0
8228c2ecf20Sopenharmony_ci	blt	fix_stk			|if less, not wrap case
8238c2ecf20Sopenharmony_ci|
8248c2ecf20Sopenharmony_ci| Check the signs of the operands.  If they are unlike, the fpu
8258c2ecf20Sopenharmony_ci| can be used to add the norm and 1.0 with the sign of the
8268c2ecf20Sopenharmony_ci| denorm and it will correctly generate the result in extended
8278c2ecf20Sopenharmony_ci| precision.  We can then call round with no sticky and the result
8288c2ecf20Sopenharmony_ci| will be correct for the user's rounding mode and precision.  If
8298c2ecf20Sopenharmony_ci| the signs are the same, we call round with the sticky bit set
8308c2ecf20Sopenharmony_ci| and the result will be correct for the user's rounding mode and
8318c2ecf20Sopenharmony_ci| precision.
8328c2ecf20Sopenharmony_ci|
8338c2ecf20Sopenharmony_ciadd_wrap:
8348c2ecf20Sopenharmony_ci	movew	ETEMP_EX(%a6),%d0
8358c2ecf20Sopenharmony_ci	movew	FPTEMP_EX(%a6),%d1
8368c2ecf20Sopenharmony_ci	eorw	%d1,%d0
8378c2ecf20Sopenharmony_ci	andiw	#0x8000,%d0
8388c2ecf20Sopenharmony_ci	beq	add_same
8398c2ecf20Sopenharmony_ci|
8408c2ecf20Sopenharmony_ci| The signs are unlike.
8418c2ecf20Sopenharmony_ci|
8428c2ecf20Sopenharmony_ci	cmpb	#0x0f,DNRM_FLG(%a6) |is dest the denorm?
8438c2ecf20Sopenharmony_ci	bnes	add_u_srcd
8448c2ecf20Sopenharmony_ci	movew	FPTEMP_EX(%a6),%d0
8458c2ecf20Sopenharmony_ci	andiw	#0x8000,%d0
8468c2ecf20Sopenharmony_ci	orw	#0x3fff,%d0	|force the exponent to +/- 1
8478c2ecf20Sopenharmony_ci	movew	%d0,FPTEMP_EX(%a6) |in the denorm
8488c2ecf20Sopenharmony_ci	movel	USER_FPCR(%a6),%d0
8498c2ecf20Sopenharmony_ci	andil	#0x30,%d0
8508c2ecf20Sopenharmony_ci	fmovel	%d0,%fpcr		|set up users rmode and X
8518c2ecf20Sopenharmony_ci	fmovex	ETEMP(%a6),%fp0
8528c2ecf20Sopenharmony_ci	faddx	FPTEMP(%a6),%fp0
8538c2ecf20Sopenharmony_ci	leal	WBTEMP(%a6),%a0	|point a0 to wbtemp in frame
8548c2ecf20Sopenharmony_ci	fmovel	%fpsr,%d1
8558c2ecf20Sopenharmony_ci	orl	%d1,USER_FPSR(%a6) |capture cc's and inex from fadd
8568c2ecf20Sopenharmony_ci	fmovex	%fp0,WBTEMP(%a6)	|write result to memory
8578c2ecf20Sopenharmony_ci	lsrl	#4,%d0		|put rmode in lower 2 bits
8588c2ecf20Sopenharmony_ci	movel	USER_FPCR(%a6),%d1
8598c2ecf20Sopenharmony_ci	andil	#0xc0,%d1
8608c2ecf20Sopenharmony_ci	lsrl	#6,%d1		|put precision in upper word
8618c2ecf20Sopenharmony_ci	swap	%d1
8628c2ecf20Sopenharmony_ci	orl	%d0,%d1		|set up for round call
8638c2ecf20Sopenharmony_ci	clrl	%d0		|force sticky to zero
8648c2ecf20Sopenharmony_ci	bclrb	#sign_bit,WBTEMP_EX(%a6)
8658c2ecf20Sopenharmony_ci	sne	WBTEMP_SGN(%a6)
8668c2ecf20Sopenharmony_ci	bsrl	round		|round result to users rmode & prec
8678c2ecf20Sopenharmony_ci	bfclr	WBTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
8688c2ecf20Sopenharmony_ci	beq	frcfpnr
8698c2ecf20Sopenharmony_ci	bsetb	#sign_bit,WBTEMP_EX(%a6)
8708c2ecf20Sopenharmony_ci	bra	frcfpnr
8718c2ecf20Sopenharmony_ciadd_u_srcd:
8728c2ecf20Sopenharmony_ci	movew	ETEMP_EX(%a6),%d0
8738c2ecf20Sopenharmony_ci	andiw	#0x8000,%d0
8748c2ecf20Sopenharmony_ci	orw	#0x3fff,%d0	|force the exponent to +/- 1
8758c2ecf20Sopenharmony_ci	movew	%d0,ETEMP_EX(%a6) |in the denorm
8768c2ecf20Sopenharmony_ci	movel	USER_FPCR(%a6),%d0
8778c2ecf20Sopenharmony_ci	andil	#0x30,%d0
8788c2ecf20Sopenharmony_ci	fmovel	%d0,%fpcr		|set up users rmode and X
8798c2ecf20Sopenharmony_ci	fmovex	ETEMP(%a6),%fp0
8808c2ecf20Sopenharmony_ci	faddx	FPTEMP(%a6),%fp0
8818c2ecf20Sopenharmony_ci	fmovel	%fpsr,%d1
8828c2ecf20Sopenharmony_ci	orl	%d1,USER_FPSR(%a6) |capture cc's and inex from fadd
8838c2ecf20Sopenharmony_ci	leal	WBTEMP(%a6),%a0	|point a0 to wbtemp in frame
8848c2ecf20Sopenharmony_ci	fmovex	%fp0,WBTEMP(%a6)	|write result to memory
8858c2ecf20Sopenharmony_ci	lsrl	#4,%d0		|put rmode in lower 2 bits
8868c2ecf20Sopenharmony_ci	movel	USER_FPCR(%a6),%d1
8878c2ecf20Sopenharmony_ci	andil	#0xc0,%d1
8888c2ecf20Sopenharmony_ci	lsrl	#6,%d1		|put precision in upper word
8898c2ecf20Sopenharmony_ci	swap	%d1
8908c2ecf20Sopenharmony_ci	orl	%d0,%d1		|set up for round call
8918c2ecf20Sopenharmony_ci	clrl	%d0		|force sticky to zero
8928c2ecf20Sopenharmony_ci	bclrb	#sign_bit,WBTEMP_EX(%a6)
8938c2ecf20Sopenharmony_ci	sne	WBTEMP_SGN(%a6)	|use internal format for round
8948c2ecf20Sopenharmony_ci	bsrl	round		|round result to users rmode & prec
8958c2ecf20Sopenharmony_ci	bfclr	WBTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
8968c2ecf20Sopenharmony_ci	beq	frcfpnr
8978c2ecf20Sopenharmony_ci	bsetb	#sign_bit,WBTEMP_EX(%a6)
8988c2ecf20Sopenharmony_ci	bra	frcfpnr
8998c2ecf20Sopenharmony_ci|
9008c2ecf20Sopenharmony_ci| Signs are alike:
9018c2ecf20Sopenharmony_ci|
9028c2ecf20Sopenharmony_ciadd_same:
9038c2ecf20Sopenharmony_ci	cmpb	#0x0f,DNRM_FLG(%a6) |is dest the denorm?
9048c2ecf20Sopenharmony_ci	bnes	add_s_srcd
9058c2ecf20Sopenharmony_ciadd_s_destd:
9068c2ecf20Sopenharmony_ci	leal	ETEMP(%a6),%a0
9078c2ecf20Sopenharmony_ci	movel	USER_FPCR(%a6),%d0
9088c2ecf20Sopenharmony_ci	andil	#0x30,%d0
9098c2ecf20Sopenharmony_ci	lsrl	#4,%d0		|put rmode in lower 2 bits
9108c2ecf20Sopenharmony_ci	movel	USER_FPCR(%a6),%d1
9118c2ecf20Sopenharmony_ci	andil	#0xc0,%d1
9128c2ecf20Sopenharmony_ci	lsrl	#6,%d1		|put precision in upper word
9138c2ecf20Sopenharmony_ci	swap	%d1
9148c2ecf20Sopenharmony_ci	orl	%d0,%d1		|set up for round call
9158c2ecf20Sopenharmony_ci	movel	#0x20000000,%d0	|set sticky for round
9168c2ecf20Sopenharmony_ci	bclrb	#sign_bit,ETEMP_EX(%a6)
9178c2ecf20Sopenharmony_ci	sne	ETEMP_SGN(%a6)
9188c2ecf20Sopenharmony_ci	bsrl	round		|round result to users rmode & prec
9198c2ecf20Sopenharmony_ci	bfclr	ETEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
9208c2ecf20Sopenharmony_ci	beqs	add_s_dclr
9218c2ecf20Sopenharmony_ci	bsetb	#sign_bit,ETEMP_EX(%a6)
9228c2ecf20Sopenharmony_ciadd_s_dclr:
9238c2ecf20Sopenharmony_ci	leal	WBTEMP(%a6),%a0
9248c2ecf20Sopenharmony_ci	movel	ETEMP(%a6),(%a0)	|write result to wbtemp
9258c2ecf20Sopenharmony_ci	movel	ETEMP_HI(%a6),4(%a0)
9268c2ecf20Sopenharmony_ci	movel	ETEMP_LO(%a6),8(%a0)
9278c2ecf20Sopenharmony_ci	tstw	ETEMP_EX(%a6)
9288c2ecf20Sopenharmony_ci	bgt	add_ckovf
9298c2ecf20Sopenharmony_ci	orl	#neg_mask,USER_FPSR(%a6)
9308c2ecf20Sopenharmony_ci	bra	add_ckovf
9318c2ecf20Sopenharmony_ciadd_s_srcd:
9328c2ecf20Sopenharmony_ci	leal	FPTEMP(%a6),%a0
9338c2ecf20Sopenharmony_ci	movel	USER_FPCR(%a6),%d0
9348c2ecf20Sopenharmony_ci	andil	#0x30,%d0
9358c2ecf20Sopenharmony_ci	lsrl	#4,%d0		|put rmode in lower 2 bits
9368c2ecf20Sopenharmony_ci	movel	USER_FPCR(%a6),%d1
9378c2ecf20Sopenharmony_ci	andil	#0xc0,%d1
9388c2ecf20Sopenharmony_ci	lsrl	#6,%d1		|put precision in upper word
9398c2ecf20Sopenharmony_ci	swap	%d1
9408c2ecf20Sopenharmony_ci	orl	%d0,%d1		|set up for round call
9418c2ecf20Sopenharmony_ci	movel	#0x20000000,%d0	|set sticky for round
9428c2ecf20Sopenharmony_ci	bclrb	#sign_bit,FPTEMP_EX(%a6)
9438c2ecf20Sopenharmony_ci	sne	FPTEMP_SGN(%a6)
9448c2ecf20Sopenharmony_ci	bsrl	round		|round result to users rmode & prec
9458c2ecf20Sopenharmony_ci	bfclr	FPTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
9468c2ecf20Sopenharmony_ci	beqs	add_s_sclr
9478c2ecf20Sopenharmony_ci	bsetb	#sign_bit,FPTEMP_EX(%a6)
9488c2ecf20Sopenharmony_ciadd_s_sclr:
9498c2ecf20Sopenharmony_ci	leal	WBTEMP(%a6),%a0
9508c2ecf20Sopenharmony_ci	movel	FPTEMP(%a6),(%a0)	|write result to wbtemp
9518c2ecf20Sopenharmony_ci	movel	FPTEMP_HI(%a6),4(%a0)
9528c2ecf20Sopenharmony_ci	movel	FPTEMP_LO(%a6),8(%a0)
9538c2ecf20Sopenharmony_ci	tstw	FPTEMP_EX(%a6)
9548c2ecf20Sopenharmony_ci	bgt	add_ckovf
9558c2ecf20Sopenharmony_ci	orl	#neg_mask,USER_FPSR(%a6)
9568c2ecf20Sopenharmony_ciadd_ckovf:
9578c2ecf20Sopenharmony_ci	movew	WBTEMP_EX(%a6),%d0
9588c2ecf20Sopenharmony_ci	andiw	#0x7fff,%d0
9598c2ecf20Sopenharmony_ci	cmpiw	#0x7fff,%d0
9608c2ecf20Sopenharmony_ci	bne	frcfpnr
9618c2ecf20Sopenharmony_ci|
9628c2ecf20Sopenharmony_ci| The result has overflowed to $7fff exponent.  Set I, ovfl,
9638c2ecf20Sopenharmony_ci| and aovfl, and clr the mantissa (incorrectly set by the
9648c2ecf20Sopenharmony_ci| round routine.)
9658c2ecf20Sopenharmony_ci|
9668c2ecf20Sopenharmony_ci	orl	#inf_mask+ovfl_inx_mask,USER_FPSR(%a6)
9678c2ecf20Sopenharmony_ci	clrl	4(%a0)
9688c2ecf20Sopenharmony_ci	bra	frcfpnr
9698c2ecf20Sopenharmony_ci|
9708c2ecf20Sopenharmony_ci| Inst is fsub.
9718c2ecf20Sopenharmony_ci|
9728c2ecf20Sopenharmony_ciwrap_sub:
9738c2ecf20Sopenharmony_ci	cmpb	#0xff,DNRM_FLG(%a6) |if both ops denorm,
9748c2ecf20Sopenharmony_ci	beq	fix_stk		 |restore to fpu
9758c2ecf20Sopenharmony_ci|
9768c2ecf20Sopenharmony_ci| One of the ops is denormalized.  Test for wrap condition
9778c2ecf20Sopenharmony_ci| and complete the instruction.
9788c2ecf20Sopenharmony_ci|
9798c2ecf20Sopenharmony_ci	cmpb	#0x0f,DNRM_FLG(%a6) |check for dest denorm
9808c2ecf20Sopenharmony_ci	bnes	sub_srcd
9818c2ecf20Sopenharmony_cisub_destd:
9828c2ecf20Sopenharmony_ci	bsrl	ckinf_ns
9838c2ecf20Sopenharmony_ci	bne	fix_stk
9848c2ecf20Sopenharmony_ci	bfextu	ETEMP_EX(%a6){#1:#15},%d0	|get src exp (always pos)
9858c2ecf20Sopenharmony_ci	bfexts	FPTEMP_EX(%a6){#1:#15},%d1	|get dest exp (always neg)
9868c2ecf20Sopenharmony_ci	subl	%d1,%d0			|subtract src from dest
9878c2ecf20Sopenharmony_ci	cmpl	#0x8000,%d0
9888c2ecf20Sopenharmony_ci	blt	fix_stk			|if less, not wrap case
9898c2ecf20Sopenharmony_ci	bra	sub_wrap
9908c2ecf20Sopenharmony_cisub_srcd:
9918c2ecf20Sopenharmony_ci	bsrl	ckinf_nd
9928c2ecf20Sopenharmony_ci	bne	fix_stk
9938c2ecf20Sopenharmony_ci	bfextu	FPTEMP_EX(%a6){#1:#15},%d0	|get dest exp (always pos)
9948c2ecf20Sopenharmony_ci	bfexts	ETEMP_EX(%a6){#1:#15},%d1	|get src exp (always neg)
9958c2ecf20Sopenharmony_ci	subl	%d1,%d0			|subtract dest from src
9968c2ecf20Sopenharmony_ci	cmpl	#0x8000,%d0
9978c2ecf20Sopenharmony_ci	blt	fix_stk			|if less, not wrap case
9988c2ecf20Sopenharmony_ci|
9998c2ecf20Sopenharmony_ci| Check the signs of the operands.  If they are alike, the fpu
10008c2ecf20Sopenharmony_ci| can be used to subtract from the norm 1.0 with the sign of the
10018c2ecf20Sopenharmony_ci| denorm and it will correctly generate the result in extended
10028c2ecf20Sopenharmony_ci| precision.  We can then call round with no sticky and the result
10038c2ecf20Sopenharmony_ci| will be correct for the user's rounding mode and precision.  If
10048c2ecf20Sopenharmony_ci| the signs are unlike, we call round with the sticky bit set
10058c2ecf20Sopenharmony_ci| and the result will be correct for the user's rounding mode and
10068c2ecf20Sopenharmony_ci| precision.
10078c2ecf20Sopenharmony_ci|
10088c2ecf20Sopenharmony_cisub_wrap:
10098c2ecf20Sopenharmony_ci	movew	ETEMP_EX(%a6),%d0
10108c2ecf20Sopenharmony_ci	movew	FPTEMP_EX(%a6),%d1
10118c2ecf20Sopenharmony_ci	eorw	%d1,%d0
10128c2ecf20Sopenharmony_ci	andiw	#0x8000,%d0
10138c2ecf20Sopenharmony_ci	bne	sub_diff
10148c2ecf20Sopenharmony_ci|
10158c2ecf20Sopenharmony_ci| The signs are alike.
10168c2ecf20Sopenharmony_ci|
10178c2ecf20Sopenharmony_ci	cmpb	#0x0f,DNRM_FLG(%a6) |is dest the denorm?
10188c2ecf20Sopenharmony_ci	bnes	sub_u_srcd
10198c2ecf20Sopenharmony_ci	movew	FPTEMP_EX(%a6),%d0
10208c2ecf20Sopenharmony_ci	andiw	#0x8000,%d0
10218c2ecf20Sopenharmony_ci	orw	#0x3fff,%d0	|force the exponent to +/- 1
10228c2ecf20Sopenharmony_ci	movew	%d0,FPTEMP_EX(%a6) |in the denorm
10238c2ecf20Sopenharmony_ci	movel	USER_FPCR(%a6),%d0
10248c2ecf20Sopenharmony_ci	andil	#0x30,%d0
10258c2ecf20Sopenharmony_ci	fmovel	%d0,%fpcr		|set up users rmode and X
10268c2ecf20Sopenharmony_ci	fmovex	FPTEMP(%a6),%fp0
10278c2ecf20Sopenharmony_ci	fsubx	ETEMP(%a6),%fp0
10288c2ecf20Sopenharmony_ci	fmovel	%fpsr,%d1
10298c2ecf20Sopenharmony_ci	orl	%d1,USER_FPSR(%a6) |capture cc's and inex from fadd
10308c2ecf20Sopenharmony_ci	leal	WBTEMP(%a6),%a0	|point a0 to wbtemp in frame
10318c2ecf20Sopenharmony_ci	fmovex	%fp0,WBTEMP(%a6)	|write result to memory
10328c2ecf20Sopenharmony_ci	lsrl	#4,%d0		|put rmode in lower 2 bits
10338c2ecf20Sopenharmony_ci	movel	USER_FPCR(%a6),%d1
10348c2ecf20Sopenharmony_ci	andil	#0xc0,%d1
10358c2ecf20Sopenharmony_ci	lsrl	#6,%d1		|put precision in upper word
10368c2ecf20Sopenharmony_ci	swap	%d1
10378c2ecf20Sopenharmony_ci	orl	%d0,%d1		|set up for round call
10388c2ecf20Sopenharmony_ci	clrl	%d0		|force sticky to zero
10398c2ecf20Sopenharmony_ci	bclrb	#sign_bit,WBTEMP_EX(%a6)
10408c2ecf20Sopenharmony_ci	sne	WBTEMP_SGN(%a6)
10418c2ecf20Sopenharmony_ci	bsrl	round		|round result to users rmode & prec
10428c2ecf20Sopenharmony_ci	bfclr	WBTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
10438c2ecf20Sopenharmony_ci	beq	frcfpnr
10448c2ecf20Sopenharmony_ci	bsetb	#sign_bit,WBTEMP_EX(%a6)
10458c2ecf20Sopenharmony_ci	bra	frcfpnr
10468c2ecf20Sopenharmony_cisub_u_srcd:
10478c2ecf20Sopenharmony_ci	movew	ETEMP_EX(%a6),%d0
10488c2ecf20Sopenharmony_ci	andiw	#0x8000,%d0
10498c2ecf20Sopenharmony_ci	orw	#0x3fff,%d0	|force the exponent to +/- 1
10508c2ecf20Sopenharmony_ci	movew	%d0,ETEMP_EX(%a6) |in the denorm
10518c2ecf20Sopenharmony_ci	movel	USER_FPCR(%a6),%d0
10528c2ecf20Sopenharmony_ci	andil	#0x30,%d0
10538c2ecf20Sopenharmony_ci	fmovel	%d0,%fpcr		|set up users rmode and X
10548c2ecf20Sopenharmony_ci	fmovex	FPTEMP(%a6),%fp0
10558c2ecf20Sopenharmony_ci	fsubx	ETEMP(%a6),%fp0
10568c2ecf20Sopenharmony_ci	fmovel	%fpsr,%d1
10578c2ecf20Sopenharmony_ci	orl	%d1,USER_FPSR(%a6) |capture cc's and inex from fadd
10588c2ecf20Sopenharmony_ci	leal	WBTEMP(%a6),%a0	|point a0 to wbtemp in frame
10598c2ecf20Sopenharmony_ci	fmovex	%fp0,WBTEMP(%a6)	|write result to memory
10608c2ecf20Sopenharmony_ci	lsrl	#4,%d0		|put rmode in lower 2 bits
10618c2ecf20Sopenharmony_ci	movel	USER_FPCR(%a6),%d1
10628c2ecf20Sopenharmony_ci	andil	#0xc0,%d1
10638c2ecf20Sopenharmony_ci	lsrl	#6,%d1		|put precision in upper word
10648c2ecf20Sopenharmony_ci	swap	%d1
10658c2ecf20Sopenharmony_ci	orl	%d0,%d1		|set up for round call
10668c2ecf20Sopenharmony_ci	clrl	%d0		|force sticky to zero
10678c2ecf20Sopenharmony_ci	bclrb	#sign_bit,WBTEMP_EX(%a6)
10688c2ecf20Sopenharmony_ci	sne	WBTEMP_SGN(%a6)
10698c2ecf20Sopenharmony_ci	bsrl	round		|round result to users rmode & prec
10708c2ecf20Sopenharmony_ci	bfclr	WBTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
10718c2ecf20Sopenharmony_ci	beq	frcfpnr
10728c2ecf20Sopenharmony_ci	bsetb	#sign_bit,WBTEMP_EX(%a6)
10738c2ecf20Sopenharmony_ci	bra	frcfpnr
10748c2ecf20Sopenharmony_ci|
10758c2ecf20Sopenharmony_ci| Signs are unlike:
10768c2ecf20Sopenharmony_ci|
10778c2ecf20Sopenharmony_cisub_diff:
10788c2ecf20Sopenharmony_ci	cmpb	#0x0f,DNRM_FLG(%a6) |is dest the denorm?
10798c2ecf20Sopenharmony_ci	bnes	sub_s_srcd
10808c2ecf20Sopenharmony_cisub_s_destd:
10818c2ecf20Sopenharmony_ci	leal	ETEMP(%a6),%a0
10828c2ecf20Sopenharmony_ci	movel	USER_FPCR(%a6),%d0
10838c2ecf20Sopenharmony_ci	andil	#0x30,%d0
10848c2ecf20Sopenharmony_ci	lsrl	#4,%d0		|put rmode in lower 2 bits
10858c2ecf20Sopenharmony_ci	movel	USER_FPCR(%a6),%d1
10868c2ecf20Sopenharmony_ci	andil	#0xc0,%d1
10878c2ecf20Sopenharmony_ci	lsrl	#6,%d1		|put precision in upper word
10888c2ecf20Sopenharmony_ci	swap	%d1
10898c2ecf20Sopenharmony_ci	orl	%d0,%d1		|set up for round call
10908c2ecf20Sopenharmony_ci	movel	#0x20000000,%d0	|set sticky for round
10918c2ecf20Sopenharmony_ci|
10928c2ecf20Sopenharmony_ci| Since the dest is the denorm, the sign is the opposite of the
10938c2ecf20Sopenharmony_ci| norm sign.
10948c2ecf20Sopenharmony_ci|
10958c2ecf20Sopenharmony_ci	eoriw	#0x8000,ETEMP_EX(%a6)	|flip sign on result
10968c2ecf20Sopenharmony_ci	tstw	ETEMP_EX(%a6)
10978c2ecf20Sopenharmony_ci	bgts	sub_s_dwr
10988c2ecf20Sopenharmony_ci	orl	#neg_mask,USER_FPSR(%a6)
10998c2ecf20Sopenharmony_cisub_s_dwr:
11008c2ecf20Sopenharmony_ci	bclrb	#sign_bit,ETEMP_EX(%a6)
11018c2ecf20Sopenharmony_ci	sne	ETEMP_SGN(%a6)
11028c2ecf20Sopenharmony_ci	bsrl	round		|round result to users rmode & prec
11038c2ecf20Sopenharmony_ci	bfclr	ETEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
11048c2ecf20Sopenharmony_ci	beqs	sub_s_dclr
11058c2ecf20Sopenharmony_ci	bsetb	#sign_bit,ETEMP_EX(%a6)
11068c2ecf20Sopenharmony_cisub_s_dclr:
11078c2ecf20Sopenharmony_ci	leal	WBTEMP(%a6),%a0
11088c2ecf20Sopenharmony_ci	movel	ETEMP(%a6),(%a0)	|write result to wbtemp
11098c2ecf20Sopenharmony_ci	movel	ETEMP_HI(%a6),4(%a0)
11108c2ecf20Sopenharmony_ci	movel	ETEMP_LO(%a6),8(%a0)
11118c2ecf20Sopenharmony_ci	bra	sub_ckovf
11128c2ecf20Sopenharmony_cisub_s_srcd:
11138c2ecf20Sopenharmony_ci	leal	FPTEMP(%a6),%a0
11148c2ecf20Sopenharmony_ci	movel	USER_FPCR(%a6),%d0
11158c2ecf20Sopenharmony_ci	andil	#0x30,%d0
11168c2ecf20Sopenharmony_ci	lsrl	#4,%d0		|put rmode in lower 2 bits
11178c2ecf20Sopenharmony_ci	movel	USER_FPCR(%a6),%d1
11188c2ecf20Sopenharmony_ci	andil	#0xc0,%d1
11198c2ecf20Sopenharmony_ci	lsrl	#6,%d1		|put precision in upper word
11208c2ecf20Sopenharmony_ci	swap	%d1
11218c2ecf20Sopenharmony_ci	orl	%d0,%d1		|set up for round call
11228c2ecf20Sopenharmony_ci	movel	#0x20000000,%d0	|set sticky for round
11238c2ecf20Sopenharmony_ci	bclrb	#sign_bit,FPTEMP_EX(%a6)
11248c2ecf20Sopenharmony_ci	sne	FPTEMP_SGN(%a6)
11258c2ecf20Sopenharmony_ci	bsrl	round		|round result to users rmode & prec
11268c2ecf20Sopenharmony_ci	bfclr	FPTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
11278c2ecf20Sopenharmony_ci	beqs	sub_s_sclr
11288c2ecf20Sopenharmony_ci	bsetb	#sign_bit,FPTEMP_EX(%a6)
11298c2ecf20Sopenharmony_cisub_s_sclr:
11308c2ecf20Sopenharmony_ci	leal	WBTEMP(%a6),%a0
11318c2ecf20Sopenharmony_ci	movel	FPTEMP(%a6),(%a0)	|write result to wbtemp
11328c2ecf20Sopenharmony_ci	movel	FPTEMP_HI(%a6),4(%a0)
11338c2ecf20Sopenharmony_ci	movel	FPTEMP_LO(%a6),8(%a0)
11348c2ecf20Sopenharmony_ci	tstw	FPTEMP_EX(%a6)
11358c2ecf20Sopenharmony_ci	bgt	sub_ckovf
11368c2ecf20Sopenharmony_ci	orl	#neg_mask,USER_FPSR(%a6)
11378c2ecf20Sopenharmony_cisub_ckovf:
11388c2ecf20Sopenharmony_ci	movew	WBTEMP_EX(%a6),%d0
11398c2ecf20Sopenharmony_ci	andiw	#0x7fff,%d0
11408c2ecf20Sopenharmony_ci	cmpiw	#0x7fff,%d0
11418c2ecf20Sopenharmony_ci	bne	frcfpnr
11428c2ecf20Sopenharmony_ci|
11438c2ecf20Sopenharmony_ci| The result has overflowed to $7fff exponent.  Set I, ovfl,
11448c2ecf20Sopenharmony_ci| and aovfl, and clr the mantissa (incorrectly set by the
11458c2ecf20Sopenharmony_ci| round routine.)
11468c2ecf20Sopenharmony_ci|
11478c2ecf20Sopenharmony_ci	orl	#inf_mask+ovfl_inx_mask,USER_FPSR(%a6)
11488c2ecf20Sopenharmony_ci	clrl	4(%a0)
11498c2ecf20Sopenharmony_ci	bra	frcfpnr
11508c2ecf20Sopenharmony_ci|
11518c2ecf20Sopenharmony_ci| Inst is fcmp.
11528c2ecf20Sopenharmony_ci|
11538c2ecf20Sopenharmony_ciwrap_cmp:
11548c2ecf20Sopenharmony_ci	cmpb	#0xff,DNRM_FLG(%a6) |if both ops denorm,
11558c2ecf20Sopenharmony_ci	beq	fix_stk		 |restore to fpu
11568c2ecf20Sopenharmony_ci|
11578c2ecf20Sopenharmony_ci| One of the ops is denormalized.  Test for wrap condition
11588c2ecf20Sopenharmony_ci| and complete the instruction.
11598c2ecf20Sopenharmony_ci|
11608c2ecf20Sopenharmony_ci	cmpb	#0x0f,DNRM_FLG(%a6) |check for dest denorm
11618c2ecf20Sopenharmony_ci	bnes	cmp_srcd
11628c2ecf20Sopenharmony_cicmp_destd:
11638c2ecf20Sopenharmony_ci	bsrl	ckinf_ns
11648c2ecf20Sopenharmony_ci	bne	fix_stk
11658c2ecf20Sopenharmony_ci	bfextu	ETEMP_EX(%a6){#1:#15},%d0	|get src exp (always pos)
11668c2ecf20Sopenharmony_ci	bfexts	FPTEMP_EX(%a6){#1:#15},%d1	|get dest exp (always neg)
11678c2ecf20Sopenharmony_ci	subl	%d1,%d0			|subtract dest from src
11688c2ecf20Sopenharmony_ci	cmpl	#0x8000,%d0
11698c2ecf20Sopenharmony_ci	blt	fix_stk			|if less, not wrap case
11708c2ecf20Sopenharmony_ci	tstw	ETEMP_EX(%a6)		|set N to ~sign_of(src)
11718c2ecf20Sopenharmony_ci	bge	cmp_setn
11728c2ecf20Sopenharmony_ci	rts
11738c2ecf20Sopenharmony_cicmp_srcd:
11748c2ecf20Sopenharmony_ci	bsrl	ckinf_nd
11758c2ecf20Sopenharmony_ci	bne	fix_stk
11768c2ecf20Sopenharmony_ci	bfextu	FPTEMP_EX(%a6){#1:#15},%d0	|get dest exp (always pos)
11778c2ecf20Sopenharmony_ci	bfexts	ETEMP_EX(%a6){#1:#15},%d1	|get src exp (always neg)
11788c2ecf20Sopenharmony_ci	subl	%d1,%d0			|subtract src from dest
11798c2ecf20Sopenharmony_ci	cmpl	#0x8000,%d0
11808c2ecf20Sopenharmony_ci	blt	fix_stk			|if less, not wrap case
11818c2ecf20Sopenharmony_ci	tstw	FPTEMP_EX(%a6)		|set N to sign_of(dest)
11828c2ecf20Sopenharmony_ci	blt	cmp_setn
11838c2ecf20Sopenharmony_ci	rts
11848c2ecf20Sopenharmony_cicmp_setn:
11858c2ecf20Sopenharmony_ci	orl	#neg_mask,USER_FPSR(%a6)
11868c2ecf20Sopenharmony_ci	rts
11878c2ecf20Sopenharmony_ci
11888c2ecf20Sopenharmony_ci|
11898c2ecf20Sopenharmony_ci| Inst is fmul.
11908c2ecf20Sopenharmony_ci|
11918c2ecf20Sopenharmony_ciwrap_mul:
11928c2ecf20Sopenharmony_ci	cmpb	#0xff,DNRM_FLG(%a6) |if both ops denorm,
11938c2ecf20Sopenharmony_ci	beq	force_unf	|force an underflow (really!)
11948c2ecf20Sopenharmony_ci|
11958c2ecf20Sopenharmony_ci| One of the ops is denormalized.  Test for wrap condition
11968c2ecf20Sopenharmony_ci| and complete the instruction.
11978c2ecf20Sopenharmony_ci|
11988c2ecf20Sopenharmony_ci	cmpb	#0x0f,DNRM_FLG(%a6) |check for dest denorm
11998c2ecf20Sopenharmony_ci	bnes	mul_srcd
12008c2ecf20Sopenharmony_cimul_destd:
12018c2ecf20Sopenharmony_ci	bsrl	ckinf_ns
12028c2ecf20Sopenharmony_ci	bne	fix_stk
12038c2ecf20Sopenharmony_ci	bfextu	ETEMP_EX(%a6){#1:#15},%d0	|get src exp (always pos)
12048c2ecf20Sopenharmony_ci	bfexts	FPTEMP_EX(%a6){#1:#15},%d1	|get dest exp (always neg)
12058c2ecf20Sopenharmony_ci	addl	%d1,%d0			|subtract dest from src
12068c2ecf20Sopenharmony_ci	bgt	fix_stk
12078c2ecf20Sopenharmony_ci	bra	force_unf
12088c2ecf20Sopenharmony_cimul_srcd:
12098c2ecf20Sopenharmony_ci	bsrl	ckinf_nd
12108c2ecf20Sopenharmony_ci	bne	fix_stk
12118c2ecf20Sopenharmony_ci	bfextu	FPTEMP_EX(%a6){#1:#15},%d0	|get dest exp (always pos)
12128c2ecf20Sopenharmony_ci	bfexts	ETEMP_EX(%a6){#1:#15},%d1	|get src exp (always neg)
12138c2ecf20Sopenharmony_ci	addl	%d1,%d0			|subtract src from dest
12148c2ecf20Sopenharmony_ci	bgt	fix_stk
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci|
12178c2ecf20Sopenharmony_ci| This code handles the case of the instruction resulting in
12188c2ecf20Sopenharmony_ci| an underflow condition.
12198c2ecf20Sopenharmony_ci|
12208c2ecf20Sopenharmony_ciforce_unf:
12218c2ecf20Sopenharmony_ci	bclrb	#E1,E_BYTE(%a6)
12228c2ecf20Sopenharmony_ci	orl	#unfinx_mask,USER_FPSR(%a6)
12238c2ecf20Sopenharmony_ci	clrw	NMNEXC(%a6)
12248c2ecf20Sopenharmony_ci	clrb	WBTEMP_SGN(%a6)
12258c2ecf20Sopenharmony_ci	movew	ETEMP_EX(%a6),%d0		|find the sign of the result
12268c2ecf20Sopenharmony_ci	movew	FPTEMP_EX(%a6),%d1
12278c2ecf20Sopenharmony_ci	eorw	%d1,%d0
12288c2ecf20Sopenharmony_ci	andiw	#0x8000,%d0
12298c2ecf20Sopenharmony_ci	beqs	frcunfcont
12308c2ecf20Sopenharmony_ci	st	WBTEMP_SGN(%a6)
12318c2ecf20Sopenharmony_cifrcunfcont:
12328c2ecf20Sopenharmony_ci	lea	WBTEMP(%a6),%a0		|point a0 to memory location
12338c2ecf20Sopenharmony_ci	movew	CMDREG1B(%a6),%d0
12348c2ecf20Sopenharmony_ci	btstl	#6,%d0			|test for forced precision
12358c2ecf20Sopenharmony_ci	beqs	frcunf_fpcr
12368c2ecf20Sopenharmony_ci	btstl	#2,%d0			|check for double
12378c2ecf20Sopenharmony_ci	bnes	frcunf_dbl
12388c2ecf20Sopenharmony_ci	movel	#0x1,%d0			|inst is forced single
12398c2ecf20Sopenharmony_ci	bras	frcunf_rnd
12408c2ecf20Sopenharmony_cifrcunf_dbl:
12418c2ecf20Sopenharmony_ci	movel	#0x2,%d0			|inst is forced double
12428c2ecf20Sopenharmony_ci	bras	frcunf_rnd
12438c2ecf20Sopenharmony_cifrcunf_fpcr:
12448c2ecf20Sopenharmony_ci	bfextu	FPCR_MODE(%a6){#0:#2},%d0	|inst not forced - use fpcr prec
12458c2ecf20Sopenharmony_cifrcunf_rnd:
12468c2ecf20Sopenharmony_ci	bsrl	unf_sub			|get correct result based on
12478c2ecf20Sopenharmony_ci|					;round precision/mode.  This
12488c2ecf20Sopenharmony_ci|					;sets FPSR_CC correctly
12498c2ecf20Sopenharmony_ci	bfclr	WBTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
12508c2ecf20Sopenharmony_ci	beqs	frcfpn
12518c2ecf20Sopenharmony_ci	bsetb	#sign_bit,WBTEMP_EX(%a6)
12528c2ecf20Sopenharmony_ci	bra	frcfpn
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_ci|
12558c2ecf20Sopenharmony_ci| Write the result to the user's fpn.  All results must be HUGE to be
12568c2ecf20Sopenharmony_ci| written; otherwise the results would have overflowed or underflowed.
12578c2ecf20Sopenharmony_ci| If the rounding precision is single or double, the ovf_res routine
12588c2ecf20Sopenharmony_ci| is needed to correctly supply the max value.
12598c2ecf20Sopenharmony_ci|
12608c2ecf20Sopenharmony_cifrcfpnr:
12618c2ecf20Sopenharmony_ci	movew	CMDREG1B(%a6),%d0
12628c2ecf20Sopenharmony_ci	btstl	#6,%d0			|test for forced precision
12638c2ecf20Sopenharmony_ci	beqs	frcfpn_fpcr
12648c2ecf20Sopenharmony_ci	btstl	#2,%d0			|check for double
12658c2ecf20Sopenharmony_ci	bnes	frcfpn_dbl
12668c2ecf20Sopenharmony_ci	movel	#0x1,%d0			|inst is forced single
12678c2ecf20Sopenharmony_ci	bras	frcfpn_rnd
12688c2ecf20Sopenharmony_cifrcfpn_dbl:
12698c2ecf20Sopenharmony_ci	movel	#0x2,%d0			|inst is forced double
12708c2ecf20Sopenharmony_ci	bras	frcfpn_rnd
12718c2ecf20Sopenharmony_cifrcfpn_fpcr:
12728c2ecf20Sopenharmony_ci	bfextu	FPCR_MODE(%a6){#0:#2},%d0	|inst not forced - use fpcr prec
12738c2ecf20Sopenharmony_ci	tstb	%d0
12748c2ecf20Sopenharmony_ci	beqs	frcfpn			|if extended, write what you got
12758c2ecf20Sopenharmony_cifrcfpn_rnd:
12768c2ecf20Sopenharmony_ci	bclrb	#sign_bit,WBTEMP_EX(%a6)
12778c2ecf20Sopenharmony_ci	sne	WBTEMP_SGN(%a6)
12788c2ecf20Sopenharmony_ci	bsrl	ovf_res			|get correct result based on
12798c2ecf20Sopenharmony_ci|					;round precision/mode.  This
12808c2ecf20Sopenharmony_ci|					;sets FPSR_CC correctly
12818c2ecf20Sopenharmony_ci	bfclr	WBTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
12828c2ecf20Sopenharmony_ci	beqs	frcfpn_clr
12838c2ecf20Sopenharmony_ci	bsetb	#sign_bit,WBTEMP_EX(%a6)
12848c2ecf20Sopenharmony_cifrcfpn_clr:
12858c2ecf20Sopenharmony_ci	orl	#ovfinx_mask,USER_FPSR(%a6)
12868c2ecf20Sopenharmony_ci|
12878c2ecf20Sopenharmony_ci| Perform the write.
12888c2ecf20Sopenharmony_ci|
12898c2ecf20Sopenharmony_cifrcfpn:
12908c2ecf20Sopenharmony_ci	bfextu	CMDREG1B(%a6){#6:#3},%d0	|extract fp destination register
12918c2ecf20Sopenharmony_ci	cmpib	#3,%d0
12928c2ecf20Sopenharmony_ci	bles	frc0123			|check if dest is fp0-fp3
12938c2ecf20Sopenharmony_ci	movel	#7,%d1
12948c2ecf20Sopenharmony_ci	subl	%d0,%d1
12958c2ecf20Sopenharmony_ci	clrl	%d0
12968c2ecf20Sopenharmony_ci	bsetl	%d1,%d0
12978c2ecf20Sopenharmony_ci	fmovemx WBTEMP(%a6),%d0
12988c2ecf20Sopenharmony_ci	rts
12998c2ecf20Sopenharmony_cifrc0123:
13008c2ecf20Sopenharmony_ci	cmpib	#0,%d0
13018c2ecf20Sopenharmony_ci	beqs	frc0_dst
13028c2ecf20Sopenharmony_ci	cmpib	#1,%d0
13038c2ecf20Sopenharmony_ci	beqs	frc1_dst
13048c2ecf20Sopenharmony_ci	cmpib	#2,%d0
13058c2ecf20Sopenharmony_ci	beqs	frc2_dst
13068c2ecf20Sopenharmony_cifrc3_dst:
13078c2ecf20Sopenharmony_ci	movel	WBTEMP_EX(%a6),USER_FP3(%a6)
13088c2ecf20Sopenharmony_ci	movel	WBTEMP_HI(%a6),USER_FP3+4(%a6)
13098c2ecf20Sopenharmony_ci	movel	WBTEMP_LO(%a6),USER_FP3+8(%a6)
13108c2ecf20Sopenharmony_ci	rts
13118c2ecf20Sopenharmony_cifrc2_dst:
13128c2ecf20Sopenharmony_ci	movel	WBTEMP_EX(%a6),USER_FP2(%a6)
13138c2ecf20Sopenharmony_ci	movel	WBTEMP_HI(%a6),USER_FP2+4(%a6)
13148c2ecf20Sopenharmony_ci	movel	WBTEMP_LO(%a6),USER_FP2+8(%a6)
13158c2ecf20Sopenharmony_ci	rts
13168c2ecf20Sopenharmony_cifrc1_dst:
13178c2ecf20Sopenharmony_ci	movel	WBTEMP_EX(%a6),USER_FP1(%a6)
13188c2ecf20Sopenharmony_ci	movel	WBTEMP_HI(%a6),USER_FP1+4(%a6)
13198c2ecf20Sopenharmony_ci	movel	WBTEMP_LO(%a6),USER_FP1+8(%a6)
13208c2ecf20Sopenharmony_ci	rts
13218c2ecf20Sopenharmony_cifrc0_dst:
13228c2ecf20Sopenharmony_ci	movel	WBTEMP_EX(%a6),USER_FP0(%a6)
13238c2ecf20Sopenharmony_ci	movel	WBTEMP_HI(%a6),USER_FP0+4(%a6)
13248c2ecf20Sopenharmony_ci	movel	WBTEMP_LO(%a6),USER_FP0+8(%a6)
13258c2ecf20Sopenharmony_ci	rts
13268c2ecf20Sopenharmony_ci
13278c2ecf20Sopenharmony_ci|
13288c2ecf20Sopenharmony_ci| Write etemp to fpn.
13298c2ecf20Sopenharmony_ci| A check is made on enabled and signalled snan exceptions,
13308c2ecf20Sopenharmony_ci| and the destination is not overwritten if this condition exists.
13318c2ecf20Sopenharmony_ci| This code is designed to make fmoveins of unsupported data types
13328c2ecf20Sopenharmony_ci| faster.
13338c2ecf20Sopenharmony_ci|
13348c2ecf20Sopenharmony_ciwr_etemp:
13358c2ecf20Sopenharmony_ci	btstb	#snan_bit,FPSR_EXCEPT(%a6)	|if snan is set, and
13368c2ecf20Sopenharmony_ci	beqs	fmoveinc		|enabled, force restore
13378c2ecf20Sopenharmony_ci	btstb	#snan_bit,FPCR_ENABLE(%a6) |and don't overwrite
13388c2ecf20Sopenharmony_ci	beqs	fmoveinc		|the dest
13398c2ecf20Sopenharmony_ci	movel	ETEMP_EX(%a6),FPTEMP_EX(%a6)	|set up fptemp sign for
13408c2ecf20Sopenharmony_ci|						;snan handler
13418c2ecf20Sopenharmony_ci	tstb	ETEMP(%a6)		|check for negative
13428c2ecf20Sopenharmony_ci	blts	snan_neg
13438c2ecf20Sopenharmony_ci	rts
13448c2ecf20Sopenharmony_cisnan_neg:
13458c2ecf20Sopenharmony_ci	orl	#neg_bit,USER_FPSR(%a6)	|snan is negative; set N
13468c2ecf20Sopenharmony_ci	rts
13478c2ecf20Sopenharmony_cifmoveinc:
13488c2ecf20Sopenharmony_ci	clrw	NMNEXC(%a6)
13498c2ecf20Sopenharmony_ci	bclrb	#E1,E_BYTE(%a6)
13508c2ecf20Sopenharmony_ci	moveb	STAG(%a6),%d0		|check if stag is inf
13518c2ecf20Sopenharmony_ci	andib	#0xe0,%d0
13528c2ecf20Sopenharmony_ci	cmpib	#0x40,%d0
13538c2ecf20Sopenharmony_ci	bnes	fminc_cnan
13548c2ecf20Sopenharmony_ci	orl	#inf_mask,USER_FPSR(%a6) |if inf, nothing yet has set I
13558c2ecf20Sopenharmony_ci	tstw	LOCAL_EX(%a0)		|check sign
13568c2ecf20Sopenharmony_ci	bges	fminc_con
13578c2ecf20Sopenharmony_ci	orl	#neg_mask,USER_FPSR(%a6)
13588c2ecf20Sopenharmony_ci	bra	fminc_con
13598c2ecf20Sopenharmony_cifminc_cnan:
13608c2ecf20Sopenharmony_ci	cmpib	#0x60,%d0			|check if stag is NaN
13618c2ecf20Sopenharmony_ci	bnes	fminc_czero
13628c2ecf20Sopenharmony_ci	orl	#nan_mask,USER_FPSR(%a6) |if nan, nothing yet has set NaN
13638c2ecf20Sopenharmony_ci	movel	ETEMP_EX(%a6),FPTEMP_EX(%a6)	|set up fptemp sign for
13648c2ecf20Sopenharmony_ci|						;snan handler
13658c2ecf20Sopenharmony_ci	tstw	LOCAL_EX(%a0)		|check sign
13668c2ecf20Sopenharmony_ci	bges	fminc_con
13678c2ecf20Sopenharmony_ci	orl	#neg_mask,USER_FPSR(%a6)
13688c2ecf20Sopenharmony_ci	bra	fminc_con
13698c2ecf20Sopenharmony_cifminc_czero:
13708c2ecf20Sopenharmony_ci	cmpib	#0x20,%d0			|check if zero
13718c2ecf20Sopenharmony_ci	bnes	fminc_con
13728c2ecf20Sopenharmony_ci	orl	#z_mask,USER_FPSR(%a6)	|if zero, set Z
13738c2ecf20Sopenharmony_ci	tstw	LOCAL_EX(%a0)		|check sign
13748c2ecf20Sopenharmony_ci	bges	fminc_con
13758c2ecf20Sopenharmony_ci	orl	#neg_mask,USER_FPSR(%a6)
13768c2ecf20Sopenharmony_cifminc_con:
13778c2ecf20Sopenharmony_ci	bfextu	CMDREG1B(%a6){#6:#3},%d0	|extract fp destination register
13788c2ecf20Sopenharmony_ci	cmpib	#3,%d0
13798c2ecf20Sopenharmony_ci	bles	fp0123			|check if dest is fp0-fp3
13808c2ecf20Sopenharmony_ci	movel	#7,%d1
13818c2ecf20Sopenharmony_ci	subl	%d0,%d1
13828c2ecf20Sopenharmony_ci	clrl	%d0
13838c2ecf20Sopenharmony_ci	bsetl	%d1,%d0
13848c2ecf20Sopenharmony_ci	fmovemx ETEMP(%a6),%d0
13858c2ecf20Sopenharmony_ci	rts
13868c2ecf20Sopenharmony_ci
13878c2ecf20Sopenharmony_cifp0123:
13888c2ecf20Sopenharmony_ci	cmpib	#0,%d0
13898c2ecf20Sopenharmony_ci	beqs	fp0_dst
13908c2ecf20Sopenharmony_ci	cmpib	#1,%d0
13918c2ecf20Sopenharmony_ci	beqs	fp1_dst
13928c2ecf20Sopenharmony_ci	cmpib	#2,%d0
13938c2ecf20Sopenharmony_ci	beqs	fp2_dst
13948c2ecf20Sopenharmony_cifp3_dst:
13958c2ecf20Sopenharmony_ci	movel	ETEMP_EX(%a6),USER_FP3(%a6)
13968c2ecf20Sopenharmony_ci	movel	ETEMP_HI(%a6),USER_FP3+4(%a6)
13978c2ecf20Sopenharmony_ci	movel	ETEMP_LO(%a6),USER_FP3+8(%a6)
13988c2ecf20Sopenharmony_ci	rts
13998c2ecf20Sopenharmony_cifp2_dst:
14008c2ecf20Sopenharmony_ci	movel	ETEMP_EX(%a6),USER_FP2(%a6)
14018c2ecf20Sopenharmony_ci	movel	ETEMP_HI(%a6),USER_FP2+4(%a6)
14028c2ecf20Sopenharmony_ci	movel	ETEMP_LO(%a6),USER_FP2+8(%a6)
14038c2ecf20Sopenharmony_ci	rts
14048c2ecf20Sopenharmony_cifp1_dst:
14058c2ecf20Sopenharmony_ci	movel	ETEMP_EX(%a6),USER_FP1(%a6)
14068c2ecf20Sopenharmony_ci	movel	ETEMP_HI(%a6),USER_FP1+4(%a6)
14078c2ecf20Sopenharmony_ci	movel	ETEMP_LO(%a6),USER_FP1+8(%a6)
14088c2ecf20Sopenharmony_ci	rts
14098c2ecf20Sopenharmony_cifp0_dst:
14108c2ecf20Sopenharmony_ci	movel	ETEMP_EX(%a6),USER_FP0(%a6)
14118c2ecf20Sopenharmony_ci	movel	ETEMP_HI(%a6),USER_FP0+4(%a6)
14128c2ecf20Sopenharmony_ci	movel	ETEMP_LO(%a6),USER_FP0+8(%a6)
14138c2ecf20Sopenharmony_ci	rts
14148c2ecf20Sopenharmony_ci
14158c2ecf20Sopenharmony_ciopclass3:
14168c2ecf20Sopenharmony_ci	st	CU_ONLY(%a6)
14178c2ecf20Sopenharmony_ci	movew	CMDREG1B(%a6),%d0	|check if packed moveout
14188c2ecf20Sopenharmony_ci	andiw	#0x0c00,%d0	|isolate last 2 bits of size field
14198c2ecf20Sopenharmony_ci	cmpiw	#0x0c00,%d0	|if size is 011 or 111, it is packed
14208c2ecf20Sopenharmony_ci	beq	pack_out	|else it is norm or denorm
14218c2ecf20Sopenharmony_ci	bra	mv_out
14228c2ecf20Sopenharmony_ci
14238c2ecf20Sopenharmony_ci
14248c2ecf20Sopenharmony_ci|
14258c2ecf20Sopenharmony_ci|	MOVE OUT
14268c2ecf20Sopenharmony_ci|
14278c2ecf20Sopenharmony_ci
14288c2ecf20Sopenharmony_cimv_tbl:
14298c2ecf20Sopenharmony_ci	.long	li
14308c2ecf20Sopenharmony_ci	.long	sgp
14318c2ecf20Sopenharmony_ci	.long	xp
14328c2ecf20Sopenharmony_ci	.long	mvout_end	|should never be taken
14338c2ecf20Sopenharmony_ci	.long	wi
14348c2ecf20Sopenharmony_ci	.long	dp
14358c2ecf20Sopenharmony_ci	.long	bi
14368c2ecf20Sopenharmony_ci	.long	mvout_end	|should never be taken
14378c2ecf20Sopenharmony_cimv_out:
14388c2ecf20Sopenharmony_ci	bfextu	CMDREG1B(%a6){#3:#3},%d1	|put source specifier in d1
14398c2ecf20Sopenharmony_ci	leal	mv_tbl,%a0
14408c2ecf20Sopenharmony_ci	movel	%a0@(%d1:l:4),%a0
14418c2ecf20Sopenharmony_ci	jmp	(%a0)
14428c2ecf20Sopenharmony_ci
14438c2ecf20Sopenharmony_ci|
14448c2ecf20Sopenharmony_ci| This exit is for move-out to memory.  The aunfl bit is
14458c2ecf20Sopenharmony_ci| set if the result is inex and unfl is signalled.
14468c2ecf20Sopenharmony_ci|
14478c2ecf20Sopenharmony_cimvout_end:
14488c2ecf20Sopenharmony_ci	btstb	#inex2_bit,FPSR_EXCEPT(%a6)
14498c2ecf20Sopenharmony_ci	beqs	no_aufl
14508c2ecf20Sopenharmony_ci	btstb	#unfl_bit,FPSR_EXCEPT(%a6)
14518c2ecf20Sopenharmony_ci	beqs	no_aufl
14528c2ecf20Sopenharmony_ci	bsetb	#aunfl_bit,FPSR_AEXCEPT(%a6)
14538c2ecf20Sopenharmony_cino_aufl:
14548c2ecf20Sopenharmony_ci	clrw	NMNEXC(%a6)
14558c2ecf20Sopenharmony_ci	bclrb	#E1,E_BYTE(%a6)
14568c2ecf20Sopenharmony_ci	fmovel	#0,%FPSR			|clear any cc bits from res_func
14578c2ecf20Sopenharmony_ci|
14588c2ecf20Sopenharmony_ci| Return ETEMP to extended format from internal extended format so
14598c2ecf20Sopenharmony_ci| that gen_except will have a correctly signed value for ovfl/unfl
14608c2ecf20Sopenharmony_ci| handlers.
14618c2ecf20Sopenharmony_ci|
14628c2ecf20Sopenharmony_ci	bfclr	ETEMP_SGN(%a6){#0:#8}
14638c2ecf20Sopenharmony_ci	beqs	mvout_con
14648c2ecf20Sopenharmony_ci	bsetb	#sign_bit,ETEMP_EX(%a6)
14658c2ecf20Sopenharmony_cimvout_con:
14668c2ecf20Sopenharmony_ci	rts
14678c2ecf20Sopenharmony_ci|
14688c2ecf20Sopenharmony_ci| This exit is for move-out to int register.  The aunfl bit is
14698c2ecf20Sopenharmony_ci| not set in any case for this move.
14708c2ecf20Sopenharmony_ci|
14718c2ecf20Sopenharmony_cimvouti_end:
14728c2ecf20Sopenharmony_ci	clrw	NMNEXC(%a6)
14738c2ecf20Sopenharmony_ci	bclrb	#E1,E_BYTE(%a6)
14748c2ecf20Sopenharmony_ci	fmovel	#0,%FPSR			|clear any cc bits from res_func
14758c2ecf20Sopenharmony_ci|
14768c2ecf20Sopenharmony_ci| Return ETEMP to extended format from internal extended format so
14778c2ecf20Sopenharmony_ci| that gen_except will have a correctly signed value for ovfl/unfl
14788c2ecf20Sopenharmony_ci| handlers.
14798c2ecf20Sopenharmony_ci|
14808c2ecf20Sopenharmony_ci	bfclr	ETEMP_SGN(%a6){#0:#8}
14818c2ecf20Sopenharmony_ci	beqs	mvouti_con
14828c2ecf20Sopenharmony_ci	bsetb	#sign_bit,ETEMP_EX(%a6)
14838c2ecf20Sopenharmony_cimvouti_con:
14848c2ecf20Sopenharmony_ci	rts
14858c2ecf20Sopenharmony_ci|
14868c2ecf20Sopenharmony_ci| li is used to handle a long integer source specifier
14878c2ecf20Sopenharmony_ci|
14888c2ecf20Sopenharmony_ci
14898c2ecf20Sopenharmony_cili:
14908c2ecf20Sopenharmony_ci	moveql	#4,%d0		|set byte count
14918c2ecf20Sopenharmony_ci
14928c2ecf20Sopenharmony_ci	btstb	#7,STAG(%a6)	|check for extended denorm
14938c2ecf20Sopenharmony_ci	bne	int_dnrm	|if so, branch
14948c2ecf20Sopenharmony_ci
14958c2ecf20Sopenharmony_ci	fmovemx ETEMP(%a6),%fp0-%fp0
14968c2ecf20Sopenharmony_ci	fcmpd	#0x41dfffffffc00000,%fp0
14978c2ecf20Sopenharmony_ci| 41dfffffffc00000 in dbl prec = 401d0000fffffffe00000000 in ext prec
14988c2ecf20Sopenharmony_ci	fbge	lo_plrg
14998c2ecf20Sopenharmony_ci	fcmpd	#0xc1e0000000000000,%fp0
15008c2ecf20Sopenharmony_ci| c1e0000000000000 in dbl prec = c01e00008000000000000000 in ext prec
15018c2ecf20Sopenharmony_ci	fble	lo_nlrg
15028c2ecf20Sopenharmony_ci|
15038c2ecf20Sopenharmony_ci| at this point, the answer is between the largest pos and neg values
15048c2ecf20Sopenharmony_ci|
15058c2ecf20Sopenharmony_ci	movel	USER_FPCR(%a6),%d1	|use user's rounding mode
15068c2ecf20Sopenharmony_ci	andil	#0x30,%d1
15078c2ecf20Sopenharmony_ci	fmovel	%d1,%fpcr
15088c2ecf20Sopenharmony_ci	fmovel	%fp0,L_SCR1(%a6)	|let the 040 perform conversion
15098c2ecf20Sopenharmony_ci	fmovel %fpsr,%d1
15108c2ecf20Sopenharmony_ci	orl	%d1,USER_FPSR(%a6)	|capture inex2/ainex if set
15118c2ecf20Sopenharmony_ci	bra	int_wrt
15128c2ecf20Sopenharmony_ci
15138c2ecf20Sopenharmony_ci
15148c2ecf20Sopenharmony_cilo_plrg:
15158c2ecf20Sopenharmony_ci	movel	#0x7fffffff,L_SCR1(%a6)	|answer is largest positive int
15168c2ecf20Sopenharmony_ci	fbeq	int_wrt			|exact answer
15178c2ecf20Sopenharmony_ci	fcmpd	#0x41dfffffffe00000,%fp0
15188c2ecf20Sopenharmony_ci| 41dfffffffe00000 in dbl prec = 401d0000ffffffff00000000 in ext prec
15198c2ecf20Sopenharmony_ci	fbge	int_operr		|set operr
15208c2ecf20Sopenharmony_ci	bra	int_inx			|set inexact
15218c2ecf20Sopenharmony_ci
15228c2ecf20Sopenharmony_cilo_nlrg:
15238c2ecf20Sopenharmony_ci	movel	#0x80000000,L_SCR1(%a6)
15248c2ecf20Sopenharmony_ci	fbeq	int_wrt			|exact answer
15258c2ecf20Sopenharmony_ci	fcmpd	#0xc1e0000000100000,%fp0
15268c2ecf20Sopenharmony_ci| c1e0000000100000 in dbl prec = c01e00008000000080000000 in ext prec
15278c2ecf20Sopenharmony_ci	fblt	int_operr		|set operr
15288c2ecf20Sopenharmony_ci	bra	int_inx			|set inexact
15298c2ecf20Sopenharmony_ci
15308c2ecf20Sopenharmony_ci|
15318c2ecf20Sopenharmony_ci| wi is used to handle a word integer source specifier
15328c2ecf20Sopenharmony_ci|
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_ciwi:
15358c2ecf20Sopenharmony_ci	moveql	#2,%d0		|set byte count
15368c2ecf20Sopenharmony_ci
15378c2ecf20Sopenharmony_ci	btstb	#7,STAG(%a6)	|check for extended denorm
15388c2ecf20Sopenharmony_ci	bne	int_dnrm	|branch if so
15398c2ecf20Sopenharmony_ci
15408c2ecf20Sopenharmony_ci	fmovemx ETEMP(%a6),%fp0-%fp0
15418c2ecf20Sopenharmony_ci	fcmps	#0x46fffe00,%fp0
15428c2ecf20Sopenharmony_ci| 46fffe00 in sgl prec = 400d0000fffe000000000000 in ext prec
15438c2ecf20Sopenharmony_ci	fbge	wo_plrg
15448c2ecf20Sopenharmony_ci	fcmps	#0xc7000000,%fp0
15458c2ecf20Sopenharmony_ci| c7000000 in sgl prec = c00e00008000000000000000 in ext prec
15468c2ecf20Sopenharmony_ci	fble	wo_nlrg
15478c2ecf20Sopenharmony_ci
15488c2ecf20Sopenharmony_ci|
15498c2ecf20Sopenharmony_ci| at this point, the answer is between the largest pos and neg values
15508c2ecf20Sopenharmony_ci|
15518c2ecf20Sopenharmony_ci	movel	USER_FPCR(%a6),%d1	|use user's rounding mode
15528c2ecf20Sopenharmony_ci	andil	#0x30,%d1
15538c2ecf20Sopenharmony_ci	fmovel	%d1,%fpcr
15548c2ecf20Sopenharmony_ci	fmovew	%fp0,L_SCR1(%a6)	|let the 040 perform conversion
15558c2ecf20Sopenharmony_ci	fmovel %fpsr,%d1
15568c2ecf20Sopenharmony_ci	orl	%d1,USER_FPSR(%a6)	|capture inex2/ainex if set
15578c2ecf20Sopenharmony_ci	bra	int_wrt
15588c2ecf20Sopenharmony_ci
15598c2ecf20Sopenharmony_ciwo_plrg:
15608c2ecf20Sopenharmony_ci	movew	#0x7fff,L_SCR1(%a6)	|answer is largest positive int
15618c2ecf20Sopenharmony_ci	fbeq	int_wrt			|exact answer
15628c2ecf20Sopenharmony_ci	fcmps	#0x46ffff00,%fp0
15638c2ecf20Sopenharmony_ci| 46ffff00 in sgl prec = 400d0000ffff000000000000 in ext prec
15648c2ecf20Sopenharmony_ci	fbge	int_operr		|set operr
15658c2ecf20Sopenharmony_ci	bra	int_inx			|set inexact
15668c2ecf20Sopenharmony_ci
15678c2ecf20Sopenharmony_ciwo_nlrg:
15688c2ecf20Sopenharmony_ci	movew	#0x8000,L_SCR1(%a6)
15698c2ecf20Sopenharmony_ci	fbeq	int_wrt			|exact answer
15708c2ecf20Sopenharmony_ci	fcmps	#0xc7000080,%fp0
15718c2ecf20Sopenharmony_ci| c7000080 in sgl prec = c00e00008000800000000000 in ext prec
15728c2ecf20Sopenharmony_ci	fblt	int_operr		|set operr
15738c2ecf20Sopenharmony_ci	bra	int_inx			|set inexact
15748c2ecf20Sopenharmony_ci
15758c2ecf20Sopenharmony_ci|
15768c2ecf20Sopenharmony_ci| bi is used to handle a byte integer source specifier
15778c2ecf20Sopenharmony_ci|
15788c2ecf20Sopenharmony_ci
15798c2ecf20Sopenharmony_cibi:
15808c2ecf20Sopenharmony_ci	moveql	#1,%d0		|set byte count
15818c2ecf20Sopenharmony_ci
15828c2ecf20Sopenharmony_ci	btstb	#7,STAG(%a6)	|check for extended denorm
15838c2ecf20Sopenharmony_ci	bne	int_dnrm	|branch if so
15848c2ecf20Sopenharmony_ci
15858c2ecf20Sopenharmony_ci	fmovemx ETEMP(%a6),%fp0-%fp0
15868c2ecf20Sopenharmony_ci	fcmps	#0x42fe0000,%fp0
15878c2ecf20Sopenharmony_ci| 42fe0000 in sgl prec = 40050000fe00000000000000 in ext prec
15888c2ecf20Sopenharmony_ci	fbge	by_plrg
15898c2ecf20Sopenharmony_ci	fcmps	#0xc3000000,%fp0
15908c2ecf20Sopenharmony_ci| c3000000 in sgl prec = c00600008000000000000000 in ext prec
15918c2ecf20Sopenharmony_ci	fble	by_nlrg
15928c2ecf20Sopenharmony_ci
15938c2ecf20Sopenharmony_ci|
15948c2ecf20Sopenharmony_ci| at this point, the answer is between the largest pos and neg values
15958c2ecf20Sopenharmony_ci|
15968c2ecf20Sopenharmony_ci	movel	USER_FPCR(%a6),%d1	|use user's rounding mode
15978c2ecf20Sopenharmony_ci	andil	#0x30,%d1
15988c2ecf20Sopenharmony_ci	fmovel	%d1,%fpcr
15998c2ecf20Sopenharmony_ci	fmoveb	%fp0,L_SCR1(%a6)	|let the 040 perform conversion
16008c2ecf20Sopenharmony_ci	fmovel %fpsr,%d1
16018c2ecf20Sopenharmony_ci	orl	%d1,USER_FPSR(%a6)	|capture inex2/ainex if set
16028c2ecf20Sopenharmony_ci	bra	int_wrt
16038c2ecf20Sopenharmony_ci
16048c2ecf20Sopenharmony_ciby_plrg:
16058c2ecf20Sopenharmony_ci	moveb	#0x7f,L_SCR1(%a6)		|answer is largest positive int
16068c2ecf20Sopenharmony_ci	fbeq	int_wrt			|exact answer
16078c2ecf20Sopenharmony_ci	fcmps	#0x42ff0000,%fp0
16088c2ecf20Sopenharmony_ci| 42ff0000 in sgl prec = 40050000ff00000000000000 in ext prec
16098c2ecf20Sopenharmony_ci	fbge	int_operr		|set operr
16108c2ecf20Sopenharmony_ci	bra	int_inx			|set inexact
16118c2ecf20Sopenharmony_ci
16128c2ecf20Sopenharmony_ciby_nlrg:
16138c2ecf20Sopenharmony_ci	moveb	#0x80,L_SCR1(%a6)
16148c2ecf20Sopenharmony_ci	fbeq	int_wrt			|exact answer
16158c2ecf20Sopenharmony_ci	fcmps	#0xc3008000,%fp0
16168c2ecf20Sopenharmony_ci| c3008000 in sgl prec = c00600008080000000000000 in ext prec
16178c2ecf20Sopenharmony_ci	fblt	int_operr		|set operr
16188c2ecf20Sopenharmony_ci	bra	int_inx			|set inexact
16198c2ecf20Sopenharmony_ci
16208c2ecf20Sopenharmony_ci|
16218c2ecf20Sopenharmony_ci| Common integer routines
16228c2ecf20Sopenharmony_ci|
16238c2ecf20Sopenharmony_ci| int_drnrm---account for possible nonzero result for round up with positive
16248c2ecf20Sopenharmony_ci| operand and round down for negative answer.  In the first case (result = 1)
16258c2ecf20Sopenharmony_ci| byte-width (store in d0) of result must be honored.  In the second case,
16268c2ecf20Sopenharmony_ci| -1 in L_SCR1(a6) will cover all contingencies (FMOVE.B/W/L out).
16278c2ecf20Sopenharmony_ci
16288c2ecf20Sopenharmony_ciint_dnrm:
16298c2ecf20Sopenharmony_ci	movel	#0,L_SCR1(%a6)	| initialize result to 0
16308c2ecf20Sopenharmony_ci	bfextu	FPCR_MODE(%a6){#2:#2},%d1	| d1 is the rounding mode
16318c2ecf20Sopenharmony_ci	cmpb	#2,%d1
16328c2ecf20Sopenharmony_ci	bmis	int_inx		| if RN or RZ, done
16338c2ecf20Sopenharmony_ci	bnes	int_rp		| if RP, continue below
16348c2ecf20Sopenharmony_ci	tstw	ETEMP(%a6)	| RM: store -1 in L_SCR1 if src is negative
16358c2ecf20Sopenharmony_ci	bpls	int_inx		| otherwise result is 0
16368c2ecf20Sopenharmony_ci	movel	#-1,L_SCR1(%a6)
16378c2ecf20Sopenharmony_ci	bras	int_inx
16388c2ecf20Sopenharmony_ciint_rp:
16398c2ecf20Sopenharmony_ci	tstw	ETEMP(%a6)	| RP: store +1 of proper width in L_SCR1 if
16408c2ecf20Sopenharmony_ci|				; source is greater than 0
16418c2ecf20Sopenharmony_ci	bmis	int_inx		| otherwise, result is 0
16428c2ecf20Sopenharmony_ci	lea	L_SCR1(%a6),%a1	| a1 is address of L_SCR1
16438c2ecf20Sopenharmony_ci	addal	%d0,%a1		| offset by destination width -1
16448c2ecf20Sopenharmony_ci	subal	#1,%a1
16458c2ecf20Sopenharmony_ci	bsetb	#0,(%a1)		| set low bit at a1 address
16468c2ecf20Sopenharmony_ciint_inx:
16478c2ecf20Sopenharmony_ci	oril	#inx2a_mask,USER_FPSR(%a6)
16488c2ecf20Sopenharmony_ci	bras	int_wrt
16498c2ecf20Sopenharmony_ciint_operr:
16508c2ecf20Sopenharmony_ci	fmovemx %fp0-%fp0,FPTEMP(%a6)	|FPTEMP must contain the extended
16518c2ecf20Sopenharmony_ci|				;precision source that needs to be
16528c2ecf20Sopenharmony_ci|				;converted to integer this is required
16538c2ecf20Sopenharmony_ci|				;if the operr exception is enabled.
16548c2ecf20Sopenharmony_ci|				;set operr/aiop (no inex2 on int ovfl)
16558c2ecf20Sopenharmony_ci
16568c2ecf20Sopenharmony_ci	oril	#opaop_mask,USER_FPSR(%a6)
16578c2ecf20Sopenharmony_ci|				;fall through to perform int_wrt
16588c2ecf20Sopenharmony_ciint_wrt:
16598c2ecf20Sopenharmony_ci	movel	EXC_EA(%a6),%a1	|load destination address
16608c2ecf20Sopenharmony_ci	tstl	%a1		|check to see if it is a dest register
16618c2ecf20Sopenharmony_ci	beqs	wrt_dn		|write data register
16628c2ecf20Sopenharmony_ci	lea	L_SCR1(%a6),%a0	|point to supervisor source address
16638c2ecf20Sopenharmony_ci	bsrl	mem_write
16648c2ecf20Sopenharmony_ci	bra	mvouti_end
16658c2ecf20Sopenharmony_ci
16668c2ecf20Sopenharmony_ciwrt_dn:
16678c2ecf20Sopenharmony_ci	movel	%d0,-(%sp)	|d0 currently contains the size to write
16688c2ecf20Sopenharmony_ci	bsrl	get_fline	|get_fline returns Dn in d0
16698c2ecf20Sopenharmony_ci	andiw	#0x7,%d0		|isolate register
16708c2ecf20Sopenharmony_ci	movel	(%sp)+,%d1	|get size
16718c2ecf20Sopenharmony_ci	cmpil	#4,%d1		|most frequent case
16728c2ecf20Sopenharmony_ci	beqs	sz_long
16738c2ecf20Sopenharmony_ci	cmpil	#2,%d1
16748c2ecf20Sopenharmony_ci	bnes	sz_con
16758c2ecf20Sopenharmony_ci	orl	#8,%d0		|add 'word' size to register#
16768c2ecf20Sopenharmony_ci	bras	sz_con
16778c2ecf20Sopenharmony_cisz_long:
16788c2ecf20Sopenharmony_ci	orl	#0x10,%d0		|add 'long' size to register#
16798c2ecf20Sopenharmony_cisz_con:
16808c2ecf20Sopenharmony_ci	movel	%d0,%d1		|reg_dest expects size:reg in d1
16818c2ecf20Sopenharmony_ci	bsrl	reg_dest	|load proper data register
16828c2ecf20Sopenharmony_ci	bra	mvouti_end
16838c2ecf20Sopenharmony_cixp:
16848c2ecf20Sopenharmony_ci	lea	ETEMP(%a6),%a0
16858c2ecf20Sopenharmony_ci	bclrb	#sign_bit,LOCAL_EX(%a0)
16868c2ecf20Sopenharmony_ci	sne	LOCAL_SGN(%a0)
16878c2ecf20Sopenharmony_ci	btstb	#7,STAG(%a6)	|check for extended denorm
16888c2ecf20Sopenharmony_ci	bne	xdnrm
16898c2ecf20Sopenharmony_ci	clrl	%d0
16908c2ecf20Sopenharmony_ci	bras	do_fp		|do normal case
16918c2ecf20Sopenharmony_cisgp:
16928c2ecf20Sopenharmony_ci	lea	ETEMP(%a6),%a0
16938c2ecf20Sopenharmony_ci	bclrb	#sign_bit,LOCAL_EX(%a0)
16948c2ecf20Sopenharmony_ci	sne	LOCAL_SGN(%a0)
16958c2ecf20Sopenharmony_ci	btstb	#7,STAG(%a6)	|check for extended denorm
16968c2ecf20Sopenharmony_ci	bne	sp_catas	|branch if so
16978c2ecf20Sopenharmony_ci	movew	LOCAL_EX(%a0),%d0
16988c2ecf20Sopenharmony_ci	lea	sp_bnds,%a1
16998c2ecf20Sopenharmony_ci	cmpw	(%a1),%d0
17008c2ecf20Sopenharmony_ci	blt	sp_under
17018c2ecf20Sopenharmony_ci	cmpw	2(%a1),%d0
17028c2ecf20Sopenharmony_ci	bgt	sp_over
17038c2ecf20Sopenharmony_ci	movel	#1,%d0		|set destination format to single
17048c2ecf20Sopenharmony_ci	bras	do_fp		|do normal case
17058c2ecf20Sopenharmony_cidp:
17068c2ecf20Sopenharmony_ci	lea	ETEMP(%a6),%a0
17078c2ecf20Sopenharmony_ci	bclrb	#sign_bit,LOCAL_EX(%a0)
17088c2ecf20Sopenharmony_ci	sne	LOCAL_SGN(%a0)
17098c2ecf20Sopenharmony_ci
17108c2ecf20Sopenharmony_ci	btstb	#7,STAG(%a6)	|check for extended denorm
17118c2ecf20Sopenharmony_ci	bne	dp_catas	|branch if so
17128c2ecf20Sopenharmony_ci
17138c2ecf20Sopenharmony_ci	movew	LOCAL_EX(%a0),%d0
17148c2ecf20Sopenharmony_ci	lea	dp_bnds,%a1
17158c2ecf20Sopenharmony_ci
17168c2ecf20Sopenharmony_ci	cmpw	(%a1),%d0
17178c2ecf20Sopenharmony_ci	blt	dp_under
17188c2ecf20Sopenharmony_ci	cmpw	2(%a1),%d0
17198c2ecf20Sopenharmony_ci	bgt	dp_over
17208c2ecf20Sopenharmony_ci
17218c2ecf20Sopenharmony_ci	movel	#2,%d0		|set destination format to double
17228c2ecf20Sopenharmony_ci|				;fall through to do_fp
17238c2ecf20Sopenharmony_ci|
17248c2ecf20Sopenharmony_cido_fp:
17258c2ecf20Sopenharmony_ci	bfextu	FPCR_MODE(%a6){#2:#2},%d1	|rnd mode in d1
17268c2ecf20Sopenharmony_ci	swap	%d0			|rnd prec in upper word
17278c2ecf20Sopenharmony_ci	addl	%d0,%d1			|d1 has PREC/MODE info
17288c2ecf20Sopenharmony_ci
17298c2ecf20Sopenharmony_ci	clrl	%d0			|clear g,r,s
17308c2ecf20Sopenharmony_ci
17318c2ecf20Sopenharmony_ci	bsrl	round			|round
17328c2ecf20Sopenharmony_ci
17338c2ecf20Sopenharmony_ci	movel	%a0,%a1
17348c2ecf20Sopenharmony_ci	movel	EXC_EA(%a6),%a0
17358c2ecf20Sopenharmony_ci
17368c2ecf20Sopenharmony_ci	bfextu	CMDREG1B(%a6){#3:#3},%d1	|extract destination format
17378c2ecf20Sopenharmony_ci|					;at this point only the dest
17388c2ecf20Sopenharmony_ci|					;formats sgl, dbl, ext are
17398c2ecf20Sopenharmony_ci|					;possible
17408c2ecf20Sopenharmony_ci	cmpb	#2,%d1
17418c2ecf20Sopenharmony_ci	bgts	ddbl			|double=5, extended=2, single=1
17428c2ecf20Sopenharmony_ci	bnes	dsgl
17438c2ecf20Sopenharmony_ci|					;fall through to dext
17448c2ecf20Sopenharmony_cidext:
17458c2ecf20Sopenharmony_ci	bsrl	dest_ext
17468c2ecf20Sopenharmony_ci	bra	mvout_end
17478c2ecf20Sopenharmony_cidsgl:
17488c2ecf20Sopenharmony_ci	bsrl	dest_sgl
17498c2ecf20Sopenharmony_ci	bra	mvout_end
17508c2ecf20Sopenharmony_ciddbl:
17518c2ecf20Sopenharmony_ci	bsrl	dest_dbl
17528c2ecf20Sopenharmony_ci	bra	mvout_end
17538c2ecf20Sopenharmony_ci
17548c2ecf20Sopenharmony_ci|
17558c2ecf20Sopenharmony_ci| Handle possible denorm or catastrophic underflow cases here
17568c2ecf20Sopenharmony_ci|
17578c2ecf20Sopenharmony_cixdnrm:
17588c2ecf20Sopenharmony_ci	bsr	set_xop		|initialize WBTEMP
17598c2ecf20Sopenharmony_ci	bsetb	#wbtemp15_bit,WB_BYTE(%a6) |set wbtemp15
17608c2ecf20Sopenharmony_ci
17618c2ecf20Sopenharmony_ci	movel	%a0,%a1
17628c2ecf20Sopenharmony_ci	movel	EXC_EA(%a6),%a0	|a0 has the destination pointer
17638c2ecf20Sopenharmony_ci	bsrl	dest_ext	|store to memory
17648c2ecf20Sopenharmony_ci	bsetb	#unfl_bit,FPSR_EXCEPT(%a6)
17658c2ecf20Sopenharmony_ci	bra	mvout_end
17668c2ecf20Sopenharmony_ci
17678c2ecf20Sopenharmony_cisp_under:
17688c2ecf20Sopenharmony_ci	bsetb	#etemp15_bit,STAG(%a6)
17698c2ecf20Sopenharmony_ci
17708c2ecf20Sopenharmony_ci	cmpw	4(%a1),%d0
17718c2ecf20Sopenharmony_ci	blts	sp_catas	|catastrophic underflow case
17728c2ecf20Sopenharmony_ci
17738c2ecf20Sopenharmony_ci	movel	#1,%d0		|load in round precision
17748c2ecf20Sopenharmony_ci	movel	#sgl_thresh,%d1	|load in single denorm threshold
17758c2ecf20Sopenharmony_ci	bsrl	dpspdnrm	|expects d1 to have the proper
17768c2ecf20Sopenharmony_ci|				;denorm threshold
17778c2ecf20Sopenharmony_ci	bsrl	dest_sgl	|stores value to destination
17788c2ecf20Sopenharmony_ci	bsetb	#unfl_bit,FPSR_EXCEPT(%a6)
17798c2ecf20Sopenharmony_ci	bra	mvout_end	|exit
17808c2ecf20Sopenharmony_ci
17818c2ecf20Sopenharmony_cidp_under:
17828c2ecf20Sopenharmony_ci	bsetb	#etemp15_bit,STAG(%a6)
17838c2ecf20Sopenharmony_ci
17848c2ecf20Sopenharmony_ci	cmpw	4(%a1),%d0
17858c2ecf20Sopenharmony_ci	blts	dp_catas	|catastrophic underflow case
17868c2ecf20Sopenharmony_ci
17878c2ecf20Sopenharmony_ci	movel	#dbl_thresh,%d1	|load in double precision threshold
17888c2ecf20Sopenharmony_ci	movel	#2,%d0
17898c2ecf20Sopenharmony_ci	bsrl	dpspdnrm	|expects d1 to have proper
17908c2ecf20Sopenharmony_ci|				;denorm threshold
17918c2ecf20Sopenharmony_ci|				;expects d0 to have round precision
17928c2ecf20Sopenharmony_ci	bsrl	dest_dbl	|store value to destination
17938c2ecf20Sopenharmony_ci	bsetb	#unfl_bit,FPSR_EXCEPT(%a6)
17948c2ecf20Sopenharmony_ci	bra	mvout_end	|exit
17958c2ecf20Sopenharmony_ci
17968c2ecf20Sopenharmony_ci|
17978c2ecf20Sopenharmony_ci| Handle catastrophic underflow cases here
17988c2ecf20Sopenharmony_ci|
17998c2ecf20Sopenharmony_cisp_catas:
18008c2ecf20Sopenharmony_ci| Temp fix for z bit set in unf_sub
18018c2ecf20Sopenharmony_ci	movel	USER_FPSR(%a6),-(%a7)
18028c2ecf20Sopenharmony_ci
18038c2ecf20Sopenharmony_ci	movel	#1,%d0		|set round precision to sgl
18048c2ecf20Sopenharmony_ci
18058c2ecf20Sopenharmony_ci	bsrl	unf_sub		|a0 points to result
18068c2ecf20Sopenharmony_ci
18078c2ecf20Sopenharmony_ci	movel	(%a7)+,USER_FPSR(%a6)
18088c2ecf20Sopenharmony_ci
18098c2ecf20Sopenharmony_ci	movel	#1,%d0
18108c2ecf20Sopenharmony_ci	subw	%d0,LOCAL_EX(%a0) |account for difference between
18118c2ecf20Sopenharmony_ci|				;denorm/norm bias
18128c2ecf20Sopenharmony_ci
18138c2ecf20Sopenharmony_ci	movel	%a0,%a1		|a1 has the operand input
18148c2ecf20Sopenharmony_ci	movel	EXC_EA(%a6),%a0	|a0 has the destination pointer
18158c2ecf20Sopenharmony_ci
18168c2ecf20Sopenharmony_ci	bsrl	dest_sgl	|store the result
18178c2ecf20Sopenharmony_ci	oril	#unfinx_mask,USER_FPSR(%a6)
18188c2ecf20Sopenharmony_ci	bra	mvout_end
18198c2ecf20Sopenharmony_ci
18208c2ecf20Sopenharmony_cidp_catas:
18218c2ecf20Sopenharmony_ci| Temp fix for z bit set in unf_sub
18228c2ecf20Sopenharmony_ci	movel	USER_FPSR(%a6),-(%a7)
18238c2ecf20Sopenharmony_ci
18248c2ecf20Sopenharmony_ci	movel	#2,%d0		|set round precision to dbl
18258c2ecf20Sopenharmony_ci	bsrl	unf_sub		|a0 points to result
18268c2ecf20Sopenharmony_ci
18278c2ecf20Sopenharmony_ci	movel	(%a7)+,USER_FPSR(%a6)
18288c2ecf20Sopenharmony_ci
18298c2ecf20Sopenharmony_ci	movel	#1,%d0
18308c2ecf20Sopenharmony_ci	subw	%d0,LOCAL_EX(%a0) |account for difference between
18318c2ecf20Sopenharmony_ci|				;denorm/norm bias
18328c2ecf20Sopenharmony_ci
18338c2ecf20Sopenharmony_ci	movel	%a0,%a1		|a1 has the operand input
18348c2ecf20Sopenharmony_ci	movel	EXC_EA(%a6),%a0	|a0 has the destination pointer
18358c2ecf20Sopenharmony_ci
18368c2ecf20Sopenharmony_ci	bsrl	dest_dbl	|store the result
18378c2ecf20Sopenharmony_ci	oril	#unfinx_mask,USER_FPSR(%a6)
18388c2ecf20Sopenharmony_ci	bra	mvout_end
18398c2ecf20Sopenharmony_ci
18408c2ecf20Sopenharmony_ci|
18418c2ecf20Sopenharmony_ci| Handle catastrophic overflow cases here
18428c2ecf20Sopenharmony_ci|
18438c2ecf20Sopenharmony_cisp_over:
18448c2ecf20Sopenharmony_ci| Temp fix for z bit set in unf_sub
18458c2ecf20Sopenharmony_ci	movel	USER_FPSR(%a6),-(%a7)
18468c2ecf20Sopenharmony_ci
18478c2ecf20Sopenharmony_ci	movel	#1,%d0
18488c2ecf20Sopenharmony_ci	leal	FP_SCR1(%a6),%a0	|use FP_SCR1 for creating result
18498c2ecf20Sopenharmony_ci	movel	ETEMP_EX(%a6),(%a0)
18508c2ecf20Sopenharmony_ci	movel	ETEMP_HI(%a6),4(%a0)
18518c2ecf20Sopenharmony_ci	movel	ETEMP_LO(%a6),8(%a0)
18528c2ecf20Sopenharmony_ci	bsrl	ovf_res
18538c2ecf20Sopenharmony_ci
18548c2ecf20Sopenharmony_ci	movel	(%a7)+,USER_FPSR(%a6)
18558c2ecf20Sopenharmony_ci
18568c2ecf20Sopenharmony_ci	movel	%a0,%a1
18578c2ecf20Sopenharmony_ci	movel	EXC_EA(%a6),%a0
18588c2ecf20Sopenharmony_ci	bsrl	dest_sgl
18598c2ecf20Sopenharmony_ci	orl	#ovfinx_mask,USER_FPSR(%a6)
18608c2ecf20Sopenharmony_ci	bra	mvout_end
18618c2ecf20Sopenharmony_ci
18628c2ecf20Sopenharmony_cidp_over:
18638c2ecf20Sopenharmony_ci| Temp fix for z bit set in ovf_res
18648c2ecf20Sopenharmony_ci	movel	USER_FPSR(%a6),-(%a7)
18658c2ecf20Sopenharmony_ci
18668c2ecf20Sopenharmony_ci	movel	#2,%d0
18678c2ecf20Sopenharmony_ci	leal	FP_SCR1(%a6),%a0	|use FP_SCR1 for creating result
18688c2ecf20Sopenharmony_ci	movel	ETEMP_EX(%a6),(%a0)
18698c2ecf20Sopenharmony_ci	movel	ETEMP_HI(%a6),4(%a0)
18708c2ecf20Sopenharmony_ci	movel	ETEMP_LO(%a6),8(%a0)
18718c2ecf20Sopenharmony_ci	bsrl	ovf_res
18728c2ecf20Sopenharmony_ci
18738c2ecf20Sopenharmony_ci	movel	(%a7)+,USER_FPSR(%a6)
18748c2ecf20Sopenharmony_ci
18758c2ecf20Sopenharmony_ci	movel	%a0,%a1
18768c2ecf20Sopenharmony_ci	movel	EXC_EA(%a6),%a0
18778c2ecf20Sopenharmony_ci	bsrl	dest_dbl
18788c2ecf20Sopenharmony_ci	orl	#ovfinx_mask,USER_FPSR(%a6)
18798c2ecf20Sopenharmony_ci	bra	mvout_end
18808c2ecf20Sopenharmony_ci
18818c2ecf20Sopenharmony_ci|
18828c2ecf20Sopenharmony_ci|	DPSPDNRM
18838c2ecf20Sopenharmony_ci|
18848c2ecf20Sopenharmony_ci| This subroutine takes an extended normalized number and denormalizes
18858c2ecf20Sopenharmony_ci| it to the given round precision. This subroutine also decrements
18868c2ecf20Sopenharmony_ci| the input operand's exponent by 1 to account for the fact that
18878c2ecf20Sopenharmony_ci| dest_sgl or dest_dbl expects a normalized number's bias.
18888c2ecf20Sopenharmony_ci|
18898c2ecf20Sopenharmony_ci| Input: a0  points to a normalized number in internal extended format
18908c2ecf20Sopenharmony_ci|	 d0  is the round precision (=1 for sgl; =2 for dbl)
18918c2ecf20Sopenharmony_ci|	 d1  is the single precision or double precision
18928c2ecf20Sopenharmony_ci|	     denorm threshold
18938c2ecf20Sopenharmony_ci|
18948c2ecf20Sopenharmony_ci| Output: (In the format for dest_sgl or dest_dbl)
18958c2ecf20Sopenharmony_ci|	 a0   points to the destination
18968c2ecf20Sopenharmony_ci|	 a1   points to the operand
18978c2ecf20Sopenharmony_ci|
18988c2ecf20Sopenharmony_ci| Exceptions: Reports inexact 2 exception by setting USER_FPSR bits
18998c2ecf20Sopenharmony_ci|
19008c2ecf20Sopenharmony_cidpspdnrm:
19018c2ecf20Sopenharmony_ci	movel	%d0,-(%a7)	|save round precision
19028c2ecf20Sopenharmony_ci	clrl	%d0		|clear initial g,r,s
19038c2ecf20Sopenharmony_ci	bsrl	dnrm_lp		|careful with d0, it's needed by round
19048c2ecf20Sopenharmony_ci
19058c2ecf20Sopenharmony_ci	bfextu	FPCR_MODE(%a6){#2:#2},%d1 |get rounding mode
19068c2ecf20Sopenharmony_ci	swap	%d1
19078c2ecf20Sopenharmony_ci	movew	2(%a7),%d1	|set rounding precision
19088c2ecf20Sopenharmony_ci	swap	%d1		|at this point d1 has PREC/MODE info
19098c2ecf20Sopenharmony_ci	bsrl	round		|round result, sets the inex bit in
19108c2ecf20Sopenharmony_ci|				;USER_FPSR if needed
19118c2ecf20Sopenharmony_ci
19128c2ecf20Sopenharmony_ci	movew	#1,%d0
19138c2ecf20Sopenharmony_ci	subw	%d0,LOCAL_EX(%a0) |account for difference in denorm
19148c2ecf20Sopenharmony_ci|				;vs norm bias
19158c2ecf20Sopenharmony_ci
19168c2ecf20Sopenharmony_ci	movel	%a0,%a1		|a1 has the operand input
19178c2ecf20Sopenharmony_ci	movel	EXC_EA(%a6),%a0	|a0 has the destination pointer
19188c2ecf20Sopenharmony_ci	addw	#4,%a7		|pop stack
19198c2ecf20Sopenharmony_ci	rts
19208c2ecf20Sopenharmony_ci|
19218c2ecf20Sopenharmony_ci| SET_XOP initialized WBTEMP with the value pointed to by a0
19228c2ecf20Sopenharmony_ci| input: a0 points to input operand in the internal extended format
19238c2ecf20Sopenharmony_ci|
19248c2ecf20Sopenharmony_ciset_xop:
19258c2ecf20Sopenharmony_ci	movel	LOCAL_EX(%a0),WBTEMP_EX(%a6)
19268c2ecf20Sopenharmony_ci	movel	LOCAL_HI(%a0),WBTEMP_HI(%a6)
19278c2ecf20Sopenharmony_ci	movel	LOCAL_LO(%a0),WBTEMP_LO(%a6)
19288c2ecf20Sopenharmony_ci	bfclr	WBTEMP_SGN(%a6){#0:#8}
19298c2ecf20Sopenharmony_ci	beqs	sxop
19308c2ecf20Sopenharmony_ci	bsetb	#sign_bit,WBTEMP_EX(%a6)
19318c2ecf20Sopenharmony_cisxop:
19328c2ecf20Sopenharmony_ci	bfclr	STAG(%a6){#5:#4}	|clear wbtm66,wbtm1,wbtm0,sbit
19338c2ecf20Sopenharmony_ci	rts
19348c2ecf20Sopenharmony_ci|
19358c2ecf20Sopenharmony_ci|	P_MOVE
19368c2ecf20Sopenharmony_ci|
19378c2ecf20Sopenharmony_cip_movet:
19388c2ecf20Sopenharmony_ci	.long	p_move
19398c2ecf20Sopenharmony_ci	.long	p_movez
19408c2ecf20Sopenharmony_ci	.long	p_movei
19418c2ecf20Sopenharmony_ci	.long	p_moven
19428c2ecf20Sopenharmony_ci	.long	p_move
19438c2ecf20Sopenharmony_cip_regd:
19448c2ecf20Sopenharmony_ci	.long	p_dyd0
19458c2ecf20Sopenharmony_ci	.long	p_dyd1
19468c2ecf20Sopenharmony_ci	.long	p_dyd2
19478c2ecf20Sopenharmony_ci	.long	p_dyd3
19488c2ecf20Sopenharmony_ci	.long	p_dyd4
19498c2ecf20Sopenharmony_ci	.long	p_dyd5
19508c2ecf20Sopenharmony_ci	.long	p_dyd6
19518c2ecf20Sopenharmony_ci	.long	p_dyd7
19528c2ecf20Sopenharmony_ci
19538c2ecf20Sopenharmony_cipack_out:
19548c2ecf20Sopenharmony_ci	leal	p_movet,%a0	|load jmp table address
19558c2ecf20Sopenharmony_ci	movew	STAG(%a6),%d0	|get source tag
19568c2ecf20Sopenharmony_ci	bfextu	%d0{#16:#3},%d0	|isolate source bits
19578c2ecf20Sopenharmony_ci	movel	(%a0,%d0.w*4),%a0	|load a0 with routine label for tag
19588c2ecf20Sopenharmony_ci	jmp	(%a0)		|go to the routine
19598c2ecf20Sopenharmony_ci
19608c2ecf20Sopenharmony_cip_write:
19618c2ecf20Sopenharmony_ci	movel	#0x0c,%d0	|get byte count
19628c2ecf20Sopenharmony_ci	movel	EXC_EA(%a6),%a1	|get the destination address
19638c2ecf20Sopenharmony_ci	bsr	mem_write	|write the user's destination
19648c2ecf20Sopenharmony_ci	moveb	#0,CU_SAVEPC(%a6) |set the cu save pc to all 0's
19658c2ecf20Sopenharmony_ci
19668c2ecf20Sopenharmony_ci|
19678c2ecf20Sopenharmony_ci| Also note that the dtag must be set to norm here - this is because
19688c2ecf20Sopenharmony_ci| the 040 uses the dtag to execute the correct microcode.
19698c2ecf20Sopenharmony_ci|
19708c2ecf20Sopenharmony_ci        bfclr    DTAG(%a6){#0:#3}  |set dtag to norm
19718c2ecf20Sopenharmony_ci
19728c2ecf20Sopenharmony_ci	rts
19738c2ecf20Sopenharmony_ci
19748c2ecf20Sopenharmony_ci| Notes on handling of special case (zero, inf, and nan) inputs:
19758c2ecf20Sopenharmony_ci|	1. Operr is not signalled if the k-factor is greater than 18.
19768c2ecf20Sopenharmony_ci|	2. Per the manual, status bits are not set.
19778c2ecf20Sopenharmony_ci|
19788c2ecf20Sopenharmony_ci
19798c2ecf20Sopenharmony_cip_move:
19808c2ecf20Sopenharmony_ci	movew	CMDREG1B(%a6),%d0
19818c2ecf20Sopenharmony_ci	btstl	#kfact_bit,%d0	|test for dynamic k-factor
19828c2ecf20Sopenharmony_ci	beqs	statick		|if clear, k-factor is static
19838c2ecf20Sopenharmony_cidynamick:
19848c2ecf20Sopenharmony_ci	bfextu	%d0{#25:#3},%d0	|isolate register for dynamic k-factor
19858c2ecf20Sopenharmony_ci	lea	p_regd,%a0
19868c2ecf20Sopenharmony_ci	movel	%a0@(%d0:l:4),%a0
19878c2ecf20Sopenharmony_ci	jmp	(%a0)
19888c2ecf20Sopenharmony_cistatick:
19898c2ecf20Sopenharmony_ci	andiw	#0x007f,%d0	|get k-factor
19908c2ecf20Sopenharmony_ci	bfexts	%d0{#25:#7},%d0	|sign extend d0 for bindec
19918c2ecf20Sopenharmony_ci	leal	ETEMP(%a6),%a0	|a0 will point to the packed decimal
19928c2ecf20Sopenharmony_ci	bsrl	bindec		|perform the convert; data at a6
19938c2ecf20Sopenharmony_ci	leal	FP_SCR1(%a6),%a0	|load a0 with result address
19948c2ecf20Sopenharmony_ci	bral	p_write
19958c2ecf20Sopenharmony_cip_movez:
19968c2ecf20Sopenharmony_ci	leal	ETEMP(%a6),%a0	|a0 will point to the packed decimal
19978c2ecf20Sopenharmony_ci	clrw	2(%a0)		|clear lower word of exp
19988c2ecf20Sopenharmony_ci	clrl	4(%a0)		|load second lword of ZERO
19998c2ecf20Sopenharmony_ci	clrl	8(%a0)		|load third lword of ZERO
20008c2ecf20Sopenharmony_ci	bra	p_write		|go write results
20018c2ecf20Sopenharmony_cip_movei:
20028c2ecf20Sopenharmony_ci	fmovel	#0,%FPSR		|clear aiop
20038c2ecf20Sopenharmony_ci	leal	ETEMP(%a6),%a0	|a0 will point to the packed decimal
20048c2ecf20Sopenharmony_ci	clrw	2(%a0)		|clear lower word of exp
20058c2ecf20Sopenharmony_ci	bra	p_write		|go write the result
20068c2ecf20Sopenharmony_cip_moven:
20078c2ecf20Sopenharmony_ci	leal	ETEMP(%a6),%a0	|a0 will point to the packed decimal
20088c2ecf20Sopenharmony_ci	clrw	2(%a0)		|clear lower word of exp
20098c2ecf20Sopenharmony_ci	bra	p_write		|go write the result
20108c2ecf20Sopenharmony_ci
20118c2ecf20Sopenharmony_ci|
20128c2ecf20Sopenharmony_ci| Routines to read the dynamic k-factor from Dn.
20138c2ecf20Sopenharmony_ci|
20148c2ecf20Sopenharmony_cip_dyd0:
20158c2ecf20Sopenharmony_ci	movel	USER_D0(%a6),%d0
20168c2ecf20Sopenharmony_ci	bras	statick
20178c2ecf20Sopenharmony_cip_dyd1:
20188c2ecf20Sopenharmony_ci	movel	USER_D1(%a6),%d0
20198c2ecf20Sopenharmony_ci	bras	statick
20208c2ecf20Sopenharmony_cip_dyd2:
20218c2ecf20Sopenharmony_ci	movel	%d2,%d0
20228c2ecf20Sopenharmony_ci	bras	statick
20238c2ecf20Sopenharmony_cip_dyd3:
20248c2ecf20Sopenharmony_ci	movel	%d3,%d0
20258c2ecf20Sopenharmony_ci	bras	statick
20268c2ecf20Sopenharmony_cip_dyd4:
20278c2ecf20Sopenharmony_ci	movel	%d4,%d0
20288c2ecf20Sopenharmony_ci	bras	statick
20298c2ecf20Sopenharmony_cip_dyd5:
20308c2ecf20Sopenharmony_ci	movel	%d5,%d0
20318c2ecf20Sopenharmony_ci	bras	statick
20328c2ecf20Sopenharmony_cip_dyd6:
20338c2ecf20Sopenharmony_ci	movel	%d6,%d0
20348c2ecf20Sopenharmony_ci	bra	statick
20358c2ecf20Sopenharmony_cip_dyd7:
20368c2ecf20Sopenharmony_ci	movel	%d7,%d0
20378c2ecf20Sopenharmony_ci	bra	statick
20388c2ecf20Sopenharmony_ci
20398c2ecf20Sopenharmony_ci	|end
2040