155115Storek /* 255115Storek * Copyright (c) 1992 The Regents of the University of California. 355115Storek * All rights reserved. 455115Storek * 555115Storek * This software was developed by the Computer Systems Engineering group 655115Storek * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 755115Storek * contributed to Berkeley. 855115Storek * 9*55500Sbostic * All advertising materials mentioning features or use of this software 10*55500Sbostic * must display the following acknowledgement: 11*55500Sbostic * This product includes software developed by the University of 12*55500Sbostic * California, Lawrence Berkeley Laboratories. 13*55500Sbostic * 1455115Storek * %sccs.include.redist.c% 1555115Storek * 16*55500Sbostic * @(#)fpu_subr.c 7.2 (Berkeley) 07/21/92 1755115Storek * 1855115Storek * from: $Header: fpu_subr.c,v 1.2 92/06/17 05:41:35 torek Exp $ 1955115Storek */ 2055115Storek 2155115Storek /* 2255115Storek * FPU subroutines. 2355115Storek */ 2455115Storek 2555115Storek #include "sys/types.h" 2655115Storek 2755115Storek #include "machine/reg.h" 2855115Storek 2955115Storek #include "fpu_arith.h" 3055115Storek #include "fpu_emu.h" 3155115Storek 3255115Storek /* 3355115Storek * Shift the given number right rsh bits. Any bits that `fall off' will get 3455115Storek * shoved into the sticky field; we return the resulting sticky. Note that 3555115Storek * shifting NaNs is legal (this will never shift all bits out); a NaN's 3655115Storek * sticky field is ignored anyway. 3755115Storek */ 3855115Storek int 3955115Storek fpu_shr(register struct fpn *fp, register int rsh) 4055115Storek { 4155115Storek register u_int m0, m1, m2, m3, s; 4255115Storek register int lsh; 4355115Storek 4455115Storek #ifdef DIAGNOSTIC 4555115Storek if (rsh <= 0 || (fp->fp_class != FPC_NUM && !ISNAN(fp))) 4655115Storek panic("fpu_rightshift 1"); 4755115Storek #endif 4855115Storek 4955115Storek m0 = fp->fp_mant[0]; 5055115Storek m1 = fp->fp_mant[1]; 5155115Storek m2 = fp->fp_mant[2]; 5255115Storek m3 = fp->fp_mant[3]; 5355115Storek 5455115Storek /* If shifting all the bits out, take a shortcut. */ 5555115Storek if (rsh >= FP_NMANT) { 5655115Storek #ifdef DIAGNOSTIC 5755115Storek if ((m0 | m1 | m2 | m3) == 0) 5855115Storek panic("fpu_rightshift 2"); 5955115Storek #endif 6055115Storek fp->fp_mant[0] = 0; 6155115Storek fp->fp_mant[1] = 0; 6255115Storek fp->fp_mant[2] = 0; 6355115Storek fp->fp_mant[3] = 0; 6455115Storek #ifdef notdef 6555115Storek if ((m0 | m1 | m2 | m3) == 0) 6655115Storek fp->fp_class = FPC_ZERO; 6755115Storek else 6855115Storek #endif 6955115Storek fp->fp_sticky = 1; 7055115Storek return (1); 7155115Storek } 7255115Storek 7355115Storek /* Squish out full words. */ 7455115Storek s = fp->fp_sticky; 7555115Storek if (rsh >= 32 * 3) { 7655115Storek s |= m3 | m2 | m1; 7755115Storek m3 = m0, m2 = 0, m1 = 0, m0 = 0; 7855115Storek } else if (rsh >= 32 * 2) { 7955115Storek s |= m3 | m2; 8055115Storek m3 = m1, m2 = m0, m1 = 0, m0 = 0; 8155115Storek } else if (rsh >= 32) { 8255115Storek s |= m3; 8355115Storek m3 = m2, m2 = m1, m1 = m0, m0 = 0; 8455115Storek } 8555115Storek 8655115Storek /* Handle any remaining partial word. */ 8755115Storek if ((rsh &= 31) != 0) { 8855115Storek lsh = 32 - rsh; 8955115Storek s |= m3 << lsh; 9055115Storek m3 = (m3 >> rsh) | (m2 << lsh); 9155115Storek m2 = (m2 >> rsh) | (m1 << lsh); 9255115Storek m1 = (m1 >> rsh) | (m0 << lsh); 9355115Storek m0 >>= rsh; 9455115Storek } 9555115Storek fp->fp_mant[0] = m0; 9655115Storek fp->fp_mant[1] = m1; 9755115Storek fp->fp_mant[2] = m2; 9855115Storek fp->fp_mant[3] = m3; 9955115Storek fp->fp_sticky = s; 10055115Storek return (s); 10155115Storek } 10255115Storek 10355115Storek /* 10455115Storek * Force a number to be normal, i.e., make its fraction have all zero 10555115Storek * bits before FP_1, then FP_1, then all 1 bits. This is used for denorms 10655115Storek * and (sometimes) for intermediate results. 10755115Storek * 10855115Storek * Internally, this may use a `supernormal' -- a number whose fp_mant 10955115Storek * is greater than or equal to 2.0 -- so as a side effect you can hand it 11055115Storek * a supernormal and it will fix it (provided fp->fp_mant[3] == 0). 11155115Storek */ 11255115Storek void 11355115Storek fpu_norm(register struct fpn *fp) 11455115Storek { 11555115Storek register u_int m0, m1, m2, m3, top, sup, nrm; 11655115Storek register int lsh, rsh, exp; 11755115Storek 11855115Storek exp = fp->fp_exp; 11955115Storek m0 = fp->fp_mant[0]; 12055115Storek m1 = fp->fp_mant[1]; 12155115Storek m2 = fp->fp_mant[2]; 12255115Storek m3 = fp->fp_mant[3]; 12355115Storek 12455115Storek /* Handle severe subnormals with 32-bit moves. */ 12555115Storek if (m0 == 0) { 12655115Storek if (m1) 12755115Storek m0 = m1, m1 = m2, m2 = m3, m3 = 0, exp -= 32; 12855115Storek else if (m2) 12955115Storek m0 = m2, m1 = m3, m2 = 0, m3 = 0, exp -= 2 * 32; 13055115Storek else if (m3) 13155115Storek m0 = m2, m1 = m3, m2 = 0, m3 = 0, exp -= 2 * 32; 13255115Storek else { 13355115Storek fp->fp_class = FPC_ZERO; 13455115Storek return; 13555115Storek } 13655115Storek } 13755115Storek 13855115Storek /* Now fix any supernormal or remaining subnormal. */ 13955115Storek nrm = FP_1; 14055115Storek sup = nrm << 1; 14155115Storek if (m0 >= sup) { 14255115Storek /* 14355115Storek * We have a supernormal number. We need to shift it right. 14455115Storek * We may assume m3==0. 14555115Storek */ 14655115Storek for (rsh = 1, top = m0 >> 1; top >= sup; rsh++) /* XXX slow */ 14755115Storek top >>= 1; 14855115Storek exp += rsh; 14955115Storek lsh = 32 - rsh; 15055115Storek m3 = m2 << lsh; 15155115Storek m2 = (m2 >> rsh) | (m1 << lsh); 15255115Storek m1 = (m1 >> rsh) | (m0 << lsh); 15355115Storek m0 = top; 15455115Storek } else if (m0 < nrm) { 15555115Storek /* 15655115Storek * We have a regular denorm (a subnormal number), and need 15755115Storek * to shift it left. 15855115Storek */ 15955115Storek for (lsh = 1, top = m0 << 1; top < nrm; lsh++) /* XXX slow */ 16055115Storek top <<= 1; 16155115Storek exp -= lsh; 16255115Storek rsh = 32 - lsh; 16355115Storek m0 = top | (m1 >> rsh); 16455115Storek m1 = (m1 << lsh) | (m2 >> rsh); 16555115Storek m2 = (m2 << lsh) | (m3 >> rsh); 16655115Storek m3 <<= lsh; 16755115Storek } 16855115Storek 16955115Storek fp->fp_exp = exp; 17055115Storek fp->fp_mant[0] = m0; 17155115Storek fp->fp_mant[1] = m1; 17255115Storek fp->fp_mant[2] = m2; 17355115Storek fp->fp_mant[3] = m3; 17455115Storek } 17555115Storek 17655115Storek /* 17755115Storek * Concoct a `fresh' Quiet NaN per Appendix N. 17855115Storek * As a side effect, we set NV (invalid) for the current exceptions. 17955115Storek */ 18055115Storek struct fpn * 18155115Storek fpu_newnan(register struct fpemu *fe) 18255115Storek { 18355115Storek register struct fpn *fp; 18455115Storek 18555115Storek fe->fe_cx = FSR_NV; 18655115Storek fp = &fe->fe_f3; 18755115Storek fp->fp_class = FPC_QNAN; 18855115Storek fp->fp_sign = 0; 18955115Storek fp->fp_mant[0] = FP_1 - 1; 19055115Storek fp->fp_mant[1] = fp->fp_mant[2] = fp->fp_mant[3] = ~0; 19155115Storek return (fp); 19255115Storek } 193