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_subr.c 8.1 (Berkeley) 6/11/93 3992986Sobrien * $NetBSD: fpu_subr.c,v 1.3 1996/03/14 19:42:01 christos Exp $ 4091174Stmm */ 4191174Stmm 4292986Sobrien#include <sys/cdefs.h> 4392986Sobrien__FBSDID("$FreeBSD$"); 4492986Sobrien 4591174Stmm/* 4691174Stmm * FPU subroutines. 4791174Stmm */ 4891174Stmm 4991174Stmm#include <sys/param.h> 5091174Stmm 5191174Stmm#include <machine/frame.h> 5291174Stmm#include <machine/fp.h> 5391174Stmm#include <machine/fsr.h> 5491174Stmm#include <machine/instr.h> 5591174Stmm 5691174Stmm#include "fpu_arith.h" 5791174Stmm#include "fpu_emu.h" 5891174Stmm#include "fpu_extern.h" 5995587Sjake#include "__sparc_utrap_private.h" 6091174Stmm 6191174Stmm/* 6291174Stmm * Shift the given number right rsh bits. Any bits that `fall off' will get 6391174Stmm * shoved into the sticky field; we return the resulting sticky. Note that 6491174Stmm * shifting NaNs is legal (this will never shift all bits out); a NaN's 6591174Stmm * sticky field is ignored anyway. 6691174Stmm */ 6791174Stmmint 6892889Sobrien__fpu_shr(struct fpn *fp, int rsh) 6991174Stmm{ 7092889Sobrien u_int m0, m1, m2, m3, s; 7192889Sobrien int lsh; 7291174Stmm 7391174Stmm#ifdef DIAGNOSTIC 7491174Stmm if (rsh <= 0 || (fp->fp_class != FPC_NUM && !ISNAN(fp))) 7595587Sjake __utrap_panic("fpu_rightshift 1"); 7691174Stmm#endif 7791174Stmm 7891174Stmm m0 = fp->fp_mant[0]; 7991174Stmm m1 = fp->fp_mant[1]; 8091174Stmm m2 = fp->fp_mant[2]; 8191174Stmm m3 = fp->fp_mant[3]; 8291174Stmm 8391174Stmm /* If shifting all the bits out, take a shortcut. */ 8491174Stmm if (rsh >= FP_NMANT) { 8591174Stmm#ifdef DIAGNOSTIC 8691174Stmm if ((m0 | m1 | m2 | m3) == 0) 8795587Sjake __utrap_panic("fpu_rightshift 2"); 8891174Stmm#endif 8991174Stmm fp->fp_mant[0] = 0; 9091174Stmm fp->fp_mant[1] = 0; 9191174Stmm fp->fp_mant[2] = 0; 9291174Stmm fp->fp_mant[3] = 0; 9391174Stmm#ifdef notdef 9491174Stmm if ((m0 | m1 | m2 | m3) == 0) 9591174Stmm fp->fp_class = FPC_ZERO; 9691174Stmm else 9791174Stmm#endif 9891174Stmm fp->fp_sticky = 1; 9991174Stmm return (1); 10091174Stmm } 10191174Stmm 10291174Stmm /* Squish out full words. */ 10391174Stmm s = fp->fp_sticky; 10491174Stmm if (rsh >= 32 * 3) { 10591174Stmm s |= m3 | m2 | m1; 10691174Stmm m3 = m0, m2 = 0, m1 = 0, m0 = 0; 10791174Stmm } else if (rsh >= 32 * 2) { 10891174Stmm s |= m3 | m2; 10991174Stmm m3 = m1, m2 = m0, m1 = 0, m0 = 0; 11091174Stmm } else if (rsh >= 32) { 11191174Stmm s |= m3; 11291174Stmm m3 = m2, m2 = m1, m1 = m0, m0 = 0; 11391174Stmm } 11491174Stmm 11591174Stmm /* Handle any remaining partial word. */ 11691174Stmm if ((rsh &= 31) != 0) { 11791174Stmm lsh = 32 - rsh; 11891174Stmm s |= m3 << lsh; 11991174Stmm m3 = (m3 >> rsh) | (m2 << lsh); 12091174Stmm m2 = (m2 >> rsh) | (m1 << lsh); 12191174Stmm m1 = (m1 >> rsh) | (m0 << lsh); 12291174Stmm m0 >>= rsh; 12391174Stmm } 12491174Stmm fp->fp_mant[0] = m0; 12591174Stmm fp->fp_mant[1] = m1; 12691174Stmm fp->fp_mant[2] = m2; 12791174Stmm fp->fp_mant[3] = m3; 12891174Stmm fp->fp_sticky = s; 12991174Stmm return (s); 13091174Stmm} 13191174Stmm 13291174Stmm/* 13391174Stmm * Force a number to be normal, i.e., make its fraction have all zero 13491174Stmm * bits before FP_1, then FP_1, then all 1 bits. This is used for denorms 13591174Stmm * and (sometimes) for intermediate results. 13691174Stmm * 13791174Stmm * Internally, this may use a `supernormal' -- a number whose fp_mant 13891174Stmm * is greater than or equal to 2.0 -- so as a side effect you can hand it 13991174Stmm * a supernormal and it will fix it (provided fp->fp_mant[3] == 0). 14091174Stmm */ 14191174Stmmvoid 14292889Sobrien__fpu_norm(struct fpn *fp) 14391174Stmm{ 14492889Sobrien u_int m0, m1, m2, m3, top, sup, nrm; 14592889Sobrien int lsh, rsh, exp; 14691174Stmm 14791174Stmm exp = fp->fp_exp; 14891174Stmm m0 = fp->fp_mant[0]; 14991174Stmm m1 = fp->fp_mant[1]; 15091174Stmm m2 = fp->fp_mant[2]; 15191174Stmm m3 = fp->fp_mant[3]; 15291174Stmm 15391174Stmm /* Handle severe subnormals with 32-bit moves. */ 15491174Stmm if (m0 == 0) { 15591174Stmm if (m1) 15691174Stmm m0 = m1, m1 = m2, m2 = m3, m3 = 0, exp -= 32; 15791174Stmm else if (m2) 15891174Stmm m0 = m2, m1 = m3, m2 = 0, m3 = 0, exp -= 2 * 32; 15991174Stmm else if (m3) 16091174Stmm m0 = m3, m1 = 0, m2 = 0, m3 = 0, exp -= 3 * 32; 16191174Stmm else { 16291174Stmm fp->fp_class = FPC_ZERO; 16391174Stmm return; 16491174Stmm } 16591174Stmm } 16691174Stmm 16791174Stmm /* Now fix any supernormal or remaining subnormal. */ 16891174Stmm nrm = FP_1; 16991174Stmm sup = nrm << 1; 17091174Stmm if (m0 >= sup) { 17191174Stmm /* 17291174Stmm * We have a supernormal number. We need to shift it right. 17391174Stmm * We may assume m3==0. 17491174Stmm */ 17591174Stmm for (rsh = 1, top = m0 >> 1; top >= sup; rsh++) /* XXX slow */ 17691174Stmm top >>= 1; 17791174Stmm exp += rsh; 17891174Stmm lsh = 32 - rsh; 17991174Stmm m3 = m2 << lsh; 18091174Stmm m2 = (m2 >> rsh) | (m1 << lsh); 18191174Stmm m1 = (m1 >> rsh) | (m0 << lsh); 18291174Stmm m0 = top; 18391174Stmm } else if (m0 < nrm) { 18491174Stmm /* 18591174Stmm * We have a regular denorm (a subnormal number), and need 18691174Stmm * to shift it left. 18791174Stmm */ 18891174Stmm for (lsh = 1, top = m0 << 1; top < nrm; lsh++) /* XXX slow */ 18991174Stmm top <<= 1; 19091174Stmm exp -= lsh; 19191174Stmm rsh = 32 - lsh; 19291174Stmm m0 = top | (m1 >> rsh); 19391174Stmm m1 = (m1 << lsh) | (m2 >> rsh); 19491174Stmm m2 = (m2 << lsh) | (m3 >> rsh); 19591174Stmm m3 <<= lsh; 19691174Stmm } 19791174Stmm 19891174Stmm fp->fp_exp = exp; 19991174Stmm fp->fp_mant[0] = m0; 20091174Stmm fp->fp_mant[1] = m1; 20191174Stmm fp->fp_mant[2] = m2; 20291174Stmm fp->fp_mant[3] = m3; 20391174Stmm} 20491174Stmm 20591174Stmm/* 20691174Stmm * Concoct a `fresh' Quiet NaN per Appendix N. 20791174Stmm * As a side effect, we set NV (invalid) for the current exceptions. 20891174Stmm */ 20991174Stmmstruct fpn * 21092889Sobrien__fpu_newnan(struct fpemu *fe) 21191174Stmm{ 21292889Sobrien struct fpn *fp; 21391174Stmm 21491174Stmm fe->fe_cx = FSR_NV; 21591174Stmm fp = &fe->fe_f3; 21691174Stmm fp->fp_class = FPC_QNAN; 21791174Stmm fp->fp_sign = 0; 21891174Stmm fp->fp_mant[0] = FP_1 - 1; 21991174Stmm fp->fp_mant[1] = fp->fp_mant[2] = fp->fp_mant[3] = ~0; 22091174Stmm return (fp); 22191174Stmm} 222