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