OpenSolaris_b135/uts/sparc/fpu/unpack.c

Compare this file to the similar file:
Show the results in this format:

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 1987, 2000, 2003 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"	/* SunOS-4.1 */

/* Unpack procedures for Sparc FPU simulator. */

#include <sys/fpu/fpu_simulator.h>
#include <sys/fpu/globals.h>

static void
unpackint32(
	unpacked	*pu,	/* unpacked result */
	int32_t		x)	/* packed int32_t */
{
	uint_t ux;

	pu->sticky = pu->rounded = 0;
	if (x == 0) {
		pu->sign = 0;
		pu->fpclass = fp_zero;
	} else {
		(*pu).sign = x < 0;
		(*pu).fpclass = fp_normal;
		(*pu).exponent = INTEGER_BIAS;
		if (x < 0) ux = -x; else ux = x;
		(*pu).significand[0] = ux>>15;
		(*pu).significand[1] = (ux&0x7fff)<<17;
		(*pu).significand[2] = 0;
		(*pu).significand[3] = 0;
		fpu_normalize(pu);
	}
}


/*
 * Workaround for bug 4287443--- we have to convince the compiler
 * that unpackint64 isn't a leaf routine.
 */
static void
subroutine(void)
{
}

static void
unpackint64(
	unpacked	*pu,	/* unpacked result */
	int64_t		x)	/* packed int64_t */
{
	union {
		uint64_t ll;
		uint32_t i[2];
	} ux;

	subroutine();

	pu->sticky = pu->rounded = 0;
	if (x == 0) {
		pu->sign = 0;
		pu->fpclass = fp_zero;
	} else {
		(*pu).sign = x < 0;
		(*pu).fpclass = fp_normal;
		(*pu).exponent = LONGLONG_BIAS;
		if (x < 0) ux.ll = -x; else ux.ll = x;
		(*pu).significand[0] = ux.i[0]>>15;
		(*pu).significand[1] = (((ux.i[0]&0x7fff)<<17) | (ux.i[1]>>15));
		(*pu).significand[2] = (ux.i[1]&0x7fff)<<17;
		(*pu).significand[3] = 0;
		fpu_normalize(pu);
	}
}

void
unpacksingle(
	fp_simd_type	*pfpsd,	/* simulator data */
	unpacked	*pu,	/* unpacked result */
	single_type	x)	/* packed single */
{
	uint_t U;

	pu->sticky = pu->rounded = 0;
	U = x.significand;
	(*pu).sign = x.sign;
	pu->significand[1] = 0;
	pu->significand[2] = 0;
	pu->significand[3] = 0;
	if (x.exponent == 0) {				/* zero or sub */
		if (x.significand == 0) {		/* zero */
			pu->fpclass = fp_zero;
			return;
		} else {				/* subnormal */
			pu->fpclass = fp_normal;
			pu->exponent = -SINGLE_BIAS-6;
			pu->significand[0] = U;
			fpu_normalize(pu);
			return;
		}
	} else if (x.exponent == 0xff) {		/* inf or nan */
		if (x.significand == 0) {		/* inf */
			pu->fpclass = fp_infinity;
			return;
		} else {				/* nan */
			if ((U & 0x400000) != 0) {	/* quiet */
				pu->fpclass = fp_quiet;
			} else {			/* signaling */
				pu->fpclass = fp_signaling;
				fpu_set_exception(pfpsd, fp_invalid);
			}
			pu->significand[0] = 0x18000 | (U >> 7);
			(*pu).significand[1] = ((U&0x7f)<<25);
			return;
		}
	}
	(*pu).exponent = x.exponent - SINGLE_BIAS;
	(*pu).fpclass = fp_normal;
	(*pu).significand[0] = 0x10000|(U>>7);
	(*pu).significand[1] = ((U&0x7f)<<25);
}

void
unpackdouble(
	fp_simd_type	*pfpsd,	/* simulator data */
	unpacked	*pu,	/* unpacked result */
	double_type	x,	/* packed double, sign/exponent/upper 20 bits */
	uint_t		y)	/* and the lower 32 bits of the significand */
{
	uint_t U;

	pu->sticky = pu->rounded = 0;
	U = x.significand;
	(*pu).sign = x.sign;
	pu->significand[1] = y;
	pu->significand[2] = 0;
	pu->significand[3] = 0;
	if (x.exponent == 0) {				/* zero or sub */
		if ((x.significand == 0) && (y == 0)) {	/* zero */
			pu->fpclass = fp_zero;
			return;
		} else {				/* subnormal */
			pu->fpclass = fp_normal;
			pu->exponent = -DOUBLE_BIAS-3;
			pu->significand[0] = U;
			fpu_normalize(pu);
			return;
		}
	} else if (x.exponent == 0x7ff) {		/* inf or nan */
		if ((U|y) == 0) {			/* inf */
			pu->fpclass = fp_infinity;
			return;
		} else {				/* nan */
			if ((U & 0x80000) != 0) {	/* quiet */
				pu->fpclass = fp_quiet;
			} else {			/* signaling */
				pu->fpclass = fp_signaling;
				fpu_set_exception(pfpsd, fp_invalid);
			}
			pu->significand[0] = 0x18000 | (U >> 4);
			(*pu).significand[1] = ((U&0xf)<<28)|(y>>4);
			(*pu).significand[2] = ((y&0xf)<<28);
			return;
		}
	}
	(*pu).exponent = x.exponent - DOUBLE_BIAS;
	(*pu).fpclass = fp_normal;
	(*pu).significand[0] = 0x10000|(U>>4);
	(*pu).significand[1] = ((U&0xf)<<28)|(y>>4);
	(*pu).significand[2] = ((y&0xf)<<28);
}

