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