162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * fp_util.S 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright Roman Zippel, 1997. All rights reserved. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 762306a36Sopenharmony_ci * modification, are permitted provided that the following conditions 862306a36Sopenharmony_ci * are met: 962306a36Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 1062306a36Sopenharmony_ci * notice, and the entire permission notice in its entirety, 1162306a36Sopenharmony_ci * including the disclaimer of warranties. 1262306a36Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 1362306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer in the 1462306a36Sopenharmony_ci * documentation and/or other materials provided with the distribution. 1562306a36Sopenharmony_ci * 3. The name of the author may not be used to endorse or promote 1662306a36Sopenharmony_ci * products derived from this software without specific prior 1762306a36Sopenharmony_ci * written permission. 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * ALTERNATIVELY, this product may be distributed under the terms of 2062306a36Sopenharmony_ci * the GNU General Public License, in which case the provisions of the GPL are 2162306a36Sopenharmony_ci * required INSTEAD OF the above restrictions. (This clause is 2262306a36Sopenharmony_ci * necessary due to a potential bad interaction between the GPL and 2362306a36Sopenharmony_ci * the restrictions contained in a BSD-style copyright.) 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 2662306a36Sopenharmony_ci * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2762306a36Sopenharmony_ci * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 2862306a36Sopenharmony_ci * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 2962306a36Sopenharmony_ci * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 3062306a36Sopenharmony_ci * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 3162306a36Sopenharmony_ci * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3262306a36Sopenharmony_ci * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 3362306a36Sopenharmony_ci * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 3462306a36Sopenharmony_ci * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 3562306a36Sopenharmony_ci * OF THE POSSIBILITY OF SUCH DAMAGE. 3662306a36Sopenharmony_ci */ 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#include "fp_emu.h" 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci/* 4162306a36Sopenharmony_ci * Here are lots of conversion and normalization functions mainly 4262306a36Sopenharmony_ci * used by fp_scan.S 4362306a36Sopenharmony_ci * Note that these functions are optimized for "normal" numbers, 4462306a36Sopenharmony_ci * these are handled first and exit as fast as possible, this is 4562306a36Sopenharmony_ci * especially important for fp_normalize_ext/fp_conv_ext2ext, as 4662306a36Sopenharmony_ci * it's called very often. 4762306a36Sopenharmony_ci * The register usage is optimized for fp_scan.S and which register 4862306a36Sopenharmony_ci * is currently at that time unused, be careful if you want change 4962306a36Sopenharmony_ci * something here. %d0 and %d1 is always usable, sometimes %d2 (or 5062306a36Sopenharmony_ci * only the lower half) most function have to return the %a0 5162306a36Sopenharmony_ci * unmodified, so that the caller can immediately reuse it. 5262306a36Sopenharmony_ci */ 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci .globl fp_ill, fp_end 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci | exits from fp_scan: 5762306a36Sopenharmony_ci | illegal instruction 5862306a36Sopenharmony_cifp_ill: 5962306a36Sopenharmony_ci printf ,"fp_illegal\n" 6062306a36Sopenharmony_ci rts 6162306a36Sopenharmony_ci | completed instruction 6262306a36Sopenharmony_cifp_end: 6362306a36Sopenharmony_ci tst.l (TASK_MM-8,%a2) 6462306a36Sopenharmony_ci jmi 1f 6562306a36Sopenharmony_ci tst.l (TASK_MM-4,%a2) 6662306a36Sopenharmony_ci jmi 1f 6762306a36Sopenharmony_ci tst.l (TASK_MM,%a2) 6862306a36Sopenharmony_ci jpl 2f 6962306a36Sopenharmony_ci1: printf ,"oops:%p,%p,%p\n",3,%a2@(TASK_MM-8),%a2@(TASK_MM-4),%a2@(TASK_MM) 7062306a36Sopenharmony_ci2: clr.l %d0 7162306a36Sopenharmony_ci rts 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci .globl fp_conv_long2ext, fp_conv_single2ext 7462306a36Sopenharmony_ci .globl fp_conv_double2ext, fp_conv_ext2ext 7562306a36Sopenharmony_ci .globl fp_normalize_ext, fp_normalize_double 7662306a36Sopenharmony_ci .globl fp_normalize_single, fp_normalize_single_fast 7762306a36Sopenharmony_ci .globl fp_conv_ext2double, fp_conv_ext2single 7862306a36Sopenharmony_ci .globl fp_conv_ext2long, fp_conv_ext2short 7962306a36Sopenharmony_ci .globl fp_conv_ext2byte 8062306a36Sopenharmony_ci .globl fp_finalrounding_single, fp_finalrounding_single_fast 8162306a36Sopenharmony_ci .globl fp_finalrounding_double 8262306a36Sopenharmony_ci .globl fp_finalrounding, fp_finaltest, fp_final 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci/* 8562306a36Sopenharmony_ci * First several conversion functions from a source operand 8662306a36Sopenharmony_ci * into the extended format. Note, that only fp_conv_ext2ext 8762306a36Sopenharmony_ci * normalizes the number and is always called after the other 8862306a36Sopenharmony_ci * conversion functions, which only move the information into 8962306a36Sopenharmony_ci * fp_ext structure. 9062306a36Sopenharmony_ci */ 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci | fp_conv_long2ext: 9362306a36Sopenharmony_ci | 9462306a36Sopenharmony_ci | args: %d0 = source (32-bit long) 9562306a36Sopenharmony_ci | %a0 = destination (ptr to struct fp_ext) 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cifp_conv_long2ext: 9862306a36Sopenharmony_ci printf PCONV,"l2e: %p -> %p(",2,%d0,%a0 9962306a36Sopenharmony_ci clr.l %d1 | sign defaults to zero 10062306a36Sopenharmony_ci tst.l %d0 10162306a36Sopenharmony_ci jeq fp_l2e_zero | is source zero? 10262306a36Sopenharmony_ci jpl 1f | positive? 10362306a36Sopenharmony_ci moveq #1,%d1 10462306a36Sopenharmony_ci neg.l %d0 10562306a36Sopenharmony_ci1: swap %d1 10662306a36Sopenharmony_ci move.w #0x3fff+31,%d1 10762306a36Sopenharmony_ci move.l %d1,(%a0)+ | set sign / exp 10862306a36Sopenharmony_ci move.l %d0,(%a0)+ | set mantissa 10962306a36Sopenharmony_ci clr.l (%a0) 11062306a36Sopenharmony_ci subq.l #8,%a0 | restore %a0 11162306a36Sopenharmony_ci printx PCONV,%a0@ 11262306a36Sopenharmony_ci printf PCONV,")\n" 11362306a36Sopenharmony_ci rts 11462306a36Sopenharmony_ci | source is zero 11562306a36Sopenharmony_cifp_l2e_zero: 11662306a36Sopenharmony_ci clr.l (%a0)+ 11762306a36Sopenharmony_ci clr.l (%a0)+ 11862306a36Sopenharmony_ci clr.l (%a0) 11962306a36Sopenharmony_ci subq.l #8,%a0 12062306a36Sopenharmony_ci printx PCONV,%a0@ 12162306a36Sopenharmony_ci printf PCONV,")\n" 12262306a36Sopenharmony_ci rts 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci | fp_conv_single2ext 12562306a36Sopenharmony_ci | args: %d0 = source (single-precision fp value) 12662306a36Sopenharmony_ci | %a0 = dest (struct fp_ext *) 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cifp_conv_single2ext: 12962306a36Sopenharmony_ci printf PCONV,"s2e: %p -> %p(",2,%d0,%a0 13062306a36Sopenharmony_ci move.l %d0,%d1 13162306a36Sopenharmony_ci lsl.l #8,%d0 | shift mantissa 13262306a36Sopenharmony_ci lsr.l #8,%d1 | exponent / sign 13362306a36Sopenharmony_ci lsr.l #7,%d1 13462306a36Sopenharmony_ci lsr.w #8,%d1 13562306a36Sopenharmony_ci jeq fp_s2e_small | zero / denormal? 13662306a36Sopenharmony_ci cmp.w #0xff,%d1 | NaN / Inf? 13762306a36Sopenharmony_ci jeq fp_s2e_large 13862306a36Sopenharmony_ci bset #31,%d0 | set explizit bit 13962306a36Sopenharmony_ci add.w #0x3fff-0x7f,%d1 | re-bias the exponent. 14062306a36Sopenharmony_ci9: move.l %d1,(%a0)+ | fp_ext.sign, fp_ext.exp 14162306a36Sopenharmony_ci move.l %d0,(%a0)+ | high lword of fp_ext.mant 14262306a36Sopenharmony_ci clr.l (%a0) | low lword = 0 14362306a36Sopenharmony_ci subq.l #8,%a0 14462306a36Sopenharmony_ci printx PCONV,%a0@ 14562306a36Sopenharmony_ci printf PCONV,")\n" 14662306a36Sopenharmony_ci rts 14762306a36Sopenharmony_ci | zeros and denormalized 14862306a36Sopenharmony_cifp_s2e_small: 14962306a36Sopenharmony_ci | exponent is zero, so explizit bit is already zero too 15062306a36Sopenharmony_ci tst.l %d0 15162306a36Sopenharmony_ci jeq 9b 15262306a36Sopenharmony_ci move.w #0x4000-0x7f,%d1 15362306a36Sopenharmony_ci jra 9b 15462306a36Sopenharmony_ci | infinities and NAN 15562306a36Sopenharmony_cifp_s2e_large: 15662306a36Sopenharmony_ci bclr #31,%d0 | clear explizit bit 15762306a36Sopenharmony_ci move.w #0x7fff,%d1 15862306a36Sopenharmony_ci jra 9b 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cifp_conv_double2ext: 16162306a36Sopenharmony_ci#ifdef FPU_EMU_DEBUG 16262306a36Sopenharmony_ci getuser.l %a1@(0),%d0,fp_err_ua2,%a1 16362306a36Sopenharmony_ci getuser.l %a1@(4),%d1,fp_err_ua2,%a1 16462306a36Sopenharmony_ci printf PCONV,"d2e: %p%p -> %p(",3,%d0,%d1,%a0 16562306a36Sopenharmony_ci#endif 16662306a36Sopenharmony_ci getuser.l (%a1)+,%d0,fp_err_ua2,%a1 16762306a36Sopenharmony_ci move.l %d0,%d1 16862306a36Sopenharmony_ci lsl.l #8,%d0 | shift high mantissa 16962306a36Sopenharmony_ci lsl.l #3,%d0 17062306a36Sopenharmony_ci lsr.l #8,%d1 | exponent / sign 17162306a36Sopenharmony_ci lsr.l #7,%d1 17262306a36Sopenharmony_ci lsr.w #5,%d1 17362306a36Sopenharmony_ci jeq fp_d2e_small | zero / denormal? 17462306a36Sopenharmony_ci cmp.w #0x7ff,%d1 | NaN / Inf? 17562306a36Sopenharmony_ci jeq fp_d2e_large 17662306a36Sopenharmony_ci bset #31,%d0 | set explizit bit 17762306a36Sopenharmony_ci add.w #0x3fff-0x3ff,%d1 | re-bias the exponent. 17862306a36Sopenharmony_ci9: move.l %d1,(%a0)+ | fp_ext.sign, fp_ext.exp 17962306a36Sopenharmony_ci move.l %d0,(%a0)+ 18062306a36Sopenharmony_ci getuser.l (%a1)+,%d0,fp_err_ua2,%a1 18162306a36Sopenharmony_ci move.l %d0,%d1 18262306a36Sopenharmony_ci lsl.l #8,%d0 18362306a36Sopenharmony_ci lsl.l #3,%d0 18462306a36Sopenharmony_ci move.l %d0,(%a0) 18562306a36Sopenharmony_ci moveq #21,%d0 18662306a36Sopenharmony_ci lsr.l %d0,%d1 18762306a36Sopenharmony_ci or.l %d1,-(%a0) 18862306a36Sopenharmony_ci subq.l #4,%a0 18962306a36Sopenharmony_ci printx PCONV,%a0@ 19062306a36Sopenharmony_ci printf PCONV,")\n" 19162306a36Sopenharmony_ci rts 19262306a36Sopenharmony_ci | zeros and denormalized 19362306a36Sopenharmony_cifp_d2e_small: 19462306a36Sopenharmony_ci | exponent is zero, so explizit bit is already zero too 19562306a36Sopenharmony_ci tst.l %d0 19662306a36Sopenharmony_ci jeq 9b 19762306a36Sopenharmony_ci move.w #0x4000-0x3ff,%d1 19862306a36Sopenharmony_ci jra 9b 19962306a36Sopenharmony_ci | infinities and NAN 20062306a36Sopenharmony_cifp_d2e_large: 20162306a36Sopenharmony_ci bclr #31,%d0 | clear explizit bit 20262306a36Sopenharmony_ci move.w #0x7fff,%d1 20362306a36Sopenharmony_ci jra 9b 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci | fp_conv_ext2ext: 20662306a36Sopenharmony_ci | originally used to get longdouble from userspace, now it's 20762306a36Sopenharmony_ci | called before arithmetic operations to make sure the number 20862306a36Sopenharmony_ci | is normalized [maybe rename it?]. 20962306a36Sopenharmony_ci | args: %a0 = dest (struct fp_ext *) 21062306a36Sopenharmony_ci | returns 0 in %d0 for a NaN, otherwise 1 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cifp_conv_ext2ext: 21362306a36Sopenharmony_ci printf PCONV,"e2e: %p(",1,%a0 21462306a36Sopenharmony_ci printx PCONV,%a0@ 21562306a36Sopenharmony_ci printf PCONV,"), " 21662306a36Sopenharmony_ci move.l (%a0)+,%d0 21762306a36Sopenharmony_ci cmp.w #0x7fff,%d0 | Inf / NaN? 21862306a36Sopenharmony_ci jeq fp_e2e_large 21962306a36Sopenharmony_ci move.l (%a0),%d0 22062306a36Sopenharmony_ci jpl fp_e2e_small | zero / denorm? 22162306a36Sopenharmony_ci | The high bit is set, so normalization is irrelevant. 22262306a36Sopenharmony_cifp_e2e_checkround: 22362306a36Sopenharmony_ci subq.l #4,%a0 22462306a36Sopenharmony_ci#ifdef CONFIG_M68KFPU_EMU_EXTRAPREC 22562306a36Sopenharmony_ci move.b (%a0),%d0 22662306a36Sopenharmony_ci jne fp_e2e_round 22762306a36Sopenharmony_ci#endif 22862306a36Sopenharmony_ci printf PCONV,"%p(",1,%a0 22962306a36Sopenharmony_ci printx PCONV,%a0@ 23062306a36Sopenharmony_ci printf PCONV,")\n" 23162306a36Sopenharmony_ci moveq #1,%d0 23262306a36Sopenharmony_ci rts 23362306a36Sopenharmony_ci#ifdef CONFIG_M68KFPU_EMU_EXTRAPREC 23462306a36Sopenharmony_cifp_e2e_round: 23562306a36Sopenharmony_ci fp_set_sr FPSR_EXC_INEX2 23662306a36Sopenharmony_ci clr.b (%a0) 23762306a36Sopenharmony_ci move.w (FPD_RND,FPDATA),%d2 23862306a36Sopenharmony_ci jne fp_e2e_roundother | %d2 == 0, round to nearest 23962306a36Sopenharmony_ci tst.b %d0 | test guard bit 24062306a36Sopenharmony_ci jpl 9f | zero is closer 24162306a36Sopenharmony_ci btst #0,(11,%a0) | test lsb bit 24262306a36Sopenharmony_ci jne fp_e2e_doroundup | round to infinity 24362306a36Sopenharmony_ci lsl.b #1,%d0 | check low bits 24462306a36Sopenharmony_ci jeq 9f | round to zero 24562306a36Sopenharmony_cifp_e2e_doroundup: 24662306a36Sopenharmony_ci addq.l #1,(8,%a0) 24762306a36Sopenharmony_ci jcc 9f 24862306a36Sopenharmony_ci addq.l #1,(4,%a0) 24962306a36Sopenharmony_ci jcc 9f 25062306a36Sopenharmony_ci move.w #0x8000,(4,%a0) 25162306a36Sopenharmony_ci addq.w #1,(2,%a0) 25262306a36Sopenharmony_ci9: printf PNORM,"%p(",1,%a0 25362306a36Sopenharmony_ci printx PNORM,%a0@ 25462306a36Sopenharmony_ci printf PNORM,")\n" 25562306a36Sopenharmony_ci rts 25662306a36Sopenharmony_cifp_e2e_roundother: 25762306a36Sopenharmony_ci subq.w #2,%d2 25862306a36Sopenharmony_ci jcs 9b | %d2 < 2, round to zero 25962306a36Sopenharmony_ci jhi 1f | %d2 > 2, round to +infinity 26062306a36Sopenharmony_ci tst.b (1,%a0) | to -inf 26162306a36Sopenharmony_ci jne fp_e2e_doroundup | negative, round to infinity 26262306a36Sopenharmony_ci jra 9b | positive, round to zero 26362306a36Sopenharmony_ci1: tst.b (1,%a0) | to +inf 26462306a36Sopenharmony_ci jeq fp_e2e_doroundup | positive, round to infinity 26562306a36Sopenharmony_ci jra 9b | negative, round to zero 26662306a36Sopenharmony_ci#endif 26762306a36Sopenharmony_ci | zeros and subnormals: 26862306a36Sopenharmony_ci | try to normalize these anyway. 26962306a36Sopenharmony_cifp_e2e_small: 27062306a36Sopenharmony_ci jne fp_e2e_small1 | high lword zero? 27162306a36Sopenharmony_ci move.l (4,%a0),%d0 27262306a36Sopenharmony_ci jne fp_e2e_small2 27362306a36Sopenharmony_ci#ifdef CONFIG_M68KFPU_EMU_EXTRAPREC 27462306a36Sopenharmony_ci clr.l %d0 27562306a36Sopenharmony_ci move.b (-4,%a0),%d0 27662306a36Sopenharmony_ci jne fp_e2e_small3 27762306a36Sopenharmony_ci#endif 27862306a36Sopenharmony_ci | Genuine zero. 27962306a36Sopenharmony_ci clr.w -(%a0) 28062306a36Sopenharmony_ci subq.l #2,%a0 28162306a36Sopenharmony_ci printf PNORM,"%p(",1,%a0 28262306a36Sopenharmony_ci printx PNORM,%a0@ 28362306a36Sopenharmony_ci printf PNORM,")\n" 28462306a36Sopenharmony_ci moveq #1,%d0 28562306a36Sopenharmony_ci rts 28662306a36Sopenharmony_ci | definitely subnormal, need to shift all 64 bits 28762306a36Sopenharmony_cifp_e2e_small1: 28862306a36Sopenharmony_ci bfffo %d0{#0,#32},%d1 28962306a36Sopenharmony_ci move.w -(%a0),%d2 29062306a36Sopenharmony_ci sub.w %d1,%d2 29162306a36Sopenharmony_ci jcc 1f 29262306a36Sopenharmony_ci | Pathologically small, denormalize. 29362306a36Sopenharmony_ci add.w %d2,%d1 29462306a36Sopenharmony_ci clr.w %d2 29562306a36Sopenharmony_ci1: move.w %d2,(%a0)+ 29662306a36Sopenharmony_ci move.w %d1,%d2 29762306a36Sopenharmony_ci jeq fp_e2e_checkround 29862306a36Sopenharmony_ci | fancy 64-bit double-shift begins here 29962306a36Sopenharmony_ci lsl.l %d2,%d0 30062306a36Sopenharmony_ci move.l %d0,(%a0)+ 30162306a36Sopenharmony_ci move.l (%a0),%d0 30262306a36Sopenharmony_ci move.l %d0,%d1 30362306a36Sopenharmony_ci lsl.l %d2,%d0 30462306a36Sopenharmony_ci move.l %d0,(%a0) 30562306a36Sopenharmony_ci neg.w %d2 30662306a36Sopenharmony_ci and.w #0x1f,%d2 30762306a36Sopenharmony_ci lsr.l %d2,%d1 30862306a36Sopenharmony_ci or.l %d1,-(%a0) 30962306a36Sopenharmony_ci#ifdef CONFIG_M68KFPU_EMU_EXTRAPREC 31062306a36Sopenharmony_cifp_e2e_extra1: 31162306a36Sopenharmony_ci clr.l %d0 31262306a36Sopenharmony_ci move.b (-4,%a0),%d0 31362306a36Sopenharmony_ci neg.w %d2 31462306a36Sopenharmony_ci add.w #24,%d2 31562306a36Sopenharmony_ci jcc 1f 31662306a36Sopenharmony_ci clr.b (-4,%a0) 31762306a36Sopenharmony_ci lsl.l %d2,%d0 31862306a36Sopenharmony_ci or.l %d0,(4,%a0) 31962306a36Sopenharmony_ci jra fp_e2e_checkround 32062306a36Sopenharmony_ci1: addq.w #8,%d2 32162306a36Sopenharmony_ci lsl.l %d2,%d0 32262306a36Sopenharmony_ci move.b %d0,(-4,%a0) 32362306a36Sopenharmony_ci lsr.l #8,%d0 32462306a36Sopenharmony_ci or.l %d0,(4,%a0) 32562306a36Sopenharmony_ci#endif 32662306a36Sopenharmony_ci jra fp_e2e_checkround 32762306a36Sopenharmony_ci | pathologically small subnormal 32862306a36Sopenharmony_cifp_e2e_small2: 32962306a36Sopenharmony_ci bfffo %d0{#0,#32},%d1 33062306a36Sopenharmony_ci add.w #32,%d1 33162306a36Sopenharmony_ci move.w -(%a0),%d2 33262306a36Sopenharmony_ci sub.w %d1,%d2 33362306a36Sopenharmony_ci jcc 1f 33462306a36Sopenharmony_ci | Beyond pathologically small, denormalize. 33562306a36Sopenharmony_ci add.w %d2,%d1 33662306a36Sopenharmony_ci clr.w %d2 33762306a36Sopenharmony_ci1: move.w %d2,(%a0)+ 33862306a36Sopenharmony_ci ext.l %d1 33962306a36Sopenharmony_ci jeq fp_e2e_checkround 34062306a36Sopenharmony_ci clr.l (4,%a0) 34162306a36Sopenharmony_ci sub.w #32,%d2 34262306a36Sopenharmony_ci jcs 1f 34362306a36Sopenharmony_ci lsl.l %d1,%d0 | lower lword needs only to be shifted 34462306a36Sopenharmony_ci move.l %d0,(%a0) | into the higher lword 34562306a36Sopenharmony_ci#ifdef CONFIG_M68KFPU_EMU_EXTRAPREC 34662306a36Sopenharmony_ci clr.l %d0 34762306a36Sopenharmony_ci move.b (-4,%a0),%d0 34862306a36Sopenharmony_ci clr.b (-4,%a0) 34962306a36Sopenharmony_ci neg.w %d1 35062306a36Sopenharmony_ci add.w #32,%d1 35162306a36Sopenharmony_ci bfins %d0,(%a0){%d1,#8} 35262306a36Sopenharmony_ci#endif 35362306a36Sopenharmony_ci jra fp_e2e_checkround 35462306a36Sopenharmony_ci1: neg.w %d1 | lower lword is splitted between 35562306a36Sopenharmony_ci bfins %d0,(%a0){%d1,#32} | higher and lower lword 35662306a36Sopenharmony_ci#ifndef CONFIG_M68KFPU_EMU_EXTRAPREC 35762306a36Sopenharmony_ci jra fp_e2e_checkround 35862306a36Sopenharmony_ci#else 35962306a36Sopenharmony_ci move.w %d1,%d2 36062306a36Sopenharmony_ci jra fp_e2e_extra1 36162306a36Sopenharmony_ci | These are extremely small numbers, that will mostly end up as zero 36262306a36Sopenharmony_ci | anyway, so this is only important for correct rounding. 36362306a36Sopenharmony_cifp_e2e_small3: 36462306a36Sopenharmony_ci bfffo %d0{#24,#8},%d1 36562306a36Sopenharmony_ci add.w #40,%d1 36662306a36Sopenharmony_ci move.w -(%a0),%d2 36762306a36Sopenharmony_ci sub.w %d1,%d2 36862306a36Sopenharmony_ci jcc 1f 36962306a36Sopenharmony_ci | Pathologically small, denormalize. 37062306a36Sopenharmony_ci add.w %d2,%d1 37162306a36Sopenharmony_ci clr.w %d2 37262306a36Sopenharmony_ci1: move.w %d2,(%a0)+ 37362306a36Sopenharmony_ci ext.l %d1 37462306a36Sopenharmony_ci jeq fp_e2e_checkround 37562306a36Sopenharmony_ci cmp.w #8,%d1 37662306a36Sopenharmony_ci jcs 2f 37762306a36Sopenharmony_ci1: clr.b (-4,%a0) 37862306a36Sopenharmony_ci sub.w #64,%d1 37962306a36Sopenharmony_ci jcs 1f 38062306a36Sopenharmony_ci add.w #24,%d1 38162306a36Sopenharmony_ci lsl.l %d1,%d0 38262306a36Sopenharmony_ci move.l %d0,(%a0) 38362306a36Sopenharmony_ci jra fp_e2e_checkround 38462306a36Sopenharmony_ci1: neg.w %d1 38562306a36Sopenharmony_ci bfins %d0,(%a0){%d1,#8} 38662306a36Sopenharmony_ci jra fp_e2e_checkround 38762306a36Sopenharmony_ci2: lsl.l %d1,%d0 38862306a36Sopenharmony_ci move.b %d0,(-4,%a0) 38962306a36Sopenharmony_ci lsr.l #8,%d0 39062306a36Sopenharmony_ci move.b %d0,(7,%a0) 39162306a36Sopenharmony_ci jra fp_e2e_checkround 39262306a36Sopenharmony_ci#endif 39362306a36Sopenharmony_ci1: move.l %d0,%d1 | lower lword is splitted between 39462306a36Sopenharmony_ci lsl.l %d2,%d0 | higher and lower lword 39562306a36Sopenharmony_ci move.l %d0,(%a0) 39662306a36Sopenharmony_ci move.l %d1,%d0 39762306a36Sopenharmony_ci neg.w %d2 39862306a36Sopenharmony_ci add.w #32,%d2 39962306a36Sopenharmony_ci lsr.l %d2,%d0 40062306a36Sopenharmony_ci move.l %d0,-(%a0) 40162306a36Sopenharmony_ci jra fp_e2e_checkround 40262306a36Sopenharmony_ci | Infinities and NaNs 40362306a36Sopenharmony_cifp_e2e_large: 40462306a36Sopenharmony_ci move.l (%a0)+,%d0 40562306a36Sopenharmony_ci jne 3f 40662306a36Sopenharmony_ci1: tst.l (%a0) 40762306a36Sopenharmony_ci jne 4f 40862306a36Sopenharmony_ci moveq #1,%d0 40962306a36Sopenharmony_ci2: subq.l #8,%a0 41062306a36Sopenharmony_ci printf PCONV,"%p(",1,%a0 41162306a36Sopenharmony_ci printx PCONV,%a0@ 41262306a36Sopenharmony_ci printf PCONV,")\n" 41362306a36Sopenharmony_ci rts 41462306a36Sopenharmony_ci | we have maybe a NaN, shift off the highest bit 41562306a36Sopenharmony_ci3: lsl.l #1,%d0 41662306a36Sopenharmony_ci jeq 1b 41762306a36Sopenharmony_ci | we have a NaN, clear the return value 41862306a36Sopenharmony_ci4: clrl %d0 41962306a36Sopenharmony_ci jra 2b 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci/* 42362306a36Sopenharmony_ci * Normalization functions. Call these on the output of general 42462306a36Sopenharmony_ci * FP operators, and before any conversion into the destination 42562306a36Sopenharmony_ci * formats. fp_normalize_ext has always to be called first, the 42662306a36Sopenharmony_ci * following conversion functions expect an already normalized 42762306a36Sopenharmony_ci * number. 42862306a36Sopenharmony_ci */ 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci | fp_normalize_ext: 43162306a36Sopenharmony_ci | normalize an extended in extended (unpacked) format, basically 43262306a36Sopenharmony_ci | it does the same as fp_conv_ext2ext, additionally it also does 43362306a36Sopenharmony_ci | the necessary postprocessing checks. 43462306a36Sopenharmony_ci | args: %a0 (struct fp_ext *) 43562306a36Sopenharmony_ci | NOTE: it does _not_ modify %a0/%a1 and the upper word of %d2 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cifp_normalize_ext: 43862306a36Sopenharmony_ci printf PNORM,"ne: %p(",1,%a0 43962306a36Sopenharmony_ci printx PNORM,%a0@ 44062306a36Sopenharmony_ci printf PNORM,"), " 44162306a36Sopenharmony_ci move.l (%a0)+,%d0 44262306a36Sopenharmony_ci cmp.w #0x7fff,%d0 | Inf / NaN? 44362306a36Sopenharmony_ci jeq fp_ne_large 44462306a36Sopenharmony_ci move.l (%a0),%d0 44562306a36Sopenharmony_ci jpl fp_ne_small | zero / denorm? 44662306a36Sopenharmony_ci | The high bit is set, so normalization is irrelevant. 44762306a36Sopenharmony_cifp_ne_checkround: 44862306a36Sopenharmony_ci subq.l #4,%a0 44962306a36Sopenharmony_ci#ifdef CONFIG_M68KFPU_EMU_EXTRAPREC 45062306a36Sopenharmony_ci move.b (%a0),%d0 45162306a36Sopenharmony_ci jne fp_ne_round 45262306a36Sopenharmony_ci#endif 45362306a36Sopenharmony_ci printf PNORM,"%p(",1,%a0 45462306a36Sopenharmony_ci printx PNORM,%a0@ 45562306a36Sopenharmony_ci printf PNORM,")\n" 45662306a36Sopenharmony_ci rts 45762306a36Sopenharmony_ci#ifdef CONFIG_M68KFPU_EMU_EXTRAPREC 45862306a36Sopenharmony_cifp_ne_round: 45962306a36Sopenharmony_ci fp_set_sr FPSR_EXC_INEX2 46062306a36Sopenharmony_ci clr.b (%a0) 46162306a36Sopenharmony_ci move.w (FPD_RND,FPDATA),%d2 46262306a36Sopenharmony_ci jne fp_ne_roundother | %d2 == 0, round to nearest 46362306a36Sopenharmony_ci tst.b %d0 | test guard bit 46462306a36Sopenharmony_ci jpl 9f | zero is closer 46562306a36Sopenharmony_ci btst #0,(11,%a0) | test lsb bit 46662306a36Sopenharmony_ci jne fp_ne_doroundup | round to infinity 46762306a36Sopenharmony_ci lsl.b #1,%d0 | check low bits 46862306a36Sopenharmony_ci jeq 9f | round to zero 46962306a36Sopenharmony_cifp_ne_doroundup: 47062306a36Sopenharmony_ci addq.l #1,(8,%a0) 47162306a36Sopenharmony_ci jcc 9f 47262306a36Sopenharmony_ci addq.l #1,(4,%a0) 47362306a36Sopenharmony_ci jcc 9f 47462306a36Sopenharmony_ci addq.w #1,(2,%a0) 47562306a36Sopenharmony_ci move.w #0x8000,(4,%a0) 47662306a36Sopenharmony_ci9: printf PNORM,"%p(",1,%a0 47762306a36Sopenharmony_ci printx PNORM,%a0@ 47862306a36Sopenharmony_ci printf PNORM,")\n" 47962306a36Sopenharmony_ci rts 48062306a36Sopenharmony_cifp_ne_roundother: 48162306a36Sopenharmony_ci subq.w #2,%d2 48262306a36Sopenharmony_ci jcs 9b | %d2 < 2, round to zero 48362306a36Sopenharmony_ci jhi 1f | %d2 > 2, round to +infinity 48462306a36Sopenharmony_ci tst.b (1,%a0) | to -inf 48562306a36Sopenharmony_ci jne fp_ne_doroundup | negative, round to infinity 48662306a36Sopenharmony_ci jra 9b | positive, round to zero 48762306a36Sopenharmony_ci1: tst.b (1,%a0) | to +inf 48862306a36Sopenharmony_ci jeq fp_ne_doroundup | positive, round to infinity 48962306a36Sopenharmony_ci jra 9b | negative, round to zero 49062306a36Sopenharmony_ci#endif 49162306a36Sopenharmony_ci | Zeros and subnormal numbers 49262306a36Sopenharmony_ci | These are probably merely subnormal, rather than "denormalized" 49362306a36Sopenharmony_ci | numbers, so we will try to make them normal again. 49462306a36Sopenharmony_cifp_ne_small: 49562306a36Sopenharmony_ci jne fp_ne_small1 | high lword zero? 49662306a36Sopenharmony_ci move.l (4,%a0),%d0 49762306a36Sopenharmony_ci jne fp_ne_small2 49862306a36Sopenharmony_ci#ifdef CONFIG_M68KFPU_EMU_EXTRAPREC 49962306a36Sopenharmony_ci clr.l %d0 50062306a36Sopenharmony_ci move.b (-4,%a0),%d0 50162306a36Sopenharmony_ci jne fp_ne_small3 50262306a36Sopenharmony_ci#endif 50362306a36Sopenharmony_ci | Genuine zero. 50462306a36Sopenharmony_ci clr.w -(%a0) 50562306a36Sopenharmony_ci subq.l #2,%a0 50662306a36Sopenharmony_ci printf PNORM,"%p(",1,%a0 50762306a36Sopenharmony_ci printx PNORM,%a0@ 50862306a36Sopenharmony_ci printf PNORM,")\n" 50962306a36Sopenharmony_ci rts 51062306a36Sopenharmony_ci | Subnormal. 51162306a36Sopenharmony_cifp_ne_small1: 51262306a36Sopenharmony_ci bfffo %d0{#0,#32},%d1 51362306a36Sopenharmony_ci move.w -(%a0),%d2 51462306a36Sopenharmony_ci sub.w %d1,%d2 51562306a36Sopenharmony_ci jcc 1f 51662306a36Sopenharmony_ci | Pathologically small, denormalize. 51762306a36Sopenharmony_ci add.w %d2,%d1 51862306a36Sopenharmony_ci clr.w %d2 51962306a36Sopenharmony_ci fp_set_sr FPSR_EXC_UNFL 52062306a36Sopenharmony_ci1: move.w %d2,(%a0)+ 52162306a36Sopenharmony_ci move.w %d1,%d2 52262306a36Sopenharmony_ci jeq fp_ne_checkround 52362306a36Sopenharmony_ci | This is exactly the same 64-bit double shift as seen above. 52462306a36Sopenharmony_ci lsl.l %d2,%d0 52562306a36Sopenharmony_ci move.l %d0,(%a0)+ 52662306a36Sopenharmony_ci move.l (%a0),%d0 52762306a36Sopenharmony_ci move.l %d0,%d1 52862306a36Sopenharmony_ci lsl.l %d2,%d0 52962306a36Sopenharmony_ci move.l %d0,(%a0) 53062306a36Sopenharmony_ci neg.w %d2 53162306a36Sopenharmony_ci and.w #0x1f,%d2 53262306a36Sopenharmony_ci lsr.l %d2,%d1 53362306a36Sopenharmony_ci or.l %d1,-(%a0) 53462306a36Sopenharmony_ci#ifdef CONFIG_M68KFPU_EMU_EXTRAPREC 53562306a36Sopenharmony_cifp_ne_extra1: 53662306a36Sopenharmony_ci clr.l %d0 53762306a36Sopenharmony_ci move.b (-4,%a0),%d0 53862306a36Sopenharmony_ci neg.w %d2 53962306a36Sopenharmony_ci add.w #24,%d2 54062306a36Sopenharmony_ci jcc 1f 54162306a36Sopenharmony_ci clr.b (-4,%a0) 54262306a36Sopenharmony_ci lsl.l %d2,%d0 54362306a36Sopenharmony_ci or.l %d0,(4,%a0) 54462306a36Sopenharmony_ci jra fp_ne_checkround 54562306a36Sopenharmony_ci1: addq.w #8,%d2 54662306a36Sopenharmony_ci lsl.l %d2,%d0 54762306a36Sopenharmony_ci move.b %d0,(-4,%a0) 54862306a36Sopenharmony_ci lsr.l #8,%d0 54962306a36Sopenharmony_ci or.l %d0,(4,%a0) 55062306a36Sopenharmony_ci#endif 55162306a36Sopenharmony_ci jra fp_ne_checkround 55262306a36Sopenharmony_ci | May or may not be subnormal, if so, only 32 bits to shift. 55362306a36Sopenharmony_cifp_ne_small2: 55462306a36Sopenharmony_ci bfffo %d0{#0,#32},%d1 55562306a36Sopenharmony_ci add.w #32,%d1 55662306a36Sopenharmony_ci move.w -(%a0),%d2 55762306a36Sopenharmony_ci sub.w %d1,%d2 55862306a36Sopenharmony_ci jcc 1f 55962306a36Sopenharmony_ci | Beyond pathologically small, denormalize. 56062306a36Sopenharmony_ci add.w %d2,%d1 56162306a36Sopenharmony_ci clr.w %d2 56262306a36Sopenharmony_ci fp_set_sr FPSR_EXC_UNFL 56362306a36Sopenharmony_ci1: move.w %d2,(%a0)+ 56462306a36Sopenharmony_ci ext.l %d1 56562306a36Sopenharmony_ci jeq fp_ne_checkround 56662306a36Sopenharmony_ci clr.l (4,%a0) 56762306a36Sopenharmony_ci sub.w #32,%d1 56862306a36Sopenharmony_ci jcs 1f 56962306a36Sopenharmony_ci lsl.l %d1,%d0 | lower lword needs only to be shifted 57062306a36Sopenharmony_ci move.l %d0,(%a0) | into the higher lword 57162306a36Sopenharmony_ci#ifdef CONFIG_M68KFPU_EMU_EXTRAPREC 57262306a36Sopenharmony_ci clr.l %d0 57362306a36Sopenharmony_ci move.b (-4,%a0),%d0 57462306a36Sopenharmony_ci clr.b (-4,%a0) 57562306a36Sopenharmony_ci neg.w %d1 57662306a36Sopenharmony_ci add.w #32,%d1 57762306a36Sopenharmony_ci bfins %d0,(%a0){%d1,#8} 57862306a36Sopenharmony_ci#endif 57962306a36Sopenharmony_ci jra fp_ne_checkround 58062306a36Sopenharmony_ci1: neg.w %d1 | lower lword is splitted between 58162306a36Sopenharmony_ci bfins %d0,(%a0){%d1,#32} | higher and lower lword 58262306a36Sopenharmony_ci#ifndef CONFIG_M68KFPU_EMU_EXTRAPREC 58362306a36Sopenharmony_ci jra fp_ne_checkround 58462306a36Sopenharmony_ci#else 58562306a36Sopenharmony_ci move.w %d1,%d2 58662306a36Sopenharmony_ci jra fp_ne_extra1 58762306a36Sopenharmony_ci | These are extremely small numbers, that will mostly end up as zero 58862306a36Sopenharmony_ci | anyway, so this is only important for correct rounding. 58962306a36Sopenharmony_cifp_ne_small3: 59062306a36Sopenharmony_ci bfffo %d0{#24,#8},%d1 59162306a36Sopenharmony_ci add.w #40,%d1 59262306a36Sopenharmony_ci move.w -(%a0),%d2 59362306a36Sopenharmony_ci sub.w %d1,%d2 59462306a36Sopenharmony_ci jcc 1f 59562306a36Sopenharmony_ci | Pathologically small, denormalize. 59662306a36Sopenharmony_ci add.w %d2,%d1 59762306a36Sopenharmony_ci clr.w %d2 59862306a36Sopenharmony_ci1: move.w %d2,(%a0)+ 59962306a36Sopenharmony_ci ext.l %d1 60062306a36Sopenharmony_ci jeq fp_ne_checkround 60162306a36Sopenharmony_ci cmp.w #8,%d1 60262306a36Sopenharmony_ci jcs 2f 60362306a36Sopenharmony_ci1: clr.b (-4,%a0) 60462306a36Sopenharmony_ci sub.w #64,%d1 60562306a36Sopenharmony_ci jcs 1f 60662306a36Sopenharmony_ci add.w #24,%d1 60762306a36Sopenharmony_ci lsl.l %d1,%d0 60862306a36Sopenharmony_ci move.l %d0,(%a0) 60962306a36Sopenharmony_ci jra fp_ne_checkround 61062306a36Sopenharmony_ci1: neg.w %d1 61162306a36Sopenharmony_ci bfins %d0,(%a0){%d1,#8} 61262306a36Sopenharmony_ci jra fp_ne_checkround 61362306a36Sopenharmony_ci2: lsl.l %d1,%d0 61462306a36Sopenharmony_ci move.b %d0,(-4,%a0) 61562306a36Sopenharmony_ci lsr.l #8,%d0 61662306a36Sopenharmony_ci move.b %d0,(7,%a0) 61762306a36Sopenharmony_ci jra fp_ne_checkround 61862306a36Sopenharmony_ci#endif 61962306a36Sopenharmony_ci | Infinities and NaNs, again, same as above. 62062306a36Sopenharmony_cifp_ne_large: 62162306a36Sopenharmony_ci move.l (%a0)+,%d0 62262306a36Sopenharmony_ci jne 3f 62362306a36Sopenharmony_ci1: tst.l (%a0) 62462306a36Sopenharmony_ci jne 4f 62562306a36Sopenharmony_ci2: subq.l #8,%a0 62662306a36Sopenharmony_ci printf PNORM,"%p(",1,%a0 62762306a36Sopenharmony_ci printx PNORM,%a0@ 62862306a36Sopenharmony_ci printf PNORM,")\n" 62962306a36Sopenharmony_ci rts 63062306a36Sopenharmony_ci | we have maybe a NaN, shift off the highest bit 63162306a36Sopenharmony_ci3: move.l %d0,%d1 63262306a36Sopenharmony_ci lsl.l #1,%d1 63362306a36Sopenharmony_ci jne 4f 63462306a36Sopenharmony_ci clr.l (-4,%a0) 63562306a36Sopenharmony_ci jra 1b 63662306a36Sopenharmony_ci | we have a NaN, test if it is signaling 63762306a36Sopenharmony_ci4: bset #30,%d0 63862306a36Sopenharmony_ci jne 2b 63962306a36Sopenharmony_ci fp_set_sr FPSR_EXC_SNAN 64062306a36Sopenharmony_ci move.l %d0,(-4,%a0) 64162306a36Sopenharmony_ci jra 2b 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci | these next two do rounding as per the IEEE standard. 64462306a36Sopenharmony_ci | values for the rounding modes appear to be: 64562306a36Sopenharmony_ci | 0: Round to nearest 64662306a36Sopenharmony_ci | 1: Round to zero 64762306a36Sopenharmony_ci | 2: Round to -Infinity 64862306a36Sopenharmony_ci | 3: Round to +Infinity 64962306a36Sopenharmony_ci | both functions expect that fp_normalize was already 65062306a36Sopenharmony_ci | called (and extended argument is already normalized 65162306a36Sopenharmony_ci | as far as possible), these are used if there is different 65262306a36Sopenharmony_ci | rounding precision is selected and before converting 65362306a36Sopenharmony_ci | into single/double 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci | fp_normalize_double: 65662306a36Sopenharmony_ci | normalize an extended with double (52-bit) precision 65762306a36Sopenharmony_ci | args: %a0 (struct fp_ext *) 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_cifp_normalize_double: 66062306a36Sopenharmony_ci printf PNORM,"nd: %p(",1,%a0 66162306a36Sopenharmony_ci printx PNORM,%a0@ 66262306a36Sopenharmony_ci printf PNORM,"), " 66362306a36Sopenharmony_ci move.l (%a0)+,%d2 66462306a36Sopenharmony_ci tst.w %d2 66562306a36Sopenharmony_ci jeq fp_nd_zero | zero / denormalized 66662306a36Sopenharmony_ci cmp.w #0x7fff,%d2 66762306a36Sopenharmony_ci jeq fp_nd_huge | NaN / infinitive. 66862306a36Sopenharmony_ci sub.w #0x4000-0x3ff,%d2 | will the exponent fit? 66962306a36Sopenharmony_ci jcs fp_nd_small | too small. 67062306a36Sopenharmony_ci cmp.w #0x7fe,%d2 67162306a36Sopenharmony_ci jcc fp_nd_large | too big. 67262306a36Sopenharmony_ci addq.l #4,%a0 67362306a36Sopenharmony_ci move.l (%a0),%d0 | low lword of mantissa 67462306a36Sopenharmony_ci | now, round off the low 11 bits. 67562306a36Sopenharmony_cifp_nd_round: 67662306a36Sopenharmony_ci moveq #21,%d1 67762306a36Sopenharmony_ci lsl.l %d1,%d0 | keep 11 low bits. 67862306a36Sopenharmony_ci jne fp_nd_checkround | Are they non-zero? 67962306a36Sopenharmony_ci | nothing to do here 68062306a36Sopenharmony_ci9: subq.l #8,%a0 68162306a36Sopenharmony_ci printf PNORM,"%p(",1,%a0 68262306a36Sopenharmony_ci printx PNORM,%a0@ 68362306a36Sopenharmony_ci printf PNORM,")\n" 68462306a36Sopenharmony_ci rts 68562306a36Sopenharmony_ci | Be careful with the X bit! It contains the lsb 68662306a36Sopenharmony_ci | from the shift above, it is needed for round to nearest. 68762306a36Sopenharmony_cifp_nd_checkround: 68862306a36Sopenharmony_ci fp_set_sr FPSR_EXC_INEX2 | INEX2 bit 68962306a36Sopenharmony_ci and.w #0xf800,(2,%a0) | clear bits 0-10 69062306a36Sopenharmony_ci move.w (FPD_RND,FPDATA),%d2 | rounding mode 69162306a36Sopenharmony_ci jne 2f | %d2 == 0, round to nearest 69262306a36Sopenharmony_ci tst.l %d0 | test guard bit 69362306a36Sopenharmony_ci jpl 9b | zero is closer 69462306a36Sopenharmony_ci | here we test the X bit by adding it to %d2 69562306a36Sopenharmony_ci clr.w %d2 | first set z bit, addx only clears it 69662306a36Sopenharmony_ci addx.w %d2,%d2 | test lsb bit 69762306a36Sopenharmony_ci | IEEE754-specified "round to even" behaviour. If the guard 69862306a36Sopenharmony_ci | bit is set, then the number is odd, so rounding works like 69962306a36Sopenharmony_ci | in grade-school arithmetic (i.e. 1.5 rounds to 2.0) 70062306a36Sopenharmony_ci | Otherwise, an equal distance rounds towards zero, so as not 70162306a36Sopenharmony_ci | to produce an odd number. This is strange, but it is what 70262306a36Sopenharmony_ci | the standard says. 70362306a36Sopenharmony_ci jne fp_nd_doroundup | round to infinity 70462306a36Sopenharmony_ci lsl.l #1,%d0 | check low bits 70562306a36Sopenharmony_ci jeq 9b | round to zero 70662306a36Sopenharmony_cifp_nd_doroundup: 70762306a36Sopenharmony_ci | round (the mantissa, that is) towards infinity 70862306a36Sopenharmony_ci add.l #0x800,(%a0) 70962306a36Sopenharmony_ci jcc 9b | no overflow, good. 71062306a36Sopenharmony_ci addq.l #1,-(%a0) | extend to high lword 71162306a36Sopenharmony_ci jcc 1f | no overflow, good. 71262306a36Sopenharmony_ci | Yow! we have managed to overflow the mantissa. Since this 71362306a36Sopenharmony_ci | only happens when %d1 was 0xfffff800, it is now zero, so 71462306a36Sopenharmony_ci | reset the high bit, and increment the exponent. 71562306a36Sopenharmony_ci move.w #0x8000,(%a0) 71662306a36Sopenharmony_ci addq.w #1,-(%a0) 71762306a36Sopenharmony_ci cmp.w #0x43ff,(%a0)+ | exponent now overflown? 71862306a36Sopenharmony_ci jeq fp_nd_large | yes, so make it infinity. 71962306a36Sopenharmony_ci1: subq.l #4,%a0 72062306a36Sopenharmony_ci printf PNORM,"%p(",1,%a0 72162306a36Sopenharmony_ci printx PNORM,%a0@ 72262306a36Sopenharmony_ci printf PNORM,")\n" 72362306a36Sopenharmony_ci rts 72462306a36Sopenharmony_ci2: subq.w #2,%d2 72562306a36Sopenharmony_ci jcs 9b | %d2 < 2, round to zero 72662306a36Sopenharmony_ci jhi 3f | %d2 > 2, round to +infinity 72762306a36Sopenharmony_ci | Round to +Inf or -Inf. High word of %d2 contains the 72862306a36Sopenharmony_ci | sign of the number, by the way. 72962306a36Sopenharmony_ci swap %d2 | to -inf 73062306a36Sopenharmony_ci tst.b %d2 73162306a36Sopenharmony_ci jne fp_nd_doroundup | negative, round to infinity 73262306a36Sopenharmony_ci jra 9b | positive, round to zero 73362306a36Sopenharmony_ci3: swap %d2 | to +inf 73462306a36Sopenharmony_ci tst.b %d2 73562306a36Sopenharmony_ci jeq fp_nd_doroundup | positive, round to infinity 73662306a36Sopenharmony_ci jra 9b | negative, round to zero 73762306a36Sopenharmony_ci | Exponent underflow. Try to make a denormal, and set it to 73862306a36Sopenharmony_ci | the smallest possible fraction if this fails. 73962306a36Sopenharmony_cifp_nd_small: 74062306a36Sopenharmony_ci fp_set_sr FPSR_EXC_UNFL | set UNFL bit 74162306a36Sopenharmony_ci move.w #0x3c01,(-2,%a0) | 2**-1022 74262306a36Sopenharmony_ci neg.w %d2 | degree of underflow 74362306a36Sopenharmony_ci cmp.w #32,%d2 | single or double shift? 74462306a36Sopenharmony_ci jcc 1f 74562306a36Sopenharmony_ci | Again, another 64-bit double shift. 74662306a36Sopenharmony_ci move.l (%a0),%d0 74762306a36Sopenharmony_ci move.l %d0,%d1 74862306a36Sopenharmony_ci lsr.l %d2,%d0 74962306a36Sopenharmony_ci move.l %d0,(%a0)+ 75062306a36Sopenharmony_ci move.l (%a0),%d0 75162306a36Sopenharmony_ci lsr.l %d2,%d0 75262306a36Sopenharmony_ci neg.w %d2 75362306a36Sopenharmony_ci add.w #32,%d2 75462306a36Sopenharmony_ci lsl.l %d2,%d1 75562306a36Sopenharmony_ci or.l %d1,%d0 75662306a36Sopenharmony_ci move.l (%a0),%d1 75762306a36Sopenharmony_ci move.l %d0,(%a0) 75862306a36Sopenharmony_ci | Check to see if we shifted off any significant bits 75962306a36Sopenharmony_ci lsl.l %d2,%d1 76062306a36Sopenharmony_ci jeq fp_nd_round | Nope, round. 76162306a36Sopenharmony_ci bset #0,%d0 | Yes, so set the "sticky bit". 76262306a36Sopenharmony_ci jra fp_nd_round | Now, round. 76362306a36Sopenharmony_ci | Another 64-bit single shift and store 76462306a36Sopenharmony_ci1: sub.w #32,%d2 76562306a36Sopenharmony_ci cmp.w #32,%d2 | Do we really need to shift? 76662306a36Sopenharmony_ci jcc 2f | No, the number is too small. 76762306a36Sopenharmony_ci move.l (%a0),%d0 76862306a36Sopenharmony_ci clr.l (%a0)+ 76962306a36Sopenharmony_ci move.l %d0,%d1 77062306a36Sopenharmony_ci lsr.l %d2,%d0 77162306a36Sopenharmony_ci neg.w %d2 77262306a36Sopenharmony_ci add.w #32,%d2 77362306a36Sopenharmony_ci | Again, check to see if we shifted off any significant bits. 77462306a36Sopenharmony_ci tst.l (%a0) 77562306a36Sopenharmony_ci jeq 1f 77662306a36Sopenharmony_ci bset #0,%d0 | Sticky bit. 77762306a36Sopenharmony_ci1: move.l %d0,(%a0) 77862306a36Sopenharmony_ci lsl.l %d2,%d1 77962306a36Sopenharmony_ci jeq fp_nd_round 78062306a36Sopenharmony_ci bset #0,%d0 78162306a36Sopenharmony_ci jra fp_nd_round 78262306a36Sopenharmony_ci | Sorry, the number is just too small. 78362306a36Sopenharmony_ci2: clr.l (%a0)+ 78462306a36Sopenharmony_ci clr.l (%a0) 78562306a36Sopenharmony_ci moveq #1,%d0 | Smallest possible fraction, 78662306a36Sopenharmony_ci jra fp_nd_round | round as desired. 78762306a36Sopenharmony_ci | zero and denormalized 78862306a36Sopenharmony_cifp_nd_zero: 78962306a36Sopenharmony_ci tst.l (%a0)+ 79062306a36Sopenharmony_ci jne 1f 79162306a36Sopenharmony_ci tst.l (%a0) 79262306a36Sopenharmony_ci jne 1f 79362306a36Sopenharmony_ci subq.l #8,%a0 79462306a36Sopenharmony_ci printf PNORM,"%p(",1,%a0 79562306a36Sopenharmony_ci printx PNORM,%a0@ 79662306a36Sopenharmony_ci printf PNORM,")\n" 79762306a36Sopenharmony_ci rts | zero. nothing to do. 79862306a36Sopenharmony_ci | These are not merely subnormal numbers, but true denormals, 79962306a36Sopenharmony_ci | i.e. pathologically small (exponent is 2**-16383) numbers. 80062306a36Sopenharmony_ci | It is clearly impossible for even a normal extended number 80162306a36Sopenharmony_ci | with that exponent to fit into double precision, so just 80262306a36Sopenharmony_ci | write these ones off as "too darn small". 80362306a36Sopenharmony_ci1: fp_set_sr FPSR_EXC_UNFL | Set UNFL bit 80462306a36Sopenharmony_ci clr.l (%a0) 80562306a36Sopenharmony_ci clr.l -(%a0) 80662306a36Sopenharmony_ci move.w #0x3c01,-(%a0) | i.e. 2**-1022 80762306a36Sopenharmony_ci addq.l #6,%a0 80862306a36Sopenharmony_ci moveq #1,%d0 80962306a36Sopenharmony_ci jra fp_nd_round | round. 81062306a36Sopenharmony_ci | Exponent overflow. Just call it infinity. 81162306a36Sopenharmony_cifp_nd_large: 81262306a36Sopenharmony_ci move.w #0x7ff,%d0 81362306a36Sopenharmony_ci and.w (6,%a0),%d0 81462306a36Sopenharmony_ci jeq 1f 81562306a36Sopenharmony_ci fp_set_sr FPSR_EXC_INEX2 81662306a36Sopenharmony_ci1: fp_set_sr FPSR_EXC_OVFL 81762306a36Sopenharmony_ci move.w (FPD_RND,FPDATA),%d2 81862306a36Sopenharmony_ci jne 3f | %d2 = 0 round to nearest 81962306a36Sopenharmony_ci1: move.w #0x7fff,(-2,%a0) 82062306a36Sopenharmony_ci clr.l (%a0)+ 82162306a36Sopenharmony_ci clr.l (%a0) 82262306a36Sopenharmony_ci2: subq.l #8,%a0 82362306a36Sopenharmony_ci printf PNORM,"%p(",1,%a0 82462306a36Sopenharmony_ci printx PNORM,%a0@ 82562306a36Sopenharmony_ci printf PNORM,")\n" 82662306a36Sopenharmony_ci rts 82762306a36Sopenharmony_ci3: subq.w #2,%d2 82862306a36Sopenharmony_ci jcs 5f | %d2 < 2, round to zero 82962306a36Sopenharmony_ci jhi 4f | %d2 > 2, round to +infinity 83062306a36Sopenharmony_ci tst.b (-3,%a0) | to -inf 83162306a36Sopenharmony_ci jne 1b 83262306a36Sopenharmony_ci jra 5f 83362306a36Sopenharmony_ci4: tst.b (-3,%a0) | to +inf 83462306a36Sopenharmony_ci jeq 1b 83562306a36Sopenharmony_ci5: move.w #0x43fe,(-2,%a0) 83662306a36Sopenharmony_ci moveq #-1,%d0 83762306a36Sopenharmony_ci move.l %d0,(%a0)+ 83862306a36Sopenharmony_ci move.w #0xf800,%d0 83962306a36Sopenharmony_ci move.l %d0,(%a0) 84062306a36Sopenharmony_ci jra 2b 84162306a36Sopenharmony_ci | Infinities or NaNs 84262306a36Sopenharmony_cifp_nd_huge: 84362306a36Sopenharmony_ci subq.l #4,%a0 84462306a36Sopenharmony_ci printf PNORM,"%p(",1,%a0 84562306a36Sopenharmony_ci printx PNORM,%a0@ 84662306a36Sopenharmony_ci printf PNORM,")\n" 84762306a36Sopenharmony_ci rts 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci | fp_normalize_single: 85062306a36Sopenharmony_ci | normalize an extended with single (23-bit) precision 85162306a36Sopenharmony_ci | args: %a0 (struct fp_ext *) 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_cifp_normalize_single: 85462306a36Sopenharmony_ci printf PNORM,"ns: %p(",1,%a0 85562306a36Sopenharmony_ci printx PNORM,%a0@ 85662306a36Sopenharmony_ci printf PNORM,") " 85762306a36Sopenharmony_ci addq.l #2,%a0 85862306a36Sopenharmony_ci move.w (%a0)+,%d2 85962306a36Sopenharmony_ci jeq fp_ns_zero | zero / denormalized 86062306a36Sopenharmony_ci cmp.w #0x7fff,%d2 86162306a36Sopenharmony_ci jeq fp_ns_huge | NaN / infinitive. 86262306a36Sopenharmony_ci sub.w #0x4000-0x7f,%d2 | will the exponent fit? 86362306a36Sopenharmony_ci jcs fp_ns_small | too small. 86462306a36Sopenharmony_ci cmp.w #0xfe,%d2 86562306a36Sopenharmony_ci jcc fp_ns_large | too big. 86662306a36Sopenharmony_ci move.l (%a0)+,%d0 | get high lword of mantissa 86762306a36Sopenharmony_cifp_ns_round: 86862306a36Sopenharmony_ci tst.l (%a0) | check the low lword 86962306a36Sopenharmony_ci jeq 1f 87062306a36Sopenharmony_ci | Set a sticky bit if it is non-zero. This should only 87162306a36Sopenharmony_ci | affect the rounding in what would otherwise be equal- 87262306a36Sopenharmony_ci | distance situations, which is what we want it to do. 87362306a36Sopenharmony_ci bset #0,%d0 87462306a36Sopenharmony_ci1: clr.l (%a0) | zap it from memory. 87562306a36Sopenharmony_ci | now, round off the low 8 bits of the hi lword. 87662306a36Sopenharmony_ci tst.b %d0 | 8 low bits. 87762306a36Sopenharmony_ci jne fp_ns_checkround | Are they non-zero? 87862306a36Sopenharmony_ci | nothing to do here 87962306a36Sopenharmony_ci subq.l #8,%a0 88062306a36Sopenharmony_ci printf PNORM,"%p(",1,%a0 88162306a36Sopenharmony_ci printx PNORM,%a0@ 88262306a36Sopenharmony_ci printf PNORM,")\n" 88362306a36Sopenharmony_ci rts 88462306a36Sopenharmony_cifp_ns_checkround: 88562306a36Sopenharmony_ci fp_set_sr FPSR_EXC_INEX2 | INEX2 bit 88662306a36Sopenharmony_ci clr.b -(%a0) | clear low byte of high lword 88762306a36Sopenharmony_ci subq.l #3,%a0 88862306a36Sopenharmony_ci move.w (FPD_RND,FPDATA),%d2 | rounding mode 88962306a36Sopenharmony_ci jne 2f | %d2 == 0, round to nearest 89062306a36Sopenharmony_ci tst.b %d0 | test guard bit 89162306a36Sopenharmony_ci jpl 9f | zero is closer 89262306a36Sopenharmony_ci btst #8,%d0 | test lsb bit 89362306a36Sopenharmony_ci | round to even behaviour, see above. 89462306a36Sopenharmony_ci jne fp_ns_doroundup | round to infinity 89562306a36Sopenharmony_ci lsl.b #1,%d0 | check low bits 89662306a36Sopenharmony_ci jeq 9f | round to zero 89762306a36Sopenharmony_cifp_ns_doroundup: 89862306a36Sopenharmony_ci | round (the mantissa, that is) towards infinity 89962306a36Sopenharmony_ci add.l #0x100,(%a0) 90062306a36Sopenharmony_ci jcc 9f | no overflow, good. 90162306a36Sopenharmony_ci | Overflow. This means that the %d1 was 0xffffff00, so it 90262306a36Sopenharmony_ci | is now zero. We will set the mantissa to reflect this, and 90362306a36Sopenharmony_ci | increment the exponent (checking for overflow there too) 90462306a36Sopenharmony_ci move.w #0x8000,(%a0) 90562306a36Sopenharmony_ci addq.w #1,-(%a0) 90662306a36Sopenharmony_ci cmp.w #0x407f,(%a0)+ | exponent now overflown? 90762306a36Sopenharmony_ci jeq fp_ns_large | yes, so make it infinity. 90862306a36Sopenharmony_ci9: subq.l #4,%a0 90962306a36Sopenharmony_ci printf PNORM,"%p(",1,%a0 91062306a36Sopenharmony_ci printx PNORM,%a0@ 91162306a36Sopenharmony_ci printf PNORM,")\n" 91262306a36Sopenharmony_ci rts 91362306a36Sopenharmony_ci | check nondefault rounding modes 91462306a36Sopenharmony_ci2: subq.w #2,%d2 91562306a36Sopenharmony_ci jcs 9b | %d2 < 2, round to zero 91662306a36Sopenharmony_ci jhi 3f | %d2 > 2, round to +infinity 91762306a36Sopenharmony_ci tst.b (-3,%a0) | to -inf 91862306a36Sopenharmony_ci jne fp_ns_doroundup | negative, round to infinity 91962306a36Sopenharmony_ci jra 9b | positive, round to zero 92062306a36Sopenharmony_ci3: tst.b (-3,%a0) | to +inf 92162306a36Sopenharmony_ci jeq fp_ns_doroundup | positive, round to infinity 92262306a36Sopenharmony_ci jra 9b | negative, round to zero 92362306a36Sopenharmony_ci | Exponent underflow. Try to make a denormal, and set it to 92462306a36Sopenharmony_ci | the smallest possible fraction if this fails. 92562306a36Sopenharmony_cifp_ns_small: 92662306a36Sopenharmony_ci fp_set_sr FPSR_EXC_UNFL | set UNFL bit 92762306a36Sopenharmony_ci move.w #0x3f81,(-2,%a0) | 2**-126 92862306a36Sopenharmony_ci neg.w %d2 | degree of underflow 92962306a36Sopenharmony_ci cmp.w #32,%d2 | single or double shift? 93062306a36Sopenharmony_ci jcc 2f 93162306a36Sopenharmony_ci | a 32-bit shift. 93262306a36Sopenharmony_ci move.l (%a0),%d0 93362306a36Sopenharmony_ci move.l %d0,%d1 93462306a36Sopenharmony_ci lsr.l %d2,%d0 93562306a36Sopenharmony_ci move.l %d0,(%a0)+ 93662306a36Sopenharmony_ci | Check to see if we shifted off any significant bits. 93762306a36Sopenharmony_ci neg.w %d2 93862306a36Sopenharmony_ci add.w #32,%d2 93962306a36Sopenharmony_ci lsl.l %d2,%d1 94062306a36Sopenharmony_ci jeq 1f 94162306a36Sopenharmony_ci bset #0,%d0 | Sticky bit. 94262306a36Sopenharmony_ci | Check the lower lword 94362306a36Sopenharmony_ci1: tst.l (%a0) 94462306a36Sopenharmony_ci jeq fp_ns_round 94562306a36Sopenharmony_ci clr (%a0) 94662306a36Sopenharmony_ci bset #0,%d0 | Sticky bit. 94762306a36Sopenharmony_ci jra fp_ns_round 94862306a36Sopenharmony_ci | Sorry, the number is just too small. 94962306a36Sopenharmony_ci2: clr.l (%a0)+ 95062306a36Sopenharmony_ci clr.l (%a0) 95162306a36Sopenharmony_ci moveq #1,%d0 | Smallest possible fraction, 95262306a36Sopenharmony_ci jra fp_ns_round | round as desired. 95362306a36Sopenharmony_ci | Exponent overflow. Just call it infinity. 95462306a36Sopenharmony_cifp_ns_large: 95562306a36Sopenharmony_ci tst.b (3,%a0) 95662306a36Sopenharmony_ci jeq 1f 95762306a36Sopenharmony_ci fp_set_sr FPSR_EXC_INEX2 95862306a36Sopenharmony_ci1: fp_set_sr FPSR_EXC_OVFL 95962306a36Sopenharmony_ci move.w (FPD_RND,FPDATA),%d2 96062306a36Sopenharmony_ci jne 3f | %d2 = 0 round to nearest 96162306a36Sopenharmony_ci1: move.w #0x7fff,(-2,%a0) 96262306a36Sopenharmony_ci clr.l (%a0)+ 96362306a36Sopenharmony_ci clr.l (%a0) 96462306a36Sopenharmony_ci2: subq.l #8,%a0 96562306a36Sopenharmony_ci printf PNORM,"%p(",1,%a0 96662306a36Sopenharmony_ci printx PNORM,%a0@ 96762306a36Sopenharmony_ci printf PNORM,")\n" 96862306a36Sopenharmony_ci rts 96962306a36Sopenharmony_ci3: subq.w #2,%d2 97062306a36Sopenharmony_ci jcs 5f | %d2 < 2, round to zero 97162306a36Sopenharmony_ci jhi 4f | %d2 > 2, round to +infinity 97262306a36Sopenharmony_ci tst.b (-3,%a0) | to -inf 97362306a36Sopenharmony_ci jne 1b 97462306a36Sopenharmony_ci jra 5f 97562306a36Sopenharmony_ci4: tst.b (-3,%a0) | to +inf 97662306a36Sopenharmony_ci jeq 1b 97762306a36Sopenharmony_ci5: move.w #0x407e,(-2,%a0) 97862306a36Sopenharmony_ci move.l #0xffffff00,(%a0)+ 97962306a36Sopenharmony_ci clr.l (%a0) 98062306a36Sopenharmony_ci jra 2b 98162306a36Sopenharmony_ci | zero and denormalized 98262306a36Sopenharmony_cifp_ns_zero: 98362306a36Sopenharmony_ci tst.l (%a0)+ 98462306a36Sopenharmony_ci jne 1f 98562306a36Sopenharmony_ci tst.l (%a0) 98662306a36Sopenharmony_ci jne 1f 98762306a36Sopenharmony_ci subq.l #8,%a0 98862306a36Sopenharmony_ci printf PNORM,"%p(",1,%a0 98962306a36Sopenharmony_ci printx PNORM,%a0@ 99062306a36Sopenharmony_ci printf PNORM,")\n" 99162306a36Sopenharmony_ci rts | zero. nothing to do. 99262306a36Sopenharmony_ci | These are not merely subnormal numbers, but true denormals, 99362306a36Sopenharmony_ci | i.e. pathologically small (exponent is 2**-16383) numbers. 99462306a36Sopenharmony_ci | It is clearly impossible for even a normal extended number 99562306a36Sopenharmony_ci | with that exponent to fit into single precision, so just 99662306a36Sopenharmony_ci | write these ones off as "too darn small". 99762306a36Sopenharmony_ci1: fp_set_sr FPSR_EXC_UNFL | Set UNFL bit 99862306a36Sopenharmony_ci clr.l (%a0) 99962306a36Sopenharmony_ci clr.l -(%a0) 100062306a36Sopenharmony_ci move.w #0x3f81,-(%a0) | i.e. 2**-126 100162306a36Sopenharmony_ci addq.l #6,%a0 100262306a36Sopenharmony_ci moveq #1,%d0 100362306a36Sopenharmony_ci jra fp_ns_round | round. 100462306a36Sopenharmony_ci | Infinities or NaNs 100562306a36Sopenharmony_cifp_ns_huge: 100662306a36Sopenharmony_ci subq.l #4,%a0 100762306a36Sopenharmony_ci printf PNORM,"%p(",1,%a0 100862306a36Sopenharmony_ci printx PNORM,%a0@ 100962306a36Sopenharmony_ci printf PNORM,")\n" 101062306a36Sopenharmony_ci rts 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci | fp_normalize_single_fast: 101362306a36Sopenharmony_ci | normalize an extended with single (23-bit) precision 101462306a36Sopenharmony_ci | this is only used by fsgldiv/fsgdlmul, where the 101562306a36Sopenharmony_ci | operand is not completly normalized. 101662306a36Sopenharmony_ci | args: %a0 (struct fp_ext *) 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_cifp_normalize_single_fast: 101962306a36Sopenharmony_ci printf PNORM,"nsf: %p(",1,%a0 102062306a36Sopenharmony_ci printx PNORM,%a0@ 102162306a36Sopenharmony_ci printf PNORM,") " 102262306a36Sopenharmony_ci addq.l #2,%a0 102362306a36Sopenharmony_ci move.w (%a0)+,%d2 102462306a36Sopenharmony_ci cmp.w #0x7fff,%d2 102562306a36Sopenharmony_ci jeq fp_nsf_huge | NaN / infinitive. 102662306a36Sopenharmony_ci move.l (%a0)+,%d0 | get high lword of mantissa 102762306a36Sopenharmony_cifp_nsf_round: 102862306a36Sopenharmony_ci tst.l (%a0) | check the low lword 102962306a36Sopenharmony_ci jeq 1f 103062306a36Sopenharmony_ci | Set a sticky bit if it is non-zero. This should only 103162306a36Sopenharmony_ci | affect the rounding in what would otherwise be equal- 103262306a36Sopenharmony_ci | distance situations, which is what we want it to do. 103362306a36Sopenharmony_ci bset #0,%d0 103462306a36Sopenharmony_ci1: clr.l (%a0) | zap it from memory. 103562306a36Sopenharmony_ci | now, round off the low 8 bits of the hi lword. 103662306a36Sopenharmony_ci tst.b %d0 | 8 low bits. 103762306a36Sopenharmony_ci jne fp_nsf_checkround | Are they non-zero? 103862306a36Sopenharmony_ci | nothing to do here 103962306a36Sopenharmony_ci subq.l #8,%a0 104062306a36Sopenharmony_ci printf PNORM,"%p(",1,%a0 104162306a36Sopenharmony_ci printx PNORM,%a0@ 104262306a36Sopenharmony_ci printf PNORM,")\n" 104362306a36Sopenharmony_ci rts 104462306a36Sopenharmony_cifp_nsf_checkround: 104562306a36Sopenharmony_ci fp_set_sr FPSR_EXC_INEX2 | INEX2 bit 104662306a36Sopenharmony_ci clr.b -(%a0) | clear low byte of high lword 104762306a36Sopenharmony_ci subq.l #3,%a0 104862306a36Sopenharmony_ci move.w (FPD_RND,FPDATA),%d2 | rounding mode 104962306a36Sopenharmony_ci jne 2f | %d2 == 0, round to nearest 105062306a36Sopenharmony_ci tst.b %d0 | test guard bit 105162306a36Sopenharmony_ci jpl 9f | zero is closer 105262306a36Sopenharmony_ci btst #8,%d0 | test lsb bit 105362306a36Sopenharmony_ci | round to even behaviour, see above. 105462306a36Sopenharmony_ci jne fp_nsf_doroundup | round to infinity 105562306a36Sopenharmony_ci lsl.b #1,%d0 | check low bits 105662306a36Sopenharmony_ci jeq 9f | round to zero 105762306a36Sopenharmony_cifp_nsf_doroundup: 105862306a36Sopenharmony_ci | round (the mantissa, that is) towards infinity 105962306a36Sopenharmony_ci add.l #0x100,(%a0) 106062306a36Sopenharmony_ci jcc 9f | no overflow, good. 106162306a36Sopenharmony_ci | Overflow. This means that the %d1 was 0xffffff00, so it 106262306a36Sopenharmony_ci | is now zero. We will set the mantissa to reflect this, and 106362306a36Sopenharmony_ci | increment the exponent (checking for overflow there too) 106462306a36Sopenharmony_ci move.w #0x8000,(%a0) 106562306a36Sopenharmony_ci addq.w #1,-(%a0) 106662306a36Sopenharmony_ci cmp.w #0x407f,(%a0)+ | exponent now overflown? 106762306a36Sopenharmony_ci jeq fp_nsf_large | yes, so make it infinity. 106862306a36Sopenharmony_ci9: subq.l #4,%a0 106962306a36Sopenharmony_ci printf PNORM,"%p(",1,%a0 107062306a36Sopenharmony_ci printx PNORM,%a0@ 107162306a36Sopenharmony_ci printf PNORM,")\n" 107262306a36Sopenharmony_ci rts 107362306a36Sopenharmony_ci | check nondefault rounding modes 107462306a36Sopenharmony_ci2: subq.w #2,%d2 107562306a36Sopenharmony_ci jcs 9b | %d2 < 2, round to zero 107662306a36Sopenharmony_ci jhi 3f | %d2 > 2, round to +infinity 107762306a36Sopenharmony_ci tst.b (-3,%a0) | to -inf 107862306a36Sopenharmony_ci jne fp_nsf_doroundup | negative, round to infinity 107962306a36Sopenharmony_ci jra 9b | positive, round to zero 108062306a36Sopenharmony_ci3: tst.b (-3,%a0) | to +inf 108162306a36Sopenharmony_ci jeq fp_nsf_doroundup | positive, round to infinity 108262306a36Sopenharmony_ci jra 9b | negative, round to zero 108362306a36Sopenharmony_ci | Exponent overflow. Just call it infinity. 108462306a36Sopenharmony_cifp_nsf_large: 108562306a36Sopenharmony_ci tst.b (3,%a0) 108662306a36Sopenharmony_ci jeq 1f 108762306a36Sopenharmony_ci fp_set_sr FPSR_EXC_INEX2 108862306a36Sopenharmony_ci1: fp_set_sr FPSR_EXC_OVFL 108962306a36Sopenharmony_ci move.w (FPD_RND,FPDATA),%d2 109062306a36Sopenharmony_ci jne 3f | %d2 = 0 round to nearest 109162306a36Sopenharmony_ci1: move.w #0x7fff,(-2,%a0) 109262306a36Sopenharmony_ci clr.l (%a0)+ 109362306a36Sopenharmony_ci clr.l (%a0) 109462306a36Sopenharmony_ci2: subq.l #8,%a0 109562306a36Sopenharmony_ci printf PNORM,"%p(",1,%a0 109662306a36Sopenharmony_ci printx PNORM,%a0@ 109762306a36Sopenharmony_ci printf PNORM,")\n" 109862306a36Sopenharmony_ci rts 109962306a36Sopenharmony_ci3: subq.w #2,%d2 110062306a36Sopenharmony_ci jcs 5f | %d2 < 2, round to zero 110162306a36Sopenharmony_ci jhi 4f | %d2 > 2, round to +infinity 110262306a36Sopenharmony_ci tst.b (-3,%a0) | to -inf 110362306a36Sopenharmony_ci jne 1b 110462306a36Sopenharmony_ci jra 5f 110562306a36Sopenharmony_ci4: tst.b (-3,%a0) | to +inf 110662306a36Sopenharmony_ci jeq 1b 110762306a36Sopenharmony_ci5: move.w #0x407e,(-2,%a0) 110862306a36Sopenharmony_ci move.l #0xffffff00,(%a0)+ 110962306a36Sopenharmony_ci clr.l (%a0) 111062306a36Sopenharmony_ci jra 2b 111162306a36Sopenharmony_ci | Infinities or NaNs 111262306a36Sopenharmony_cifp_nsf_huge: 111362306a36Sopenharmony_ci subq.l #4,%a0 111462306a36Sopenharmony_ci printf PNORM,"%p(",1,%a0 111562306a36Sopenharmony_ci printx PNORM,%a0@ 111662306a36Sopenharmony_ci printf PNORM,")\n" 111762306a36Sopenharmony_ci rts 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci | conv_ext2int (macro): 112062306a36Sopenharmony_ci | Generates a subroutine that converts an extended value to an 112162306a36Sopenharmony_ci | integer of a given size, again, with the appropriate type of 112262306a36Sopenharmony_ci | rounding. 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci | Macro arguments: 112562306a36Sopenharmony_ci | s: size, as given in an assembly instruction. 112662306a36Sopenharmony_ci | b: number of bits in that size. 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci | Subroutine arguments: 112962306a36Sopenharmony_ci | %a0: source (struct fp_ext *) 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci | Returns the integer in %d0 (like it should) 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci.macro conv_ext2int s,b 113462306a36Sopenharmony_ci .set inf,(1<<(\b-1))-1 | i.e. MAXINT 113562306a36Sopenharmony_ci printf PCONV,"e2i%d: %p(",2,#\b,%a0 113662306a36Sopenharmony_ci printx PCONV,%a0@ 113762306a36Sopenharmony_ci printf PCONV,") " 113862306a36Sopenharmony_ci addq.l #2,%a0 113962306a36Sopenharmony_ci move.w (%a0)+,%d2 | exponent 114062306a36Sopenharmony_ci jeq fp_e2i_zero\b | zero / denorm (== 0, here) 114162306a36Sopenharmony_ci cmp.w #0x7fff,%d2 114262306a36Sopenharmony_ci jeq fp_e2i_huge\b | Inf / NaN 114362306a36Sopenharmony_ci sub.w #0x3ffe,%d2 114462306a36Sopenharmony_ci jcs fp_e2i_small\b 114562306a36Sopenharmony_ci cmp.w #\b,%d2 114662306a36Sopenharmony_ci jhi fp_e2i_large\b 114762306a36Sopenharmony_ci move.l (%a0),%d0 114862306a36Sopenharmony_ci move.l %d0,%d1 114962306a36Sopenharmony_ci lsl.l %d2,%d1 115062306a36Sopenharmony_ci jne fp_e2i_round\b 115162306a36Sopenharmony_ci tst.l (4,%a0) 115262306a36Sopenharmony_ci jne fp_e2i_round\b 115362306a36Sopenharmony_ci neg.w %d2 115462306a36Sopenharmony_ci add.w #32,%d2 115562306a36Sopenharmony_ci lsr.l %d2,%d0 115662306a36Sopenharmony_ci9: tst.w (-4,%a0) 115762306a36Sopenharmony_ci jne 1f 115862306a36Sopenharmony_ci tst.\s %d0 115962306a36Sopenharmony_ci jmi fp_e2i_large\b 116062306a36Sopenharmony_ci printf PCONV,"-> %p\n",1,%d0 116162306a36Sopenharmony_ci rts 116262306a36Sopenharmony_ci1: neg.\s %d0 116362306a36Sopenharmony_ci jeq 1f 116462306a36Sopenharmony_ci jpl fp_e2i_large\b 116562306a36Sopenharmony_ci1: printf PCONV,"-> %p\n",1,%d0 116662306a36Sopenharmony_ci rts 116762306a36Sopenharmony_cifp_e2i_round\b: 116862306a36Sopenharmony_ci fp_set_sr FPSR_EXC_INEX2 | INEX2 bit 116962306a36Sopenharmony_ci neg.w %d2 117062306a36Sopenharmony_ci add.w #32,%d2 117162306a36Sopenharmony_ci .if \b>16 117262306a36Sopenharmony_ci jeq 5f 117362306a36Sopenharmony_ci .endif 117462306a36Sopenharmony_ci lsr.l %d2,%d0 117562306a36Sopenharmony_ci move.w (FPD_RND,FPDATA),%d2 | rounding mode 117662306a36Sopenharmony_ci jne 2f | %d2 == 0, round to nearest 117762306a36Sopenharmony_ci tst.l %d1 | test guard bit 117862306a36Sopenharmony_ci jpl 9b | zero is closer 117962306a36Sopenharmony_ci btst %d2,%d0 | test lsb bit (%d2 still 0) 118062306a36Sopenharmony_ci jne fp_e2i_doroundup\b 118162306a36Sopenharmony_ci lsl.l #1,%d1 | check low bits 118262306a36Sopenharmony_ci jne fp_e2i_doroundup\b 118362306a36Sopenharmony_ci tst.l (4,%a0) 118462306a36Sopenharmony_ci jeq 9b 118562306a36Sopenharmony_cifp_e2i_doroundup\b: 118662306a36Sopenharmony_ci addq.l #1,%d0 118762306a36Sopenharmony_ci jra 9b 118862306a36Sopenharmony_ci | check nondefault rounding modes 118962306a36Sopenharmony_ci2: subq.w #2,%d2 119062306a36Sopenharmony_ci jcs 9b | %d2 < 2, round to zero 119162306a36Sopenharmony_ci jhi 3f | %d2 > 2, round to +infinity 119262306a36Sopenharmony_ci tst.w (-4,%a0) | to -inf 119362306a36Sopenharmony_ci jne fp_e2i_doroundup\b | negative, round to infinity 119462306a36Sopenharmony_ci jra 9b | positive, round to zero 119562306a36Sopenharmony_ci3: tst.w (-4,%a0) | to +inf 119662306a36Sopenharmony_ci jeq fp_e2i_doroundup\b | positive, round to infinity 119762306a36Sopenharmony_ci jra 9b | negative, round to zero 119862306a36Sopenharmony_ci | we are only want -2**127 get correctly rounded here, 119962306a36Sopenharmony_ci | since the guard bit is in the lower lword. 120062306a36Sopenharmony_ci | everything else ends up anyway as overflow. 120162306a36Sopenharmony_ci .if \b>16 120262306a36Sopenharmony_ci5: move.w (FPD_RND,FPDATA),%d2 | rounding mode 120362306a36Sopenharmony_ci jne 2b | %d2 == 0, round to nearest 120462306a36Sopenharmony_ci move.l (4,%a0),%d1 | test guard bit 120562306a36Sopenharmony_ci jpl 9b | zero is closer 120662306a36Sopenharmony_ci lsl.l #1,%d1 | check low bits 120762306a36Sopenharmony_ci jne fp_e2i_doroundup\b 120862306a36Sopenharmony_ci jra 9b 120962306a36Sopenharmony_ci .endif 121062306a36Sopenharmony_cifp_e2i_zero\b: 121162306a36Sopenharmony_ci clr.l %d0 121262306a36Sopenharmony_ci tst.l (%a0)+ 121362306a36Sopenharmony_ci jne 1f 121462306a36Sopenharmony_ci tst.l (%a0) 121562306a36Sopenharmony_ci jeq 3f 121662306a36Sopenharmony_ci1: subq.l #4,%a0 121762306a36Sopenharmony_ci fp_clr_sr FPSR_EXC_UNFL | fp_normalize_ext has set this bit 121862306a36Sopenharmony_cifp_e2i_small\b: 121962306a36Sopenharmony_ci fp_set_sr FPSR_EXC_INEX2 122062306a36Sopenharmony_ci clr.l %d0 122162306a36Sopenharmony_ci move.w (FPD_RND,FPDATA),%d2 | rounding mode 122262306a36Sopenharmony_ci subq.w #2,%d2 122362306a36Sopenharmony_ci jcs 3f | %d2 < 2, round to nearest/zero 122462306a36Sopenharmony_ci jhi 2f | %d2 > 2, round to +infinity 122562306a36Sopenharmony_ci tst.w (-4,%a0) | to -inf 122662306a36Sopenharmony_ci jeq 3f 122762306a36Sopenharmony_ci subq.\s #1,%d0 122862306a36Sopenharmony_ci jra 3f 122962306a36Sopenharmony_ci2: tst.w (-4,%a0) | to +inf 123062306a36Sopenharmony_ci jne 3f 123162306a36Sopenharmony_ci addq.\s #1,%d0 123262306a36Sopenharmony_ci3: printf PCONV,"-> %p\n",1,%d0 123362306a36Sopenharmony_ci rts 123462306a36Sopenharmony_cifp_e2i_large\b: 123562306a36Sopenharmony_ci fp_set_sr FPSR_EXC_OPERR 123662306a36Sopenharmony_ci move.\s #inf,%d0 123762306a36Sopenharmony_ci tst.w (-4,%a0) 123862306a36Sopenharmony_ci jeq 1f 123962306a36Sopenharmony_ci addq.\s #1,%d0 124062306a36Sopenharmony_ci1: printf PCONV,"-> %p\n",1,%d0 124162306a36Sopenharmony_ci rts 124262306a36Sopenharmony_cifp_e2i_huge\b: 124362306a36Sopenharmony_ci move.\s (%a0),%d0 124462306a36Sopenharmony_ci tst.l (%a0) 124562306a36Sopenharmony_ci jne 1f 124662306a36Sopenharmony_ci tst.l (%a0) 124762306a36Sopenharmony_ci jeq fp_e2i_large\b 124862306a36Sopenharmony_ci | fp_normalize_ext has set this bit already 124962306a36Sopenharmony_ci | and made the number nonsignaling 125062306a36Sopenharmony_ci1: fp_tst_sr FPSR_EXC_SNAN 125162306a36Sopenharmony_ci jne 1f 125262306a36Sopenharmony_ci fp_set_sr FPSR_EXC_OPERR 125362306a36Sopenharmony_ci1: printf PCONV,"-> %p\n",1,%d0 125462306a36Sopenharmony_ci rts 125562306a36Sopenharmony_ci.endm 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_cifp_conv_ext2long: 125862306a36Sopenharmony_ci conv_ext2int l,32 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_cifp_conv_ext2short: 126162306a36Sopenharmony_ci conv_ext2int w,16 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_cifp_conv_ext2byte: 126462306a36Sopenharmony_ci conv_ext2int b,8 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_cifp_conv_ext2double: 126762306a36Sopenharmony_ci jsr fp_normalize_double 126862306a36Sopenharmony_ci printf PCONV,"e2d: %p(",1,%a0 126962306a36Sopenharmony_ci printx PCONV,%a0@ 127062306a36Sopenharmony_ci printf PCONV,"), " 127162306a36Sopenharmony_ci move.l (%a0)+,%d2 127262306a36Sopenharmony_ci cmp.w #0x7fff,%d2 127362306a36Sopenharmony_ci jne 1f 127462306a36Sopenharmony_ci move.w #0x7ff,%d2 127562306a36Sopenharmony_ci move.l (%a0)+,%d0 127662306a36Sopenharmony_ci jra 2f 127762306a36Sopenharmony_ci1: sub.w #0x3fff-0x3ff,%d2 127862306a36Sopenharmony_ci move.l (%a0)+,%d0 127962306a36Sopenharmony_ci jmi 2f 128062306a36Sopenharmony_ci clr.w %d2 128162306a36Sopenharmony_ci2: lsl.w #5,%d2 128262306a36Sopenharmony_ci lsl.l #7,%d2 128362306a36Sopenharmony_ci lsl.l #8,%d2 128462306a36Sopenharmony_ci move.l %d0,%d1 128562306a36Sopenharmony_ci lsl.l #1,%d0 128662306a36Sopenharmony_ci lsr.l #4,%d0 128762306a36Sopenharmony_ci lsr.l #8,%d0 128862306a36Sopenharmony_ci or.l %d2,%d0 128962306a36Sopenharmony_ci putuser.l %d0,(%a1)+,fp_err_ua2,%a1 129062306a36Sopenharmony_ci moveq #21,%d0 129162306a36Sopenharmony_ci lsl.l %d0,%d1 129262306a36Sopenharmony_ci move.l (%a0),%d0 129362306a36Sopenharmony_ci lsr.l #4,%d0 129462306a36Sopenharmony_ci lsr.l #7,%d0 129562306a36Sopenharmony_ci or.l %d1,%d0 129662306a36Sopenharmony_ci putuser.l %d0,(%a1),fp_err_ua2,%a1 129762306a36Sopenharmony_ci#ifdef FPU_EMU_DEBUG 129862306a36Sopenharmony_ci getuser.l %a1@(-4),%d0,fp_err_ua2,%a1 129962306a36Sopenharmony_ci getuser.l %a1@(0),%d1,fp_err_ua2,%a1 130062306a36Sopenharmony_ci printf PCONV,"%p(%08x%08x)\n",3,%a1,%d0,%d1 130162306a36Sopenharmony_ci#endif 130262306a36Sopenharmony_ci rts 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_cifp_conv_ext2single: 130562306a36Sopenharmony_ci jsr fp_normalize_single 130662306a36Sopenharmony_ci printf PCONV,"e2s: %p(",1,%a0 130762306a36Sopenharmony_ci printx PCONV,%a0@ 130862306a36Sopenharmony_ci printf PCONV,"), " 130962306a36Sopenharmony_ci move.l (%a0)+,%d1 131062306a36Sopenharmony_ci cmp.w #0x7fff,%d1 131162306a36Sopenharmony_ci jne 1f 131262306a36Sopenharmony_ci move.w #0xff,%d1 131362306a36Sopenharmony_ci move.l (%a0)+,%d0 131462306a36Sopenharmony_ci jra 2f 131562306a36Sopenharmony_ci1: sub.w #0x3fff-0x7f,%d1 131662306a36Sopenharmony_ci move.l (%a0)+,%d0 131762306a36Sopenharmony_ci jmi 2f 131862306a36Sopenharmony_ci clr.w %d1 131962306a36Sopenharmony_ci2: lsl.w #8,%d1 132062306a36Sopenharmony_ci lsl.l #7,%d1 132162306a36Sopenharmony_ci lsl.l #8,%d1 132262306a36Sopenharmony_ci bclr #31,%d0 132362306a36Sopenharmony_ci lsr.l #8,%d0 132462306a36Sopenharmony_ci or.l %d1,%d0 132562306a36Sopenharmony_ci printf PCONV,"%08x\n",1,%d0 132662306a36Sopenharmony_ci rts 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci | special return addresses for instr that 132962306a36Sopenharmony_ci | encode the rounding precision in the opcode 133062306a36Sopenharmony_ci | (e.g. fsmove,fdmove) 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_cifp_finalrounding_single: 133362306a36Sopenharmony_ci addq.l #8,%sp 133462306a36Sopenharmony_ci jsr fp_normalize_ext 133562306a36Sopenharmony_ci jsr fp_normalize_single 133662306a36Sopenharmony_ci jra fp_finaltest 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_cifp_finalrounding_single_fast: 133962306a36Sopenharmony_ci addq.l #8,%sp 134062306a36Sopenharmony_ci jsr fp_normalize_ext 134162306a36Sopenharmony_ci jsr fp_normalize_single_fast 134262306a36Sopenharmony_ci jra fp_finaltest 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_cifp_finalrounding_double: 134562306a36Sopenharmony_ci addq.l #8,%sp 134662306a36Sopenharmony_ci jsr fp_normalize_ext 134762306a36Sopenharmony_ci jsr fp_normalize_double 134862306a36Sopenharmony_ci jra fp_finaltest 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci | fp_finaltest: 135162306a36Sopenharmony_ci | set the emulated status register based on the outcome of an 135262306a36Sopenharmony_ci | emulated instruction. 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_cifp_finalrounding: 135562306a36Sopenharmony_ci addq.l #8,%sp 135662306a36Sopenharmony_ci| printf ,"f: %p\n",1,%a0 135762306a36Sopenharmony_ci jsr fp_normalize_ext 135862306a36Sopenharmony_ci move.w (FPD_PREC,FPDATA),%d0 135962306a36Sopenharmony_ci subq.w #1,%d0 136062306a36Sopenharmony_ci jcs fp_finaltest 136162306a36Sopenharmony_ci jne 1f 136262306a36Sopenharmony_ci jsr fp_normalize_single 136362306a36Sopenharmony_ci jra 2f 136462306a36Sopenharmony_ci1: jsr fp_normalize_double 136562306a36Sopenharmony_ci2:| printf ,"f: %p\n",1,%a0 136662306a36Sopenharmony_cifp_finaltest: 136762306a36Sopenharmony_ci | First, we do some of the obvious tests for the exception 136862306a36Sopenharmony_ci | status byte and condition code bytes of fp_sr here, so that 136962306a36Sopenharmony_ci | they do not have to be handled individually by every 137062306a36Sopenharmony_ci | emulated instruction. 137162306a36Sopenharmony_ci clr.l %d0 137262306a36Sopenharmony_ci addq.l #1,%a0 137362306a36Sopenharmony_ci tst.b (%a0)+ | sign 137462306a36Sopenharmony_ci jeq 1f 137562306a36Sopenharmony_ci bset #FPSR_CC_NEG-24,%d0 | N bit 137662306a36Sopenharmony_ci1: cmp.w #0x7fff,(%a0)+ | exponent 137762306a36Sopenharmony_ci jeq 2f 137862306a36Sopenharmony_ci | test for zero 137962306a36Sopenharmony_ci moveq #FPSR_CC_Z-24,%d1 138062306a36Sopenharmony_ci tst.l (%a0)+ 138162306a36Sopenharmony_ci jne 9f 138262306a36Sopenharmony_ci tst.l (%a0) 138362306a36Sopenharmony_ci jne 9f 138462306a36Sopenharmony_ci jra 8f 138562306a36Sopenharmony_ci | infinitiv and NAN 138662306a36Sopenharmony_ci2: moveq #FPSR_CC_NAN-24,%d1 138762306a36Sopenharmony_ci move.l (%a0)+,%d2 138862306a36Sopenharmony_ci lsl.l #1,%d2 | ignore high bit 138962306a36Sopenharmony_ci jne 8f 139062306a36Sopenharmony_ci tst.l (%a0) 139162306a36Sopenharmony_ci jne 8f 139262306a36Sopenharmony_ci moveq #FPSR_CC_INF-24,%d1 139362306a36Sopenharmony_ci8: bset %d1,%d0 139462306a36Sopenharmony_ci9: move.b %d0,(FPD_FPSR+0,FPDATA) | set condition test result 139562306a36Sopenharmony_ci | move instructions enter here 139662306a36Sopenharmony_ci | Here, we test things in the exception status byte, and set 139762306a36Sopenharmony_ci | other things in the accrued exception byte accordingly. 139862306a36Sopenharmony_ci | Emulated instructions can set various things in the former, 139962306a36Sopenharmony_ci | as defined in fp_emu.h. 140062306a36Sopenharmony_cifp_final: 140162306a36Sopenharmony_ci move.l (FPD_FPSR,FPDATA),%d0 140262306a36Sopenharmony_ci#if 0 140362306a36Sopenharmony_ci btst #FPSR_EXC_SNAN,%d0 | EXC_SNAN 140462306a36Sopenharmony_ci jne 1f 140562306a36Sopenharmony_ci btst #FPSR_EXC_OPERR,%d0 | EXC_OPERR 140662306a36Sopenharmony_ci jeq 2f 140762306a36Sopenharmony_ci1: bset #FPSR_AEXC_IOP,%d0 | set IOP bit 140862306a36Sopenharmony_ci2: btst #FPSR_EXC_OVFL,%d0 | EXC_OVFL 140962306a36Sopenharmony_ci jeq 1f 141062306a36Sopenharmony_ci bset #FPSR_AEXC_OVFL,%d0 | set OVFL bit 141162306a36Sopenharmony_ci1: btst #FPSR_EXC_UNFL,%d0 | EXC_UNFL 141262306a36Sopenharmony_ci jeq 1f 141362306a36Sopenharmony_ci btst #FPSR_EXC_INEX2,%d0 | EXC_INEX2 141462306a36Sopenharmony_ci jeq 1f 141562306a36Sopenharmony_ci bset #FPSR_AEXC_UNFL,%d0 | set UNFL bit 141662306a36Sopenharmony_ci1: btst #FPSR_EXC_DZ,%d0 | EXC_INEX1 141762306a36Sopenharmony_ci jeq 1f 141862306a36Sopenharmony_ci bset #FPSR_AEXC_DZ,%d0 | set DZ bit 141962306a36Sopenharmony_ci1: btst #FPSR_EXC_OVFL,%d0 | EXC_OVFL 142062306a36Sopenharmony_ci jne 1f 142162306a36Sopenharmony_ci btst #FPSR_EXC_INEX2,%d0 | EXC_INEX2 142262306a36Sopenharmony_ci jne 1f 142362306a36Sopenharmony_ci btst #FPSR_EXC_INEX1,%d0 | EXC_INEX1 142462306a36Sopenharmony_ci jeq 2f 142562306a36Sopenharmony_ci1: bset #FPSR_AEXC_INEX,%d0 | set INEX bit 142662306a36Sopenharmony_ci2: move.l %d0,(FPD_FPSR,FPDATA) 142762306a36Sopenharmony_ci#else 142862306a36Sopenharmony_ci | same as above, greatly optimized, but untested (yet) 142962306a36Sopenharmony_ci move.l %d0,%d2 143062306a36Sopenharmony_ci lsr.l #5,%d0 143162306a36Sopenharmony_ci move.l %d0,%d1 143262306a36Sopenharmony_ci lsr.l #4,%d1 143362306a36Sopenharmony_ci or.l %d0,%d1 143462306a36Sopenharmony_ci and.b #0x08,%d1 143562306a36Sopenharmony_ci move.l %d2,%d0 143662306a36Sopenharmony_ci lsr.l #6,%d0 143762306a36Sopenharmony_ci or.l %d1,%d0 143862306a36Sopenharmony_ci move.l %d2,%d1 143962306a36Sopenharmony_ci lsr.l #4,%d1 144062306a36Sopenharmony_ci or.b #0xdf,%d1 144162306a36Sopenharmony_ci and.b %d1,%d0 144262306a36Sopenharmony_ci move.l %d2,%d1 144362306a36Sopenharmony_ci lsr.l #7,%d1 144462306a36Sopenharmony_ci and.b #0x80,%d1 144562306a36Sopenharmony_ci or.b %d1,%d0 144662306a36Sopenharmony_ci and.b #0xf8,%d0 144762306a36Sopenharmony_ci or.b %d0,%d2 144862306a36Sopenharmony_ci move.l %d2,(FPD_FPSR,FPDATA) 144962306a36Sopenharmony_ci#endif 145062306a36Sopenharmony_ci move.b (FPD_FPSR+2,FPDATA),%d0 145162306a36Sopenharmony_ci and.b (FPD_FPCR+2,FPDATA),%d0 145262306a36Sopenharmony_ci jeq 1f 145362306a36Sopenharmony_ci printf ,"send signal!!!\n" 145462306a36Sopenharmony_ci1: jra fp_end 1455