17e76048aSMarcel Moolenaar /* $NetBSD: fpu_explode.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
437e76048aSMarcel Moolenaar /*
447e76048aSMarcel Moolenaar * FPU subroutines: `explode' the machine's `packed binary' format numbers
457e76048aSMarcel Moolenaar * into our internal format.
467e76048aSMarcel Moolenaar */
477e76048aSMarcel Moolenaar
487e76048aSMarcel Moolenaar #include <sys/types.h>
492aa95aceSPeter Grehan #include <sys/systm.h>
507e76048aSMarcel Moolenaar
517e76048aSMarcel Moolenaar #include <machine/fpu.h>
527e76048aSMarcel Moolenaar #include <machine/ieee.h>
53aa59d767SJohn Baldwin #include <machine/pcb.h>
547e76048aSMarcel Moolenaar
557e76048aSMarcel Moolenaar #include <powerpc/fpu/fpu_arith.h>
567e76048aSMarcel Moolenaar #include <powerpc/fpu/fpu_emu.h>
577e76048aSMarcel Moolenaar #include <powerpc/fpu/fpu_extern.h>
587e76048aSMarcel Moolenaar #include <powerpc/fpu/fpu_instr.h>
597e76048aSMarcel Moolenaar
607e76048aSMarcel Moolenaar /*
617e76048aSMarcel Moolenaar * N.B.: in all of the following, we assume the FP format is
627e76048aSMarcel Moolenaar *
637e76048aSMarcel Moolenaar * ---------------------------
647e76048aSMarcel Moolenaar * | s | exponent | fraction |
657e76048aSMarcel Moolenaar * ---------------------------
667e76048aSMarcel Moolenaar *
677e76048aSMarcel Moolenaar * (which represents -1**s * 1.fraction * 2**exponent), so that the
687e76048aSMarcel Moolenaar * sign bit is way at the top (bit 31), the exponent is next, and
697e76048aSMarcel Moolenaar * then the remaining bits mark the fraction. A zero exponent means
707e76048aSMarcel Moolenaar * zero or denormalized (0.fraction rather than 1.fraction), and the
717e76048aSMarcel Moolenaar * maximum possible exponent, 2bias+1, signals inf (fraction==0) or NaN.
727e76048aSMarcel Moolenaar *
737e76048aSMarcel Moolenaar * Since the sign bit is always the topmost bit---this holds even for
747e76048aSMarcel Moolenaar * integers---we set that outside all the *tof functions. Each function
757e76048aSMarcel Moolenaar * returns the class code for the new number (but note that we use
767e76048aSMarcel Moolenaar * FPC_QNAN for all NaNs; fpu_explode will fix this if appropriate).
777e76048aSMarcel Moolenaar */
787e76048aSMarcel Moolenaar
797e76048aSMarcel Moolenaar /*
807e76048aSMarcel Moolenaar * int -> fpn.
817e76048aSMarcel Moolenaar */
827e76048aSMarcel Moolenaar int
fpu_itof(struct fpn * fp,u_int i)837e76048aSMarcel Moolenaar fpu_itof(struct fpn *fp, u_int i)
847e76048aSMarcel Moolenaar {
857e76048aSMarcel Moolenaar
867e76048aSMarcel Moolenaar if (i == 0)
877e76048aSMarcel Moolenaar return (FPC_ZERO);
887e76048aSMarcel Moolenaar /*
897e76048aSMarcel Moolenaar * The value FP_1 represents 2^FP_LG, so set the exponent
907e76048aSMarcel Moolenaar * there and let normalization fix it up. Convert negative
917e76048aSMarcel Moolenaar * numbers to sign-and-magnitude. Note that this relies on
927e76048aSMarcel Moolenaar * fpu_norm()'s handling of `supernormals'; see fpu_subr.c.
937e76048aSMarcel Moolenaar */
947e76048aSMarcel Moolenaar fp->fp_exp = FP_LG;
957e76048aSMarcel Moolenaar fp->fp_mant[0] = (int)i < 0 ? -i : i;
967e76048aSMarcel Moolenaar fp->fp_mant[1] = 0;
977e76048aSMarcel Moolenaar fp->fp_mant[2] = 0;
987e76048aSMarcel Moolenaar fp->fp_mant[3] = 0;
997e76048aSMarcel Moolenaar fpu_norm(fp);
1007e76048aSMarcel Moolenaar return (FPC_NUM);
1017e76048aSMarcel Moolenaar }
1027e76048aSMarcel Moolenaar
1037e76048aSMarcel Moolenaar /*
1047e76048aSMarcel Moolenaar * 64-bit int -> fpn.
1057e76048aSMarcel Moolenaar */
1067e76048aSMarcel Moolenaar int
fpu_xtof(struct fpn * fp,u_int64_t i)1077e76048aSMarcel Moolenaar fpu_xtof(struct fpn *fp, u_int64_t i)
1087e76048aSMarcel Moolenaar {
1097e76048aSMarcel Moolenaar
1107e76048aSMarcel Moolenaar if (i == 0)
1117e76048aSMarcel Moolenaar return (FPC_ZERO);
1127e76048aSMarcel Moolenaar /*
1137e76048aSMarcel Moolenaar * The value FP_1 represents 2^FP_LG, so set the exponent
1147e76048aSMarcel Moolenaar * there and let normalization fix it up. Convert negative
1157e76048aSMarcel Moolenaar * numbers to sign-and-magnitude. Note that this relies on
1167e76048aSMarcel Moolenaar * fpu_norm()'s handling of `supernormals'; see fpu_subr.c.
1177e76048aSMarcel Moolenaar */
1187e76048aSMarcel Moolenaar fp->fp_exp = FP_LG2;
1197e76048aSMarcel Moolenaar *((int64_t*)fp->fp_mant) = (int64_t)i < 0 ? -i : i;
1207e76048aSMarcel Moolenaar fp->fp_mant[2] = 0;
1217e76048aSMarcel Moolenaar fp->fp_mant[3] = 0;
1227e76048aSMarcel Moolenaar fpu_norm(fp);
1237e76048aSMarcel Moolenaar return (FPC_NUM);
1247e76048aSMarcel Moolenaar }
1257e76048aSMarcel Moolenaar
1267e76048aSMarcel Moolenaar #define mask(nbits) ((1L << (nbits)) - 1)
1277e76048aSMarcel Moolenaar
1287e76048aSMarcel Moolenaar /*
1297e76048aSMarcel Moolenaar * All external floating formats convert to internal in the same manner,
1307e76048aSMarcel Moolenaar * as defined here. Note that only normals get an implied 1.0 inserted.
1317e76048aSMarcel Moolenaar */
1327e76048aSMarcel Moolenaar #define FP_TOF(exp, expbias, allfrac, f0, f1, f2, f3) \
1337e76048aSMarcel Moolenaar if (exp == 0) { \
1347e76048aSMarcel Moolenaar if (allfrac == 0) \
1357e76048aSMarcel Moolenaar return (FPC_ZERO); \
1367e76048aSMarcel Moolenaar fp->fp_exp = 1 - expbias; \
1377e76048aSMarcel Moolenaar fp->fp_mant[0] = f0; \
1387e76048aSMarcel Moolenaar fp->fp_mant[1] = f1; \
1397e76048aSMarcel Moolenaar fp->fp_mant[2] = f2; \
1407e76048aSMarcel Moolenaar fp->fp_mant[3] = f3; \
1417e76048aSMarcel Moolenaar fpu_norm(fp); \
1427e76048aSMarcel Moolenaar return (FPC_NUM); \
1437e76048aSMarcel Moolenaar } \
1447e76048aSMarcel Moolenaar if (exp == (2 * expbias + 1)) { \
1457e76048aSMarcel Moolenaar if (allfrac == 0) \
1467e76048aSMarcel Moolenaar return (FPC_INF); \
1477e76048aSMarcel Moolenaar fp->fp_mant[0] = f0; \
1487e76048aSMarcel Moolenaar fp->fp_mant[1] = f1; \
1497e76048aSMarcel Moolenaar fp->fp_mant[2] = f2; \
1507e76048aSMarcel Moolenaar fp->fp_mant[3] = f3; \
1517e76048aSMarcel Moolenaar return (FPC_QNAN); \
1527e76048aSMarcel Moolenaar } \
1537e76048aSMarcel Moolenaar fp->fp_exp = exp - expbias; \
1547e76048aSMarcel Moolenaar fp->fp_mant[0] = FP_1 | f0; \
1557e76048aSMarcel Moolenaar fp->fp_mant[1] = f1; \
1567e76048aSMarcel Moolenaar fp->fp_mant[2] = f2; \
1577e76048aSMarcel Moolenaar fp->fp_mant[3] = f3; \
1587e76048aSMarcel Moolenaar return (FPC_NUM)
1597e76048aSMarcel Moolenaar
1607e76048aSMarcel Moolenaar /*
1617e76048aSMarcel Moolenaar * 32-bit single precision -> fpn.
1627e76048aSMarcel Moolenaar * We assume a single occupies at most (64-FP_LG) bits in the internal
1637e76048aSMarcel Moolenaar * format: i.e., needs at most fp_mant[0] and fp_mant[1].
1647e76048aSMarcel Moolenaar */
1657e76048aSMarcel Moolenaar int
fpu_stof(struct fpn * fp,u_int i)1667e76048aSMarcel Moolenaar fpu_stof(struct fpn *fp, u_int i)
1677e76048aSMarcel Moolenaar {
1687e76048aSMarcel Moolenaar int exp;
1697e76048aSMarcel Moolenaar u_int frac, f0, f1;
1707e76048aSMarcel Moolenaar #define SNG_SHIFT (SNG_FRACBITS - FP_LG)
1717e76048aSMarcel Moolenaar
1727e76048aSMarcel Moolenaar exp = (i >> (32 - 1 - SNG_EXPBITS)) & mask(SNG_EXPBITS);
1737e76048aSMarcel Moolenaar frac = i & mask(SNG_FRACBITS);
1747e76048aSMarcel Moolenaar f0 = frac >> SNG_SHIFT;
1757e76048aSMarcel Moolenaar f1 = frac << (32 - SNG_SHIFT);
1767e76048aSMarcel Moolenaar FP_TOF(exp, SNG_EXP_BIAS, frac, f0, f1, 0, 0);
1777e76048aSMarcel Moolenaar }
1787e76048aSMarcel Moolenaar
1797e76048aSMarcel Moolenaar /*
1807e76048aSMarcel Moolenaar * 64-bit double -> fpn.
1817e76048aSMarcel Moolenaar * We assume this uses at most (96-FP_LG) bits.
1827e76048aSMarcel Moolenaar */
1837e76048aSMarcel Moolenaar int
fpu_dtof(struct fpn * fp,u_int i,u_int j)1847e76048aSMarcel Moolenaar fpu_dtof(struct fpn *fp, u_int i, u_int j)
1857e76048aSMarcel Moolenaar {
1867e76048aSMarcel Moolenaar int exp;
1877e76048aSMarcel Moolenaar u_int frac, f0, f1, f2;
1887e76048aSMarcel Moolenaar #define DBL_SHIFT (DBL_FRACBITS - 32 - FP_LG)
1897e76048aSMarcel Moolenaar
1907e76048aSMarcel Moolenaar exp = (i >> (32 - 1 - DBL_EXPBITS)) & mask(DBL_EXPBITS);
1917e76048aSMarcel Moolenaar frac = i & mask(DBL_FRACBITS - 32);
1927e76048aSMarcel Moolenaar f0 = frac >> DBL_SHIFT;
1937e76048aSMarcel Moolenaar f1 = (frac << (32 - DBL_SHIFT)) | (j >> DBL_SHIFT);
1947e76048aSMarcel Moolenaar f2 = j << (32 - DBL_SHIFT);
1957e76048aSMarcel Moolenaar frac |= j;
1967e76048aSMarcel Moolenaar FP_TOF(exp, DBL_EXP_BIAS, frac, f0, f1, f2, 0);
1977e76048aSMarcel Moolenaar }
1987e76048aSMarcel Moolenaar
1997e76048aSMarcel Moolenaar /*
2007e76048aSMarcel Moolenaar * Explode the contents of a register / regpair / regquad.
2017e76048aSMarcel Moolenaar * If the input is a signalling NaN, an NV (invalid) exception
2027e76048aSMarcel Moolenaar * will be set. (Note that nothing but NV can occur until ALU
2037e76048aSMarcel Moolenaar * operations are performed.)
2047e76048aSMarcel Moolenaar */
2057e76048aSMarcel Moolenaar void
fpu_explode(struct fpemu * fe,struct fpn * fp,int type,int reg)2067e76048aSMarcel Moolenaar fpu_explode(struct fpemu *fe, struct fpn *fp, int type, int reg)
2077e76048aSMarcel Moolenaar {
2087e76048aSMarcel Moolenaar u_int s, *space;
2097e76048aSMarcel Moolenaar u_int64_t l, *xspace;
2107e76048aSMarcel Moolenaar
211aa59d767SJohn Baldwin xspace = (u_int64_t *)&fe->fe_fpstate->fpr[reg].fpr;
2127e76048aSMarcel Moolenaar l = xspace[0];
213aa59d767SJohn Baldwin space = (u_int *)&fe->fe_fpstate->fpr[reg].fpr;
2147e76048aSMarcel Moolenaar s = space[0];
2157e76048aSMarcel Moolenaar fp->fp_sign = s >> 31;
2167e76048aSMarcel Moolenaar fp->fp_sticky = 0;
2177e76048aSMarcel Moolenaar switch (type) {
2187e76048aSMarcel Moolenaar case FTYPE_LNG:
2197e76048aSMarcel Moolenaar s = fpu_xtof(fp, l);
2207e76048aSMarcel Moolenaar break;
2217e76048aSMarcel Moolenaar
2227e76048aSMarcel Moolenaar case FTYPE_INT:
2237e76048aSMarcel Moolenaar s = fpu_itof(fp, space[1]);
2247e76048aSMarcel Moolenaar break;
2257e76048aSMarcel Moolenaar
2267e76048aSMarcel Moolenaar case FTYPE_SNG:
2277e76048aSMarcel Moolenaar s = fpu_stof(fp, s);
2287e76048aSMarcel Moolenaar break;
2297e76048aSMarcel Moolenaar
2307e76048aSMarcel Moolenaar case FTYPE_DBL:
2317e76048aSMarcel Moolenaar s = fpu_dtof(fp, s, space[1]);
2327e76048aSMarcel Moolenaar break;
2337e76048aSMarcel Moolenaar
234b8201e1cSNathan Whitehorn default:
2357e76048aSMarcel Moolenaar panic("fpu_explode");
2367e76048aSMarcel Moolenaar panic("fpu_explode: invalid type %d", type);
2377e76048aSMarcel Moolenaar }
2387e76048aSMarcel Moolenaar
2397e76048aSMarcel Moolenaar if (s == FPC_QNAN && (fp->fp_mant[0] & FP_QUIETBIT) == 0) {
2407e76048aSMarcel Moolenaar /*
2417e76048aSMarcel Moolenaar * Input is a signalling NaN. All operations that return
2427e76048aSMarcel Moolenaar * an input NaN operand put it through a ``NaN conversion'',
2437e76048aSMarcel Moolenaar * which basically just means ``turn on the quiet bit''.
2447e76048aSMarcel Moolenaar * We do this here so that all NaNs internally look quiet
2457e76048aSMarcel Moolenaar * (we can tell signalling ones by their class).
2467e76048aSMarcel Moolenaar */
2477e76048aSMarcel Moolenaar fp->fp_mant[0] |= FP_QUIETBIT;
2487e76048aSMarcel Moolenaar fe->fe_cx = FPSCR_VXSNAN; /* assert invalid operand */
2497e76048aSMarcel Moolenaar s = FPC_SNAN;
2507e76048aSMarcel Moolenaar }
2517e76048aSMarcel Moolenaar fp->fp_class = s;
2527e76048aSMarcel Moolenaar DPRINTF(FPE_REG, ("fpu_explode: %%%c%d => ", (type == FTYPE_LNG) ? 'x' :
2537e76048aSMarcel Moolenaar ((type == FTYPE_INT) ? 'i' :
2547e76048aSMarcel Moolenaar ((type == FTYPE_SNG) ? 's' :
2557e76048aSMarcel Moolenaar ((type == FTYPE_DBL) ? 'd' : '?'))),
2567e76048aSMarcel Moolenaar reg));
2577e76048aSMarcel Moolenaar DUMPFPN(FPE_REG, fp);
2587e76048aSMarcel Moolenaar DPRINTF(FPE_REG, ("\n"));
2597e76048aSMarcel Moolenaar }
260