static void
unpackextended(
	fp_simd_type	*pfpsd,	/* simulator data */
	unpacked	*pu,	/* unpacked result */
	extended_type	x,	/* packed extended, sign/exponent/16 bits */
	uint32_t	y,	/* 2nd word of extended significand */
	uint32_t	z,	/* 3rd word of extended significand */
	uint32_t	w)	/* 4th word of extended significand */
{
	uint_t U;

	pu->sticky = pu->rounded = 0;
	U = x.significand;
	(*pu).sign = x.sign;
	(*pu).fpclass = fp_normal;
	(*pu).exponent = x.exponent - EXTENDED_BIAS;
	(*pu).significand[0] = (x.exponent == 0) ? U : 0x10000|U;
	(*pu).significand[1] = y;
	(*pu).significand[2] = z;
	(*pu).significand[3] = w;
	if (x.exponent < 0x7fff) {	/* zero, normal, or subnormal */
		if ((z|y|w|pu->significand[0]) == 0) {	/* zero */
			pu->fpclass = fp_zero;
			return;
		} else {			/* normal or subnormal */
			if (x.exponent == 0) {
				fpu_normalize(pu);
				pu->exponent += 1;
			}
			return;
		}
	} else {					/* inf or nan */
		if ((U|z|y|w) == 0) {			/* inf */
			pu->fpclass = fp_infinity;
			return;
		} else {				/* nan */
			if ((U & 0x00008000) != 0) {	/* quiet */
				pu->fpclass = fp_quiet;
			} else {			/* signaling */
				pu->fpclass = fp_signaling;
				fpu_set_exception(pfpsd, fp_invalid);
			}
			pu->significand[0] |= 0x8000;	/* make quiet */
			return;
		}
	}
}

void
_fp_unpack(
	fp_simd_type	*pfpsd,	/* simulator data */
	unpacked	*pu,	/* unpacked result */
	uint_t		n,	/* register where data starts */
	enum fp_op_type	dtype)	/* type of datum */
{
	freg_type	f;
	union {
		uint32_t	y[4];
		uint64_t	ll[2];
		freg_type	f;
	} fp;

	switch (dtype) {
	case fp_op_int32:
		pfpsd->fp_current_read_freg(&f, n, pfpsd);
		unpackint32(pu, f.int32_reg);
		break;
	case fp_op_int64:

		if ((n & 0x1) == 1)	/* fix register encoding */
			n = (n & 0x1e) | 0x20;
		pfpsd->fp_current_read_dreg(&fp.ll[0], DOUBLE(n), pfpsd);
		unpackint64(pu, fp.f.int64_reg);
		break;
	case fp_op_single:
		pfpsd->fp_current_read_freg(&f, n, pfpsd);
		unpacksingle(pfpsd, pu, f.single_reg);
		break;
	case fp_op_double:
		if ((n & 0x1) == 1)	/* fix register encoding */
			n = (n & 0x1e) | 0x20;
		pfpsd->fp_current_read_dreg(&fp.ll[0], DOUBLE(n), pfpsd);
		unpackdouble(pfpsd, pu, fp.f.double_reg, fp.y[1]);
		break;
	case fp_op_extended:
		if ((n & 0x1) == 1)	/* fix register encoding */
			n = (n & 0x1e) | 0x20;
		pfpsd->fp_current_read_dreg(&fp.ll[0], QUAD_E(n), pfpsd);
		pfpsd->fp_current_read_dreg(&fp.ll[1], QUAD_F(n), pfpsd);
		unpackextended(pfpsd, pu, fp.f.extended_reg, fp.y[1],
					fp.y[2], fp.y[3]);
		break;
	}
}

void
_fp_unpack_word(
	fp_simd_type	*pfpsd,	/* simulator data */
	uint32_t	*pu,	/* unpacked result */
	uint_t		n)	/* register where data starts */
{
	pfpsd->fp_current_read_freg(pu, n, pfpsd);
}

void
_fp_unpack_extword(
	fp_simd_type	*pfpsd,	/* simulator data */
	uint64_t	*pu,	/* unpacked result */
	uint_t		n)	/* register where data starts */
{
	if ((n & 0x1) == 1)	/* fix register encoding */
		n = (n & 0x1e) | 0x20;
	pfpsd->fp_current_read_dreg(pu, DOUBLE(n), pfpsd);
}