/* * 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 #include 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); }