17e76048aSMarcel Moolenaar /* $NetBSD: fpu_implode.c,v 1.6 2005/12/11 12:18:42 christos Exp $ */ 27e76048aSMarcel Moolenaar 37e76048aSMarcel Moolenaar /* 47e76048aSMarcel Moolenaar * Copyright (c) 1992, 1993 57e76048aSMarcel Moolenaar * The Regents of the University of California. All rights reserved. 67e76048aSMarcel Moolenaar * 77e76048aSMarcel Moolenaar * This software was developed by the Computer Systems Engineering group 87e76048aSMarcel Moolenaar * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 97e76048aSMarcel Moolenaar * contributed to Berkeley. 107e76048aSMarcel Moolenaar * 117e76048aSMarcel Moolenaar * All advertising materials mentioning features or use of this software 127e76048aSMarcel Moolenaar * must display the following acknowledgement: 137e76048aSMarcel Moolenaar * This product includes software developed by the University of 147e76048aSMarcel Moolenaar * California, Lawrence Berkeley Laboratory. 157e76048aSMarcel Moolenaar * 167e76048aSMarcel Moolenaar * Redistribution and use in source and binary forms, with or without 177e76048aSMarcel Moolenaar * modification, are permitted provided that the following conditions 187e76048aSMarcel Moolenaar * are met: 197e76048aSMarcel Moolenaar * 1. Redistributions of source code must retain the above copyright 207e76048aSMarcel Moolenaar * notice, this list of conditions and the following disclaimer. 217e76048aSMarcel Moolenaar * 2. Redistributions in binary form must reproduce the above copyright 227e76048aSMarcel Moolenaar * notice, this list of conditions and the following disclaimer in the 237e76048aSMarcel Moolenaar * documentation and/or other materials provided with the distribution. 247e76048aSMarcel Moolenaar * 3. Neither the name of the University nor the names of its contributors 257e76048aSMarcel Moolenaar * may be used to endorse or promote products derived from this software 267e76048aSMarcel Moolenaar * without specific prior written permission. 277e76048aSMarcel Moolenaar * 287e76048aSMarcel Moolenaar * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 297e76048aSMarcel Moolenaar * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 307e76048aSMarcel Moolenaar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 317e76048aSMarcel Moolenaar * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 327e76048aSMarcel Moolenaar * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 337e76048aSMarcel Moolenaar * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 347e76048aSMarcel Moolenaar * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 357e76048aSMarcel Moolenaar * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 367e76048aSMarcel Moolenaar * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 377e76048aSMarcel Moolenaar * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 387e76048aSMarcel Moolenaar * SUCH DAMAGE. 397e76048aSMarcel Moolenaar * 407e76048aSMarcel Moolenaar * @(#)fpu_implode.c 8.1 (Berkeley) 6/11/93 417e76048aSMarcel Moolenaar */ 427e76048aSMarcel Moolenaar 437e76048aSMarcel Moolenaar /* 447e76048aSMarcel Moolenaar * FPU subroutines: `implode' internal format numbers into the machine's 457e76048aSMarcel Moolenaar * `packed binary' format. 467e76048aSMarcel Moolenaar */ 477e76048aSMarcel Moolenaar 487e76048aSMarcel Moolenaar #include <sys/cdefs.h> 497e76048aSMarcel Moolenaar __FBSDID("$FreeBSD$"); 507e76048aSMarcel Moolenaar 517e76048aSMarcel Moolenaar #include <sys/types.h> 522aa95aceSPeter Grehan #include <sys/systm.h> 537e76048aSMarcel Moolenaar 547e76048aSMarcel Moolenaar #include <machine/fpu.h> 557e76048aSMarcel Moolenaar #include <machine/ieee.h> 567e76048aSMarcel Moolenaar #include <machine/ieeefp.h> 577e76048aSMarcel Moolenaar #include <machine/reg.h> 587e76048aSMarcel Moolenaar 597e76048aSMarcel Moolenaar #include <powerpc/fpu/fpu_arith.h> 607e76048aSMarcel Moolenaar #include <powerpc/fpu/fpu_emu.h> 617e76048aSMarcel Moolenaar #include <powerpc/fpu/fpu_extern.h> 627e76048aSMarcel Moolenaar #include <powerpc/fpu/fpu_instr.h> 637e76048aSMarcel Moolenaar 647e76048aSMarcel Moolenaar static int round(struct fpemu *, struct fpn *); 657e76048aSMarcel Moolenaar static int toinf(struct fpemu *, int); 667e76048aSMarcel Moolenaar 677e76048aSMarcel Moolenaar /* 687e76048aSMarcel Moolenaar * Round a number (algorithm from Motorola MC68882 manual, modified for 697e76048aSMarcel Moolenaar * our internal format). Set inexact exception if rounding is required. 707e76048aSMarcel Moolenaar * Return true iff we rounded up. 717e76048aSMarcel Moolenaar * 727e76048aSMarcel Moolenaar * After rounding, we discard the guard and round bits by shifting right 737e76048aSMarcel Moolenaar * 2 bits (a la fpu_shr(), but we do not bother with fp->fp_sticky). 747e76048aSMarcel Moolenaar * This saves effort later. 757e76048aSMarcel Moolenaar * 767e76048aSMarcel Moolenaar * Note that we may leave the value 2.0 in fp->fp_mant; it is the caller's 777e76048aSMarcel Moolenaar * responsibility to fix this if necessary. 787e76048aSMarcel Moolenaar */ 797e76048aSMarcel Moolenaar static int 807e76048aSMarcel Moolenaar round(struct fpemu *fe, struct fpn *fp) 817e76048aSMarcel Moolenaar { 827e76048aSMarcel Moolenaar u_int m0, m1, m2, m3; 837e76048aSMarcel Moolenaar int gr, s; 847e76048aSMarcel Moolenaar FPU_DECL_CARRY; 857e76048aSMarcel Moolenaar 867e76048aSMarcel Moolenaar m0 = fp->fp_mant[0]; 877e76048aSMarcel Moolenaar m1 = fp->fp_mant[1]; 887e76048aSMarcel Moolenaar m2 = fp->fp_mant[2]; 897e76048aSMarcel Moolenaar m3 = fp->fp_mant[3]; 907e76048aSMarcel Moolenaar gr = m3 & 3; 917e76048aSMarcel Moolenaar s = fp->fp_sticky; 927e76048aSMarcel Moolenaar 937e76048aSMarcel Moolenaar /* mant >>= FP_NG */ 947e76048aSMarcel Moolenaar m3 = (m3 >> FP_NG) | (m2 << (32 - FP_NG)); 957e76048aSMarcel Moolenaar m2 = (m2 >> FP_NG) | (m1 << (32 - FP_NG)); 967e76048aSMarcel Moolenaar m1 = (m1 >> FP_NG) | (m0 << (32 - FP_NG)); 977e76048aSMarcel Moolenaar m0 >>= FP_NG; 987e76048aSMarcel Moolenaar 997e76048aSMarcel Moolenaar if ((gr | s) == 0) /* result is exact: no rounding needed */ 1007e76048aSMarcel Moolenaar goto rounddown; 1017e76048aSMarcel Moolenaar 1027e76048aSMarcel Moolenaar fe->fe_cx |= FPSCR_XX|FPSCR_FI; /* inexact */ 1037e76048aSMarcel Moolenaar 1047e76048aSMarcel Moolenaar /* Go to rounddown to round down; break to round up. */ 1057e76048aSMarcel Moolenaar switch ((fe->fe_fpscr) & FPSCR_RN) { 1067e76048aSMarcel Moolenaar 1077e76048aSMarcel Moolenaar case FP_RN: 1087e76048aSMarcel Moolenaar default: 1097e76048aSMarcel Moolenaar /* 1107e76048aSMarcel Moolenaar * Round only if guard is set (gr & 2). If guard is set, 1117e76048aSMarcel Moolenaar * but round & sticky both clear, then we want to round 1127e76048aSMarcel Moolenaar * but have a tie, so round to even, i.e., add 1 iff odd. 1137e76048aSMarcel Moolenaar */ 1147e76048aSMarcel Moolenaar if ((gr & 2) == 0) 1157e76048aSMarcel Moolenaar goto rounddown; 1167e76048aSMarcel Moolenaar if ((gr & 1) || fp->fp_sticky || (m3 & 1)) 1177e76048aSMarcel Moolenaar break; 1187e76048aSMarcel Moolenaar goto rounddown; 1197e76048aSMarcel Moolenaar 1207e76048aSMarcel Moolenaar case FP_RZ: 1217e76048aSMarcel Moolenaar /* Round towards zero, i.e., down. */ 1227e76048aSMarcel Moolenaar goto rounddown; 1237e76048aSMarcel Moolenaar 1247e76048aSMarcel Moolenaar case FP_RM: 1257e76048aSMarcel Moolenaar /* Round towards -Inf: up if negative, down if positive. */ 1267e76048aSMarcel Moolenaar if (fp->fp_sign) 1277e76048aSMarcel Moolenaar break; 1287e76048aSMarcel Moolenaar goto rounddown; 1297e76048aSMarcel Moolenaar 1307e76048aSMarcel Moolenaar case FP_RP: 1317e76048aSMarcel Moolenaar /* Round towards +Inf: up if positive, down otherwise. */ 1327e76048aSMarcel Moolenaar if (!fp->fp_sign) 1337e76048aSMarcel Moolenaar break; 1347e76048aSMarcel Moolenaar goto rounddown; 1357e76048aSMarcel Moolenaar } 1367e76048aSMarcel Moolenaar 1377e76048aSMarcel Moolenaar /* Bump low bit of mantissa, with carry. */ 1387e76048aSMarcel Moolenaar fe->fe_cx |= FPSCR_FR; 1397e76048aSMarcel Moolenaar 1407e76048aSMarcel Moolenaar FPU_ADDS(m3, m3, 1); 1417e76048aSMarcel Moolenaar FPU_ADDCS(m2, m2, 0); 1427e76048aSMarcel Moolenaar FPU_ADDCS(m1, m1, 0); 1437e76048aSMarcel Moolenaar FPU_ADDC(m0, m0, 0); 1447e76048aSMarcel Moolenaar fp->fp_mant[0] = m0; 1457e76048aSMarcel Moolenaar fp->fp_mant[1] = m1; 1467e76048aSMarcel Moolenaar fp->fp_mant[2] = m2; 1477e76048aSMarcel Moolenaar fp->fp_mant[3] = m3; 1487e76048aSMarcel Moolenaar return (1); 1497e76048aSMarcel Moolenaar 1507e76048aSMarcel Moolenaar rounddown: 1517e76048aSMarcel Moolenaar fp->fp_mant[0] = m0; 1527e76048aSMarcel Moolenaar fp->fp_mant[1] = m1; 1537e76048aSMarcel Moolenaar fp->fp_mant[2] = m2; 1547e76048aSMarcel Moolenaar fp->fp_mant[3] = m3; 1557e76048aSMarcel Moolenaar return (0); 1567e76048aSMarcel Moolenaar } 1577e76048aSMarcel Moolenaar 1587e76048aSMarcel Moolenaar /* 1597e76048aSMarcel Moolenaar * For overflow: return true if overflow is to go to +/-Inf, according 1607e76048aSMarcel Moolenaar * to the sign of the overflowing result. If false, overflow is to go 1617e76048aSMarcel Moolenaar * to the largest magnitude value instead. 1627e76048aSMarcel Moolenaar */ 1637e76048aSMarcel Moolenaar static int 1647e76048aSMarcel Moolenaar toinf(struct fpemu *fe, int sign) 1657e76048aSMarcel Moolenaar { 1667e76048aSMarcel Moolenaar int inf; 1677e76048aSMarcel Moolenaar 1687e76048aSMarcel Moolenaar /* look at rounding direction */ 1697e76048aSMarcel Moolenaar switch ((fe->fe_fpscr) & FPSCR_RN) { 1707e76048aSMarcel Moolenaar 1717e76048aSMarcel Moolenaar default: 1727e76048aSMarcel Moolenaar case FP_RN: /* the nearest value is always Inf */ 1737e76048aSMarcel Moolenaar inf = 1; 1747e76048aSMarcel Moolenaar break; 1757e76048aSMarcel Moolenaar 1767e76048aSMarcel Moolenaar case FP_RZ: /* toward 0 => never towards Inf */ 1777e76048aSMarcel Moolenaar inf = 0; 1787e76048aSMarcel Moolenaar break; 1797e76048aSMarcel Moolenaar 1807e76048aSMarcel Moolenaar case FP_RP: /* toward +Inf iff positive */ 1817e76048aSMarcel Moolenaar inf = sign == 0; 1827e76048aSMarcel Moolenaar break; 1837e76048aSMarcel Moolenaar 1847e76048aSMarcel Moolenaar case FP_RM: /* toward -Inf iff negative */ 1857e76048aSMarcel Moolenaar inf = sign; 1867e76048aSMarcel Moolenaar break; 1877e76048aSMarcel Moolenaar } 1887e76048aSMarcel Moolenaar if (inf) 1897e76048aSMarcel Moolenaar fe->fe_cx |= FPSCR_OX; 1907e76048aSMarcel Moolenaar return (inf); 1917e76048aSMarcel Moolenaar } 1927e76048aSMarcel Moolenaar 1937e76048aSMarcel Moolenaar /* 1947e76048aSMarcel Moolenaar * fpn -> int (int value returned as return value). 1957e76048aSMarcel Moolenaar * 1967e76048aSMarcel Moolenaar * N.B.: this conversion always rounds towards zero (this is a peculiarity 1977e76048aSMarcel Moolenaar * of the SPARC instruction set). 1987e76048aSMarcel Moolenaar */ 1997e76048aSMarcel Moolenaar u_int 2007e76048aSMarcel Moolenaar fpu_ftoi(struct fpemu *fe, struct fpn *fp) 2017e76048aSMarcel Moolenaar { 2027e76048aSMarcel Moolenaar u_int i; 2037e76048aSMarcel Moolenaar int sign, exp; 2047e76048aSMarcel Moolenaar 2057e76048aSMarcel Moolenaar sign = fp->fp_sign; 2067e76048aSMarcel Moolenaar switch (fp->fp_class) { 2077e76048aSMarcel Moolenaar 2087e76048aSMarcel Moolenaar case FPC_ZERO: 2097e76048aSMarcel Moolenaar return (0); 2107e76048aSMarcel Moolenaar 2117e76048aSMarcel Moolenaar case FPC_NUM: 2127e76048aSMarcel Moolenaar /* 2137e76048aSMarcel Moolenaar * If exp >= 2^32, overflow. Otherwise shift value right 2147e76048aSMarcel Moolenaar * into last mantissa word (this will not exceed 0xffffffff), 2157e76048aSMarcel Moolenaar * shifting any guard and round bits out into the sticky 2167e76048aSMarcel Moolenaar * bit. Then ``round'' towards zero, i.e., just set an 2177e76048aSMarcel Moolenaar * inexact exception if sticky is set (see round()). 2187e76048aSMarcel Moolenaar * If the result is > 0x80000000, or is positive and equals 2197e76048aSMarcel Moolenaar * 0x80000000, overflow; otherwise the last fraction word 2207e76048aSMarcel Moolenaar * is the result. 2217e76048aSMarcel Moolenaar */ 2227e76048aSMarcel Moolenaar if ((exp = fp->fp_exp) >= 32) 2237e76048aSMarcel Moolenaar break; 2247e76048aSMarcel Moolenaar /* NB: the following includes exp < 0 cases */ 2257e76048aSMarcel Moolenaar if (fpu_shr(fp, FP_NMANT - 1 - exp) != 0) 2267e76048aSMarcel Moolenaar fe->fe_cx |= FPSCR_UX; 2277e76048aSMarcel Moolenaar i = fp->fp_mant[3]; 2287e76048aSMarcel Moolenaar if (i >= ((u_int)0x80000000 + sign)) 2297e76048aSMarcel Moolenaar break; 2307e76048aSMarcel Moolenaar return (sign ? -i : i); 2317e76048aSMarcel Moolenaar 2327e76048aSMarcel Moolenaar default: /* Inf, qNaN, sNaN */ 2337e76048aSMarcel Moolenaar break; 2347e76048aSMarcel Moolenaar } 2357e76048aSMarcel Moolenaar /* overflow: replace any inexact exception with invalid */ 2367e76048aSMarcel Moolenaar fe->fe_cx |= FPSCR_VXCVI; 2377e76048aSMarcel Moolenaar return (0x7fffffff + sign); 2387e76048aSMarcel Moolenaar } 2397e76048aSMarcel Moolenaar 2407e76048aSMarcel Moolenaar /* 2417e76048aSMarcel Moolenaar * fpn -> extended int (high bits of int value returned as return value). 2427e76048aSMarcel Moolenaar * 2437e76048aSMarcel Moolenaar * N.B.: this conversion always rounds towards zero (this is a peculiarity 2447e76048aSMarcel Moolenaar * of the SPARC instruction set). 2457e76048aSMarcel Moolenaar */ 2467e76048aSMarcel Moolenaar u_int 2477e76048aSMarcel Moolenaar fpu_ftox(struct fpemu *fe, struct fpn *fp, u_int *res) 2487e76048aSMarcel Moolenaar { 2497e76048aSMarcel Moolenaar u_int64_t i; 2507e76048aSMarcel Moolenaar int sign, exp; 2517e76048aSMarcel Moolenaar 2527e76048aSMarcel Moolenaar sign = fp->fp_sign; 2537e76048aSMarcel Moolenaar switch (fp->fp_class) { 2547e76048aSMarcel Moolenaar 2557e76048aSMarcel Moolenaar case FPC_ZERO: 2567e76048aSMarcel Moolenaar res[1] = 0; 2577e76048aSMarcel Moolenaar return (0); 2587e76048aSMarcel Moolenaar 2597e76048aSMarcel Moolenaar case FPC_NUM: 2607e76048aSMarcel Moolenaar /* 2617e76048aSMarcel Moolenaar * If exp >= 2^64, overflow. Otherwise shift value right 2627e76048aSMarcel Moolenaar * into last mantissa word (this will not exceed 0xffffffffffffffff), 2637e76048aSMarcel Moolenaar * shifting any guard and round bits out into the sticky 2647e76048aSMarcel Moolenaar * bit. Then ``round'' towards zero, i.e., just set an 2657e76048aSMarcel Moolenaar * inexact exception if sticky is set (see round()). 2667e76048aSMarcel Moolenaar * If the result is > 0x8000000000000000, or is positive and equals 2677e76048aSMarcel Moolenaar * 0x8000000000000000, overflow; otherwise the last fraction word 2687e76048aSMarcel Moolenaar * is the result. 2697e76048aSMarcel Moolenaar */ 2707e76048aSMarcel Moolenaar if ((exp = fp->fp_exp) >= 64) 2717e76048aSMarcel Moolenaar break; 2727e76048aSMarcel Moolenaar /* NB: the following includes exp < 0 cases */ 2737e76048aSMarcel Moolenaar if (fpu_shr(fp, FP_NMANT - 1 - exp) != 0) 2747e76048aSMarcel Moolenaar fe->fe_cx |= FPSCR_UX; 2757e76048aSMarcel Moolenaar i = ((u_int64_t)fp->fp_mant[2]<<32)|fp->fp_mant[3]; 2767e76048aSMarcel Moolenaar if (i >= ((u_int64_t)0x8000000000000000LL + sign)) 2777e76048aSMarcel Moolenaar break; 2787e76048aSMarcel Moolenaar return (sign ? -i : i); 2797e76048aSMarcel Moolenaar 2807e76048aSMarcel Moolenaar default: /* Inf, qNaN, sNaN */ 2817e76048aSMarcel Moolenaar break; 2827e76048aSMarcel Moolenaar } 2837e76048aSMarcel Moolenaar /* overflow: replace any inexact exception with invalid */ 2847e76048aSMarcel Moolenaar fe->fe_cx |= FPSCR_VXCVI; 2857e76048aSMarcel Moolenaar return (0x7fffffffffffffffLL + sign); 2867e76048aSMarcel Moolenaar } 2877e76048aSMarcel Moolenaar 2887e76048aSMarcel Moolenaar /* 2897e76048aSMarcel Moolenaar * fpn -> single (32 bit single returned as return value). 2907e76048aSMarcel Moolenaar * We assume <= 29 bits in a single-precision fraction (1.f part). 2917e76048aSMarcel Moolenaar */ 2927e76048aSMarcel Moolenaar u_int 2937e76048aSMarcel Moolenaar fpu_ftos(struct fpemu *fe, struct fpn *fp) 2947e76048aSMarcel Moolenaar { 2957e76048aSMarcel Moolenaar u_int sign = fp->fp_sign << 31; 2967e76048aSMarcel Moolenaar int exp; 2977e76048aSMarcel Moolenaar 2987e76048aSMarcel Moolenaar #define SNG_EXP(e) ((e) << SNG_FRACBITS) /* makes e an exponent */ 2997e76048aSMarcel Moolenaar #define SNG_MASK (SNG_EXP(1) - 1) /* mask for fraction */ 3007e76048aSMarcel Moolenaar 3017e76048aSMarcel Moolenaar /* Take care of non-numbers first. */ 3027e76048aSMarcel Moolenaar if (ISNAN(fp)) { 3037e76048aSMarcel Moolenaar /* 3047e76048aSMarcel Moolenaar * Preserve upper bits of NaN, per SPARC V8 appendix N. 3057e76048aSMarcel Moolenaar * Note that fp->fp_mant[0] has the quiet bit set, 3067e76048aSMarcel Moolenaar * even if it is classified as a signalling NaN. 3077e76048aSMarcel Moolenaar */ 3087e76048aSMarcel Moolenaar (void) fpu_shr(fp, FP_NMANT - 1 - SNG_FRACBITS); 3097e76048aSMarcel Moolenaar exp = SNG_EXP_INFNAN; 3107e76048aSMarcel Moolenaar goto done; 3117e76048aSMarcel Moolenaar } 3127e76048aSMarcel Moolenaar if (ISINF(fp)) 3137e76048aSMarcel Moolenaar return (sign | SNG_EXP(SNG_EXP_INFNAN)); 3147e76048aSMarcel Moolenaar if (ISZERO(fp)) 3157e76048aSMarcel Moolenaar return (sign); 3167e76048aSMarcel Moolenaar 3177e76048aSMarcel Moolenaar /* 3187e76048aSMarcel Moolenaar * Normals (including subnormals). Drop all the fraction bits 3197e76048aSMarcel Moolenaar * (including the explicit ``implied'' 1 bit) down into the 3207e76048aSMarcel Moolenaar * single-precision range. If the number is subnormal, move 3217e76048aSMarcel Moolenaar * the ``implied'' 1 into the explicit range as well, and shift 3227e76048aSMarcel Moolenaar * right to introduce leading zeroes. Rounding then acts 3237e76048aSMarcel Moolenaar * differently for normals and subnormals: the largest subnormal 3247e76048aSMarcel Moolenaar * may round to the smallest normal (1.0 x 2^minexp), or may 3257e76048aSMarcel Moolenaar * remain subnormal. In the latter case, signal an underflow 3267e76048aSMarcel Moolenaar * if the result was inexact or if underflow traps are enabled. 3277e76048aSMarcel Moolenaar * 3287e76048aSMarcel Moolenaar * Rounding a normal, on the other hand, always produces another 3297e76048aSMarcel Moolenaar * normal (although either way the result might be too big for 3307e76048aSMarcel Moolenaar * single precision, and cause an overflow). If rounding a 3317e76048aSMarcel Moolenaar * normal produces 2.0 in the fraction, we need not adjust that 3327e76048aSMarcel Moolenaar * fraction at all, since both 1.0 and 2.0 are zero under the 3337e76048aSMarcel Moolenaar * fraction mask. 3347e76048aSMarcel Moolenaar * 3357e76048aSMarcel Moolenaar * Note that the guard and round bits vanish from the number after 3367e76048aSMarcel Moolenaar * rounding. 3377e76048aSMarcel Moolenaar */ 3387e76048aSMarcel Moolenaar if ((exp = fp->fp_exp + SNG_EXP_BIAS) <= 0) { /* subnormal */ 3397e76048aSMarcel Moolenaar /* -NG for g,r; -SNG_FRACBITS-exp for fraction */ 3407e76048aSMarcel Moolenaar (void) fpu_shr(fp, FP_NMANT - FP_NG - SNG_FRACBITS - exp); 3417e76048aSMarcel Moolenaar if (round(fe, fp) && fp->fp_mant[3] == SNG_EXP(1)) 3427e76048aSMarcel Moolenaar return (sign | SNG_EXP(1) | 0); 3437e76048aSMarcel Moolenaar if ((fe->fe_cx & FPSCR_FI) || 3447e76048aSMarcel Moolenaar (fe->fe_fpscr & FPSCR_UX)) 3457e76048aSMarcel Moolenaar fe->fe_cx |= FPSCR_UX; 3467e76048aSMarcel Moolenaar return (sign | SNG_EXP(0) | fp->fp_mant[3]); 3477e76048aSMarcel Moolenaar } 3487e76048aSMarcel Moolenaar /* -FP_NG for g,r; -1 for implied 1; -SNG_FRACBITS for fraction */ 3497e76048aSMarcel Moolenaar (void) fpu_shr(fp, FP_NMANT - FP_NG - 1 - SNG_FRACBITS); 3507e76048aSMarcel Moolenaar #ifdef DIAGNOSTIC 3517e76048aSMarcel Moolenaar if ((fp->fp_mant[3] & SNG_EXP(1 << FP_NG)) == 0) 3527e76048aSMarcel Moolenaar panic("fpu_ftos"); 3537e76048aSMarcel Moolenaar #endif 3547e76048aSMarcel Moolenaar if (round(fe, fp) && fp->fp_mant[3] == SNG_EXP(2)) 3557e76048aSMarcel Moolenaar exp++; 3567e76048aSMarcel Moolenaar if (exp >= SNG_EXP_INFNAN) { 3577e76048aSMarcel Moolenaar /* overflow to inf or to max single */ 3587e76048aSMarcel Moolenaar if (toinf(fe, sign)) 3597e76048aSMarcel Moolenaar return (sign | SNG_EXP(SNG_EXP_INFNAN)); 3607e76048aSMarcel Moolenaar return (sign | SNG_EXP(SNG_EXP_INFNAN - 1) | SNG_MASK); 3617e76048aSMarcel Moolenaar } 3627e76048aSMarcel Moolenaar done: 3637e76048aSMarcel Moolenaar /* phew, made it */ 3647e76048aSMarcel Moolenaar return (sign | SNG_EXP(exp) | (fp->fp_mant[3] & SNG_MASK)); 3657e76048aSMarcel Moolenaar } 3667e76048aSMarcel Moolenaar 3677e76048aSMarcel Moolenaar /* 3687e76048aSMarcel Moolenaar * fpn -> double (32 bit high-order result returned; 32-bit low order result 3697e76048aSMarcel Moolenaar * left in res[1]). Assumes <= 61 bits in double precision fraction. 3707e76048aSMarcel Moolenaar * 3717e76048aSMarcel Moolenaar * This code mimics fpu_ftos; see it for comments. 3727e76048aSMarcel Moolenaar */ 3737e76048aSMarcel Moolenaar u_int 3747e76048aSMarcel Moolenaar fpu_ftod(struct fpemu *fe, struct fpn *fp, u_int *res) 3757e76048aSMarcel Moolenaar { 3767e76048aSMarcel Moolenaar u_int sign = fp->fp_sign << 31; 3777e76048aSMarcel Moolenaar int exp; 3787e76048aSMarcel Moolenaar 3797e76048aSMarcel Moolenaar #define DBL_EXP(e) ((e) << (DBL_FRACBITS & 31)) 3807e76048aSMarcel Moolenaar #define DBL_MASK (DBL_EXP(1) - 1) 3817e76048aSMarcel Moolenaar 3827e76048aSMarcel Moolenaar if (ISNAN(fp)) { 3837e76048aSMarcel Moolenaar (void) fpu_shr(fp, FP_NMANT - 1 - DBL_FRACBITS); 3847e76048aSMarcel Moolenaar exp = DBL_EXP_INFNAN; 3857e76048aSMarcel Moolenaar goto done; 3867e76048aSMarcel Moolenaar } 3877e76048aSMarcel Moolenaar if (ISINF(fp)) { 3887e76048aSMarcel Moolenaar sign |= DBL_EXP(DBL_EXP_INFNAN); 3897e76048aSMarcel Moolenaar goto zero; 3907e76048aSMarcel Moolenaar } 3917e76048aSMarcel Moolenaar if (ISZERO(fp)) { 3927e76048aSMarcel Moolenaar zero: res[1] = 0; 3937e76048aSMarcel Moolenaar return (sign); 3947e76048aSMarcel Moolenaar } 3957e76048aSMarcel Moolenaar 3967e76048aSMarcel Moolenaar if ((exp = fp->fp_exp + DBL_EXP_BIAS) <= 0) { 3977e76048aSMarcel Moolenaar (void) fpu_shr(fp, FP_NMANT - FP_NG - DBL_FRACBITS - exp); 3987e76048aSMarcel Moolenaar if (round(fe, fp) && fp->fp_mant[2] == DBL_EXP(1)) { 3997e76048aSMarcel Moolenaar res[1] = 0; 4007e76048aSMarcel Moolenaar return (sign | DBL_EXP(1) | 0); 4017e76048aSMarcel Moolenaar } 4027e76048aSMarcel Moolenaar if ((fe->fe_cx & FPSCR_FI) || 4037e76048aSMarcel Moolenaar (fe->fe_fpscr & FPSCR_UX)) 4047e76048aSMarcel Moolenaar fe->fe_cx |= FPSCR_UX; 4057e76048aSMarcel Moolenaar exp = 0; 4067e76048aSMarcel Moolenaar goto done; 4077e76048aSMarcel Moolenaar } 4087e76048aSMarcel Moolenaar (void) fpu_shr(fp, FP_NMANT - FP_NG - 1 - DBL_FRACBITS); 4097e76048aSMarcel Moolenaar if (round(fe, fp) && fp->fp_mant[2] == DBL_EXP(2)) 4107e76048aSMarcel Moolenaar exp++; 4117e76048aSMarcel Moolenaar if (exp >= DBL_EXP_INFNAN) { 4127e76048aSMarcel Moolenaar fe->fe_cx |= FPSCR_OX | FPSCR_UX; 4137e76048aSMarcel Moolenaar if (toinf(fe, sign)) { 4147e76048aSMarcel Moolenaar res[1] = 0; 4157e76048aSMarcel Moolenaar return (sign | DBL_EXP(DBL_EXP_INFNAN) | 0); 4167e76048aSMarcel Moolenaar } 4177e76048aSMarcel Moolenaar res[1] = ~0; 4187e76048aSMarcel Moolenaar return (sign | DBL_EXP(DBL_EXP_INFNAN) | DBL_MASK); 4197e76048aSMarcel Moolenaar } 4207e76048aSMarcel Moolenaar done: 4217e76048aSMarcel Moolenaar res[1] = fp->fp_mant[3]; 4227e76048aSMarcel Moolenaar return (sign | DBL_EXP(exp) | (fp->fp_mant[2] & DBL_MASK)); 4237e76048aSMarcel Moolenaar } 4247e76048aSMarcel Moolenaar 4257e76048aSMarcel Moolenaar /* 4267e76048aSMarcel Moolenaar * Implode an fpn, writing the result into the given space. 4277e76048aSMarcel Moolenaar */ 4287e76048aSMarcel Moolenaar void 4297e76048aSMarcel Moolenaar fpu_implode(struct fpemu *fe, struct fpn *fp, int type, u_int *space) 4307e76048aSMarcel Moolenaar { 4317e76048aSMarcel Moolenaar 4327e76048aSMarcel Moolenaar switch (type) { 4337e76048aSMarcel Moolenaar 4347e76048aSMarcel Moolenaar case FTYPE_LNG: 4357e76048aSMarcel Moolenaar space[0] = fpu_ftox(fe, fp, space); 4367e76048aSMarcel Moolenaar DPRINTF(FPE_REG, ("fpu_implode: long %x %x\n", 4377e76048aSMarcel Moolenaar space[0], space[1])); 4387e76048aSMarcel Moolenaar break; 4397e76048aSMarcel Moolenaar 4407e76048aSMarcel Moolenaar case FTYPE_INT: 4417e76048aSMarcel Moolenaar space[0] = 0; 4427e76048aSMarcel Moolenaar space[1] = fpu_ftoi(fe, fp); 4437e76048aSMarcel Moolenaar DPRINTF(FPE_REG, ("fpu_implode: int %x\n", 4447e76048aSMarcel Moolenaar space[1])); 4457e76048aSMarcel Moolenaar break; 4467e76048aSMarcel Moolenaar 4477e76048aSMarcel Moolenaar case FTYPE_SNG: 4487e76048aSMarcel Moolenaar space[0] = fpu_ftos(fe, fp); 4497e76048aSMarcel Moolenaar DPRINTF(FPE_REG, ("fpu_implode: single %x\n", 4507e76048aSMarcel Moolenaar space[0])); 4517e76048aSMarcel Moolenaar break; 4527e76048aSMarcel Moolenaar 4537e76048aSMarcel Moolenaar case FTYPE_DBL: 4547e76048aSMarcel Moolenaar space[0] = fpu_ftod(fe, fp, space); 4557e76048aSMarcel Moolenaar DPRINTF(FPE_REG, ("fpu_implode: double %x %x\n", 4567e76048aSMarcel Moolenaar space[0], space[1])); 4577e76048aSMarcel Moolenaar break; break; 4587e76048aSMarcel Moolenaar 4597e76048aSMarcel Moolenaar default: 4607e76048aSMarcel Moolenaar panic("fpu_implode: invalid type %d", type); 4617e76048aSMarcel Moolenaar } 4627e76048aSMarcel Moolenaar } 463