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