1246223Ssjg/* $NetBSD: fpu_subr.c,v 1.4 2005/12/11 12:18:42 christos Exp $ */ 2246223Ssjg 3236769Sobrien/* 4236769Sobrien * Copyright (c) 1992, 1993 5236769Sobrien * The Regents of the University of California. All rights reserved. 6236769Sobrien * 7236769Sobrien * This software was developed by the Computer Systems Engineering group 8236769Sobrien * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 9236769Sobrien * contributed to Berkeley. 10236769Sobrien * 11236769Sobrien * All advertising materials mentioning features or use of this software 12236769Sobrien * must display the following acknowledgement: 13236769Sobrien * This product includes software developed by the University of 14236769Sobrien * California, Lawrence Berkeley Laboratory. 15236769Sobrien * 16236769Sobrien * Redistribution and use in source and binary forms, with or without 17236769Sobrien * modification, are permitted provided that the following conditions 18236769Sobrien * are met: 19236769Sobrien * 1. Redistributions of source code must retain the above copyright 20236769Sobrien * notice, this list of conditions and the following disclaimer. 21236769Sobrien * 2. Redistributions in binary form must reproduce the above copyright 22236769Sobrien * notice, this list of conditions and the following disclaimer in the 23236769Sobrien * documentation and/or other materials provided with the distribution. 24236769Sobrien * 3. Neither the name of the University nor the names of its contributors 25236769Sobrien * may be used to endorse or promote products derived from this software 26236769Sobrien * without specific prior written permission. 27236769Sobrien * 28236769Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29236769Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30236769Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31236769Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32236769Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33236769Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34236769Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35236769Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36236769Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37236769Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38236769Sobrien * SUCH DAMAGE. 39236769Sobrien * 40236769Sobrien * @(#)fpu_subr.c 8.1 (Berkeley) 6/11/93 41236769Sobrien */ 42236769Sobrien 43236769Sobrien/* 44236769Sobrien * FPU subroutines. 45236769Sobrien */ 46236769Sobrien 47236769Sobrien#include <sys/cdefs.h> 48236769Sobrien__FBSDID("$FreeBSD$"); 49236769Sobrien 50236769Sobrien#include <sys/types.h> 51236769Sobrien#include <sys/systm.h> 52236769Sobrien 53236769Sobrien#include <machine/fpu.h> 54236769Sobrien#include <machine/reg.h> 55246223Ssjg 56246223Ssjg#include <powerpc/fpu/fpu_arith.h> 57246223Ssjg#include <powerpc/fpu/fpu_emu.h> 58246223Ssjg 59236769Sobrien/* 60246223Ssjg * Shift the given number right rsh bits. Any bits that `fall off' will get 61236769Sobrien * shoved into the sticky field; we return the resulting sticky. Note that 62236769Sobrien * shifting NaNs is legal (this will never shift all bits out); a NaN's 63236769Sobrien * sticky field is ignored anyway. 64236769Sobrien */ 65236769Sobrienint 66236769Sobrienfpu_shr(struct fpn *fp, int rsh) 67246223Ssjg{ 68236769Sobrien u_int m0, m1, m2, m3, s; 69236769Sobrien int lsh; 70246223Ssjg 71236769Sobrien#ifdef DIAGNOSTIC 72246223Ssjg if (rsh <= 0 || (fp->fp_class != FPC_NUM && !ISNAN(fp))) 73236769Sobrien panic("fpu_rightshift 1"); 74246223Ssjg#endif 75236769Sobrien 76246223Ssjg m0 = fp->fp_mant[0]; 77246223Ssjg m1 = fp->fp_mant[1]; 78246223Ssjg m2 = fp->fp_mant[2]; 79246223Ssjg m3 = fp->fp_mant[3]; 80246223Ssjg 81236769Sobrien /* If shifting all the bits out, take a shortcut. */ 82246223Ssjg if (rsh >= FP_NMANT) { 83246223Ssjg#ifdef DIAGNOSTIC 84246223Ssjg if ((m0 | m1 | m2 | m3) == 0) 85246223Ssjg panic("fpu_rightshift 2"); 86246223Ssjg#endif 87246223Ssjg fp->fp_mant[0] = 0; 88246223Ssjg fp->fp_mant[1] = 0; 89246223Ssjg fp->fp_mant[2] = 0; 90236769Sobrien fp->fp_mant[3] = 0; 91236769Sobrien#ifdef notdef 92236769Sobrien if ((m0 | m1 | m2 | m3) == 0) 93236769Sobrien fp->fp_class = FPC_ZERO; 94236769Sobrien else 95236769Sobrien#endif 96236769Sobrien fp->fp_sticky = 1; 97236769Sobrien return (1); 98236769Sobrien } 99236769Sobrien 100236769Sobrien /* Squish out full words. */ 101246223Ssjg s = fp->fp_sticky; 102246223Ssjg if (rsh >= 32 * 3) { 103236769Sobrien s |= m3 | m2 | m1; 104246223Ssjg m3 = m0, m2 = 0, m1 = 0, m0 = 0; 105236769Sobrien } else if (rsh >= 32 * 2) { 106236769Sobrien s |= m3 | m2; 107236769Sobrien m3 = m1, m2 = m0, m1 = 0, m0 = 0; 108236769Sobrien } else if (rsh >= 32) { 109236769Sobrien s |= m3; 110236769Sobrien m3 = m2, m2 = m1, m1 = m0, m0 = 0; 111236769Sobrien } 112246223Ssjg 113246223Ssjg /* Handle any remaining partial word. */ 114236769Sobrien if ((rsh &= 31) != 0) { 115236769Sobrien lsh = 32 - rsh; 116236769Sobrien s |= m3 << lsh; 117236769Sobrien m3 = (m3 >> rsh) | (m2 << lsh); 118236769Sobrien m2 = (m2 >> rsh) | (m1 << lsh); 119236769Sobrien m1 = (m1 >> rsh) | (m0 << lsh); 120236769Sobrien m0 >>= rsh; 121236769Sobrien } 122236769Sobrien fp->fp_mant[0] = m0; 123236769Sobrien fp->fp_mant[1] = m1; 124236769Sobrien fp->fp_mant[2] = m2; 125246223Ssjg fp->fp_mant[3] = m3; 126236769Sobrien fp->fp_sticky = s; 127236769Sobrien return (s); 128246223Ssjg} 129246223Ssjg 130236769Sobrien/* 131236769Sobrien * Force a number to be normal, i.e., make its fraction have all zero 132236769Sobrien * bits before FP_1, then FP_1, then all 1 bits. This is used for denorms 133236769Sobrien * and (sometimes) for intermediate results. 134236769Sobrien * 135236769Sobrien * Internally, this may use a `supernormal' -- a number whose fp_mant 136246223Ssjg * is greater than or equal to 2.0 -- so as a side effect you can hand it 137236769Sobrien * a supernormal and it will fix it (provided fp->fp_mant[3] == 0). 138236769Sobrien */ 139236769Sobrienvoid 140236769Sobrienfpu_norm(struct fpn *fp) 141236769Sobrien{ 142236769Sobrien u_int m0, m1, m2, m3, top, sup, nrm; 143236769Sobrien int lsh, rsh, exp; 144236769Sobrien 145236769Sobrien exp = fp->fp_exp; 146236769Sobrien m0 = fp->fp_mant[0]; 147236769Sobrien m1 = fp->fp_mant[1]; 148246223Ssjg m2 = fp->fp_mant[2]; 149236769Sobrien m3 = fp->fp_mant[3]; 150236769Sobrien 151236769Sobrien /* Handle severe subnormals with 32-bit moves. */ 152236769Sobrien if (m0 == 0) { 153236769Sobrien if (m1) 154236769Sobrien m0 = m1, m1 = m2, m2 = m3, m3 = 0, exp -= 32; 155236769Sobrien else if (m2) 156236769Sobrien m0 = m2, m1 = m3, m2 = 0, m3 = 0, exp -= 2 * 32; 157236769Sobrien else if (m3) 158236769Sobrien m0 = m3, m1 = 0, m2 = 0, m3 = 0, exp -= 3 * 32; 159246223Ssjg else { 160246223Ssjg fp->fp_class = FPC_ZERO; 161236769Sobrien return; 162236769Sobrien } 163236769Sobrien } 164236769Sobrien 165236769Sobrien /* Now fix any supernormal or remaining subnormal. */ 166246223Ssjg nrm = FP_1; 167236769Sobrien sup = nrm << 1; 168236769Sobrien if (m0 >= sup) { 169236769Sobrien /* 170236769Sobrien * We have a supernormal number. We need to shift it right. 171236769Sobrien * We may assume m3==0. 172246223Ssjg */ 173246223Ssjg for (rsh = 1, top = m0 >> 1; top >= sup; rsh++) /* XXX slow */ 174246223Ssjg top >>= 1; 175236769Sobrien exp += rsh; 176236769Sobrien lsh = 32 - rsh; 177236769Sobrien m3 = m2 << lsh; 178246223Ssjg m2 = (m2 >> rsh) | (m1 << lsh); 179236769Sobrien m1 = (m1 >> rsh) | (m0 << lsh); 180236769Sobrien m0 = top; 181236769Sobrien } else if (m0 < nrm) { 182246223Ssjg /* 183236769Sobrien * We have a regular denorm (a subnormal number), and need 184236769Sobrien * to shift it left. 185246223Ssjg */ 186236769Sobrien for (lsh = 1, top = m0 << 1; top < nrm; lsh++) /* XXX slow */ 187236769Sobrien top <<= 1; 188236769Sobrien exp -= lsh; 189236769Sobrien rsh = 32 - lsh; 190236769Sobrien m0 = top | (m1 >> rsh); 191246223Ssjg m1 = (m1 << lsh) | (m2 >> rsh); 192236769Sobrien m2 = (m2 << lsh) | (m3 >> rsh); 193236769Sobrien m3 <<= lsh; 194236769Sobrien } 195236769Sobrien 196236769Sobrien fp->fp_exp = exp; 197236769Sobrien fp->fp_mant[0] = m0; 198236769Sobrien fp->fp_mant[1] = m1; 199236769Sobrien fp->fp_mant[2] = m2; 200236769Sobrien fp->fp_mant[3] = m3; 201236769Sobrien} 202236769Sobrien 203236769Sobrien/* 204246223Ssjg * Concoct a `fresh' Quiet NaN per Appendix N. 205236769Sobrien * As a side effect, we set NV (invalid) for the current exceptions. 206236769Sobrien */ 207236769Sobrienstruct fpn * 208236769Sobrienfpu_newnan(struct fpemu *fe) 209236769Sobrien{ 210236769Sobrien struct fpn *fp; 211246223Ssjg 212246223Ssjg fe->fe_cx |= FPSCR_VXSNAN; 213246223Ssjg fp = &fe->fe_f3; 214236769Sobrien fp->fp_class = FPC_QNAN; 215236769Sobrien fp->fp_sign = 0; 216 fp->fp_mant[0] = FP_1 - 1; 217 fp->fp_mant[1] = fp->fp_mant[2] = fp->fp_mant[3] = ~0; 218 DUMPFPN(FPE_REG, fp); 219 return (fp); 220} 221