PageRenderTime 62ms CodeModel.GetById 10ms app.highlight 42ms RepoModel.GetById 1ms app.codeStats 1ms

/arch/m68k/math-emu/fp_util.S

https://bitbucket.org/evzijst/gittest
Assembly | 1455 lines | 1425 code | 30 blank | 0 comment | 32 complexity | 9f8f6f7f66708f044745bf6a15518cef MD5 | raw file
   1/*
   2 * fp_util.S
   3 *
   4 * Copyright Roman Zippel, 1997.  All rights reserved.
   5 *
   6 * Redistribution and use in source and binary forms, with or without
   7 * modification, are permitted provided that the following conditions
   8 * are met:
   9 * 1. Redistributions of source code must retain the above copyright
  10 *    notice, and the entire permission notice in its entirety,
  11 *    including the disclaimer of warranties.
  12 * 2. Redistributions in binary form must reproduce the above copyright
  13 *    notice, this list of conditions and the following disclaimer in the
  14 *    documentation and/or other materials provided with the distribution.
  15 * 3. The name of the author may not be used to endorse or promote
  16 *    products derived from this software without specific prior
  17 *    written permission.
  18 *
  19 * ALTERNATIVELY, this product may be distributed under the terms of
  20 * the GNU General Public License, in which case the provisions of the GPL are
  21 * required INSTEAD OF the above restrictions.  (This clause is
  22 * necessary due to a potential bad interaction between the GPL and
  23 * the restrictions contained in a BSD-style copyright.)
  24 *
  25 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
  26 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  27 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  28 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
  29 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  33 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  35 * OF THE POSSIBILITY OF SUCH DAMAGE.
  36 */
  37
  38#include <linux/config.h>
  39#include "fp_emu.h"
  40
  41/*
  42 * Here are lots of conversion and normalization functions mainly
  43 * used by fp_scan.S
  44 * Note that these functions are optimized for "normal" numbers,
  45 * these are handled first and exit as fast as possible, this is
  46 * especially important for fp_normalize_ext/fp_conv_ext2ext, as
  47 * it's called very often.
  48 * The register usage is optimized for fp_scan.S and which register
  49 * is currently at that time unused, be careful if you want change
  50 * something here. %d0 and %d1 is always usable, sometimes %d2 (or
  51 * only the lower half) most function have to return the %a0
  52 * unmodified, so that the caller can immediately reuse it.
  53 */
  54
  55	.globl	fp_ill, fp_end
  56
  57	| exits from fp_scan:
  58	| illegal instruction
  59fp_ill:
  60	printf	,"fp_illegal\n"
  61	rts
  62	| completed instruction
  63fp_end:
  64	tst.l	(TASK_MM-8,%a2)
  65	jmi	1f
  66	tst.l	(TASK_MM-4,%a2)
  67	jmi	1f
  68	tst.l	(TASK_MM,%a2)
  69	jpl	2f
  701:	printf	,"oops:%p,%p,%p\n",3,%a2@(TASK_MM-8),%a2@(TASK_MM-4),%a2@(TASK_MM)
  712:	clr.l	%d0
  72	rts
  73
  74	.globl	fp_conv_long2ext, fp_conv_single2ext
  75	.globl	fp_conv_double2ext, fp_conv_ext2ext
  76	.globl	fp_normalize_ext, fp_normalize_double
  77	.globl	fp_normalize_single, fp_normalize_single_fast
  78	.globl	fp_conv_ext2double, fp_conv_ext2single
  79	.globl	fp_conv_ext2long, fp_conv_ext2short
  80	.globl	fp_conv_ext2byte
  81	.globl	fp_finalrounding_single, fp_finalrounding_single_fast
  82	.globl	fp_finalrounding_double
  83	.globl	fp_finalrounding, fp_finaltest, fp_final
  84
  85/*
  86 * First several conversion functions from a source operand
  87 * into the extended format. Note, that only fp_conv_ext2ext
  88 * normalizes the number and is always called after the other
  89 * conversion functions, which only move the information into
  90 * fp_ext structure.
  91 */
  92
  93	| fp_conv_long2ext:
  94	|
  95	| args:	%d0 = source (32-bit long)
  96	|	%a0 = destination (ptr to struct fp_ext)
  97
  98fp_conv_long2ext:
  99	printf	PCONV,"l2e: %p -> %p(",2,%d0,%a0
 100	clr.l	%d1			| sign defaults to zero
 101	tst.l	%d0
 102	jeq	fp_l2e_zero		| is source zero?
 103	jpl	1f			| positive?
 104	moveq	#1,%d1
 105	neg.l	%d0
 1061:	swap	%d1
 107	move.w	#0x3fff+31,%d1
 108	move.l	%d1,(%a0)+		| set sign / exp
 109	move.l	%d0,(%a0)+		| set mantissa
 110	clr.l	(%a0)
 111	subq.l	#8,%a0			| restore %a0
 112	printx	PCONV,%a0@
 113	printf	PCONV,")\n"
 114	rts
 115	| source is zero
 116fp_l2e_zero:
 117	clr.l	(%a0)+
 118	clr.l	(%a0)+
 119	clr.l	(%a0)
 120	subq.l	#8,%a0
 121	printx	PCONV,%a0@
 122	printf	PCONV,")\n"
 123	rts
 124
 125	| fp_conv_single2ext
 126	| args:	%d0 = source (single-precision fp value)
 127	|	%a0 = dest (struct fp_ext *)
 128
 129fp_conv_single2ext:
 130	printf	PCONV,"s2e: %p -> %p(",2,%d0,%a0
 131	move.l	%d0,%d1
 132	lsl.l	#8,%d0			| shift mantissa
 133	lsr.l	#8,%d1			| exponent / sign
 134	lsr.l	#7,%d1
 135	lsr.w	#8,%d1
 136	jeq	fp_s2e_small		| zero / denormal?
 137	cmp.w	#0xff,%d1		| NaN / Inf?
 138	jeq	fp_s2e_large
 139	bset	#31,%d0			| set explizit bit
 140	add.w	#0x3fff-0x7f,%d1	| re-bias the exponent.
 1419:	move.l	%d1,(%a0)+		| fp_ext.sign, fp_ext.exp
 142	move.l	%d0,(%a0)+		| high lword of fp_ext.mant
 143	clr.l	(%a0)			| low lword = 0
 144	subq.l	#8,%a0
 145	printx	PCONV,%a0@
 146	printf	PCONV,")\n"
 147	rts
 148	| zeros and denormalized
 149fp_s2e_small:
 150	| exponent is zero, so explizit bit is already zero too
 151	tst.l	%d0
 152	jeq	9b
 153	move.w	#0x4000-0x7f,%d1
 154	jra	9b
 155	| infinities and NAN
 156fp_s2e_large:
 157	bclr	#31,%d0			| clear explizit bit
 158	move.w	#0x7fff,%d1
 159	jra	9b
 160
 161fp_conv_double2ext:
 162#ifdef FPU_EMU_DEBUG
 163	getuser.l %a1@(0),%d0,fp_err_ua2,%a1
 164	getuser.l %a1@(4),%d1,fp_err_ua2,%a1
 165	printf	PCONV,"d2e: %p%p -> %p(",3,%d0,%d1,%a0
 166#endif
 167	getuser.l (%a1)+,%d0,fp_err_ua2,%a1
 168	move.l	%d0,%d1
 169	lsl.l	#8,%d0			| shift high mantissa
 170	lsl.l	#3,%d0
 171	lsr.l	#8,%d1			| exponent / sign
 172	lsr.l	#7,%d1
 173	lsr.w	#5,%d1
 174	jeq	fp_d2e_small		| zero / denormal?
 175	cmp.w	#0x7ff,%d1		| NaN / Inf?
 176	jeq	fp_d2e_large
 177	bset	#31,%d0			| set explizit bit
 178	add.w	#0x3fff-0x3ff,%d1	| re-bias the exponent.
 1799:	move.l	%d1,(%a0)+		| fp_ext.sign, fp_ext.exp
 180	move.l	%d0,(%a0)+
 181	getuser.l (%a1)+,%d0,fp_err_ua2,%a1
 182	move.l	%d0,%d1
 183	lsl.l	#8,%d0
 184	lsl.l	#3,%d0
 185	move.l	%d0,(%a0)
 186	moveq	#21,%d0
 187	lsr.l	%d0,%d1
 188	or.l	%d1,-(%a0)
 189	subq.l	#4,%a0
 190	printx	PCONV,%a0@
 191	printf	PCONV,")\n"
 192	rts
 193	| zeros and denormalized
 194fp_d2e_small:
 195	| exponent is zero, so explizit bit is already zero too
 196	tst.l	%d0
 197	jeq	9b
 198	move.w	#0x4000-0x3ff,%d1
 199	jra	9b
 200	| infinities and NAN
 201fp_d2e_large:
 202	bclr	#31,%d0			| clear explizit bit
 203	move.w	#0x7fff,%d1
 204	jra	9b
 205
 206	| fp_conv_ext2ext:
 207	| originally used to get longdouble from userspace, now it's
 208	| called before arithmetic operations to make sure the number
 209	| is normalized [maybe rename it?].
 210	| args:	%a0 = dest (struct fp_ext *)
 211	| returns 0 in %d0 for a NaN, otherwise 1
 212
 213fp_conv_ext2ext:
 214	printf	PCONV,"e2e: %p(",1,%a0
 215	printx	PCONV,%a0@
 216	printf	PCONV,"), "
 217	move.l	(%a0)+,%d0
 218	cmp.w	#0x7fff,%d0		| Inf / NaN?
 219	jeq	fp_e2e_large
 220	move.l	(%a0),%d0
 221	jpl	fp_e2e_small		| zero / denorm?
 222	| The high bit is set, so normalization is irrelevant.
 223fp_e2e_checkround:
 224	subq.l	#4,%a0
 225#ifdef CONFIG_M68KFPU_EMU_EXTRAPREC
 226	move.b	(%a0),%d0
 227	jne	fp_e2e_round
 228#endif
 229	printf	PCONV,"%p(",1,%a0
 230	printx	PCONV,%a0@
 231	printf	PCONV,")\n"
 232	moveq	#1,%d0
 233	rts
 234#ifdef CONFIG_M68KFPU_EMU_EXTRAPREC
 235fp_e2e_round:
 236	fp_set_sr FPSR_EXC_INEX2
 237	clr.b	(%a0)
 238	move.w	(FPD_RND,FPDATA),%d2
 239	jne	fp_e2e_roundother	| %d2 == 0, round to nearest
 240	tst.b	%d0			| test guard bit
 241	jpl	9f			| zero is closer
 242	btst	#0,(11,%a0)		| test lsb bit
 243	jne	fp_e2e_doroundup	| round to infinity
 244	lsl.b	#1,%d0			| check low bits
 245	jeq	9f			| round to zero
 246fp_e2e_doroundup:
 247	addq.l	#1,(8,%a0)
 248	jcc	9f
 249	addq.l	#1,(4,%a0)
 250	jcc	9f
 251	move.w	#0x8000,(4,%a0)
 252	addq.w	#1,(2,%a0)
 2539:	printf	PNORM,"%p(",1,%a0
 254	printx	PNORM,%a0@
 255	printf	PNORM,")\n"
 256	rts
 257fp_e2e_roundother:
 258	subq.w	#2,%d2
 259	jcs	9b			| %d2 < 2, round to zero
 260	jhi	1f			| %d2 > 2, round to +infinity
 261	tst.b	(1,%a0)			| to -inf
 262	jne	fp_e2e_doroundup	| negative, round to infinity
 263	jra	9b			| positive, round to zero
 2641:	tst.b	(1,%a0)			| to +inf
 265	jeq	fp_e2e_doroundup	| positive, round to infinity
 266	jra	9b			| negative, round to zero
 267#endif
 268	| zeros and subnormals:
 269	| try to normalize these anyway.
 270fp_e2e_small:
 271	jne	fp_e2e_small1		| high lword zero?
 272	move.l	(4,%a0),%d0
 273	jne	fp_e2e_small2
 274#ifdef CONFIG_M68KFPU_EMU_EXTRAPREC
 275	clr.l	%d0
 276	move.b	(-4,%a0),%d0
 277	jne	fp_e2e_small3
 278#endif
 279	| Genuine zero.
 280	clr.w	-(%a0)
 281	subq.l	#2,%a0
 282	printf	PNORM,"%p(",1,%a0
 283	printx	PNORM,%a0@
 284	printf	PNORM,")\n"
 285	moveq	#1,%d0
 286	rts
 287	| definitely subnormal, need to shift all 64 bits
 288fp_e2e_small1:
 289	bfffo	%d0{#0,#32},%d1
 290	move.w	-(%a0),%d2
 291	sub.w	%d1,%d2
 292	jcc	1f
 293	| Pathologically small, denormalize.
 294	add.w	%d2,%d1
 295	clr.w	%d2
 2961:	move.w	%d2,(%a0)+
 297	move.w	%d1,%d2
 298	jeq	fp_e2e_checkround
 299	| fancy 64-bit double-shift begins here
 300	lsl.l	%d2,%d0
 301	move.l	%d0,(%a0)+
 302	move.l	(%a0),%d0
 303	move.l	%d0,%d1
 304	lsl.l	%d2,%d0
 305	move.l	%d0,(%a0)
 306	neg.w	%d2
 307	and.w	#0x1f,%d2
 308	lsr.l	%d2,%d1
 309	or.l	%d1,-(%a0)
 310#ifdef CONFIG_M68KFPU_EMU_EXTRAPREC
 311fp_e2e_extra1:
 312	clr.l	%d0
 313	move.b	(-4,%a0),%d0
 314	neg.w	%d2
 315	add.w	#24,%d2
 316	jcc	1f
 317	clr.b	(-4,%a0)
 318	lsl.l	%d2,%d0
 319	or.l	%d0,(4,%a0)
 320	jra	fp_e2e_checkround
 3211:	addq.w	#8,%d2
 322	lsl.l	%d2,%d0
 323	move.b	%d0,(-4,%a0)
 324	lsr.l	#8,%d0
 325	or.l	%d0,(4,%a0)
 326#endif
 327	jra	fp_e2e_checkround
 328	| pathologically small subnormal
 329fp_e2e_small2:
 330	bfffo	%d0{#0,#32},%d1
 331	add.w	#32,%d1
 332	move.w	-(%a0),%d2
 333	sub.w	%d1,%d2
 334	jcc	1f
 335	| Beyond pathologically small, denormalize.
 336	add.w	%d2,%d1
 337	clr.w	%d2
 3381:	move.w	%d2,(%a0)+
 339	ext.l	%d1
 340	jeq	fp_e2e_checkround
 341	clr.l	(4,%a0)
 342	sub.w	#32,%d2
 343	jcs	1f
 344	lsl.l	%d1,%d0			| lower lword needs only to be shifted
 345	move.l	%d0,(%a0)		| into the higher lword
 346#ifdef CONFIG_M68KFPU_EMU_EXTRAPREC
 347	clr.l	%d0
 348	move.b	(-4,%a0),%d0
 349	clr.b	(-4,%a0)
 350	neg.w	%d1
 351	add.w	#32,%d1
 352	bfins	%d0,(%a0){%d1,#8}
 353#endif
 354	jra	fp_e2e_checkround
 3551:	neg.w	%d1			| lower lword is splitted between
 356	bfins	%d0,(%a0){%d1,#32}	| higher and lower lword
 357#ifndef CONFIG_M68KFPU_EMU_EXTRAPREC
 358	jra	fp_e2e_checkround
 359#else
 360	move.w	%d1,%d2
 361	jra	fp_e2e_extra1
 362	| These are extremely small numbers, that will mostly end up as zero
 363	| anyway, so this is only important for correct rounding.
 364fp_e2e_small3:
 365	bfffo	%d0{#24,#8},%d1
 366	add.w	#40,%d1
 367	move.w	-(%a0),%d2
 368	sub.w	%d1,%d2
 369	jcc	1f
 370	| Pathologically small, denormalize.
 371	add.w	%d2,%d1
 372	clr.w	%d2
 3731:	move.w	%d2,(%a0)+
 374	ext.l	%d1
 375	jeq	fp_e2e_checkround
 376	cmp.w	#8,%d1
 377	jcs	2f
 3781:	clr.b	(-4,%a0)
 379	sub.w	#64,%d1
 380	jcs	1f
 381	add.w	#24,%d1
 382	lsl.l	%d1,%d0
 383	move.l	%d0,(%a0)
 384	jra	fp_e2e_checkround
 3851:	neg.w	%d1
 386	bfins	%d0,(%a0){%d1,#8}
 387	jra	fp_e2e_checkround
 3882:	lsl.l	%d1,%d0
 389	move.b	%d0,(-4,%a0)
 390	lsr.l	#8,%d0
 391	move.b	%d0,(7,%a0)
 392	jra	fp_e2e_checkround
 393#endif
 3941:	move.l	%d0,%d1			| lower lword is splitted between
 395	lsl.l	%d2,%d0			| higher and lower lword
 396	move.l	%d0,(%a0)
 397	move.l	%d1,%d0
 398	neg.w	%d2
 399	add.w	#32,%d2
 400	lsr.l	%d2,%d0
 401	move.l	%d0,-(%a0)
 402	jra	fp_e2e_checkround
 403	| Infinities and NaNs
 404fp_e2e_large:
 405	move.l	(%a0)+,%d0
 406	jne	3f
 4071:	tst.l	(%a0)
 408	jne	4f
 409	moveq	#1,%d0
 4102:	subq.l	#8,%a0
 411	printf	PCONV,"%p(",1,%a0
 412	printx	PCONV,%a0@
 413	printf	PCONV,")\n"
 414	rts
 415	| we have maybe a NaN, shift off the highest bit
 4163:	lsl.l	#1,%d0
 417	jeq	1b
 418	| we have a NaN, clear the return value
 4194:	clrl	%d0
 420	jra	2b
 421
 422
 423/*
 424 * Normalization functions.  Call these on the output of general
 425 * FP operators, and before any conversion into the destination
 426 * formats. fp_normalize_ext has always to be called first, the
 427 * following conversion functions expect an already normalized
 428 * number.
 429 */
 430
 431	| fp_normalize_ext:
 432	| normalize an extended in extended (unpacked) format, basically
 433	| it does the same as fp_conv_ext2ext, additionally it also does
 434	| the necessary postprocessing checks.
 435	| args:	%a0 (struct fp_ext *)
 436	| NOTE: it does _not_ modify %a0/%a1 and the upper word of %d2
 437
 438fp_normalize_ext:
 439	printf	PNORM,"ne: %p(",1,%a0
 440	printx	PNORM,%a0@
 441	printf	PNORM,"), "
 442	move.l	(%a0)+,%d0
 443	cmp.w	#0x7fff,%d0		| Inf / NaN?
 444	jeq	fp_ne_large
 445	move.l	(%a0),%d0
 446	jpl	fp_ne_small		| zero / denorm?
 447	| The high bit is set, so normalization is irrelevant.
 448fp_ne_checkround:
 449	subq.l	#4,%a0
 450#ifdef CONFIG_M68KFPU_EMU_EXTRAPREC
 451	move.b	(%a0),%d0
 452	jne	fp_ne_round
 453#endif
 454	printf	PNORM,"%p(",1,%a0
 455	printx	PNORM,%a0@
 456	printf	PNORM,")\n"
 457	rts
 458#ifdef CONFIG_M68KFPU_EMU_EXTRAPREC
 459fp_ne_round:
 460	fp_set_sr FPSR_EXC_INEX2
 461	clr.b	(%a0)
 462	move.w	(FPD_RND,FPDATA),%d2
 463	jne	fp_ne_roundother	| %d2 == 0, round to nearest
 464	tst.b	%d0			| test guard bit
 465	jpl	9f			| zero is closer
 466	btst	#0,(11,%a0)		| test lsb bit
 467	jne	fp_ne_doroundup		| round to infinity
 468	lsl.b	#1,%d0			| check low bits
 469	jeq	9f			| round to zero
 470fp_ne_doroundup:
 471	addq.l	#1,(8,%a0)
 472	jcc	9f
 473	addq.l	#1,(4,%a0)
 474	jcc	9f
 475	addq.w	#1,(2,%a0)
 476	move.w	#0x8000,(4,%a0)
 4779:	printf	PNORM,"%p(",1,%a0
 478	printx	PNORM,%a0@
 479	printf	PNORM,")\n"
 480	rts
 481fp_ne_roundother:
 482	subq.w	#2,%d2
 483	jcs	9b			| %d2 < 2, round to zero
 484	jhi	1f			| %d2 > 2, round to +infinity
 485	tst.b	(1,%a0)			| to -inf
 486	jne	fp_ne_doroundup		| negative, round to infinity
 487	jra	9b			| positive, round to zero
 4881:	tst.b	(1,%a0)			| to +inf
 489	jeq	fp_ne_doroundup		| positive, round to infinity
 490	jra	9b			| negative, round to zero
 491#endif
 492	| Zeros and subnormal numbers
 493	| These are probably merely subnormal, rather than "denormalized"
 494	|  numbers, so we will try to make them normal again.
 495fp_ne_small:
 496	jne	fp_ne_small1		| high lword zero?
 497	move.l	(4,%a0),%d0
 498	jne	fp_ne_small2
 499#ifdef CONFIG_M68KFPU_EMU_EXTRAPREC
 500	clr.l	%d0
 501	move.b	(-4,%a0),%d0
 502	jne	fp_ne_small3
 503#endif
 504	| Genuine zero.
 505	clr.w	-(%a0)
 506	subq.l	#2,%a0
 507	printf	PNORM,"%p(",1,%a0
 508	printx	PNORM,%a0@
 509	printf	PNORM,")\n"
 510	rts
 511	| Subnormal.
 512fp_ne_small1:
 513	bfffo	%d0{#0,#32},%d1
 514	move.w	-(%a0),%d2
 515	sub.w	%d1,%d2
 516	jcc	1f
 517	| Pathologically small, denormalize.
 518	add.w	%d2,%d1
 519	clr.w	%d2
 520	fp_set_sr FPSR_EXC_UNFL
 5211:	move.w	%d2,(%a0)+
 522	move.w	%d1,%d2
 523	jeq	fp_ne_checkround
 524	| This is exactly the same 64-bit double shift as seen above.
 525	lsl.l	%d2,%d0
 526	move.l	%d0,(%a0)+
 527	move.l	(%a0),%d0
 528	move.l	%d0,%d1
 529	lsl.l	%d2,%d0
 530	move.l	%d0,(%a0)
 531	neg.w	%d2
 532	and.w	#0x1f,%d2
 533	lsr.l	%d2,%d1
 534	or.l	%d1,-(%a0)
 535#ifdef CONFIG_M68KFPU_EMU_EXTRAPREC
 536fp_ne_extra1:
 537	clr.l	%d0
 538	move.b	(-4,%a0),%d0
 539	neg.w	%d2
 540	add.w	#24,%d2
 541	jcc	1f
 542	clr.b	(-4,%a0)
 543	lsl.l	%d2,%d0
 544	or.l	%d0,(4,%a0)
 545	jra	fp_ne_checkround
 5461:	addq.w	#8,%d2
 547	lsl.l	%d2,%d0
 548	move.b	%d0,(-4,%a0)
 549	lsr.l	#8,%d0
 550	or.l	%d0,(4,%a0)
 551#endif
 552	jra	fp_ne_checkround
 553	| May or may not be subnormal, if so, only 32 bits to shift.
 554fp_ne_small2:
 555	bfffo	%d0{#0,#32},%d1
 556	add.w	#32,%d1
 557	move.w	-(%a0),%d2
 558	sub.w	%d1,%d2
 559	jcc	1f
 560	| Beyond pathologically small, denormalize.
 561	add.w	%d2,%d1
 562	clr.w	%d2
 563	fp_set_sr FPSR_EXC_UNFL
 5641:	move.w	%d2,(%a0)+
 565	ext.l	%d1
 566	jeq	fp_ne_checkround
 567	clr.l	(4,%a0)
 568	sub.w	#32,%d1
 569	jcs	1f
 570	lsl.l	%d1,%d0			| lower lword needs only to be shifted
 571	move.l	%d0,(%a0)		| into the higher lword
 572#ifdef CONFIG_M68KFPU_EMU_EXTRAPREC
 573	clr.l	%d0
 574	move.b	(-4,%a0),%d0
 575	clr.b	(-4,%a0)
 576	neg.w	%d1
 577	add.w	#32,%d1
 578	bfins	%d0,(%a0){%d1,#8}
 579#endif
 580	jra	fp_ne_checkround
 5811:	neg.w	%d1			| lower lword is splitted between
 582	bfins	%d0,(%a0){%d1,#32}	| higher and lower lword
 583#ifndef CONFIG_M68KFPU_EMU_EXTRAPREC
 584	jra	fp_ne_checkround
 585#else
 586	move.w	%d1,%d2
 587	jra	fp_ne_extra1
 588	| These are extremely small numbers, that will mostly end up as zero
 589	| anyway, so this is only important for correct rounding.
 590fp_ne_small3:
 591	bfffo	%d0{#24,#8},%d1
 592	add.w	#40,%d1
 593	move.w	-(%a0),%d2
 594	sub.w	%d1,%d2
 595	jcc	1f
 596	| Pathologically small, denormalize.
 597	add.w	%d2,%d1
 598	clr.w	%d2
 5991:	move.w	%d2,(%a0)+
 600	ext.l	%d1
 601	jeq	fp_ne_checkround
 602	cmp.w	#8,%d1
 603	jcs	2f
 6041:	clr.b	(-4,%a0)
 605	sub.w	#64,%d1
 606	jcs	1f
 607	add.w	#24,%d1
 608	lsl.l	%d1,%d0
 609	move.l	%d0,(%a0)
 610	jra	fp_ne_checkround
 6111:	neg.w	%d1
 612	bfins	%d0,(%a0){%d1,#8}
 613	jra	fp_ne_checkround
 6142:	lsl.l	%d1,%d0
 615	move.b	%d0,(-4,%a0)
 616	lsr.l	#8,%d0
 617	move.b	%d0,(7,%a0)
 618	jra	fp_ne_checkround
 619#endif
 620	| Infinities and NaNs, again, same as above.
 621fp_ne_large:
 622	move.l	(%a0)+,%d0
 623	jne	3f
 6241:	tst.l	(%a0)
 625	jne	4f
 6262:	subq.l	#8,%a0
 627	printf	PNORM,"%p(",1,%a0
 628	printx	PNORM,%a0@
 629	printf	PNORM,")\n"
 630	rts
 631	| we have maybe a NaN, shift off the highest bit
 6323:	move.l	%d0,%d1
 633	lsl.l	#1,%d1
 634	jne	4f
 635	clr.l	(-4,%a0)
 636	jra	1b
 637	| we have a NaN, test if it is signaling
 6384:	bset	#30,%d0
 639	jne	2b
 640	fp_set_sr FPSR_EXC_SNAN
 641	move.l	%d0,(-4,%a0)
 642	jra	2b
 643
 644	| these next two do rounding as per the IEEE standard.
 645	| values for the rounding modes appear to be:
 646	| 0:	Round to nearest
 647	| 1:	Round to zero
 648	| 2:	Round to -Infinity
 649	| 3:	Round to +Infinity
 650	| both functions expect that fp_normalize was already
 651	| called (and extended argument is already normalized
 652	| as far as possible), these are used if there is different
 653	| rounding precision is selected and before converting
 654	| into single/double
 655
 656	| fp_normalize_double:
 657	| normalize an extended with double (52-bit) precision
 658	| args:	 %a0 (