191174Stmm/* 291174Stmm * Copyright (c) 1992, 1993 391174Stmm * The Regents of the University of California. All rights reserved. 491174Stmm * 591174Stmm * This software was developed by the Computer Systems Engineering group 691174Stmm * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 791174Stmm * contributed to Berkeley. 891174Stmm * 991174Stmm * All advertising materials mentioning features or use of this software 1091174Stmm * must display the following acknowledgement: 1191174Stmm * This product includes software developed by the University of 1291174Stmm * California, Lawrence Berkeley Laboratory. 1391174Stmm * 1491174Stmm * Redistribution and use in source and binary forms, with or without 1591174Stmm * modification, are permitted provided that the following conditions 1691174Stmm * are met: 1791174Stmm * 1. Redistributions of source code must retain the above copyright 1891174Stmm * notice, this list of conditions and the following disclaimer. 1991174Stmm * 2. Redistributions in binary form must reproduce the above copyright 2091174Stmm * notice, this list of conditions and the following disclaimer in the 2191174Stmm * documentation and/or other materials provided with the distribution. 2291174Stmm * 4. Neither the name of the University nor the names of its contributors 2391174Stmm * may be used to endorse or promote products derived from this software 2491174Stmm * without specific prior written permission. 2591174Stmm * 2691174Stmm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2791174Stmm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2891174Stmm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2991174Stmm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 3091174Stmm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3191174Stmm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3291174Stmm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3391174Stmm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3491174Stmm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3591174Stmm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3691174Stmm * SUCH DAMAGE. 3791174Stmm * 3891174Stmm * @(#)fpu_implode.c 8.1 (Berkeley) 6/11/93 3992986Sobrien * $NetBSD: fpu_implode.c,v 1.8 2001/08/26 05:44:46 eeh Exp $ 4091174Stmm */ 4191174Stmm 4292986Sobrien#include <sys/cdefs.h> 4392986Sobrien__FBSDID("$FreeBSD$"); 4492986Sobrien 4591174Stmm/* 4691174Stmm * FPU subroutines: `implode' internal format numbers into the machine's 4791174Stmm * `packed binary' format. 4891174Stmm */ 4991174Stmm 5091174Stmm#include <sys/param.h> 5191174Stmm 52205395Smarius#ifdef FPU_DEBUG 53205395Smarius#include <stdio.h> 54205395Smarius#endif 55205395Smarius 5691174Stmm#include <machine/frame.h> 5791174Stmm#include <machine/fp.h> 5891174Stmm#include <machine/fsr.h> 5991174Stmm#include <machine/ieee.h> 6091174Stmm#include <machine/instr.h> 6191174Stmm 6291174Stmm#include "fpu_arith.h" 6391174Stmm#include "fpu_emu.h" 6491174Stmm#include "fpu_extern.h" 6595587Sjake#include "__sparc_utrap_private.h" 6691174Stmm 67132755Skanstatic int fpround(struct fpemu *, struct fpn *); 6892905Sobrienstatic int toinf(struct fpemu *, int); 6991174Stmm 7091174Stmm/* 7191174Stmm * Round a number (algorithm from Motorola MC68882 manual, modified for 7291174Stmm * our internal format). Set inexact exception if rounding is required. 7391174Stmm * Return true iff we rounded up. 7491174Stmm * 7591174Stmm * After rounding, we discard the guard and round bits by shifting right 7691174Stmm * 2 bits (a la fpu_shr(), but we do not bother with fp->fp_sticky). 7791174Stmm * This saves effort later. 7891174Stmm * 7991174Stmm * Note that we may leave the value 2.0 in fp->fp_mant; it is the caller's 8091174Stmm * responsibility to fix this if necessary. 8191174Stmm */ 8291174Stmmstatic int 83132755Skanfpround(struct fpemu *fe, struct fpn *fp) 8491174Stmm{ 8592889Sobrien u_int m0, m1, m2, m3; 8692889Sobrien int gr, s; 8791174Stmm 8891174Stmm m0 = fp->fp_mant[0]; 8991174Stmm m1 = fp->fp_mant[1]; 9091174Stmm m2 = fp->fp_mant[2]; 9191174Stmm m3 = fp->fp_mant[3]; 9291174Stmm gr = m3 & 3; 9391174Stmm s = fp->fp_sticky; 9491174Stmm 9591174Stmm /* mant >>= FP_NG */ 9691174Stmm m3 = (m3 >> FP_NG) | (m2 << (32 - FP_NG)); 9791174Stmm m2 = (m2 >> FP_NG) | (m1 << (32 - FP_NG)); 9891174Stmm m1 = (m1 >> FP_NG) | (m0 << (32 - FP_NG)); 9991174Stmm m0 >>= FP_NG; 10091174Stmm 10191174Stmm if ((gr | s) == 0) /* result is exact: no rounding needed */ 10291174Stmm goto rounddown; 10391174Stmm 10491174Stmm fe->fe_cx |= FSR_NX; /* inexact */ 10591174Stmm 10691174Stmm /* Go to rounddown to round down; break to round up. */ 10791174Stmm switch (FSR_GET_RD(fe->fe_fsr)) { 10891174Stmm case FSR_RD_N: 10991174Stmm default: 11091174Stmm /* 11191174Stmm * Round only if guard is set (gr & 2). If guard is set, 11291174Stmm * but round & sticky both clear, then we want to round 11391174Stmm * but have a tie, so round to even, i.e., add 1 iff odd. 11491174Stmm */ 11591174Stmm if ((gr & 2) == 0) 11691174Stmm goto rounddown; 11791174Stmm if ((gr & 1) || fp->fp_sticky || (m3 & 1)) 11891174Stmm break; 11991174Stmm goto rounddown; 12091174Stmm 12191174Stmm case FSR_RD_Z: 12291174Stmm /* Round towards zero, i.e., down. */ 12391174Stmm goto rounddown; 12491174Stmm 12591174Stmm case FSR_RD_NINF: 12691174Stmm /* Round towards -Inf: up if negative, down if positive. */ 12791174Stmm if (fp->fp_sign) 12891174Stmm break; 12991174Stmm goto rounddown; 13091174Stmm 13191174Stmm case FSR_RD_PINF: 13291174Stmm /* Round towards +Inf: up if positive, down otherwise. */ 13391174Stmm if (!fp->fp_sign) 13491174Stmm break; 13591174Stmm goto rounddown; 13691174Stmm } 13791174Stmm 13891174Stmm /* Bump low bit of mantissa, with carry. */ 13991174Stmm FPU_ADDS(m3, m3, 1); 14091174Stmm FPU_ADDCS(m2, m2, 0); 14191174Stmm FPU_ADDCS(m1, m1, 0); 14291174Stmm FPU_ADDC(m0, m0, 0); 14391174Stmm fp->fp_mant[0] = m0; 14491174Stmm fp->fp_mant[1] = m1; 14591174Stmm fp->fp_mant[2] = m2; 14691174Stmm fp->fp_mant[3] = m3; 14791174Stmm return (1); 14891174Stmm 14991174Stmmrounddown: 15091174Stmm fp->fp_mant[0] = m0; 15191174Stmm fp->fp_mant[1] = m1; 15291174Stmm fp->fp_mant[2] = m2; 15391174Stmm fp->fp_mant[3] = m3; 15491174Stmm return (0); 15591174Stmm} 15691174Stmm 15791174Stmm/* 15891174Stmm * For overflow: return true if overflow is to go to +/-Inf, according 15991174Stmm * to the sign of the overflowing result. If false, overflow is to go 16091174Stmm * to the largest magnitude value instead. 16191174Stmm */ 16291174Stmmstatic int 16391174Stmmtoinf(struct fpemu *fe, int sign) 16491174Stmm{ 16591174Stmm int inf; 16691174Stmm 16791174Stmm /* look at rounding direction */ 16891174Stmm switch (FSR_GET_RD(fe->fe_fsr)) { 16991174Stmm default: 17091174Stmm case FSR_RD_N: /* the nearest value is always Inf */ 17191174Stmm inf = 1; 17291174Stmm break; 17391174Stmm 17491174Stmm case FSR_RD_Z: /* toward 0 => never towards Inf */ 17591174Stmm inf = 0; 17691174Stmm break; 17791174Stmm 17891174Stmm case FSR_RD_PINF: /* toward +Inf iff positive */ 17991174Stmm inf = sign == 0; 18091174Stmm break; 18191174Stmm 18291174Stmm case FSR_RD_NINF: /* toward -Inf iff negative */ 18391174Stmm inf = sign; 18491174Stmm break; 18591174Stmm } 18691174Stmm return (inf); 18791174Stmm} 18891174Stmm 18991174Stmm/* 19091174Stmm * fpn -> int (int value returned as return value). 19191174Stmm * 19291174Stmm * N.B.: this conversion always rounds towards zero (this is a peculiarity 19391174Stmm * of the SPARC instruction set). 19491174Stmm */ 19591174Stmmu_int 19691174Stmm__fpu_ftoi(fe, fp) 19791174Stmm struct fpemu *fe; 19892889Sobrien struct fpn *fp; 19991174Stmm{ 20092889Sobrien u_int i; 20192889Sobrien int sign, exp; 20291174Stmm 20391174Stmm sign = fp->fp_sign; 20491174Stmm switch (fp->fp_class) { 20591174Stmm case FPC_ZERO: 20691174Stmm return (0); 20791174Stmm 20891174Stmm case FPC_NUM: 20991174Stmm /* 21091174Stmm * If exp >= 2^32, overflow. Otherwise shift value right 21191174Stmm * into last mantissa word (this will not exceed 0xffffffff), 21291174Stmm * shifting any guard and round bits out into the sticky 21391174Stmm * bit. Then ``round'' towards zero, i.e., just set an 21491174Stmm * inexact exception if sticky is set (see round()). 21591174Stmm * If the result is > 0x80000000, or is positive and equals 21691174Stmm * 0x80000000, overflow; otherwise the last fraction word 21791174Stmm * is the result. 21891174Stmm */ 21991174Stmm if ((exp = fp->fp_exp) >= 32) 22091174Stmm break; 22191174Stmm /* NB: the following includes exp < 0 cases */ 22291174Stmm if (__fpu_shr(fp, FP_NMANT - 1 - exp) != 0) 22391174Stmm fe->fe_cx |= FSR_NX; 22491174Stmm i = fp->fp_mant[3]; 22591174Stmm if (i >= ((u_int)0x80000000 + sign)) 22691174Stmm break; 22791174Stmm return (sign ? -i : i); 22891174Stmm 22991174Stmm default: /* Inf, qNaN, sNaN */ 23091174Stmm break; 23191174Stmm } 23291174Stmm /* overflow: replace any inexact exception with invalid */ 23391174Stmm fe->fe_cx = (fe->fe_cx & ~FSR_NX) | FSR_NV; 23491174Stmm return (0x7fffffff + sign); 23591174Stmm} 23691174Stmm 23791174Stmm/* 23891174Stmm * fpn -> extended int (high bits of int value returned as return value). 23991174Stmm * 24091174Stmm * N.B.: this conversion always rounds towards zero (this is a peculiarity 24191174Stmm * of the SPARC instruction set). 24291174Stmm */ 24391174Stmmu_int 24491174Stmm__fpu_ftox(fe, fp, res) 24591174Stmm struct fpemu *fe; 24692889Sobrien struct fpn *fp; 24791174Stmm u_int *res; 24891174Stmm{ 24992889Sobrien u_int64_t i; 25092889Sobrien int sign, exp; 25191174Stmm 25291174Stmm sign = fp->fp_sign; 25391174Stmm switch (fp->fp_class) { 25491174Stmm case FPC_ZERO: 255205394Smarius i = 0; 256205394Smarius goto done; 25791174Stmm 25891174Stmm case FPC_NUM: 25991174Stmm /* 260165529Smarius * If exp >= 2^64, overflow. Otherwise shift value 261165529Smarius * right into last mantissa word (this will not exceed 262165529Smarius * 0xffffffffffffffff), shifting any guard and round 263165529Smarius * bits out into the sticky bit. Then ``round'' towards 264165529Smarius * zero, i.e., just set an inexact exception if sticky 265165529Smarius * is set (see round()). 266165529Smarius * If the result is > 0x8000000000000000, or is positive 267165529Smarius * and equals 0x8000000000000000, overflow; otherwise 268165529Smarius * the last fraction word is the result. 26991174Stmm */ 27091174Stmm if ((exp = fp->fp_exp) >= 64) 27191174Stmm break; 27291174Stmm /* NB: the following includes exp < 0 cases */ 27391174Stmm if (__fpu_shr(fp, FP_NMANT - 1 - exp) != 0) 27491174Stmm fe->fe_cx |= FSR_NX; 27591174Stmm i = ((u_int64_t)fp->fp_mant[2]<<32)|fp->fp_mant[3]; 27691174Stmm if (i >= ((u_int64_t)0x8000000000000000LL + sign)) 27791174Stmm break; 27891174Stmm if (sign) 279165529Smarius i = -i; 280205394Smarius goto done; 28191174Stmm 28291174Stmm default: /* Inf, qNaN, sNaN */ 28391174Stmm break; 28491174Stmm } 28591174Stmm /* overflow: replace any inexact exception with invalid */ 28691174Stmm fe->fe_cx = (fe->fe_cx & ~FSR_NX) | FSR_NV; 287205394Smarius i = 0x7fffffffffffffffLL + sign; 288205394Smariusdone: 289205394Smarius res[1] = i & 0xffffffff; 290205394Smarius return (i >> 32); 29191174Stmm} 29291174Stmm 29391174Stmm/* 29491174Stmm * fpn -> single (32 bit single returned as return value). 29591174Stmm * We assume <= 29 bits in a single-precision fraction (1.f part). 29691174Stmm */ 29791174Stmmu_int 29891174Stmm__fpu_ftos(fe, fp) 29991174Stmm struct fpemu *fe; 30092889Sobrien struct fpn *fp; 30191174Stmm{ 30292889Sobrien u_int sign = fp->fp_sign << 31; 30392889Sobrien int exp; 30491174Stmm 30591174Stmm#define SNG_EXP(e) ((e) << SNG_FRACBITS) /* makes e an exponent */ 30691174Stmm#define SNG_MASK (SNG_EXP(1) - 1) /* mask for fraction */ 30791174Stmm 30891174Stmm /* Take care of non-numbers first. */ 30991174Stmm if (ISNAN(fp)) { 31091174Stmm /* 31191174Stmm * Preserve upper bits of NaN, per SPARC V8 appendix N. 31291174Stmm * Note that fp->fp_mant[0] has the quiet bit set, 31391174Stmm * even if it is classified as a signalling NaN. 31491174Stmm */ 31591174Stmm (void) __fpu_shr(fp, FP_NMANT - 1 - SNG_FRACBITS); 31691174Stmm exp = SNG_EXP_INFNAN; 31791174Stmm goto done; 31891174Stmm } 31991174Stmm if (ISINF(fp)) 32091174Stmm return (sign | SNG_EXP(SNG_EXP_INFNAN)); 32191174Stmm if (ISZERO(fp)) 32291174Stmm return (sign); 32391174Stmm 32491174Stmm /* 32591174Stmm * Normals (including subnormals). Drop all the fraction bits 32691174Stmm * (including the explicit ``implied'' 1 bit) down into the 32791174Stmm * single-precision range. If the number is subnormal, move 32891174Stmm * the ``implied'' 1 into the explicit range as well, and shift 32991174Stmm * right to introduce leading zeroes. Rounding then acts 33091174Stmm * differently for normals and subnormals: the largest subnormal 33191174Stmm * may round to the smallest normal (1.0 x 2^minexp), or may 332205397Smarius * remain subnormal. A number that is subnormal before rounding 333205397Smarius * will signal an underflow if the result is inexact or if underflow 334205397Smarius * traps are enabled. 33591174Stmm * 33691174Stmm * Rounding a normal, on the other hand, always produces another 33791174Stmm * normal (although either way the result might be too big for 33891174Stmm * single precision, and cause an overflow). If rounding a 33991174Stmm * normal produces 2.0 in the fraction, we need not adjust that 34091174Stmm * fraction at all, since both 1.0 and 2.0 are zero under the 34191174Stmm * fraction mask. 34291174Stmm * 34391174Stmm * Note that the guard and round bits vanish from the number after 34491174Stmm * rounding. 34591174Stmm */ 34691174Stmm if ((exp = fp->fp_exp + SNG_EXP_BIAS) <= 0) { /* subnormal */ 34791174Stmm /* -NG for g,r; -SNG_FRACBITS-exp for fraction */ 34891174Stmm (void) __fpu_shr(fp, FP_NMANT - FP_NG - SNG_FRACBITS - exp); 349205397Smarius if (fpround(fe, fp) && fp->fp_mant[3] == SNG_EXP(1)) { 350205397Smarius fe->fe_cx |= FSR_UF; 35191174Stmm return (sign | SNG_EXP(1) | 0); 352205397Smarius } 35391174Stmm if ((fe->fe_cx & FSR_NX) || 35491174Stmm (fe->fe_fsr & (FSR_UF << FSR_TEM_SHIFT))) 35591174Stmm fe->fe_cx |= FSR_UF; 35691174Stmm return (sign | SNG_EXP(0) | fp->fp_mant[3]); 35791174Stmm } 35891174Stmm /* -FP_NG for g,r; -1 for implied 1; -SNG_FRACBITS for fraction */ 35991174Stmm (void) __fpu_shr(fp, FP_NMANT - FP_NG - 1 - SNG_FRACBITS); 36091174Stmm#ifdef DIAGNOSTIC 36191174Stmm if ((fp->fp_mant[3] & SNG_EXP(1 << FP_NG)) == 0) 36295587Sjake __utrap_panic("fpu_ftos"); 36391174Stmm#endif 364132755Skan if (fpround(fe, fp) && fp->fp_mant[3] == SNG_EXP(2)) 36591174Stmm exp++; 36691174Stmm if (exp >= SNG_EXP_INFNAN) { 36791174Stmm /* overflow to inf or to max single */ 36891174Stmm fe->fe_cx |= FSR_OF | FSR_NX; 36991174Stmm if (toinf(fe, sign)) 37091174Stmm return (sign | SNG_EXP(SNG_EXP_INFNAN)); 37191174Stmm return (sign | SNG_EXP(SNG_EXP_INFNAN - 1) | SNG_MASK); 37291174Stmm } 37391174Stmmdone: 37491174Stmm /* phew, made it */ 37591174Stmm return (sign | SNG_EXP(exp) | (fp->fp_mant[3] & SNG_MASK)); 37691174Stmm} 37791174Stmm 37891174Stmm/* 37991174Stmm * fpn -> double (32 bit high-order result returned; 32-bit low order result 38091174Stmm * left in res[1]). Assumes <= 61 bits in double precision fraction. 38191174Stmm * 38291174Stmm * This code mimics fpu_ftos; see it for comments. 38391174Stmm */ 38491174Stmmu_int 38591174Stmm__fpu_ftod(fe, fp, res) 38691174Stmm struct fpemu *fe; 38792889Sobrien struct fpn *fp; 38891174Stmm u_int *res; 38991174Stmm{ 39092889Sobrien u_int sign = fp->fp_sign << 31; 39192889Sobrien int exp; 39291174Stmm 39391174Stmm#define DBL_EXP(e) ((e) << (DBL_FRACBITS & 31)) 39491174Stmm#define DBL_MASK (DBL_EXP(1) - 1) 39591174Stmm 39691174Stmm if (ISNAN(fp)) { 39791174Stmm (void) __fpu_shr(fp, FP_NMANT - 1 - DBL_FRACBITS); 39891174Stmm exp = DBL_EXP_INFNAN; 39991174Stmm goto done; 40091174Stmm } 40191174Stmm if (ISINF(fp)) { 40291174Stmm sign |= DBL_EXP(DBL_EXP_INFNAN); 40391174Stmm goto zero; 40491174Stmm } 40591174Stmm if (ISZERO(fp)) { 40691174Stmmzero: res[1] = 0; 40791174Stmm return (sign); 40891174Stmm } 40991174Stmm 41091174Stmm if ((exp = fp->fp_exp + DBL_EXP_BIAS) <= 0) { 41191174Stmm (void) __fpu_shr(fp, FP_NMANT - FP_NG - DBL_FRACBITS - exp); 412132755Skan if (fpround(fe, fp) && fp->fp_mant[2] == DBL_EXP(1)) { 413205397Smarius fe->fe_cx |= FSR_UF; 41491174Stmm res[1] = 0; 41591174Stmm return (sign | DBL_EXP(1) | 0); 41691174Stmm } 41791174Stmm if ((fe->fe_cx & FSR_NX) || 41891174Stmm (fe->fe_fsr & (FSR_UF << FSR_TEM_SHIFT))) 41991174Stmm fe->fe_cx |= FSR_UF; 42091174Stmm exp = 0; 42191174Stmm goto done; 42291174Stmm } 42391174Stmm (void) __fpu_shr(fp, FP_NMANT - FP_NG - 1 - DBL_FRACBITS); 424132755Skan if (fpround(fe, fp) && fp->fp_mant[2] == DBL_EXP(2)) 42591174Stmm exp++; 42691174Stmm if (exp >= DBL_EXP_INFNAN) { 42791174Stmm fe->fe_cx |= FSR_OF | FSR_NX; 42891174Stmm if (toinf(fe, sign)) { 42991174Stmm res[1] = 0; 43091174Stmm return (sign | DBL_EXP(DBL_EXP_INFNAN) | 0); 43191174Stmm } 43291174Stmm res[1] = ~0; 433205397Smarius return (sign | DBL_EXP(DBL_EXP_INFNAN - 1) | DBL_MASK); 43491174Stmm } 43591174Stmmdone: 43691174Stmm res[1] = fp->fp_mant[3]; 43791174Stmm return (sign | DBL_EXP(exp) | (fp->fp_mant[2] & DBL_MASK)); 43891174Stmm} 43991174Stmm 44091174Stmm/* 44191174Stmm * fpn -> extended (32 bit high-order result returned; low-order fraction 44291174Stmm * words left in res[1]..res[3]). Like ftod, which is like ftos ... but 44391174Stmm * our internal format *is* extended precision, plus 2 bits for guard/round, 44491174Stmm * so we can avoid a small bit of work. 44591174Stmm */ 44691174Stmmu_int 44791174Stmm__fpu_ftoq(fe, fp, res) 44891174Stmm struct fpemu *fe; 44992889Sobrien struct fpn *fp; 45091174Stmm u_int *res; 45191174Stmm{ 45292889Sobrien u_int sign = fp->fp_sign << 31; 45392889Sobrien int exp; 45491174Stmm 45591174Stmm#define EXT_EXP(e) ((e) << (EXT_FRACBITS & 31)) 45691174Stmm#define EXT_MASK (EXT_EXP(1) - 1) 45791174Stmm 45891174Stmm if (ISNAN(fp)) { 45991174Stmm (void) __fpu_shr(fp, 2); /* since we are not rounding */ 46091174Stmm exp = EXT_EXP_INFNAN; 46191174Stmm goto done; 46291174Stmm } 46391174Stmm if (ISINF(fp)) { 46491174Stmm sign |= EXT_EXP(EXT_EXP_INFNAN); 46591174Stmm goto zero; 46691174Stmm } 46791174Stmm if (ISZERO(fp)) { 46891174Stmmzero: res[1] = res[2] = res[3] = 0; 46991174Stmm return (sign); 47091174Stmm } 47191174Stmm 47291174Stmm if ((exp = fp->fp_exp + EXT_EXP_BIAS) <= 0) { 47391174Stmm (void) __fpu_shr(fp, FP_NMANT - FP_NG - EXT_FRACBITS - exp); 474132755Skan if (fpround(fe, fp) && fp->fp_mant[0] == EXT_EXP(1)) { 475205397Smarius fe->fe_cx |= FSR_UF; 47691174Stmm res[1] = res[2] = res[3] = 0; 47791174Stmm return (sign | EXT_EXP(1) | 0); 47891174Stmm } 47991174Stmm if ((fe->fe_cx & FSR_NX) || 48091174Stmm (fe->fe_fsr & (FSR_UF << FSR_TEM_SHIFT))) 48191174Stmm fe->fe_cx |= FSR_UF; 48291174Stmm exp = 0; 48391174Stmm goto done; 48491174Stmm } 48591174Stmm /* Since internal == extended, no need to shift here. */ 486132755Skan if (fpround(fe, fp) && fp->fp_mant[0] == EXT_EXP(2)) 48791174Stmm exp++; 48891174Stmm if (exp >= EXT_EXP_INFNAN) { 48991174Stmm fe->fe_cx |= FSR_OF | FSR_NX; 49091174Stmm if (toinf(fe, sign)) { 49191174Stmm res[1] = res[2] = res[3] = 0; 49291174Stmm return (sign | EXT_EXP(EXT_EXP_INFNAN) | 0); 49391174Stmm } 49491174Stmm res[1] = res[2] = res[3] = ~0; 495205397Smarius return (sign | EXT_EXP(EXT_EXP_INFNAN - 1) | EXT_MASK); 49691174Stmm } 49791174Stmmdone: 49891174Stmm res[1] = fp->fp_mant[1]; 49991174Stmm res[2] = fp->fp_mant[2]; 50091174Stmm res[3] = fp->fp_mant[3]; 50191174Stmm return (sign | EXT_EXP(exp) | (fp->fp_mant[0] & EXT_MASK)); 50291174Stmm} 50391174Stmm 50491174Stmm/* 50591174Stmm * Implode an fpn, writing the result into the given space. 50691174Stmm */ 50791174Stmmvoid 50891174Stmm__fpu_implode(fe, fp, type, space) 50991174Stmm struct fpemu *fe; 51092889Sobrien struct fpn *fp; 51191174Stmm int type; 51292889Sobrien u_int *space; 51391174Stmm{ 51491174Stmm 51591174Stmm switch (type) { 51691174Stmm case FTYPE_LNG: 51791174Stmm space[0] = __fpu_ftox(fe, fp, space); 51891174Stmm break; 51991174Stmm 52091174Stmm case FTYPE_INT: 52191174Stmm space[0] = __fpu_ftoi(fe, fp); 52291174Stmm break; 52391174Stmm 52491174Stmm case FTYPE_SNG: 52591174Stmm space[0] = __fpu_ftos(fe, fp); 52691174Stmm break; 52791174Stmm 52891174Stmm case FTYPE_DBL: 52991174Stmm space[0] = __fpu_ftod(fe, fp, space); 53091174Stmm break; 53191174Stmm 53291174Stmm case FTYPE_EXT: 53391174Stmm /* funky rounding precision options ?? */ 53491174Stmm space[0] = __fpu_ftoq(fe, fp, space); 53591174Stmm break; 53691174Stmm 53791174Stmm default: 53895587Sjake __utrap_panic("fpu_implode"); 53991174Stmm } 54091174Stmm DPRINTF(FPE_REG, ("fpu_implode: %x %x %x %x\n", 54191174Stmm space[0], space[1], space[2], space[3])); 54291174Stmm} 543