18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * fp_util.S
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright Roman Zippel, 1997.  All rights reserved.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without
78c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions
88c2ecf20Sopenharmony_ci * are met:
98c2ecf20Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright
108c2ecf20Sopenharmony_ci *    notice, and the entire permission notice in its entirety,
118c2ecf20Sopenharmony_ci *    including the disclaimer of warranties.
128c2ecf20Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright
138c2ecf20Sopenharmony_ci *    notice, this list of conditions and the following disclaimer in the
148c2ecf20Sopenharmony_ci *    documentation and/or other materials provided with the distribution.
158c2ecf20Sopenharmony_ci * 3. The name of the author may not be used to endorse or promote
168c2ecf20Sopenharmony_ci *    products derived from this software without specific prior
178c2ecf20Sopenharmony_ci *    written permission.
188c2ecf20Sopenharmony_ci *
198c2ecf20Sopenharmony_ci * ALTERNATIVELY, this product may be distributed under the terms of
208c2ecf20Sopenharmony_ci * the GNU General Public License, in which case the provisions of the GPL are
218c2ecf20Sopenharmony_ci * required INSTEAD OF the above restrictions.  (This clause is
228c2ecf20Sopenharmony_ci * necessary due to a potential bad interaction between the GPL and
238c2ecf20Sopenharmony_ci * the restrictions contained in a BSD-style copyright.)
248c2ecf20Sopenharmony_ci *
258c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
268c2ecf20Sopenharmony_ci * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
278c2ecf20Sopenharmony_ci * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
288c2ecf20Sopenharmony_ci * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
298c2ecf20Sopenharmony_ci * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
308c2ecf20Sopenharmony_ci * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
318c2ecf20Sopenharmony_ci * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
328c2ecf20Sopenharmony_ci * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
338c2ecf20Sopenharmony_ci * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
348c2ecf20Sopenharmony_ci * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
358c2ecf20Sopenharmony_ci * OF THE POSSIBILITY OF SUCH DAMAGE.
368c2ecf20Sopenharmony_ci */
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci#include "fp_emu.h"
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci/*
418c2ecf20Sopenharmony_ci * Here are lots of conversion and normalization functions mainly
428c2ecf20Sopenharmony_ci * used by fp_scan.S
438c2ecf20Sopenharmony_ci * Note that these functions are optimized for "normal" numbers,
448c2ecf20Sopenharmony_ci * these are handled first and exit as fast as possible, this is
458c2ecf20Sopenharmony_ci * especially important for fp_normalize_ext/fp_conv_ext2ext, as
468c2ecf20Sopenharmony_ci * it's called very often.
478c2ecf20Sopenharmony_ci * The register usage is optimized for fp_scan.S and which register
488c2ecf20Sopenharmony_ci * is currently at that time unused, be careful if you want change
498c2ecf20Sopenharmony_ci * something here. %d0 and %d1 is always usable, sometimes %d2 (or
508c2ecf20Sopenharmony_ci * only the lower half) most function have to return the %a0
518c2ecf20Sopenharmony_ci * unmodified, so that the caller can immediately reuse it.
528c2ecf20Sopenharmony_ci */
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	.globl	fp_ill, fp_end
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	| exits from fp_scan:
578c2ecf20Sopenharmony_ci	| illegal instruction
588c2ecf20Sopenharmony_cifp_ill:
598c2ecf20Sopenharmony_ci	printf	,"fp_illegal\n"
608c2ecf20Sopenharmony_ci	rts
618c2ecf20Sopenharmony_ci	| completed instruction
628c2ecf20Sopenharmony_cifp_end:
638c2ecf20Sopenharmony_ci	tst.l	(TASK_MM-8,%a2)
648c2ecf20Sopenharmony_ci	jmi	1f
658c2ecf20Sopenharmony_ci	tst.l	(TASK_MM-4,%a2)
668c2ecf20Sopenharmony_ci	jmi	1f
678c2ecf20Sopenharmony_ci	tst.l	(TASK_MM,%a2)
688c2ecf20Sopenharmony_ci	jpl	2f
698c2ecf20Sopenharmony_ci1:	printf	,"oops:%p,%p,%p\n",3,%a2@(TASK_MM-8),%a2@(TASK_MM-4),%a2@(TASK_MM)
708c2ecf20Sopenharmony_ci2:	clr.l	%d0
718c2ecf20Sopenharmony_ci	rts
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	.globl	fp_conv_long2ext, fp_conv_single2ext
748c2ecf20Sopenharmony_ci	.globl	fp_conv_double2ext, fp_conv_ext2ext
758c2ecf20Sopenharmony_ci	.globl	fp_normalize_ext, fp_normalize_double
768c2ecf20Sopenharmony_ci	.globl	fp_normalize_single, fp_normalize_single_fast
778c2ecf20Sopenharmony_ci	.globl	fp_conv_ext2double, fp_conv_ext2single
788c2ecf20Sopenharmony_ci	.globl	fp_conv_ext2long, fp_conv_ext2short
798c2ecf20Sopenharmony_ci	.globl	fp_conv_ext2byte
808c2ecf20Sopenharmony_ci	.globl	fp_finalrounding_single, fp_finalrounding_single_fast
818c2ecf20Sopenharmony_ci	.globl	fp_finalrounding_double
828c2ecf20Sopenharmony_ci	.globl	fp_finalrounding, fp_finaltest, fp_final
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci/*
858c2ecf20Sopenharmony_ci * First several conversion functions from a source operand
868c2ecf20Sopenharmony_ci * into the extended format. Note, that only fp_conv_ext2ext
878c2ecf20Sopenharmony_ci * normalizes the number and is always called after the other
888c2ecf20Sopenharmony_ci * conversion functions, which only move the information into
898c2ecf20Sopenharmony_ci * fp_ext structure.
908c2ecf20Sopenharmony_ci */
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	| fp_conv_long2ext:
938c2ecf20Sopenharmony_ci	|
948c2ecf20Sopenharmony_ci	| args:	%d0 = source (32-bit long)
958c2ecf20Sopenharmony_ci	|	%a0 = destination (ptr to struct fp_ext)
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_cifp_conv_long2ext:
988c2ecf20Sopenharmony_ci	printf	PCONV,"l2e: %p -> %p(",2,%d0,%a0
998c2ecf20Sopenharmony_ci	clr.l	%d1			| sign defaults to zero
1008c2ecf20Sopenharmony_ci	tst.l	%d0
1018c2ecf20Sopenharmony_ci	jeq	fp_l2e_zero		| is source zero?
1028c2ecf20Sopenharmony_ci	jpl	1f			| positive?
1038c2ecf20Sopenharmony_ci	moveq	#1,%d1
1048c2ecf20Sopenharmony_ci	neg.l	%d0
1058c2ecf20Sopenharmony_ci1:	swap	%d1
1068c2ecf20Sopenharmony_ci	move.w	#0x3fff+31,%d1
1078c2ecf20Sopenharmony_ci	move.l	%d1,(%a0)+		| set sign / exp
1088c2ecf20Sopenharmony_ci	move.l	%d0,(%a0)+		| set mantissa
1098c2ecf20Sopenharmony_ci	clr.l	(%a0)
1108c2ecf20Sopenharmony_ci	subq.l	#8,%a0			| restore %a0
1118c2ecf20Sopenharmony_ci	printx	PCONV,%a0@
1128c2ecf20Sopenharmony_ci	printf	PCONV,")\n"
1138c2ecf20Sopenharmony_ci	rts
1148c2ecf20Sopenharmony_ci	| source is zero
1158c2ecf20Sopenharmony_cifp_l2e_zero:
1168c2ecf20Sopenharmony_ci	clr.l	(%a0)+
1178c2ecf20Sopenharmony_ci	clr.l	(%a0)+
1188c2ecf20Sopenharmony_ci	clr.l	(%a0)
1198c2ecf20Sopenharmony_ci	subq.l	#8,%a0
1208c2ecf20Sopenharmony_ci	printx	PCONV,%a0@
1218c2ecf20Sopenharmony_ci	printf	PCONV,")\n"
1228c2ecf20Sopenharmony_ci	rts
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	| fp_conv_single2ext
1258c2ecf20Sopenharmony_ci	| args:	%d0 = source (single-precision fp value)
1268c2ecf20Sopenharmony_ci	|	%a0 = dest (struct fp_ext *)
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_cifp_conv_single2ext:
1298c2ecf20Sopenharmony_ci	printf	PCONV,"s2e: %p -> %p(",2,%d0,%a0
1308c2ecf20Sopenharmony_ci	move.l	%d0,%d1
1318c2ecf20Sopenharmony_ci	lsl.l	#8,%d0			| shift mantissa
1328c2ecf20Sopenharmony_ci	lsr.l	#8,%d1			| exponent / sign
1338c2ecf20Sopenharmony_ci	lsr.l	#7,%d1
1348c2ecf20Sopenharmony_ci	lsr.w	#8,%d1
1358c2ecf20Sopenharmony_ci	jeq	fp_s2e_small		| zero / denormal?
1368c2ecf20Sopenharmony_ci	cmp.w	#0xff,%d1		| NaN / Inf?
1378c2ecf20Sopenharmony_ci	jeq	fp_s2e_large
1388c2ecf20Sopenharmony_ci	bset	#31,%d0			| set explizit bit
1398c2ecf20Sopenharmony_ci	add.w	#0x3fff-0x7f,%d1	| re-bias the exponent.
1408c2ecf20Sopenharmony_ci9:	move.l	%d1,(%a0)+		| fp_ext.sign, fp_ext.exp
1418c2ecf20Sopenharmony_ci	move.l	%d0,(%a0)+		| high lword of fp_ext.mant
1428c2ecf20Sopenharmony_ci	clr.l	(%a0)			| low lword = 0
1438c2ecf20Sopenharmony_ci	subq.l	#8,%a0
1448c2ecf20Sopenharmony_ci	printx	PCONV,%a0@
1458c2ecf20Sopenharmony_ci	printf	PCONV,")\n"
1468c2ecf20Sopenharmony_ci	rts
1478c2ecf20Sopenharmony_ci	| zeros and denormalized
1488c2ecf20Sopenharmony_cifp_s2e_small:
1498c2ecf20Sopenharmony_ci	| exponent is zero, so explizit bit is already zero too
1508c2ecf20Sopenharmony_ci	tst.l	%d0
1518c2ecf20Sopenharmony_ci	jeq	9b
1528c2ecf20Sopenharmony_ci	move.w	#0x4000-0x7f,%d1
1538c2ecf20Sopenharmony_ci	jra	9b
1548c2ecf20Sopenharmony_ci	| infinities and NAN
1558c2ecf20Sopenharmony_cifp_s2e_large:
1568c2ecf20Sopenharmony_ci	bclr	#31,%d0			| clear explizit bit
1578c2ecf20Sopenharmony_ci	move.w	#0x7fff,%d1
1588c2ecf20Sopenharmony_ci	jra	9b
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_cifp_conv_double2ext:
1618c2ecf20Sopenharmony_ci#ifdef FPU_EMU_DEBUG
1628c2ecf20Sopenharmony_ci	getuser.l %a1@(0),%d0,fp_err_ua2,%a1
1638c2ecf20Sopenharmony_ci	getuser.l %a1@(4),%d1,fp_err_ua2,%a1
1648c2ecf20Sopenharmony_ci	printf	PCONV,"d2e: %p%p -> %p(",3,%d0,%d1,%a0
1658c2ecf20Sopenharmony_ci#endif
1668c2ecf20Sopenharmony_ci	getuser.l (%a1)+,%d0,fp_err_ua2,%a1
1678c2ecf20Sopenharmony_ci	move.l	%d0,%d1
1688c2ecf20Sopenharmony_ci	lsl.l	#8,%d0			| shift high mantissa
1698c2ecf20Sopenharmony_ci	lsl.l	#3,%d0
1708c2ecf20Sopenharmony_ci	lsr.l	#8,%d1			| exponent / sign
1718c2ecf20Sopenharmony_ci	lsr.l	#7,%d1
1728c2ecf20Sopenharmony_ci	lsr.w	#5,%d1
1738c2ecf20Sopenharmony_ci	jeq	fp_d2e_small		| zero / denormal?
1748c2ecf20Sopenharmony_ci	cmp.w	#0x7ff,%d1		| NaN / Inf?
1758c2ecf20Sopenharmony_ci	jeq	fp_d2e_large
1768c2ecf20Sopenharmony_ci	bset	#31,%d0			| set explizit bit
1778c2ecf20Sopenharmony_ci	add.w	#0x3fff-0x3ff,%d1	| re-bias the exponent.
1788c2ecf20Sopenharmony_ci9:	move.l	%d1,(%a0)+		| fp_ext.sign, fp_ext.exp
1798c2ecf20Sopenharmony_ci	move.l	%d0,(%a0)+
1808c2ecf20Sopenharmony_ci	getuser.l (%a1)+,%d0,fp_err_ua2,%a1
1818c2ecf20Sopenharmony_ci	move.l	%d0,%d1
1828c2ecf20Sopenharmony_ci	lsl.l	#8,%d0
1838c2ecf20Sopenharmony_ci	lsl.l	#3,%d0
1848c2ecf20Sopenharmony_ci	move.l	%d0,(%a0)
1858c2ecf20Sopenharmony_ci	moveq	#21,%d0
1868c2ecf20Sopenharmony_ci	lsr.l	%d0,%d1
1878c2ecf20Sopenharmony_ci	or.l	%d1,-(%a0)
1888c2ecf20Sopenharmony_ci	subq.l	#4,%a0
1898c2ecf20Sopenharmony_ci	printx	PCONV,%a0@
1908c2ecf20Sopenharmony_ci	printf	PCONV,")\n"
1918c2ecf20Sopenharmony_ci	rts
1928c2ecf20Sopenharmony_ci	| zeros and denormalized
1938c2ecf20Sopenharmony_cifp_d2e_small:
1948c2ecf20Sopenharmony_ci	| exponent is zero, so explizit bit is already zero too
1958c2ecf20Sopenharmony_ci	tst.l	%d0
1968c2ecf20Sopenharmony_ci	jeq	9b
1978c2ecf20Sopenharmony_ci	move.w	#0x4000-0x3ff,%d1
1988c2ecf20Sopenharmony_ci	jra	9b
1998c2ecf20Sopenharmony_ci	| infinities and NAN
2008c2ecf20Sopenharmony_cifp_d2e_large:
2018c2ecf20Sopenharmony_ci	bclr	#31,%d0			| clear explizit bit
2028c2ecf20Sopenharmony_ci	move.w	#0x7fff,%d1
2038c2ecf20Sopenharmony_ci	jra	9b
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	| fp_conv_ext2ext:
2068c2ecf20Sopenharmony_ci	| originally used to get longdouble from userspace, now it's
2078c2ecf20Sopenharmony_ci	| called before arithmetic operations to make sure the number
2088c2ecf20Sopenharmony_ci	| is normalized [maybe rename it?].
2098c2ecf20Sopenharmony_ci	| args:	%a0 = dest (struct fp_ext *)
2108c2ecf20Sopenharmony_ci	| returns 0 in %d0 for a NaN, otherwise 1
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_cifp_conv_ext2ext:
2138c2ecf20Sopenharmony_ci	printf	PCONV,"e2e: %p(",1,%a0
2148c2ecf20Sopenharmony_ci	printx	PCONV,%a0@
2158c2ecf20Sopenharmony_ci	printf	PCONV,"), "
2168c2ecf20Sopenharmony_ci	move.l	(%a0)+,%d0
2178c2ecf20Sopenharmony_ci	cmp.w	#0x7fff,%d0		| Inf / NaN?
2188c2ecf20Sopenharmony_ci	jeq	fp_e2e_large
2198c2ecf20Sopenharmony_ci	move.l	(%a0),%d0
2208c2ecf20Sopenharmony_ci	jpl	fp_e2e_small		| zero / denorm?
2218c2ecf20Sopenharmony_ci	| The high bit is set, so normalization is irrelevant.
2228c2ecf20Sopenharmony_cifp_e2e_checkround:
2238c2ecf20Sopenharmony_ci	subq.l	#4,%a0
2248c2ecf20Sopenharmony_ci#ifdef CONFIG_M68KFPU_EMU_EXTRAPREC
2258c2ecf20Sopenharmony_ci	move.b	(%a0),%d0
2268c2ecf20Sopenharmony_ci	jne	fp_e2e_round
2278c2ecf20Sopenharmony_ci#endif
2288c2ecf20Sopenharmony_ci	printf	PCONV,"%p(",1,%a0
2298c2ecf20Sopenharmony_ci	printx	PCONV,%a0@
2308c2ecf20Sopenharmony_ci	printf	PCONV,")\n"
2318c2ecf20Sopenharmony_ci	moveq	#1,%d0
2328c2ecf20Sopenharmony_ci	rts
2338c2ecf20Sopenharmony_ci#ifdef CONFIG_M68KFPU_EMU_EXTRAPREC
2348c2ecf20Sopenharmony_cifp_e2e_round:
2358c2ecf20Sopenharmony_ci	fp_set_sr FPSR_EXC_INEX2
2368c2ecf20Sopenharmony_ci	clr.b	(%a0)
2378c2ecf20Sopenharmony_ci	move.w	(FPD_RND,FPDATA),%d2
2388c2ecf20Sopenharmony_ci	jne	fp_e2e_roundother	| %d2 == 0, round to nearest
2398c2ecf20Sopenharmony_ci	tst.b	%d0			| test guard bit
2408c2ecf20Sopenharmony_ci	jpl	9f			| zero is closer
2418c2ecf20Sopenharmony_ci	btst	#0,(11,%a0)		| test lsb bit
2428c2ecf20Sopenharmony_ci	jne	fp_e2e_doroundup	| round to infinity
2438c2ecf20Sopenharmony_ci	lsl.b	#1,%d0			| check low bits
2448c2ecf20Sopenharmony_ci	jeq	9f			| round to zero
2458c2ecf20Sopenharmony_cifp_e2e_doroundup:
2468c2ecf20Sopenharmony_ci	addq.l	#1,(8,%a0)
2478c2ecf20Sopenharmony_ci	jcc	9f
2488c2ecf20Sopenharmony_ci	addq.l	#1,(4,%a0)
2498c2ecf20Sopenharmony_ci	jcc	9f
2508c2ecf20Sopenharmony_ci	move.w	#0x8000,(4,%a0)
2518c2ecf20Sopenharmony_ci	addq.w	#1,(2,%a0)
2528c2ecf20Sopenharmony_ci9:	printf	PNORM,"%p(",1,%a0
2538c2ecf20Sopenharmony_ci	printx	PNORM,%a0@
2548c2ecf20Sopenharmony_ci	printf	PNORM,")\n"
2558c2ecf20Sopenharmony_ci	rts
2568c2ecf20Sopenharmony_cifp_e2e_roundother:
2578c2ecf20Sopenharmony_ci	subq.w	#2,%d2
2588c2ecf20Sopenharmony_ci	jcs	9b			| %d2 < 2, round to zero
2598c2ecf20Sopenharmony_ci	jhi	1f			| %d2 > 2, round to +infinity
2608c2ecf20Sopenharmony_ci	tst.b	(1,%a0)			| to -inf
2618c2ecf20Sopenharmony_ci	jne	fp_e2e_doroundup	| negative, round to infinity
2628c2ecf20Sopenharmony_ci	jra	9b			| positive, round to zero
2638c2ecf20Sopenharmony_ci1:	tst.b	(1,%a0)			| to +inf
2648c2ecf20Sopenharmony_ci	jeq	fp_e2e_doroundup	| positive, round to infinity
2658c2ecf20Sopenharmony_ci	jra	9b			| negative, round to zero
2668c2ecf20Sopenharmony_ci#endif
2678c2ecf20Sopenharmony_ci	| zeros and subnormals:
2688c2ecf20Sopenharmony_ci	| try to normalize these anyway.
2698c2ecf20Sopenharmony_cifp_e2e_small:
2708c2ecf20Sopenharmony_ci	jne	fp_e2e_small1		| high lword zero?
2718c2ecf20Sopenharmony_ci	move.l	(4,%a0),%d0
2728c2ecf20Sopenharmony_ci	jne	fp_e2e_small2
2738c2ecf20Sopenharmony_ci#ifdef CONFIG_M68KFPU_EMU_EXTRAPREC
2748c2ecf20Sopenharmony_ci	clr.l	%d0
2758c2ecf20Sopenharmony_ci	move.b	(-4,%a0),%d0
2768c2ecf20Sopenharmony_ci	jne	fp_e2e_small3
2778c2ecf20Sopenharmony_ci#endif
2788c2ecf20Sopenharmony_ci	| Genuine zero.
2798c2ecf20Sopenharmony_ci	clr.w	-(%a0)
2808c2ecf20Sopenharmony_ci	subq.l	#2,%a0
2818c2ecf20Sopenharmony_ci	printf	PNORM,"%p(",1,%a0
2828c2ecf20Sopenharmony_ci	printx	PNORM,%a0@
2838c2ecf20Sopenharmony_ci	printf	PNORM,")\n"
2848c2ecf20Sopenharmony_ci	moveq	#1,%d0
2858c2ecf20Sopenharmony_ci	rts
2868c2ecf20Sopenharmony_ci	| definitely subnormal, need to shift all 64 bits
2878c2ecf20Sopenharmony_cifp_e2e_small1:
2888c2ecf20Sopenharmony_ci	bfffo	%d0{#0,#32},%d1
2898c2ecf20Sopenharmony_ci	move.w	-(%a0),%d2
2908c2ecf20Sopenharmony_ci	sub.w	%d1,%d2
2918c2ecf20Sopenharmony_ci	jcc	1f
2928c2ecf20Sopenharmony_ci	| Pathologically small, denormalize.
2938c2ecf20Sopenharmony_ci	add.w	%d2,%d1
2948c2ecf20Sopenharmony_ci	clr.w	%d2
2958c2ecf20Sopenharmony_ci1:	move.w	%d2,(%a0)+
2968c2ecf20Sopenharmony_ci	move.w	%d1,%d2
2978c2ecf20Sopenharmony_ci	jeq	fp_e2e_checkround
2988c2ecf20Sopenharmony_ci	| fancy 64-bit double-shift begins here
2998c2ecf20Sopenharmony_ci	lsl.l	%d2,%d0
3008c2ecf20Sopenharmony_ci	move.l	%d0,(%a0)+
3018c2ecf20Sopenharmony_ci	move.l	(%a0),%d0
3028c2ecf20Sopenharmony_ci	move.l	%d0,%d1
3038c2ecf20Sopenharmony_ci	lsl.l	%d2,%d0
3048c2ecf20Sopenharmony_ci	move.l	%d0,(%a0)
3058c2ecf20Sopenharmony_ci	neg.w	%d2
3068c2ecf20Sopenharmony_ci	and.w	#0x1f,%d2
3078c2ecf20Sopenharmony_ci	lsr.l	%d2,%d1
3088c2ecf20Sopenharmony_ci	or.l	%d1,-(%a0)
3098c2ecf20Sopenharmony_ci#ifdef CONFIG_M68KFPU_EMU_EXTRAPREC
3108c2ecf20Sopenharmony_cifp_e2e_extra1:
3118c2ecf20Sopenharmony_ci	clr.l	%d0
3128c2ecf20Sopenharmony_ci	move.b	(-4,%a0),%d0
3138c2ecf20Sopenharmony_ci	neg.w	%d2
3148c2ecf20Sopenharmony_ci	add.w	#24,%d2
3158c2ecf20Sopenharmony_ci	jcc	1f
3168c2ecf20Sopenharmony_ci	clr.b	(-4,%a0)
3178c2ecf20Sopenharmony_ci	lsl.l	%d2,%d0
3188c2ecf20Sopenharmony_ci	or.l	%d0,(4,%a0)
3198c2ecf20Sopenharmony_ci	jra	fp_e2e_checkround
3208c2ecf20Sopenharmony_ci1:	addq.w	#8,%d2
3218c2ecf20Sopenharmony_ci	lsl.l	%d2,%d0
3228c2ecf20Sopenharmony_ci	move.b	%d0,(-4,%a0)
3238c2ecf20Sopenharmony_ci	lsr.l	#8,%d0
3248c2ecf20Sopenharmony_ci	or.l	%d0,(4,%a0)
3258c2ecf20Sopenharmony_ci#endif
3268c2ecf20Sopenharmony_ci	jra	fp_e2e_checkround
3278c2ecf20Sopenharmony_ci	| pathologically small subnormal
3288c2ecf20Sopenharmony_cifp_e2e_small2:
3298c2ecf20Sopenharmony_ci	bfffo	%d0{#0,#32},%d1
3308c2ecf20Sopenharmony_ci	add.w	#32,%d1
3318c2ecf20Sopenharmony_ci	move.w	-(%a0),%d2
3328c2ecf20Sopenharmony_ci	sub.w	%d1,%d2
3338c2ecf20Sopenharmony_ci	jcc	1f
3348c2ecf20Sopenharmony_ci	| Beyond pathologically small, denormalize.
3358c2ecf20Sopenharmony_ci	add.w	%d2,%d1
3368c2ecf20Sopenharmony_ci	clr.w	%d2
3378c2ecf20Sopenharmony_ci1:	move.w	%d2,(%a0)+
3388c2ecf20Sopenharmony_ci	ext.l	%d1
3398c2ecf20Sopenharmony_ci	jeq	fp_e2e_checkround
3408c2ecf20Sopenharmony_ci	clr.l	(4,%a0)
3418c2ecf20Sopenharmony_ci	sub.w	#32,%d2
3428c2ecf20Sopenharmony_ci	jcs	1f
3438c2ecf20Sopenharmony_ci	lsl.l	%d1,%d0			| lower lword needs only to be shifted
3448c2ecf20Sopenharmony_ci	move.l	%d0,(%a0)		| into the higher lword
3458c2ecf20Sopenharmony_ci#ifdef CONFIG_M68KFPU_EMU_EXTRAPREC
3468c2ecf20Sopenharmony_ci	clr.l	%d0
3478c2ecf20Sopenharmony_ci	move.b	(-4,%a0),%d0
3488c2ecf20Sopenharmony_ci	clr.b	(-4,%a0)
3498c2ecf20Sopenharmony_ci	neg.w	%d1
3508c2ecf20Sopenharmony_ci	add.w	#32,%d1
3518c2ecf20Sopenharmony_ci	bfins	%d0,(%a0){%d1,#8}
3528c2ecf20Sopenharmony_ci#endif
3538c2ecf20Sopenharmony_ci	jra	fp_e2e_checkround
3548c2ecf20Sopenharmony_ci1:	neg.w	%d1			| lower lword is splitted between
3558c2ecf20Sopenharmony_ci	bfins	%d0,(%a0){%d1,#32}	| higher and lower lword
3568c2ecf20Sopenharmony_ci#ifndef CONFIG_M68KFPU_EMU_EXTRAPREC
3578c2ecf20Sopenharmony_ci	jra	fp_e2e_checkround
3588c2ecf20Sopenharmony_ci#else
3598c2ecf20Sopenharmony_ci	move.w	%d1,%d2
3608c2ecf20Sopenharmony_ci	jra	fp_e2e_extra1
3618c2ecf20Sopenharmony_ci	| These are extremely small numbers, that will mostly end up as zero
3628c2ecf20Sopenharmony_ci	| anyway, so this is only important for correct rounding.
3638c2ecf20Sopenharmony_cifp_e2e_small3:
3648c2ecf20Sopenharmony_ci	bfffo	%d0{#24,#8},%d1
3658c2ecf20Sopenharmony_ci	add.w	#40,%d1
3668c2ecf20Sopenharmony_ci	move.w	-(%a0),%d2
3678c2ecf20Sopenharmony_ci	sub.w	%d1,%d2
3688c2ecf20Sopenharmony_ci	jcc	1f
3698c2ecf20Sopenharmony_ci	| Pathologically small, denormalize.
3708c2ecf20Sopenharmony_ci	add.w	%d2,%d1
3718c2ecf20Sopenharmony_ci	clr.w	%d2
3728c2ecf20Sopenharmony_ci1:	move.w	%d2,(%a0)+
3738c2ecf20Sopenharmony_ci	ext.l	%d1
3748c2ecf20Sopenharmony_ci	jeq	fp_e2e_checkround
3758c2ecf20Sopenharmony_ci	cmp.w	#8,%d1
3768c2ecf20Sopenharmony_ci	jcs	2f
3778c2ecf20Sopenharmony_ci1:	clr.b	(-4,%a0)
3788c2ecf20Sopenharmony_ci	sub.w	#64,%d1
3798c2ecf20Sopenharmony_ci	jcs	1f
3808c2ecf20Sopenharmony_ci	add.w	#24,%d1
3818c2ecf20Sopenharmony_ci	lsl.l	%d1,%d0
3828c2ecf20Sopenharmony_ci	move.l	%d0,(%a0)
3838c2ecf20Sopenharmony_ci	jra	fp_e2e_checkround
3848c2ecf20Sopenharmony_ci1:	neg.w	%d1
3858c2ecf20Sopenharmony_ci	bfins	%d0,(%a0){%d1,#8}
3868c2ecf20Sopenharmony_ci	jra	fp_e2e_checkround
3878c2ecf20Sopenharmony_ci2:	lsl.l	%d1,%d0
3888c2ecf20Sopenharmony_ci	move.b	%d0,(-4,%a0)
3898c2ecf20Sopenharmony_ci	lsr.l	#8,%d0
3908c2ecf20Sopenharmony_ci	move.b	%d0,(7,%a0)
3918c2ecf20Sopenharmony_ci	jra	fp_e2e_checkround
3928c2ecf20Sopenharmony_ci#endif
3938c2ecf20Sopenharmony_ci1:	move.l	%d0,%d1			| lower lword is splitted between
3948c2ecf20Sopenharmony_ci	lsl.l	%d2,%d0			| higher and lower lword
3958c2ecf20Sopenharmony_ci	move.l	%d0,(%a0)
3968c2ecf20Sopenharmony_ci	move.l	%d1,%d0
3978c2ecf20Sopenharmony_ci	neg.w	%d2
3988c2ecf20Sopenharmony_ci	add.w	#32,%d2
3998c2ecf20Sopenharmony_ci	lsr.l	%d2,%d0
4008c2ecf20Sopenharmony_ci	move.l	%d0,-(%a0)
4018c2ecf20Sopenharmony_ci	jra	fp_e2e_checkround
4028c2ecf20Sopenharmony_ci	| Infinities and NaNs
4038c2ecf20Sopenharmony_cifp_e2e_large:
4048c2ecf20Sopenharmony_ci	move.l	(%a0)+,%d0
4058c2ecf20Sopenharmony_ci	jne	3f
4068c2ecf20Sopenharmony_ci1:	tst.l	(%a0)
4078c2ecf20Sopenharmony_ci	jne	4f
4088c2ecf20Sopenharmony_ci	moveq	#1,%d0
4098c2ecf20Sopenharmony_ci2:	subq.l	#8,%a0
4108c2ecf20Sopenharmony_ci	printf	PCONV,"%p(",1,%a0
4118c2ecf20Sopenharmony_ci	printx	PCONV,%a0@
4128c2ecf20Sopenharmony_ci	printf	PCONV,")\n"
4138c2ecf20Sopenharmony_ci	rts
4148c2ecf20Sopenharmony_ci	| we have maybe a NaN, shift off the highest bit
4158c2ecf20Sopenharmony_ci3:	lsl.l	#1,%d0
4168c2ecf20Sopenharmony_ci	jeq	1b
4178c2ecf20Sopenharmony_ci	| we have a NaN, clear the return value
4188c2ecf20Sopenharmony_ci4:	clrl	%d0
4198c2ecf20Sopenharmony_ci	jra	2b
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci/*
4238c2ecf20Sopenharmony_ci * Normalization functions.  Call these on the output of general
4248c2ecf20Sopenharmony_ci * FP operators, and before any conversion into the destination
4258c2ecf20Sopenharmony_ci * formats. fp_normalize_ext has always to be called first, the
4268c2ecf20Sopenharmony_ci * following conversion functions expect an already normalized
4278c2ecf20Sopenharmony_ci * number.
4288c2ecf20Sopenharmony_ci */
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	| fp_normalize_ext:
4318c2ecf20Sopenharmony_ci	| normalize an extended in extended (unpacked) format, basically
4328c2ecf20Sopenharmony_ci	| it does the same as fp_conv_ext2ext, additionally it also does
4338c2ecf20Sopenharmony_ci	| the necessary postprocessing checks.
4348c2ecf20Sopenharmony_ci	| args:	%a0 (struct fp_ext *)
4358c2ecf20Sopenharmony_ci	| NOTE: it does _not_ modify %a0/%a1 and the upper word of %d2
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_cifp_normalize_ext:
4388c2ecf20Sopenharmony_ci	printf	PNORM,"ne: %p(",1,%a0
4398c2ecf20Sopenharmony_ci	printx	PNORM,%a0@
4408c2ecf20Sopenharmony_ci	printf	PNORM,"), "
4418c2ecf20Sopenharmony_ci	move.l	(%a0)+,%d0
4428c2ecf20Sopenharmony_ci	cmp.w	#0x7fff,%d0		| Inf / NaN?
4438c2ecf20Sopenharmony_ci	jeq	fp_ne_large
4448c2ecf20Sopenharmony_ci	move.l	(%a0),%d0
4458c2ecf20Sopenharmony_ci	jpl	fp_ne_small		| zero / denorm?
4468c2ecf20Sopenharmony_ci	| The high bit is set, so normalization is irrelevant.
4478c2ecf20Sopenharmony_cifp_ne_checkround:
4488c2ecf20Sopenharmony_ci	subq.l	#4,%a0
4498c2ecf20Sopenharmony_ci#ifdef CONFIG_M68KFPU_EMU_EXTRAPREC
4508c2ecf20Sopenharmony_ci	move.b	(%a0),%d0
4518c2ecf20Sopenharmony_ci	jne	fp_ne_round
4528c2ecf20Sopenharmony_ci#endif
4538c2ecf20Sopenharmony_ci	printf	PNORM,"%p(",1,%a0
4548c2ecf20Sopenharmony_ci	printx	PNORM,%a0@
4558c2ecf20Sopenharmony_ci	printf	PNORM,")\n"
4568c2ecf20Sopenharmony_ci	rts
4578c2ecf20Sopenharmony_ci#ifdef CONFIG_M68KFPU_EMU_EXTRAPREC
4588c2ecf20Sopenharmony_cifp_ne_round:
4598c2ecf20Sopenharmony_ci	fp_set_sr FPSR_EXC_INEX2
4608c2ecf20Sopenharmony_ci	clr.b	(%a0)
4618c2ecf20Sopenharmony_ci	move.w	(FPD_RND,FPDATA),%d2
4628c2ecf20Sopenharmony_ci	jne	fp_ne_roundother	| %d2 == 0, round to nearest
4638c2ecf20Sopenharmony_ci	tst.b	%d0			| test guard bit
4648c2ecf20Sopenharmony_ci	jpl	9f			| zero is closer
4658c2ecf20Sopenharmony_ci	btst	#0,(11,%a0)		| test lsb bit
4668c2ecf20Sopenharmony_ci	jne	fp_ne_doroundup		| round to infinity
4678c2ecf20Sopenharmony_ci	lsl.b	#1,%d0			| check low bits
4688c2ecf20Sopenharmony_ci	jeq	9f			| round to zero
4698c2ecf20Sopenharmony_cifp_ne_doroundup:
4708c2ecf20Sopenharmony_ci	addq.l	#1,(8,%a0)
4718c2ecf20Sopenharmony_ci	jcc	9f
4728c2ecf20Sopenharmony_ci	addq.l	#1,(4,%a0)
4738c2ecf20Sopenharmony_ci	jcc	9f
4748c2ecf20Sopenharmony_ci	addq.w	#1,(2,%a0)
4758c2ecf20Sopenharmony_ci	move.w	#0x8000,(4,%a0)
4768c2ecf20Sopenharmony_ci9:	printf	PNORM,"%p(",1,%a0
4778c2ecf20Sopenharmony_ci	printx	PNORM,%a0@
4788c2ecf20Sopenharmony_ci	printf	PNORM,")\n"
4798c2ecf20Sopenharmony_ci	rts
4808c2ecf20Sopenharmony_cifp_ne_roundother:
4818c2ecf20Sopenharmony_ci	subq.w	#2,%d2
4828c2ecf20Sopenharmony_ci	jcs	9b			| %d2 < 2, round to zero
4838c2ecf20Sopenharmony_ci	jhi	1f			| %d2 > 2, round to +infinity
4848c2ecf20Sopenharmony_ci	tst.b	(1,%a0)			| to -inf
4858c2ecf20Sopenharmony_ci	jne	fp_ne_doroundup		| negative, round to infinity
4868c2ecf20Sopenharmony_ci	jra	9b			| positive, round to zero
4878c2ecf20Sopenharmony_ci1:	tst.b	(1,%a0)			| to +inf
4888c2ecf20Sopenharmony_ci	jeq	fp_ne_doroundup		| positive, round to infinity
4898c2ecf20Sopenharmony_ci	jra	9b			| negative, round to zero
4908c2ecf20Sopenharmony_ci#endif
4918c2ecf20Sopenharmony_ci	| Zeros and subnormal numbers
4928c2ecf20Sopenharmony_ci	| These are probably merely subnormal, rather than "denormalized"
4938c2ecf20Sopenharmony_ci	|  numbers, so we will try to make them normal again.
4948c2ecf20Sopenharmony_cifp_ne_small:
4958c2ecf20Sopenharmony_ci	jne	fp_ne_small1		| high lword zero?
4968c2ecf20Sopenharmony_ci	move.l	(4,%a0),%d0
4978c2ecf20Sopenharmony_ci	jne	fp_ne_small2
4988c2ecf20Sopenharmony_ci#ifdef CONFIG_M68KFPU_EMU_EXTRAPREC
4998c2ecf20Sopenharmony_ci	clr.l	%d0
5008c2ecf20Sopenharmony_ci	move.b	(-4,%a0),%d0
5018c2ecf20Sopenharmony_ci	jne	fp_ne_small3
5028c2ecf20Sopenharmony_ci#endif
5038c2ecf20Sopenharmony_ci	| Genuine zero.
5048c2ecf20Sopenharmony_ci	clr.w	-(%a0)
5058c2ecf20Sopenharmony_ci	subq.l	#2,%a0
5068c2ecf20Sopenharmony_ci	printf	PNORM,"%p(",1,%a0
5078c2ecf20Sopenharmony_ci	printx	PNORM,%a0@
5088c2ecf20Sopenharmony_ci	printf	PNORM,")\n"
5098c2ecf20Sopenharmony_ci	rts
5108c2ecf20Sopenharmony_ci	| Subnormal.
5118c2ecf20Sopenharmony_cifp_ne_small1:
5128c2ecf20Sopenharmony_ci	bfffo	%d0{#0,#32},%d1
5138c2ecf20Sopenharmony_ci	move.w	-(%a0),%d2
5148c2ecf20Sopenharmony_ci	sub.w	%d1,%d2
5158c2ecf20Sopenharmony_ci	jcc	1f
5168c2ecf20Sopenharmony_ci	| Pathologically small, denormalize.
5178c2ecf20Sopenharmony_ci	add.w	%d2,%d1
5188c2ecf20Sopenharmony_ci	clr.w	%d2
5198c2ecf20Sopenharmony_ci	fp_set_sr FPSR_EXC_UNFL
5208c2ecf20Sopenharmony_ci1:	move.w	%d2,(%a0)+
5218c2ecf20Sopenharmony_ci	move.w	%d1,%d2
5228c2ecf20Sopenharmony_ci	jeq	fp_ne_checkround
5238c2ecf20Sopenharmony_ci	| This is exactly the same 64-bit double shift as seen above.
5248c2ecf20Sopenharmony_ci	lsl.l	%d2,%d0
5258c2ecf20Sopenharmony_ci	move.l	%d0,(%a0)+
5268c2ecf20Sopenharmony_ci	move.l	(%a0),%d0
5278c2ecf20Sopenharmony_ci	move.l	%d0,%d1
5288c2ecf20Sopenharmony_ci	lsl.l	%d2,%d0
5298c2ecf20Sopenharmony_ci	move.l	%d0,(%a0)
5308c2ecf20Sopenharmony_ci	neg.w	%d2
5318c2ecf20Sopenharmony_ci	and.w	#0x1f,%d2
5328c2ecf20Sopenharmony_ci	lsr.l	%d2,%d1
5338c2ecf20Sopenharmony_ci	or.l	%d1,-(%a0)
5348c2ecf20Sopenharmony_ci#ifdef CONFIG_M68KFPU_EMU_EXTRAPREC
5358c2ecf20Sopenharmony_cifp_ne_extra1:
5368c2ecf20Sopenharmony_ci	clr.l	%d0
5378c2ecf20Sopenharmony_ci	move.b	(-4,%a0),%d0
5388c2ecf20Sopenharmony_ci	neg.w	%d2
5398c2ecf20Sopenharmony_ci	add.w	#24,%d2
5408c2ecf20Sopenharmony_ci	jcc	1f
5418c2ecf20Sopenharmony_ci	clr.b	(-4,%a0)
5428c2ecf20Sopenharmony_ci	lsl.l	%d2,%d0
5438c2ecf20Sopenharmony_ci	or.l	%d0,(4,%a0)
5448c2ecf20Sopenharmony_ci	jra	fp_ne_checkround
5458c2ecf20Sopenharmony_ci1:	addq.w	#8,%d2
5468c2ecf20Sopenharmony_ci	lsl.l	%d2,%d0
5478c2ecf20Sopenharmony_ci	move.b	%d0,(-4,%a0)
5488c2ecf20Sopenharmony_ci	lsr.l	#8,%d0
5498c2ecf20Sopenharmony_ci	or.l	%d0,(4,%a0)
5508c2ecf20Sopenharmony_ci#endif
5518c2ecf20Sopenharmony_ci	jra	fp_ne_checkround
5528c2ecf20Sopenharmony_ci	| May or may not be subnormal, if so, only 32 bits to shift.
5538c2ecf20Sopenharmony_cifp_ne_small2:
5548c2ecf20Sopenharmony_ci	bfffo	%d0{#0,#32},%d1
5558c2ecf20Sopenharmony_ci	add.w	#32,%d1
5568c2ecf20Sopenharmony_ci	move.w	-(%a0),%d2
5578c2ecf20Sopenharmony_ci	sub.w	%d1,%d2
5588c2ecf20Sopenharmony_ci	jcc	1f
5598c2ecf20Sopenharmony_ci	| Beyond pathologically small, denormalize.
5608c2ecf20Sopenharmony_ci	add.w	%d2,%d1
5618c2ecf20Sopenharmony_ci	clr.w	%d2
5628c2ecf20Sopenharmony_ci	fp_set_sr FPSR_EXC_UNFL
5638c2ecf20Sopenharmony_ci1:	move.w	%d2,(%a0)+
5648c2ecf20Sopenharmony_ci	ext.l	%d1
5658c2ecf20Sopenharmony_ci	jeq	fp_ne_checkround
5668c2ecf20Sopenharmony_ci	clr.l	(4,%a0)
5678c2ecf20Sopenharmony_ci	sub.w	#32,%d1
5688c2ecf20Sopenharmony_ci	jcs	1f
5698c2ecf20Sopenharmony_ci	lsl.l	%d1,%d0			| lower lword needs only to be shifted
5708c2ecf20Sopenharmony_ci	move.l	%d0,(%a0)		| into the higher lword
5718c2ecf20Sopenharmony_ci#ifdef CONFIG_M68KFPU_EMU_EXTRAPREC
5728c2ecf20Sopenharmony_ci	clr.l	%d0
5738c2ecf20Sopenharmony_ci	move.b	(-4,%a0),%d0
5748c2ecf20Sopenharmony_ci	clr.b	(-4,%a0)
5758c2ecf20Sopenharmony_ci	neg.w	%d1
5768c2ecf20Sopenharmony_ci	add.w	#32,%d1
5778c2ecf20Sopenharmony_ci	bfins	%d0,(%a0){%d1,#8}
5788c2ecf20Sopenharmony_ci#endif
5798c2ecf20Sopenharmony_ci	jra	fp_ne_checkround
5808c2ecf20Sopenharmony_ci1:	neg.w	%d1			| lower lword is splitted between
5818c2ecf20Sopenharmony_ci	bfins	%d0,(%a0){%d1,#32}	| higher and lower lword
5828c2ecf20Sopenharmony_ci#ifndef CONFIG_M68KFPU_EMU_EXTRAPREC
5838c2ecf20Sopenharmony_ci	jra	fp_ne_checkround
5848c2ecf20Sopenharmony_ci#else
5858c2ecf20Sopenharmony_ci	move.w	%d1,%d2
5868c2ecf20Sopenharmony_ci	jra	fp_ne_extra1
5878c2ecf20Sopenharmony_ci	| These are extremely small numbers, that will mostly end up as zero
5888c2ecf20Sopenharmony_ci	| anyway, so this is only important for correct rounding.
5898c2ecf20Sopenharmony_cifp_ne_small3:
5908c2ecf20Sopenharmony_ci	bfffo	%d0{#24,#8},%d1
5918c2ecf20Sopenharmony_ci	add.w	#40,%d1
5928c2ecf20Sopenharmony_ci	move.w	-(%a0),%d2
5938c2ecf20Sopenharmony_ci	sub.w	%d1,%d2
5948c2ecf20Sopenharmony_ci	jcc	1f
5958c2ecf20Sopenharmony_ci	| Pathologically small, denormalize.
5968c2ecf20Sopenharmony_ci	add.w	%d2,%d1
5978c2ecf20Sopenharmony_ci	clr.w	%d2
5988c2ecf20Sopenharmony_ci1:	move.w	%d2,(%a0)+
5998c2ecf20Sopenharmony_ci	ext.l	%d1
6008c2ecf20Sopenharmony_ci	jeq	fp_ne_checkround
6018c2ecf20Sopenharmony_ci	cmp.w	#8,%d1
6028c2ecf20Sopenharmony_ci	jcs	2f
6038c2ecf20Sopenharmony_ci1:	clr.b	(-4,%a0)
6048c2ecf20Sopenharmony_ci	sub.w	#64,%d1
6058c2ecf20Sopenharmony_ci	jcs	1f
6068c2ecf20Sopenharmony_ci	add.w	#24,%d1
6078c2ecf20Sopenharmony_ci	lsl.l	%d1,%d0
6088c2ecf20Sopenharmony_ci	move.l	%d0,(%a0)
6098c2ecf20Sopenharmony_ci	jra	fp_ne_checkround
6108c2ecf20Sopenharmony_ci1:	neg.w	%d1
6118c2ecf20Sopenharmony_ci	bfins	%d0,(%a0){%d1,#8}
6128c2ecf20Sopenharmony_ci	jra	fp_ne_checkround
6138c2ecf20Sopenharmony_ci2:	lsl.l	%d1,%d0
6148c2ecf20Sopenharmony_ci	move.b	%d0,(-4,%a0)
6158c2ecf20Sopenharmony_ci	lsr.l	#8,%d0
6168c2ecf20Sopenharmony_ci	move.b	%d0,(7,%a0)
6178c2ecf20Sopenharmony_ci	jra	fp_ne_checkround
6188c2ecf20Sopenharmony_ci#endif
6198c2ecf20Sopenharmony_ci	| Infinities and NaNs, again, same as above.
6208c2ecf20Sopenharmony_cifp_ne_large:
6218c2ecf20Sopenharmony_ci	move.l	(%a0)+,%d0
6228c2ecf20Sopenharmony_ci	jne	3f
6238c2ecf20Sopenharmony_ci1:	tst.l	(%a0)
6248c2ecf20Sopenharmony_ci	jne	4f
6258c2ecf20Sopenharmony_ci2:	subq.l	#8,%a0
6268c2ecf20Sopenharmony_ci	printf	PNORM,"%p(",1,%a0
6278c2ecf20Sopenharmony_ci	printx	PNORM,%a0@
6288c2ecf20Sopenharmony_ci	printf	PNORM,")\n"
6298c2ecf20Sopenharmony_ci	rts
6308c2ecf20Sopenharmony_ci	| we have maybe a NaN, shift off the highest bit
6318c2ecf20Sopenharmony_ci3:	move.l	%d0,%d1
6328c2ecf20Sopenharmony_ci	lsl.l	#1,%d1
6338c2ecf20Sopenharmony_ci	jne	4f
6348c2ecf20Sopenharmony_ci	clr.l	(-4,%a0)
6358c2ecf20Sopenharmony_ci	jra	1b
6368c2ecf20Sopenharmony_ci	| we have a NaN, test if it is signaling
6378c2ecf20Sopenharmony_ci4:	bset	#30,%d0
6388c2ecf20Sopenharmony_ci	jne	2b
6398c2ecf20Sopenharmony_ci	fp_set_sr FPSR_EXC_SNAN
6408c2ecf20Sopenharmony_ci	move.l	%d0,(-4,%a0)
6418c2ecf20Sopenharmony_ci	jra	2b
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	| these next two do rounding as per the IEEE standard.
6448c2ecf20Sopenharmony_ci	| values for the rounding modes appear to be:
6458c2ecf20Sopenharmony_ci	| 0:	Round to nearest
6468c2ecf20Sopenharmony_ci	| 1:	Round to zero
6478c2ecf20Sopenharmony_ci	| 2:	Round to -Infinity
6488c2ecf20Sopenharmony_ci	| 3:	Round to +Infinity
6498c2ecf20Sopenharmony_ci	| both functions expect that fp_normalize was already
6508c2ecf20Sopenharmony_ci	| called (and extended argument is already normalized
6518c2ecf20Sopenharmony_ci	| as far as possible), these are used if there is different
6528c2ecf20Sopenharmony_ci	| rounding precision is selected and before converting
6538c2ecf20Sopenharmony_ci	| into single/double
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci	| fp_normalize_double:
6568c2ecf20Sopenharmony_ci	| normalize an extended with double (52-bit) precision
6578c2ecf20Sopenharmony_ci	| args:	 %a0 (struct fp_ext *)
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_cifp_normalize_double:
6608c2ecf20Sopenharmony_ci	printf	PNORM,"nd: %p(",1,%a0
6618c2ecf20Sopenharmony_ci	printx	PNORM,%a0@
6628c2ecf20Sopenharmony_ci	printf	PNORM,"), "
6638c2ecf20Sopenharmony_ci	move.l	(%a0)+,%d2
6648c2ecf20Sopenharmony_ci	tst.w	%d2
6658c2ecf20Sopenharmony_ci	jeq	fp_nd_zero		| zero / denormalized
6668c2ecf20Sopenharmony_ci	cmp.w	#0x7fff,%d2
6678c2ecf20Sopenharmony_ci	jeq	fp_nd_huge		| NaN / infinitive.
6688c2ecf20Sopenharmony_ci	sub.w	#0x4000-0x3ff,%d2	| will the exponent fit?
6698c2ecf20Sopenharmony_ci	jcs	fp_nd_small		| too small.
6708c2ecf20Sopenharmony_ci	cmp.w	#0x7fe,%d2
6718c2ecf20Sopenharmony_ci	jcc	fp_nd_large		| too big.
6728c2ecf20Sopenharmony_ci	addq.l	#4,%a0
6738c2ecf20Sopenharmony_ci	move.l	(%a0),%d0		| low lword of mantissa
6748c2ecf20Sopenharmony_ci	| now, round off the low 11 bits.
6758c2ecf20Sopenharmony_cifp_nd_round:
6768c2ecf20Sopenharmony_ci	moveq	#21,%d1
6778c2ecf20Sopenharmony_ci	lsl.l	%d1,%d0			| keep 11 low bits.
6788c2ecf20Sopenharmony_ci	jne	fp_nd_checkround	| Are they non-zero?
6798c2ecf20Sopenharmony_ci	| nothing to do here
6808c2ecf20Sopenharmony_ci9:	subq.l	#8,%a0
6818c2ecf20Sopenharmony_ci	printf	PNORM,"%p(",1,%a0
6828c2ecf20Sopenharmony_ci	printx	PNORM,%a0@
6838c2ecf20Sopenharmony_ci	printf	PNORM,")\n"
6848c2ecf20Sopenharmony_ci	rts
6858c2ecf20Sopenharmony_ci	| Be careful with the X bit! It contains the lsb
6868c2ecf20Sopenharmony_ci	| from the shift above, it is needed for round to nearest.
6878c2ecf20Sopenharmony_cifp_nd_checkround:
6888c2ecf20Sopenharmony_ci	fp_set_sr FPSR_EXC_INEX2	| INEX2 bit
6898c2ecf20Sopenharmony_ci	and.w	#0xf800,(2,%a0)		| clear bits 0-10
6908c2ecf20Sopenharmony_ci	move.w	(FPD_RND,FPDATA),%d2	| rounding mode
6918c2ecf20Sopenharmony_ci	jne	2f			| %d2 == 0, round to nearest
6928c2ecf20Sopenharmony_ci	tst.l	%d0			| test guard bit
6938c2ecf20Sopenharmony_ci	jpl	9b			| zero is closer
6948c2ecf20Sopenharmony_ci	| here we test the X bit by adding it to %d2
6958c2ecf20Sopenharmony_ci	clr.w	%d2			| first set z bit, addx only clears it
6968c2ecf20Sopenharmony_ci	addx.w	%d2,%d2			| test lsb bit
6978c2ecf20Sopenharmony_ci	| IEEE754-specified "round to even" behaviour.  If the guard
6988c2ecf20Sopenharmony_ci	| bit is set, then the number is odd, so rounding works like
6998c2ecf20Sopenharmony_ci	| in grade-school arithmetic (i.e. 1.5 rounds to 2.0)
7008c2ecf20Sopenharmony_ci	| Otherwise, an equal distance rounds towards zero, so as not
7018c2ecf20Sopenharmony_ci	| to produce an odd number.  This is strange, but it is what
7028c2ecf20Sopenharmony_ci	| the standard says.
7038c2ecf20Sopenharmony_ci	jne	fp_nd_doroundup		| round to infinity
7048c2ecf20Sopenharmony_ci	lsl.l	#1,%d0			| check low bits
7058c2ecf20Sopenharmony_ci	jeq	9b			| round to zero
7068c2ecf20Sopenharmony_cifp_nd_doroundup:
7078c2ecf20Sopenharmony_ci	| round (the mantissa, that is) towards infinity
7088c2ecf20Sopenharmony_ci	add.l	#0x800,(%a0)
7098c2ecf20Sopenharmony_ci	jcc	9b			| no overflow, good.
7108c2ecf20Sopenharmony_ci	addq.l	#1,-(%a0)		| extend to high lword
7118c2ecf20Sopenharmony_ci	jcc	1f			| no overflow, good.
7128c2ecf20Sopenharmony_ci	| Yow! we have managed to overflow the mantissa.  Since this
7138c2ecf20Sopenharmony_ci	| only happens when %d1 was 0xfffff800, it is now zero, so
7148c2ecf20Sopenharmony_ci	| reset the high bit, and increment the exponent.
7158c2ecf20Sopenharmony_ci	move.w	#0x8000,(%a0)
7168c2ecf20Sopenharmony_ci	addq.w	#1,-(%a0)
7178c2ecf20Sopenharmony_ci	cmp.w	#0x43ff,(%a0)+		| exponent now overflown?
7188c2ecf20Sopenharmony_ci	jeq	fp_nd_large		| yes, so make it infinity.
7198c2ecf20Sopenharmony_ci1:	subq.l	#4,%a0
7208c2ecf20Sopenharmony_ci	printf	PNORM,"%p(",1,%a0
7218c2ecf20Sopenharmony_ci	printx	PNORM,%a0@
7228c2ecf20Sopenharmony_ci	printf	PNORM,")\n"
7238c2ecf20Sopenharmony_ci	rts
7248c2ecf20Sopenharmony_ci2:	subq.w	#2,%d2
7258c2ecf20Sopenharmony_ci	jcs	9b			| %d2 < 2, round to zero
7268c2ecf20Sopenharmony_ci	jhi	3f			| %d2 > 2, round to +infinity
7278c2ecf20Sopenharmony_ci	| Round to +Inf or -Inf.  High word of %d2 contains the
7288c2ecf20Sopenharmony_ci	| sign of the number, by the way.
7298c2ecf20Sopenharmony_ci	swap	%d2			| to -inf
7308c2ecf20Sopenharmony_ci	tst.b	%d2
7318c2ecf20Sopenharmony_ci	jne	fp_nd_doroundup		| negative, round to infinity
7328c2ecf20Sopenharmony_ci	jra	9b			| positive, round to zero
7338c2ecf20Sopenharmony_ci3:	swap	%d2			| to +inf
7348c2ecf20Sopenharmony_ci	tst.b	%d2
7358c2ecf20Sopenharmony_ci	jeq	fp_nd_doroundup		| positive, round to infinity
7368c2ecf20Sopenharmony_ci	jra	9b			| negative, round to zero
7378c2ecf20Sopenharmony_ci	| Exponent underflow.  Try to make a denormal, and set it to
7388c2ecf20Sopenharmony_ci	| the smallest possible fraction if this fails.
7398c2ecf20Sopenharmony_cifp_nd_small:
7408c2ecf20Sopenharmony_ci	fp_set_sr FPSR_EXC_UNFL		| set UNFL bit
7418c2ecf20Sopenharmony_ci	move.w	#0x3c01,(-2,%a0)	| 2**-1022
7428c2ecf20Sopenharmony_ci	neg.w	%d2			| degree of underflow
7438c2ecf20Sopenharmony_ci	cmp.w	#32,%d2			| single or double shift?
7448c2ecf20Sopenharmony_ci	jcc	1f
7458c2ecf20Sopenharmony_ci	| Again, another 64-bit double shift.
7468c2ecf20Sopenharmony_ci	move.l	(%a0),%d0
7478c2ecf20Sopenharmony_ci	move.l	%d0,%d1
7488c2ecf20Sopenharmony_ci	lsr.l	%d2,%d0
7498c2ecf20Sopenharmony_ci	move.l	%d0,(%a0)+
7508c2ecf20Sopenharmony_ci	move.l	(%a0),%d0
7518c2ecf20Sopenharmony_ci	lsr.l	%d2,%d0
7528c2ecf20Sopenharmony_ci	neg.w	%d2
7538c2ecf20Sopenharmony_ci	add.w	#32,%d2
7548c2ecf20Sopenharmony_ci	lsl.l	%d2,%d1
7558c2ecf20Sopenharmony_ci	or.l	%d1,%d0
7568c2ecf20Sopenharmony_ci	move.l	(%a0),%d1
7578c2ecf20Sopenharmony_ci	move.l	%d0,(%a0)
7588c2ecf20Sopenharmony_ci	| Check to see if we shifted off any significant bits
7598c2ecf20Sopenharmony_ci	lsl.l	%d2,%d1
7608c2ecf20Sopenharmony_ci	jeq	fp_nd_round		| Nope, round.
7618c2ecf20Sopenharmony_ci	bset	#0,%d0			| Yes, so set the "sticky bit".
7628c2ecf20Sopenharmony_ci	jra	fp_nd_round		| Now, round.
7638c2ecf20Sopenharmony_ci	| Another 64-bit single shift and store
7648c2ecf20Sopenharmony_ci1:	sub.w	#32,%d2
7658c2ecf20Sopenharmony_ci	cmp.w	#32,%d2			| Do we really need to shift?
7668c2ecf20Sopenharmony_ci	jcc	2f			| No, the number is too small.
7678c2ecf20Sopenharmony_ci	move.l	(%a0),%d0
7688c2ecf20Sopenharmony_ci	clr.l	(%a0)+
7698c2ecf20Sopenharmony_ci	move.l	%d0,%d1
7708c2ecf20Sopenharmony_ci	lsr.l	%d2,%d0
7718c2ecf20Sopenharmony_ci	neg.w	%d2
7728c2ecf20Sopenharmony_ci	add.w	#32,%d2
7738c2ecf20Sopenharmony_ci	| Again, check to see if we shifted off any significant bits.
7748c2ecf20Sopenharmony_ci	tst.l	(%a0)
7758c2ecf20Sopenharmony_ci	jeq	1f
7768c2ecf20Sopenharmony_ci	bset	#0,%d0			| Sticky bit.
7778c2ecf20Sopenharmony_ci1:	move.l	%d0,(%a0)
7788c2ecf20Sopenharmony_ci	lsl.l	%d2,%d1
7798c2ecf20Sopenharmony_ci	jeq	fp_nd_round
7808c2ecf20Sopenharmony_ci	bset	#0,%d0
7818c2ecf20Sopenharmony_ci	jra	fp_nd_round
7828c2ecf20Sopenharmony_ci	| Sorry, the number is just too small.
7838c2ecf20Sopenharmony_ci2:	clr.l	(%a0)+
7848c2ecf20Sopenharmony_ci	clr.l	(%a0)
7858c2ecf20Sopenharmony_ci	moveq	#1,%d0			| Smallest possible fraction,
7868c2ecf20Sopenharmony_ci	jra	fp_nd_round		| round as desired.
7878c2ecf20Sopenharmony_ci	| zero and denormalized
7888c2ecf20Sopenharmony_cifp_nd_zero:
7898c2ecf20Sopenharmony_ci	tst.l	(%a0)+
7908c2ecf20Sopenharmony_ci	jne	1f
7918c2ecf20Sopenharmony_ci	tst.l	(%a0)
7928c2ecf20Sopenharmony_ci	jne	1f
7938c2ecf20Sopenharmony_ci	subq.l	#8,%a0
7948c2ecf20Sopenharmony_ci	printf	PNORM,"%p(",1,%a0
7958c2ecf20Sopenharmony_ci	printx	PNORM,%a0@
7968c2ecf20Sopenharmony_ci	printf	PNORM,")\n"
7978c2ecf20Sopenharmony_ci	rts				| zero.  nothing to do.
7988c2ecf20Sopenharmony_ci	| These are not merely subnormal numbers, but true denormals,
7998c2ecf20Sopenharmony_ci	| i.e. pathologically small (exponent is 2**-16383) numbers.
8008c2ecf20Sopenharmony_ci	| It is clearly impossible for even a normal extended number
8018c2ecf20Sopenharmony_ci	| with that exponent to fit into double precision, so just
8028c2ecf20Sopenharmony_ci	| write these ones off as "too darn small".
8038c2ecf20Sopenharmony_ci1:	fp_set_sr FPSR_EXC_UNFL		| Set UNFL bit
8048c2ecf20Sopenharmony_ci	clr.l	(%a0)
8058c2ecf20Sopenharmony_ci	clr.l	-(%a0)
8068c2ecf20Sopenharmony_ci	move.w	#0x3c01,-(%a0)		| i.e. 2**-1022
8078c2ecf20Sopenharmony_ci	addq.l	#6,%a0
8088c2ecf20Sopenharmony_ci	moveq	#1,%d0
8098c2ecf20Sopenharmony_ci	jra	fp_nd_round		| round.
8108c2ecf20Sopenharmony_ci	| Exponent overflow.  Just call it infinity.
8118c2ecf20Sopenharmony_cifp_nd_large:
8128c2ecf20Sopenharmony_ci	move.w	#0x7ff,%d0
8138c2ecf20Sopenharmony_ci	and.w	(6,%a0),%d0
8148c2ecf20Sopenharmony_ci	jeq	1f
8158c2ecf20Sopenharmony_ci	fp_set_sr FPSR_EXC_INEX2
8168c2ecf20Sopenharmony_ci1:	fp_set_sr FPSR_EXC_OVFL
8178c2ecf20Sopenharmony_ci	move.w	(FPD_RND,FPDATA),%d2
8188c2ecf20Sopenharmony_ci	jne	3f			| %d2 = 0 round to nearest
8198c2ecf20Sopenharmony_ci1:	move.w	#0x7fff,(-2,%a0)
8208c2ecf20Sopenharmony_ci	clr.l	(%a0)+
8218c2ecf20Sopenharmony_ci	clr.l	(%a0)
8228c2ecf20Sopenharmony_ci2:	subq.l	#8,%a0
8238c2ecf20Sopenharmony_ci	printf	PNORM,"%p(",1,%a0
8248c2ecf20Sopenharmony_ci	printx	PNORM,%a0@
8258c2ecf20Sopenharmony_ci	printf	PNORM,")\n"
8268c2ecf20Sopenharmony_ci	rts
8278c2ecf20Sopenharmony_ci3:	subq.w	#2,%d2
8288c2ecf20Sopenharmony_ci	jcs	5f			| %d2 < 2, round to zero
8298c2ecf20Sopenharmony_ci	jhi	4f			| %d2 > 2, round to +infinity
8308c2ecf20Sopenharmony_ci	tst.b	(-3,%a0)		| to -inf
8318c2ecf20Sopenharmony_ci	jne	1b
8328c2ecf20Sopenharmony_ci	jra	5f
8338c2ecf20Sopenharmony_ci4:	tst.b	(-3,%a0)		| to +inf
8348c2ecf20Sopenharmony_ci	jeq	1b
8358c2ecf20Sopenharmony_ci5:	move.w	#0x43fe,(-2,%a0)
8368c2ecf20Sopenharmony_ci	moveq	#-1,%d0
8378c2ecf20Sopenharmony_ci	move.l	%d0,(%a0)+
8388c2ecf20Sopenharmony_ci	move.w	#0xf800,%d0
8398c2ecf20Sopenharmony_ci	move.l	%d0,(%a0)
8408c2ecf20Sopenharmony_ci	jra	2b
8418c2ecf20Sopenharmony_ci	| Infinities or NaNs
8428c2ecf20Sopenharmony_cifp_nd_huge:
8438c2ecf20Sopenharmony_ci	subq.l	#4,%a0
8448c2ecf20Sopenharmony_ci	printf	PNORM,"%p(",1,%a0
8458c2ecf20Sopenharmony_ci	printx	PNORM,%a0@
8468c2ecf20Sopenharmony_ci	printf	PNORM,")\n"
8478c2ecf20Sopenharmony_ci	rts
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci	| fp_normalize_single:
8508c2ecf20Sopenharmony_ci	| normalize an extended with single (23-bit) precision
8518c2ecf20Sopenharmony_ci	| args:	 %a0 (struct fp_ext *)
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_cifp_normalize_single:
8548c2ecf20Sopenharmony_ci	printf	PNORM,"ns: %p(",1,%a0
8558c2ecf20Sopenharmony_ci	printx	PNORM,%a0@
8568c2ecf20Sopenharmony_ci	printf	PNORM,") "
8578c2ecf20Sopenharmony_ci	addq.l	#2,%a0
8588c2ecf20Sopenharmony_ci	move.w	(%a0)+,%d2
8598c2ecf20Sopenharmony_ci	jeq	fp_ns_zero		| zero / denormalized
8608c2ecf20Sopenharmony_ci	cmp.w	#0x7fff,%d2
8618c2ecf20Sopenharmony_ci	jeq	fp_ns_huge		| NaN / infinitive.
8628c2ecf20Sopenharmony_ci	sub.w	#0x4000-0x7f,%d2	| will the exponent fit?
8638c2ecf20Sopenharmony_ci	jcs	fp_ns_small		| too small.
8648c2ecf20Sopenharmony_ci	cmp.w	#0xfe,%d2
8658c2ecf20Sopenharmony_ci	jcc	fp_ns_large		| too big.
8668c2ecf20Sopenharmony_ci	move.l	(%a0)+,%d0		| get high lword of mantissa
8678c2ecf20Sopenharmony_cifp_ns_round:
8688c2ecf20Sopenharmony_ci	tst.l	(%a0)			| check the low lword
8698c2ecf20Sopenharmony_ci	jeq	1f
8708c2ecf20Sopenharmony_ci	| Set a sticky bit if it is non-zero.  This should only
8718c2ecf20Sopenharmony_ci	| affect the rounding in what would otherwise be equal-
8728c2ecf20Sopenharmony_ci	| distance situations, which is what we want it to do.
8738c2ecf20Sopenharmony_ci	bset	#0,%d0
8748c2ecf20Sopenharmony_ci1:	clr.l	(%a0)			| zap it from memory.
8758c2ecf20Sopenharmony_ci	| now, round off the low 8 bits of the hi lword.
8768c2ecf20Sopenharmony_ci	tst.b	%d0			| 8 low bits.
8778c2ecf20Sopenharmony_ci	jne	fp_ns_checkround	| Are they non-zero?
8788c2ecf20Sopenharmony_ci	| nothing to do here
8798c2ecf20Sopenharmony_ci	subq.l	#8,%a0
8808c2ecf20Sopenharmony_ci	printf	PNORM,"%p(",1,%a0
8818c2ecf20Sopenharmony_ci	printx	PNORM,%a0@
8828c2ecf20Sopenharmony_ci	printf	PNORM,")\n"
8838c2ecf20Sopenharmony_ci	rts
8848c2ecf20Sopenharmony_cifp_ns_checkround:
8858c2ecf20Sopenharmony_ci	fp_set_sr FPSR_EXC_INEX2	| INEX2 bit
8868c2ecf20Sopenharmony_ci	clr.b	-(%a0)			| clear low byte of high lword
8878c2ecf20Sopenharmony_ci	subq.l	#3,%a0
8888c2ecf20Sopenharmony_ci	move.w	(FPD_RND,FPDATA),%d2	| rounding mode
8898c2ecf20Sopenharmony_ci	jne	2f			| %d2 == 0, round to nearest
8908c2ecf20Sopenharmony_ci	tst.b	%d0			| test guard bit
8918c2ecf20Sopenharmony_ci	jpl	9f			| zero is closer
8928c2ecf20Sopenharmony_ci	btst	#8,%d0			| test lsb bit
8938c2ecf20Sopenharmony_ci	| round to even behaviour, see above.
8948c2ecf20Sopenharmony_ci	jne	fp_ns_doroundup		| round to infinity
8958c2ecf20Sopenharmony_ci	lsl.b	#1,%d0			| check low bits
8968c2ecf20Sopenharmony_ci	jeq	9f			| round to zero
8978c2ecf20Sopenharmony_cifp_ns_doroundup:
8988c2ecf20Sopenharmony_ci	| round (the mantissa, that is) towards infinity
8998c2ecf20Sopenharmony_ci	add.l	#0x100,(%a0)
9008c2ecf20Sopenharmony_ci	jcc	9f			| no overflow, good.
9018c2ecf20Sopenharmony_ci	| Overflow.  This means that the %d1 was 0xffffff00, so it
9028c2ecf20Sopenharmony_ci	| is now zero.  We will set the mantissa to reflect this, and
9038c2ecf20Sopenharmony_ci	| increment the exponent (checking for overflow there too)
9048c2ecf20Sopenharmony_ci	move.w	#0x8000,(%a0)
9058c2ecf20Sopenharmony_ci	addq.w	#1,-(%a0)
9068c2ecf20Sopenharmony_ci	cmp.w	#0x407f,(%a0)+		| exponent now overflown?
9078c2ecf20Sopenharmony_ci	jeq	fp_ns_large		| yes, so make it infinity.
9088c2ecf20Sopenharmony_ci9:	subq.l	#4,%a0
9098c2ecf20Sopenharmony_ci	printf	PNORM,"%p(",1,%a0
9108c2ecf20Sopenharmony_ci	printx	PNORM,%a0@
9118c2ecf20Sopenharmony_ci	printf	PNORM,")\n"
9128c2ecf20Sopenharmony_ci	rts
9138c2ecf20Sopenharmony_ci	| check nondefault rounding modes
9148c2ecf20Sopenharmony_ci2:	subq.w	#2,%d2
9158c2ecf20Sopenharmony_ci	jcs	9b			| %d2 < 2, round to zero
9168c2ecf20Sopenharmony_ci	jhi	3f			| %d2 > 2, round to +infinity
9178c2ecf20Sopenharmony_ci	tst.b	(-3,%a0)		| to -inf
9188c2ecf20Sopenharmony_ci	jne	fp_ns_doroundup		| negative, round to infinity
9198c2ecf20Sopenharmony_ci	jra	9b			| positive, round to zero
9208c2ecf20Sopenharmony_ci3:	tst.b	(-3,%a0)		| to +inf
9218c2ecf20Sopenharmony_ci	jeq	fp_ns_doroundup		| positive, round to infinity
9228c2ecf20Sopenharmony_ci	jra	9b			| negative, round to zero
9238c2ecf20Sopenharmony_ci	| Exponent underflow.  Try to make a denormal, and set it to
9248c2ecf20Sopenharmony_ci	| the smallest possible fraction if this fails.
9258c2ecf20Sopenharmony_cifp_ns_small:
9268c2ecf20Sopenharmony_ci	fp_set_sr FPSR_EXC_UNFL		| set UNFL bit
9278c2ecf20Sopenharmony_ci	move.w	#0x3f81,(-2,%a0)	| 2**-126
9288c2ecf20Sopenharmony_ci	neg.w	%d2			| degree of underflow
9298c2ecf20Sopenharmony_ci	cmp.w	#32,%d2			| single or double shift?
9308c2ecf20Sopenharmony_ci	jcc	2f
9318c2ecf20Sopenharmony_ci	| a 32-bit shift.
9328c2ecf20Sopenharmony_ci	move.l	(%a0),%d0
9338c2ecf20Sopenharmony_ci	move.l	%d0,%d1
9348c2ecf20Sopenharmony_ci	lsr.l	%d2,%d0
9358c2ecf20Sopenharmony_ci	move.l	%d0,(%a0)+
9368c2ecf20Sopenharmony_ci	| Check to see if we shifted off any significant bits.
9378c2ecf20Sopenharmony_ci	neg.w	%d2
9388c2ecf20Sopenharmony_ci	add.w	#32,%d2
9398c2ecf20Sopenharmony_ci	lsl.l	%d2,%d1
9408c2ecf20Sopenharmony_ci	jeq	1f
9418c2ecf20Sopenharmony_ci	bset	#0,%d0			| Sticky bit.
9428c2ecf20Sopenharmony_ci	| Check the lower lword
9438c2ecf20Sopenharmony_ci1:	tst.l	(%a0)
9448c2ecf20Sopenharmony_ci	jeq	fp_ns_round
9458c2ecf20Sopenharmony_ci	clr	(%a0)
9468c2ecf20Sopenharmony_ci	bset	#0,%d0			| Sticky bit.
9478c2ecf20Sopenharmony_ci	jra	fp_ns_round
9488c2ecf20Sopenharmony_ci	| Sorry, the number is just too small.
9498c2ecf20Sopenharmony_ci2:	clr.l	(%a0)+
9508c2ecf20Sopenharmony_ci	clr.l	(%a0)
9518c2ecf20Sopenharmony_ci	moveq	#1,%d0			| Smallest possible fraction,
9528c2ecf20Sopenharmony_ci	jra	fp_ns_round		| round as desired.
9538c2ecf20Sopenharmony_ci	| Exponent overflow.  Just call it infinity.
9548c2ecf20Sopenharmony_cifp_ns_large:
9558c2ecf20Sopenharmony_ci	tst.b	(3,%a0)
9568c2ecf20Sopenharmony_ci	jeq	1f
9578c2ecf20Sopenharmony_ci	fp_set_sr FPSR_EXC_INEX2
9588c2ecf20Sopenharmony_ci1:	fp_set_sr FPSR_EXC_OVFL
9598c2ecf20Sopenharmony_ci	move.w	(FPD_RND,FPDATA),%d2
9608c2ecf20Sopenharmony_ci	jne	3f			| %d2 = 0 round to nearest
9618c2ecf20Sopenharmony_ci1:	move.w	#0x7fff,(-2,%a0)
9628c2ecf20Sopenharmony_ci	clr.l	(%a0)+
9638c2ecf20Sopenharmony_ci	clr.l	(%a0)
9648c2ecf20Sopenharmony_ci2:	subq.l	#8,%a0
9658c2ecf20Sopenharmony_ci	printf	PNORM,"%p(",1,%a0
9668c2ecf20Sopenharmony_ci	printx	PNORM,%a0@
9678c2ecf20Sopenharmony_ci	printf	PNORM,")\n"
9688c2ecf20Sopenharmony_ci	rts
9698c2ecf20Sopenharmony_ci3:	subq.w	#2,%d2
9708c2ecf20Sopenharmony_ci	jcs	5f			| %d2 < 2, round to zero
9718c2ecf20Sopenharmony_ci	jhi	4f			| %d2 > 2, round to +infinity
9728c2ecf20Sopenharmony_ci	tst.b	(-3,%a0)		| to -inf
9738c2ecf20Sopenharmony_ci	jne	1b
9748c2ecf20Sopenharmony_ci	jra	5f
9758c2ecf20Sopenharmony_ci4:	tst.b	(-3,%a0)		| to +inf
9768c2ecf20Sopenharmony_ci	jeq	1b
9778c2ecf20Sopenharmony_ci5:	move.w	#0x407e,(-2,%a0)
9788c2ecf20Sopenharmony_ci	move.l	#0xffffff00,(%a0)+
9798c2ecf20Sopenharmony_ci	clr.l	(%a0)
9808c2ecf20Sopenharmony_ci	jra	2b
9818c2ecf20Sopenharmony_ci	| zero and denormalized
9828c2ecf20Sopenharmony_cifp_ns_zero:
9838c2ecf20Sopenharmony_ci	tst.l	(%a0)+
9848c2ecf20Sopenharmony_ci	jne	1f
9858c2ecf20Sopenharmony_ci	tst.l	(%a0)
9868c2ecf20Sopenharmony_ci	jne	1f
9878c2ecf20Sopenharmony_ci	subq.l	#8,%a0
9888c2ecf20Sopenharmony_ci	printf	PNORM,"%p(",1,%a0
9898c2ecf20Sopenharmony_ci	printx	PNORM,%a0@
9908c2ecf20Sopenharmony_ci	printf	PNORM,")\n"
9918c2ecf20Sopenharmony_ci	rts				| zero.  nothing to do.
9928c2ecf20Sopenharmony_ci	| These are not merely subnormal numbers, but true denormals,
9938c2ecf20Sopenharmony_ci	| i.e. pathologically small (exponent is 2**-16383) numbers.
9948c2ecf20Sopenharmony_ci	| It is clearly impossible for even a normal extended number
9958c2ecf20Sopenharmony_ci	| with that exponent to fit into single precision, so just
9968c2ecf20Sopenharmony_ci	| write these ones off as "too darn small".
9978c2ecf20Sopenharmony_ci1:	fp_set_sr FPSR_EXC_UNFL		| Set UNFL bit
9988c2ecf20Sopenharmony_ci	clr.l	(%a0)
9998c2ecf20Sopenharmony_ci	clr.l	-(%a0)
10008c2ecf20Sopenharmony_ci	move.w	#0x3f81,-(%a0)		| i.e. 2**-126
10018c2ecf20Sopenharmony_ci	addq.l	#6,%a0
10028c2ecf20Sopenharmony_ci	moveq	#1,%d0
10038c2ecf20Sopenharmony_ci	jra	fp_ns_round		| round.
10048c2ecf20Sopenharmony_ci	| Infinities or NaNs
10058c2ecf20Sopenharmony_cifp_ns_huge:
10068c2ecf20Sopenharmony_ci	subq.l	#4,%a0
10078c2ecf20Sopenharmony_ci	printf	PNORM,"%p(",1,%a0
10088c2ecf20Sopenharmony_ci	printx	PNORM,%a0@
10098c2ecf20Sopenharmony_ci	printf	PNORM,")\n"
10108c2ecf20Sopenharmony_ci	rts
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_ci	| fp_normalize_single_fast:
10138c2ecf20Sopenharmony_ci	| normalize an extended with single (23-bit) precision
10148c2ecf20Sopenharmony_ci	| this is only used by fsgldiv/fsgdlmul, where the
10158c2ecf20Sopenharmony_ci	| operand is not completly normalized.
10168c2ecf20Sopenharmony_ci	| args:	 %a0 (struct fp_ext *)
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_cifp_normalize_single_fast:
10198c2ecf20Sopenharmony_ci	printf	PNORM,"nsf: %p(",1,%a0
10208c2ecf20Sopenharmony_ci	printx	PNORM,%a0@
10218c2ecf20Sopenharmony_ci	printf	PNORM,") "
10228c2ecf20Sopenharmony_ci	addq.l	#2,%a0
10238c2ecf20Sopenharmony_ci	move.w	(%a0)+,%d2
10248c2ecf20Sopenharmony_ci	cmp.w	#0x7fff,%d2
10258c2ecf20Sopenharmony_ci	jeq	fp_nsf_huge		| NaN / infinitive.
10268c2ecf20Sopenharmony_ci	move.l	(%a0)+,%d0		| get high lword of mantissa
10278c2ecf20Sopenharmony_cifp_nsf_round:
10288c2ecf20Sopenharmony_ci	tst.l	(%a0)			| check the low lword
10298c2ecf20Sopenharmony_ci	jeq	1f
10308c2ecf20Sopenharmony_ci	| Set a sticky bit if it is non-zero.  This should only
10318c2ecf20Sopenharmony_ci	| affect the rounding in what would otherwise be equal-
10328c2ecf20Sopenharmony_ci	| distance situations, which is what we want it to do.
10338c2ecf20Sopenharmony_ci	bset	#0,%d0
10348c2ecf20Sopenharmony_ci1:	clr.l	(%a0)			| zap it from memory.
10358c2ecf20Sopenharmony_ci	| now, round off the low 8 bits of the hi lword.
10368c2ecf20Sopenharmony_ci	tst.b	%d0			| 8 low bits.
10378c2ecf20Sopenharmony_ci	jne	fp_nsf_checkround	| Are they non-zero?
10388c2ecf20Sopenharmony_ci	| nothing to do here
10398c2ecf20Sopenharmony_ci	subq.l	#8,%a0
10408c2ecf20Sopenharmony_ci	printf	PNORM,"%p(",1,%a0
10418c2ecf20Sopenharmony_ci	printx	PNORM,%a0@
10428c2ecf20Sopenharmony_ci	printf	PNORM,")\n"
10438c2ecf20Sopenharmony_ci	rts
10448c2ecf20Sopenharmony_cifp_nsf_checkround:
10458c2ecf20Sopenharmony_ci	fp_set_sr FPSR_EXC_INEX2	| INEX2 bit
10468c2ecf20Sopenharmony_ci	clr.b	-(%a0)			| clear low byte of high lword
10478c2ecf20Sopenharmony_ci	subq.l	#3,%a0
10488c2ecf20Sopenharmony_ci	move.w	(FPD_RND,FPDATA),%d2	| rounding mode
10498c2ecf20Sopenharmony_ci	jne	2f			| %d2 == 0, round to nearest
10508c2ecf20Sopenharmony_ci	tst.b	%d0			| test guard bit
10518c2ecf20Sopenharmony_ci	jpl	9f			| zero is closer
10528c2ecf20Sopenharmony_ci	btst	#8,%d0			| test lsb bit
10538c2ecf20Sopenharmony_ci	| round to even behaviour, see above.
10548c2ecf20Sopenharmony_ci	jne	fp_nsf_doroundup		| round to infinity
10558c2ecf20Sopenharmony_ci	lsl.b	#1,%d0			| check low bits
10568c2ecf20Sopenharmony_ci	jeq	9f			| round to zero
10578c2ecf20Sopenharmony_cifp_nsf_doroundup:
10588c2ecf20Sopenharmony_ci	| round (the mantissa, that is) towards infinity
10598c2ecf20Sopenharmony_ci	add.l	#0x100,(%a0)
10608c2ecf20Sopenharmony_ci	jcc	9f			| no overflow, good.
10618c2ecf20Sopenharmony_ci	| Overflow.  This means that the %d1 was 0xffffff00, so it
10628c2ecf20Sopenharmony_ci	| is now zero.  We will set the mantissa to reflect this, and
10638c2ecf20Sopenharmony_ci	| increment the exponent (checking for overflow there too)
10648c2ecf20Sopenharmony_ci	move.w	#0x8000,(%a0)
10658c2ecf20Sopenharmony_ci	addq.w	#1,-(%a0)
10668c2ecf20Sopenharmony_ci	cmp.w	#0x407f,(%a0)+		| exponent now overflown?
10678c2ecf20Sopenharmony_ci	jeq	fp_nsf_large		| yes, so make it infinity.
10688c2ecf20Sopenharmony_ci9:	subq.l	#4,%a0
10698c2ecf20Sopenharmony_ci	printf	PNORM,"%p(",1,%a0
10708c2ecf20Sopenharmony_ci	printx	PNORM,%a0@
10718c2ecf20Sopenharmony_ci	printf	PNORM,")\n"
10728c2ecf20Sopenharmony_ci	rts
10738c2ecf20Sopenharmony_ci	| check nondefault rounding modes
10748c2ecf20Sopenharmony_ci2:	subq.w	#2,%d2
10758c2ecf20Sopenharmony_ci	jcs	9b			| %d2 < 2, round to zero
10768c2ecf20Sopenharmony_ci	jhi	3f			| %d2 > 2, round to +infinity
10778c2ecf20Sopenharmony_ci	tst.b	(-3,%a0)		| to -inf
10788c2ecf20Sopenharmony_ci	jne	fp_nsf_doroundup	| negative, round to infinity
10798c2ecf20Sopenharmony_ci	jra	9b			| positive, round to zero
10808c2ecf20Sopenharmony_ci3:	tst.b	(-3,%a0)		| to +inf
10818c2ecf20Sopenharmony_ci	jeq	fp_nsf_doroundup		| positive, round to infinity
10828c2ecf20Sopenharmony_ci	jra	9b			| negative, round to zero
10838c2ecf20Sopenharmony_ci	| Exponent overflow.  Just call it infinity.
10848c2ecf20Sopenharmony_cifp_nsf_large:
10858c2ecf20Sopenharmony_ci	tst.b	(3,%a0)
10868c2ecf20Sopenharmony_ci	jeq	1f
10878c2ecf20Sopenharmony_ci	fp_set_sr FPSR_EXC_INEX2
10888c2ecf20Sopenharmony_ci1:	fp_set_sr FPSR_EXC_OVFL
10898c2ecf20Sopenharmony_ci	move.w	(FPD_RND,FPDATA),%d2
10908c2ecf20Sopenharmony_ci	jne	3f			| %d2 = 0 round to nearest
10918c2ecf20Sopenharmony_ci1:	move.w	#0x7fff,(-2,%a0)
10928c2ecf20Sopenharmony_ci	clr.l	(%a0)+
10938c2ecf20Sopenharmony_ci	clr.l	(%a0)
10948c2ecf20Sopenharmony_ci2:	subq.l	#8,%a0
10958c2ecf20Sopenharmony_ci	printf	PNORM,"%p(",1,%a0
10968c2ecf20Sopenharmony_ci	printx	PNORM,%a0@
10978c2ecf20Sopenharmony_ci	printf	PNORM,")\n"
10988c2ecf20Sopenharmony_ci	rts
10998c2ecf20Sopenharmony_ci3:	subq.w	#2,%d2
11008c2ecf20Sopenharmony_ci	jcs	5f			| %d2 < 2, round to zero
11018c2ecf20Sopenharmony_ci	jhi	4f			| %d2 > 2, round to +infinity
11028c2ecf20Sopenharmony_ci	tst.b	(-3,%a0)		| to -inf
11038c2ecf20Sopenharmony_ci	jne	1b
11048c2ecf20Sopenharmony_ci	jra	5f
11058c2ecf20Sopenharmony_ci4:	tst.b	(-3,%a0)		| to +inf
11068c2ecf20Sopenharmony_ci	jeq	1b
11078c2ecf20Sopenharmony_ci5:	move.w	#0x407e,(-2,%a0)
11088c2ecf20Sopenharmony_ci	move.l	#0xffffff00,(%a0)+
11098c2ecf20Sopenharmony_ci	clr.l	(%a0)
11108c2ecf20Sopenharmony_ci	jra	2b
11118c2ecf20Sopenharmony_ci	| Infinities or NaNs
11128c2ecf20Sopenharmony_cifp_nsf_huge:
11138c2ecf20Sopenharmony_ci	subq.l	#4,%a0
11148c2ecf20Sopenharmony_ci	printf	PNORM,"%p(",1,%a0
11158c2ecf20Sopenharmony_ci	printx	PNORM,%a0@
11168c2ecf20Sopenharmony_ci	printf	PNORM,")\n"
11178c2ecf20Sopenharmony_ci	rts
11188c2ecf20Sopenharmony_ci
11198c2ecf20Sopenharmony_ci	| conv_ext2int (macro):
11208c2ecf20Sopenharmony_ci	| Generates a subroutine that converts an extended value to an
11218c2ecf20Sopenharmony_ci	| integer of a given size, again, with the appropriate type of
11228c2ecf20Sopenharmony_ci	| rounding.
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_ci	| Macro arguments:
11258c2ecf20Sopenharmony_ci	| s:	size, as given in an assembly instruction.
11268c2ecf20Sopenharmony_ci	| b:	number of bits in that size.
11278c2ecf20Sopenharmony_ci
11288c2ecf20Sopenharmony_ci	| Subroutine arguments:
11298c2ecf20Sopenharmony_ci	| %a0:	source (struct fp_ext *)
11308c2ecf20Sopenharmony_ci
11318c2ecf20Sopenharmony_ci	| Returns the integer in %d0 (like it should)
11328c2ecf20Sopenharmony_ci
11338c2ecf20Sopenharmony_ci.macro conv_ext2int s,b
11348c2ecf20Sopenharmony_ci	.set	inf,(1<<(\b-1))-1	| i.e. MAXINT
11358c2ecf20Sopenharmony_ci	printf	PCONV,"e2i%d: %p(",2,#\b,%a0
11368c2ecf20Sopenharmony_ci	printx	PCONV,%a0@
11378c2ecf20Sopenharmony_ci	printf	PCONV,") "
11388c2ecf20Sopenharmony_ci	addq.l	#2,%a0
11398c2ecf20Sopenharmony_ci	move.w	(%a0)+,%d2		| exponent
11408c2ecf20Sopenharmony_ci	jeq	fp_e2i_zero\b		| zero / denorm (== 0, here)
11418c2ecf20Sopenharmony_ci	cmp.w	#0x7fff,%d2
11428c2ecf20Sopenharmony_ci	jeq	fp_e2i_huge\b		| Inf / NaN
11438c2ecf20Sopenharmony_ci	sub.w	#0x3ffe,%d2
11448c2ecf20Sopenharmony_ci	jcs	fp_e2i_small\b
11458c2ecf20Sopenharmony_ci	cmp.w	#\b,%d2
11468c2ecf20Sopenharmony_ci	jhi	fp_e2i_large\b
11478c2ecf20Sopenharmony_ci	move.l	(%a0),%d0
11488c2ecf20Sopenharmony_ci	move.l	%d0,%d1
11498c2ecf20Sopenharmony_ci	lsl.l	%d2,%d1
11508c2ecf20Sopenharmony_ci	jne	fp_e2i_round\b
11518c2ecf20Sopenharmony_ci	tst.l	(4,%a0)
11528c2ecf20Sopenharmony_ci	jne	fp_e2i_round\b
11538c2ecf20Sopenharmony_ci	neg.w	%d2
11548c2ecf20Sopenharmony_ci	add.w	#32,%d2
11558c2ecf20Sopenharmony_ci	lsr.l	%d2,%d0
11568c2ecf20Sopenharmony_ci9:	tst.w	(-4,%a0)
11578c2ecf20Sopenharmony_ci	jne	1f
11588c2ecf20Sopenharmony_ci	tst.\s	%d0
11598c2ecf20Sopenharmony_ci	jmi	fp_e2i_large\b
11608c2ecf20Sopenharmony_ci	printf	PCONV,"-> %p\n",1,%d0
11618c2ecf20Sopenharmony_ci	rts
11628c2ecf20Sopenharmony_ci1:	neg.\s	%d0
11638c2ecf20Sopenharmony_ci	jeq	1f
11648c2ecf20Sopenharmony_ci	jpl	fp_e2i_large\b
11658c2ecf20Sopenharmony_ci1:	printf	PCONV,"-> %p\n",1,%d0
11668c2ecf20Sopenharmony_ci	rts
11678c2ecf20Sopenharmony_cifp_e2i_round\b:
11688c2ecf20Sopenharmony_ci	fp_set_sr FPSR_EXC_INEX2	| INEX2 bit
11698c2ecf20Sopenharmony_ci	neg.w	%d2
11708c2ecf20Sopenharmony_ci	add.w	#32,%d2
11718c2ecf20Sopenharmony_ci	.if	\b>16
11728c2ecf20Sopenharmony_ci	jeq	5f
11738c2ecf20Sopenharmony_ci	.endif
11748c2ecf20Sopenharmony_ci	lsr.l	%d2,%d0
11758c2ecf20Sopenharmony_ci	move.w	(FPD_RND,FPDATA),%d2	| rounding mode
11768c2ecf20Sopenharmony_ci	jne	2f			| %d2 == 0, round to nearest
11778c2ecf20Sopenharmony_ci	tst.l	%d1			| test guard bit
11788c2ecf20Sopenharmony_ci	jpl	9b			| zero is closer
11798c2ecf20Sopenharmony_ci	btst	%d2,%d0			| test lsb bit (%d2 still 0)
11808c2ecf20Sopenharmony_ci	jne	fp_e2i_doroundup\b
11818c2ecf20Sopenharmony_ci	lsl.l	#1,%d1			| check low bits
11828c2ecf20Sopenharmony_ci	jne	fp_e2i_doroundup\b
11838c2ecf20Sopenharmony_ci	tst.l	(4,%a0)
11848c2ecf20Sopenharmony_ci	jeq	9b
11858c2ecf20Sopenharmony_cifp_e2i_doroundup\b:
11868c2ecf20Sopenharmony_ci	addq.l	#1,%d0
11878c2ecf20Sopenharmony_ci	jra	9b
11888c2ecf20Sopenharmony_ci	| check nondefault rounding modes
11898c2ecf20Sopenharmony_ci2:	subq.w	#2,%d2
11908c2ecf20Sopenharmony_ci	jcs	9b			| %d2 < 2, round to zero
11918c2ecf20Sopenharmony_ci	jhi	3f			| %d2 > 2, round to +infinity
11928c2ecf20Sopenharmony_ci	tst.w	(-4,%a0)		| to -inf
11938c2ecf20Sopenharmony_ci	jne	fp_e2i_doroundup\b	| negative, round to infinity
11948c2ecf20Sopenharmony_ci	jra	9b			| positive, round to zero
11958c2ecf20Sopenharmony_ci3:	tst.w	(-4,%a0)		| to +inf
11968c2ecf20Sopenharmony_ci	jeq	fp_e2i_doroundup\b	| positive, round to infinity
11978c2ecf20Sopenharmony_ci	jra	9b	| negative, round to zero
11988c2ecf20Sopenharmony_ci	| we are only want -2**127 get correctly rounded here,
11998c2ecf20Sopenharmony_ci	| since the guard bit is in the lower lword.
12008c2ecf20Sopenharmony_ci	| everything else ends up anyway as overflow.
12018c2ecf20Sopenharmony_ci	.if	\b>16
12028c2ecf20Sopenharmony_ci5:	move.w	(FPD_RND,FPDATA),%d2	| rounding mode
12038c2ecf20Sopenharmony_ci	jne	2b			| %d2 == 0, round to nearest
12048c2ecf20Sopenharmony_ci	move.l	(4,%a0),%d1		| test guard bit
12058c2ecf20Sopenharmony_ci	jpl	9b			| zero is closer
12068c2ecf20Sopenharmony_ci	lsl.l	#1,%d1			| check low bits
12078c2ecf20Sopenharmony_ci	jne	fp_e2i_doroundup\b
12088c2ecf20Sopenharmony_ci	jra	9b
12098c2ecf20Sopenharmony_ci	.endif
12108c2ecf20Sopenharmony_cifp_e2i_zero\b:
12118c2ecf20Sopenharmony_ci	clr.l	%d0
12128c2ecf20Sopenharmony_ci	tst.l	(%a0)+
12138c2ecf20Sopenharmony_ci	jne	1f
12148c2ecf20Sopenharmony_ci	tst.l	(%a0)
12158c2ecf20Sopenharmony_ci	jeq	3f
12168c2ecf20Sopenharmony_ci1:	subq.l	#4,%a0
12178c2ecf20Sopenharmony_ci	fp_clr_sr FPSR_EXC_UNFL		| fp_normalize_ext has set this bit
12188c2ecf20Sopenharmony_cifp_e2i_small\b:
12198c2ecf20Sopenharmony_ci	fp_set_sr FPSR_EXC_INEX2
12208c2ecf20Sopenharmony_ci	clr.l	%d0
12218c2ecf20Sopenharmony_ci	move.w	(FPD_RND,FPDATA),%d2	| rounding mode
12228c2ecf20Sopenharmony_ci	subq.w	#2,%d2
12238c2ecf20Sopenharmony_ci	jcs	3f			| %d2 < 2, round to nearest/zero
12248c2ecf20Sopenharmony_ci	jhi	2f			| %d2 > 2, round to +infinity
12258c2ecf20Sopenharmony_ci	tst.w	(-4,%a0)		| to -inf
12268c2ecf20Sopenharmony_ci	jeq	3f
12278c2ecf20Sopenharmony_ci	subq.\s	#1,%d0
12288c2ecf20Sopenharmony_ci	jra	3f
12298c2ecf20Sopenharmony_ci2:	tst.w	(-4,%a0)		| to +inf
12308c2ecf20Sopenharmony_ci	jne	3f
12318c2ecf20Sopenharmony_ci	addq.\s	#1,%d0
12328c2ecf20Sopenharmony_ci3:	printf	PCONV,"-> %p\n",1,%d0
12338c2ecf20Sopenharmony_ci	rts
12348c2ecf20Sopenharmony_cifp_e2i_large\b:
12358c2ecf20Sopenharmony_ci	fp_set_sr FPSR_EXC_OPERR
12368c2ecf20Sopenharmony_ci	move.\s	#inf,%d0
12378c2ecf20Sopenharmony_ci	tst.w	(-4,%a0)
12388c2ecf20Sopenharmony_ci	jeq	1f
12398c2ecf20Sopenharmony_ci	addq.\s	#1,%d0
12408c2ecf20Sopenharmony_ci1:	printf	PCONV,"-> %p\n",1,%d0
12418c2ecf20Sopenharmony_ci	rts
12428c2ecf20Sopenharmony_cifp_e2i_huge\b:
12438c2ecf20Sopenharmony_ci	move.\s	(%a0),%d0
12448c2ecf20Sopenharmony_ci	tst.l	(%a0)
12458c2ecf20Sopenharmony_ci	jne	1f
12468c2ecf20Sopenharmony_ci	tst.l	(%a0)
12478c2ecf20Sopenharmony_ci	jeq	fp_e2i_large\b
12488c2ecf20Sopenharmony_ci	| fp_normalize_ext has set this bit already
12498c2ecf20Sopenharmony_ci	| and made the number nonsignaling
12508c2ecf20Sopenharmony_ci1:	fp_tst_sr FPSR_EXC_SNAN
12518c2ecf20Sopenharmony_ci	jne	1f
12528c2ecf20Sopenharmony_ci	fp_set_sr FPSR_EXC_OPERR
12538c2ecf20Sopenharmony_ci1:	printf	PCONV,"-> %p\n",1,%d0
12548c2ecf20Sopenharmony_ci	rts
12558c2ecf20Sopenharmony_ci.endm
12568c2ecf20Sopenharmony_ci
12578c2ecf20Sopenharmony_cifp_conv_ext2long:
12588c2ecf20Sopenharmony_ci	conv_ext2int l,32
12598c2ecf20Sopenharmony_ci
12608c2ecf20Sopenharmony_cifp_conv_ext2short:
12618c2ecf20Sopenharmony_ci	conv_ext2int w,16
12628c2ecf20Sopenharmony_ci
12638c2ecf20Sopenharmony_cifp_conv_ext2byte:
12648c2ecf20Sopenharmony_ci	conv_ext2int b,8
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_cifp_conv_ext2double:
12678c2ecf20Sopenharmony_ci	jsr	fp_normalize_double
12688c2ecf20Sopenharmony_ci	printf	PCONV,"e2d: %p(",1,%a0
12698c2ecf20Sopenharmony_ci	printx	PCONV,%a0@
12708c2ecf20Sopenharmony_ci	printf	PCONV,"), "
12718c2ecf20Sopenharmony_ci	move.l	(%a0)+,%d2
12728c2ecf20Sopenharmony_ci	cmp.w	#0x7fff,%d2
12738c2ecf20Sopenharmony_ci	jne	1f
12748c2ecf20Sopenharmony_ci	move.w	#0x7ff,%d2
12758c2ecf20Sopenharmony_ci	move.l	(%a0)+,%d0
12768c2ecf20Sopenharmony_ci	jra	2f
12778c2ecf20Sopenharmony_ci1:	sub.w	#0x3fff-0x3ff,%d2
12788c2ecf20Sopenharmony_ci	move.l	(%a0)+,%d0
12798c2ecf20Sopenharmony_ci	jmi	2f
12808c2ecf20Sopenharmony_ci	clr.w	%d2
12818c2ecf20Sopenharmony_ci2:	lsl.w	#5,%d2
12828c2ecf20Sopenharmony_ci	lsl.l	#7,%d2
12838c2ecf20Sopenharmony_ci	lsl.l	#8,%d2
12848c2ecf20Sopenharmony_ci	move.l	%d0,%d1
12858c2ecf20Sopenharmony_ci	lsl.l	#1,%d0
12868c2ecf20Sopenharmony_ci	lsr.l	#4,%d0
12878c2ecf20Sopenharmony_ci	lsr.l	#8,%d0
12888c2ecf20Sopenharmony_ci	or.l	%d2,%d0
12898c2ecf20Sopenharmony_ci	putuser.l %d0,(%a1)+,fp_err_ua2,%a1
12908c2ecf20Sopenharmony_ci	moveq	#21,%d0
12918c2ecf20Sopenharmony_ci	lsl.l	%d0,%d1
12928c2ecf20Sopenharmony_ci	move.l	(%a0),%d0
12938c2ecf20Sopenharmony_ci	lsr.l	#4,%d0
12948c2ecf20Sopenharmony_ci	lsr.l	#7,%d0
12958c2ecf20Sopenharmony_ci	or.l	%d1,%d0
12968c2ecf20Sopenharmony_ci	putuser.l %d0,(%a1),fp_err_ua2,%a1
12978c2ecf20Sopenharmony_ci#ifdef FPU_EMU_DEBUG
12988c2ecf20Sopenharmony_ci	getuser.l %a1@(-4),%d0,fp_err_ua2,%a1
12998c2ecf20Sopenharmony_ci	getuser.l %a1@(0),%d1,fp_err_ua2,%a1
13008c2ecf20Sopenharmony_ci	printf	PCONV,"%p(%08x%08x)\n",3,%a1,%d0,%d1
13018c2ecf20Sopenharmony_ci#endif
13028c2ecf20Sopenharmony_ci	rts
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_cifp_conv_ext2single:
13058c2ecf20Sopenharmony_ci	jsr	fp_normalize_single
13068c2ecf20Sopenharmony_ci	printf	PCONV,"e2s: %p(",1,%a0
13078c2ecf20Sopenharmony_ci	printx	PCONV,%a0@
13088c2ecf20Sopenharmony_ci	printf	PCONV,"), "
13098c2ecf20Sopenharmony_ci	move.l	(%a0)+,%d1
13108c2ecf20Sopenharmony_ci	cmp.w	#0x7fff,%d1
13118c2ecf20Sopenharmony_ci	jne	1f
13128c2ecf20Sopenharmony_ci	move.w	#0xff,%d1
13138c2ecf20Sopenharmony_ci	move.l	(%a0)+,%d0
13148c2ecf20Sopenharmony_ci	jra	2f
13158c2ecf20Sopenharmony_ci1:	sub.w	#0x3fff-0x7f,%d1
13168c2ecf20Sopenharmony_ci	move.l	(%a0)+,%d0
13178c2ecf20Sopenharmony_ci	jmi	2f
13188c2ecf20Sopenharmony_ci	clr.w	%d1
13198c2ecf20Sopenharmony_ci2:	lsl.w	#8,%d1
13208c2ecf20Sopenharmony_ci	lsl.l	#7,%d1
13218c2ecf20Sopenharmony_ci	lsl.l	#8,%d1
13228c2ecf20Sopenharmony_ci	bclr	#31,%d0
13238c2ecf20Sopenharmony_ci	lsr.l	#8,%d0
13248c2ecf20Sopenharmony_ci	or.l	%d1,%d0
13258c2ecf20Sopenharmony_ci	printf	PCONV,"%08x\n",1,%d0
13268c2ecf20Sopenharmony_ci	rts
13278c2ecf20Sopenharmony_ci
13288c2ecf20Sopenharmony_ci	| special return addresses for instr that
13298c2ecf20Sopenharmony_ci	| encode the rounding precision in the opcode
13308c2ecf20Sopenharmony_ci	| (e.g. fsmove,fdmove)
13318c2ecf20Sopenharmony_ci
13328c2ecf20Sopenharmony_cifp_finalrounding_single:
13338c2ecf20Sopenharmony_ci	addq.l	#8,%sp
13348c2ecf20Sopenharmony_ci	jsr	fp_normalize_ext
13358c2ecf20Sopenharmony_ci	jsr	fp_normalize_single
13368c2ecf20Sopenharmony_ci	jra	fp_finaltest
13378c2ecf20Sopenharmony_ci
13388c2ecf20Sopenharmony_cifp_finalrounding_single_fast:
13398c2ecf20Sopenharmony_ci	addq.l	#8,%sp
13408c2ecf20Sopenharmony_ci	jsr	fp_normalize_ext
13418c2ecf20Sopenharmony_ci	jsr	fp_normalize_single_fast
13428c2ecf20Sopenharmony_ci	jra	fp_finaltest
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_cifp_finalrounding_double:
13458c2ecf20Sopenharmony_ci	addq.l	#8,%sp
13468c2ecf20Sopenharmony_ci	jsr	fp_normalize_ext
13478c2ecf20Sopenharmony_ci	jsr	fp_normalize_double
13488c2ecf20Sopenharmony_ci	jra	fp_finaltest
13498c2ecf20Sopenharmony_ci
13508c2ecf20Sopenharmony_ci	| fp_finaltest:
13518c2ecf20Sopenharmony_ci	| set the emulated status register based on the outcome of an
13528c2ecf20Sopenharmony_ci	| emulated instruction.
13538c2ecf20Sopenharmony_ci
13548c2ecf20Sopenharmony_cifp_finalrounding:
13558c2ecf20Sopenharmony_ci	addq.l	#8,%sp
13568c2ecf20Sopenharmony_ci|	printf	,"f: %p\n",1,%a0
13578c2ecf20Sopenharmony_ci	jsr	fp_normalize_ext
13588c2ecf20Sopenharmony_ci	move.w	(FPD_PREC,FPDATA),%d0
13598c2ecf20Sopenharmony_ci	subq.w	#1,%d0
13608c2ecf20Sopenharmony_ci	jcs	fp_finaltest
13618c2ecf20Sopenharmony_ci	jne	1f
13628c2ecf20Sopenharmony_ci	jsr	fp_normalize_single
13638c2ecf20Sopenharmony_ci	jra	2f
13648c2ecf20Sopenharmony_ci1:	jsr	fp_normalize_double
13658c2ecf20Sopenharmony_ci2:|	printf	,"f: %p\n",1,%a0
13668c2ecf20Sopenharmony_cifp_finaltest:
13678c2ecf20Sopenharmony_ci	| First, we do some of the obvious tests for the exception
13688c2ecf20Sopenharmony_ci	| status byte and condition code bytes of fp_sr here, so that
13698c2ecf20Sopenharmony_ci	| they do not have to be handled individually by every
13708c2ecf20Sopenharmony_ci	| emulated instruction.
13718c2ecf20Sopenharmony_ci	clr.l	%d0
13728c2ecf20Sopenharmony_ci	addq.l	#1,%a0
13738c2ecf20Sopenharmony_ci	tst.b	(%a0)+			| sign
13748c2ecf20Sopenharmony_ci	jeq	1f
13758c2ecf20Sopenharmony_ci	bset	#FPSR_CC_NEG-24,%d0	| N bit
13768c2ecf20Sopenharmony_ci1:	cmp.w	#0x7fff,(%a0)+		| exponent
13778c2ecf20Sopenharmony_ci	jeq	2f
13788c2ecf20Sopenharmony_ci	| test for zero
13798c2ecf20Sopenharmony_ci	moveq	#FPSR_CC_Z-24,%d1
13808c2ecf20Sopenharmony_ci	tst.l	(%a0)+
13818c2ecf20Sopenharmony_ci	jne	9f
13828c2ecf20Sopenharmony_ci	tst.l	(%a0)
13838c2ecf20Sopenharmony_ci	jne	9f
13848c2ecf20Sopenharmony_ci	jra	8f
13858c2ecf20Sopenharmony_ci	| infinitiv and NAN
13868c2ecf20Sopenharmony_ci2:	moveq	#FPSR_CC_NAN-24,%d1
13878c2ecf20Sopenharmony_ci	move.l	(%a0)+,%d2
13888c2ecf20Sopenharmony_ci	lsl.l	#1,%d2			| ignore high bit
13898c2ecf20Sopenharmony_ci	jne	8f
13908c2ecf20Sopenharmony_ci	tst.l	(%a0)
13918c2ecf20Sopenharmony_ci	jne	8f
13928c2ecf20Sopenharmony_ci	moveq	#FPSR_CC_INF-24,%d1
13938c2ecf20Sopenharmony_ci8:	bset	%d1,%d0
13948c2ecf20Sopenharmony_ci9:	move.b	%d0,(FPD_FPSR+0,FPDATA)	| set condition test result
13958c2ecf20Sopenharmony_ci	| move instructions enter here
13968c2ecf20Sopenharmony_ci	| Here, we test things in the exception status byte, and set
13978c2ecf20Sopenharmony_ci	| other things in the accrued exception byte accordingly.
13988c2ecf20Sopenharmony_ci	| Emulated instructions can set various things in the former,
13998c2ecf20Sopenharmony_ci	| as defined in fp_emu.h.
14008c2ecf20Sopenharmony_cifp_final:
14018c2ecf20Sopenharmony_ci	move.l	(FPD_FPSR,FPDATA),%d0
14028c2ecf20Sopenharmony_ci#if 0
14038c2ecf20Sopenharmony_ci	btst	#FPSR_EXC_SNAN,%d0	| EXC_SNAN
14048c2ecf20Sopenharmony_ci	jne	1f
14058c2ecf20Sopenharmony_ci	btst	#FPSR_EXC_OPERR,%d0	| EXC_OPERR
14068c2ecf20Sopenharmony_ci	jeq	2f
14078c2ecf20Sopenharmony_ci1:	bset	#FPSR_AEXC_IOP,%d0	| set IOP bit
14088c2ecf20Sopenharmony_ci2:	btst	#FPSR_EXC_OVFL,%d0	| EXC_OVFL
14098c2ecf20Sopenharmony_ci	jeq	1f
14108c2ecf20Sopenharmony_ci	bset	#FPSR_AEXC_OVFL,%d0	| set OVFL bit
14118c2ecf20Sopenharmony_ci1:	btst	#FPSR_EXC_UNFL,%d0	| EXC_UNFL
14128c2ecf20Sopenharmony_ci	jeq	1f
14138c2ecf20Sopenharmony_ci	btst	#FPSR_EXC_INEX2,%d0	| EXC_INEX2
14148c2ecf20Sopenharmony_ci	jeq	1f
14158c2ecf20Sopenharmony_ci	bset	#FPSR_AEXC_UNFL,%d0	| set UNFL bit
14168c2ecf20Sopenharmony_ci1:	btst	#FPSR_EXC_DZ,%d0	| EXC_INEX1
14178c2ecf20Sopenharmony_ci	jeq	1f
14188c2ecf20Sopenharmony_ci	bset	#FPSR_AEXC_DZ,%d0	| set DZ bit
14198c2ecf20Sopenharmony_ci1:	btst	#FPSR_EXC_OVFL,%d0	| EXC_OVFL
14208c2ecf20Sopenharmony_ci	jne	1f
14218c2ecf20Sopenharmony_ci	btst	#FPSR_EXC_INEX2,%d0	| EXC_INEX2
14228c2ecf20Sopenharmony_ci	jne	1f
14238c2ecf20Sopenharmony_ci	btst	#FPSR_EXC_INEX1,%d0	| EXC_INEX1
14248c2ecf20Sopenharmony_ci	jeq	2f
14258c2ecf20Sopenharmony_ci1:	bset	#FPSR_AEXC_INEX,%d0	| set INEX bit
14268c2ecf20Sopenharmony_ci2:	move.l	%d0,(FPD_FPSR,FPDATA)
14278c2ecf20Sopenharmony_ci#else
14288c2ecf20Sopenharmony_ci	| same as above, greatly optimized, but untested (yet)
14298c2ecf20Sopenharmony_ci	move.l	%d0,%d2
14308c2ecf20Sopenharmony_ci	lsr.l	#5,%d0
14318c2ecf20Sopenharmony_ci	move.l	%d0,%d1
14328c2ecf20Sopenharmony_ci	lsr.l	#4,%d1
14338c2ecf20Sopenharmony_ci	or.l	%d0,%d1
14348c2ecf20Sopenharmony_ci	and.b	#0x08,%d1
14358c2ecf20Sopenharmony_ci	move.l	%d2,%d0
14368c2ecf20Sopenharmony_ci	lsr.l	#6,%d0
14378c2ecf20Sopenharmony_ci	or.l	%d1,%d0
14388c2ecf20Sopenharmony_ci	move.l	%d2,%d1
14398c2ecf20Sopenharmony_ci	lsr.l	#4,%d1
14408c2ecf20Sopenharmony_ci	or.b	#0xdf,%d1
14418c2ecf20Sopenharmony_ci	and.b	%d1,%d0
14428c2ecf20Sopenharmony_ci	move.l	%d2,%d1
14438c2ecf20Sopenharmony_ci	lsr.l	#7,%d1
14448c2ecf20Sopenharmony_ci	and.b	#0x80,%d1
14458c2ecf20Sopenharmony_ci	or.b	%d1,%d0
14468c2ecf20Sopenharmony_ci	and.b	#0xf8,%d0
14478c2ecf20Sopenharmony_ci	or.b	%d0,%d2
14488c2ecf20Sopenharmony_ci	move.l	%d2,(FPD_FPSR,FPDATA)
14498c2ecf20Sopenharmony_ci#endif
14508c2ecf20Sopenharmony_ci	move.b	(FPD_FPSR+2,FPDATA),%d0
14518c2ecf20Sopenharmony_ci	and.b	(FPD_FPCR+2,FPDATA),%d0
14528c2ecf20Sopenharmony_ci	jeq	1f
14538c2ecf20Sopenharmony_ci	printf	,"send signal!!!\n"
14548c2ecf20Sopenharmony_ci1:	jra	fp_end
1455