10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*6812Sraf * Common Development and Distribution License (the "License").
6*6812Sraf * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
21*6812Sraf
220Sstevel@tonic-gate /*
23*6812Sraf * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
240Sstevel@tonic-gate * Use is subject to license terms.
250Sstevel@tonic-gate */
260Sstevel@tonic-gate
270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
280Sstevel@tonic-gate
29*6812Sraf #include "lint.h"
300Sstevel@tonic-gate #include "base_conversion.h"
310Sstevel@tonic-gate
320Sstevel@tonic-gate /* conversion from hex chars to hex values */
330Sstevel@tonic-gate #define HEXVAL(c) (('0' <= c && c <= '9')? c - '0' : \
340Sstevel@tonic-gate 10 + (('a' <= c && c <= 'f')? c - 'a' : c - 'A'))
350Sstevel@tonic-gate
360Sstevel@tonic-gate /*
370Sstevel@tonic-gate * Convert a hexadecimal record in *pd to unpacked form in *pu.
380Sstevel@tonic-gate *
390Sstevel@tonic-gate * Up to 30 hexadecimal digits from pd->ds are converted to a binary
400Sstevel@tonic-gate * value in px->significand, which is then normalized so that the most
410Sstevel@tonic-gate * significant bit is 1. If there are additional, unused digits in
420Sstevel@tonic-gate * pd->ds, the least significant bit of px->significand will be set.
430Sstevel@tonic-gate */
440Sstevel@tonic-gate static void
__hex_to_unpacked(decimal_record * pd,unpacked * pu)450Sstevel@tonic-gate __hex_to_unpacked(decimal_record *pd, unpacked *pu)
460Sstevel@tonic-gate {
470Sstevel@tonic-gate int i, n;
480Sstevel@tonic-gate
490Sstevel@tonic-gate pu->sign = pd->sign;
500Sstevel@tonic-gate pu->fpclass = pd->fpclass;
510Sstevel@tonic-gate
520Sstevel@tonic-gate /*
530Sstevel@tonic-gate * Adjust the (base two) exponent to reflect the fact that the
540Sstevel@tonic-gate * radix point in *pd lies to the right of the last (base sixteen)
550Sstevel@tonic-gate * digit while the radix point in *pu lies to the right of the
560Sstevel@tonic-gate * most significant bit.
570Sstevel@tonic-gate */
580Sstevel@tonic-gate pu->exponent = pd->exponent + (pd->ndigits << 2) - 1;
590Sstevel@tonic-gate
600Sstevel@tonic-gate /* fill in the significand */
610Sstevel@tonic-gate for (i = 0; i < 5; i++)
620Sstevel@tonic-gate pu->significand[i] = 0;
630Sstevel@tonic-gate
640Sstevel@tonic-gate n = pd->ndigits;
650Sstevel@tonic-gate if (n > 30)
660Sstevel@tonic-gate n = 30;
670Sstevel@tonic-gate for (i = 0; i < n; i++) {
680Sstevel@tonic-gate pu->significand[i >> 3] |= HEXVAL(pd->ds[i]) <<
690Sstevel@tonic-gate ((7 - (i & 7)) << 2);
700Sstevel@tonic-gate }
710Sstevel@tonic-gate
720Sstevel@tonic-gate /* sanity check */
730Sstevel@tonic-gate if (pu->significand[0] == 0) {
740Sstevel@tonic-gate pu->fpclass = fp_zero;
750Sstevel@tonic-gate return;
760Sstevel@tonic-gate }
770Sstevel@tonic-gate
780Sstevel@tonic-gate /* normalize so the most significant bit is set */
790Sstevel@tonic-gate while (pu->significand[0] < 0x80000000u) {
800Sstevel@tonic-gate pu->significand[0] = (pu->significand[0] << 1) |
810Sstevel@tonic-gate (pu->significand[1] >> 31);
820Sstevel@tonic-gate pu->significand[1] = (pu->significand[1] << 1) |
830Sstevel@tonic-gate (pu->significand[2] >> 31);
840Sstevel@tonic-gate pu->significand[2] = (pu->significand[2] << 1) |
850Sstevel@tonic-gate (pu->significand[3] >> 31);
860Sstevel@tonic-gate pu->significand[3] <<= 1;
870Sstevel@tonic-gate pu->exponent--;
880Sstevel@tonic-gate }
890Sstevel@tonic-gate
900Sstevel@tonic-gate /* if there are any unused digits, set a sticky bit */
910Sstevel@tonic-gate if (pd->ndigits > 30 || pd->more)
920Sstevel@tonic-gate pu->significand[4] = 1;
930Sstevel@tonic-gate }
940Sstevel@tonic-gate
950Sstevel@tonic-gate /*
960Sstevel@tonic-gate * The following routines convert the hexadecimal value encoded in the
970Sstevel@tonic-gate * decimal record *pd to a floating point value *px observing the round-
980Sstevel@tonic-gate * ing mode specified in rd and passing back any exceptions raised via
990Sstevel@tonic-gate * *ps.
1000Sstevel@tonic-gate *
1010Sstevel@tonic-gate * These routines assume pd->fpclass is either fp_zero or fp_normal.
1020Sstevel@tonic-gate * If pd->fpclass is fp_zero, *px is set to zero with the sign indicated
1030Sstevel@tonic-gate * by pd->sign and no exceptions are raised. Otherwise, pd->ds must
1040Sstevel@tonic-gate * contain a string of hexadecimal digits of length pd->ndigits > 0, and
1050Sstevel@tonic-gate * the first digit must be nonzero. Let m be the integer represented by
1060Sstevel@tonic-gate * this string. Then *px is set to a correctly rounded approximation to
1070Sstevel@tonic-gate *
1080Sstevel@tonic-gate * (-1)^(pd->sign) * m * 2^(pd->exponent)
1090Sstevel@tonic-gate *
1100Sstevel@tonic-gate * with inexact, underflow, and/or overflow raised as appropriate.
1110Sstevel@tonic-gate */
1120Sstevel@tonic-gate
1130Sstevel@tonic-gate void
__hex_to_single(decimal_record * pd,enum fp_direction_type rd,single * px,fp_exception_field_type * ps)1140Sstevel@tonic-gate __hex_to_single(decimal_record *pd, enum fp_direction_type rd, single *px,
1150Sstevel@tonic-gate fp_exception_field_type *ps)
1160Sstevel@tonic-gate {
1170Sstevel@tonic-gate single_equivalence kluge;
1180Sstevel@tonic-gate unpacked u;
1190Sstevel@tonic-gate
1200Sstevel@tonic-gate *ps = 0;
1210Sstevel@tonic-gate if (pd->fpclass == fp_zero) {
1220Sstevel@tonic-gate kluge.f.msw.sign = pd->sign? 1 : 0;
1230Sstevel@tonic-gate kluge.f.msw.exponent = 0;
1240Sstevel@tonic-gate kluge.f.msw.significand = 0;
1250Sstevel@tonic-gate *px = kluge.x;
1260Sstevel@tonic-gate } else {
1270Sstevel@tonic-gate __hex_to_unpacked(pd, &u);
1280Sstevel@tonic-gate __pack_single(&u, px, rd, ps);
1290Sstevel@tonic-gate if (*ps != 0)
1300Sstevel@tonic-gate __base_conversion_set_exception(*ps);
1310Sstevel@tonic-gate }
1320Sstevel@tonic-gate }
1330Sstevel@tonic-gate
1340Sstevel@tonic-gate void
__hex_to_double(decimal_record * pd,enum fp_direction_type rd,double * px,fp_exception_field_type * ps)1350Sstevel@tonic-gate __hex_to_double(decimal_record *pd, enum fp_direction_type rd, double *px,
1360Sstevel@tonic-gate fp_exception_field_type *ps)
1370Sstevel@tonic-gate {
1380Sstevel@tonic-gate double_equivalence kluge;
1390Sstevel@tonic-gate unpacked u;
1400Sstevel@tonic-gate
1410Sstevel@tonic-gate *ps = 0;
1420Sstevel@tonic-gate if (pd->fpclass == fp_zero) {
1430Sstevel@tonic-gate kluge.f.msw.sign = pd->sign? 1 : 0;
1440Sstevel@tonic-gate kluge.f.msw.exponent = 0;
1450Sstevel@tonic-gate kluge.f.msw.significand = 0;
1460Sstevel@tonic-gate kluge.f.significand2 = 0;
1470Sstevel@tonic-gate *px = kluge.x;
1480Sstevel@tonic-gate } else {
1490Sstevel@tonic-gate __hex_to_unpacked(pd, &u);
1500Sstevel@tonic-gate __pack_double(&u, px, rd, ps);
1510Sstevel@tonic-gate if (*ps != 0)
1520Sstevel@tonic-gate __base_conversion_set_exception(*ps);
1530Sstevel@tonic-gate }
1540Sstevel@tonic-gate }
1550Sstevel@tonic-gate
1560Sstevel@tonic-gate #if defined(__sparc)
1570Sstevel@tonic-gate
1580Sstevel@tonic-gate void
__hex_to_quadruple(decimal_record * pd,enum fp_direction_type rd,quadruple * px,fp_exception_field_type * ps)1590Sstevel@tonic-gate __hex_to_quadruple(decimal_record *pd, enum fp_direction_type rd, quadruple *px,
1600Sstevel@tonic-gate fp_exception_field_type *ps)
1610Sstevel@tonic-gate {
1620Sstevel@tonic-gate quadruple_equivalence kluge;
1630Sstevel@tonic-gate unpacked u;
1640Sstevel@tonic-gate
1650Sstevel@tonic-gate *ps = 0;
1660Sstevel@tonic-gate if (pd->fpclass == fp_zero) {
1670Sstevel@tonic-gate kluge.f.msw.sign = pd->sign? 1 : 0;
1680Sstevel@tonic-gate kluge.f.msw.exponent = 0;
1690Sstevel@tonic-gate kluge.f.msw.significand = 0;
1700Sstevel@tonic-gate kluge.f.significand2 = 0;
1710Sstevel@tonic-gate kluge.f.significand3 = 0;
1720Sstevel@tonic-gate kluge.f.significand4 = 0;
1730Sstevel@tonic-gate *px = kluge.x;
1740Sstevel@tonic-gate } else {
1750Sstevel@tonic-gate __hex_to_unpacked(pd, &u);
1760Sstevel@tonic-gate __pack_quadruple(&u, px, rd, ps);
1770Sstevel@tonic-gate if (*ps != 0)
1780Sstevel@tonic-gate __base_conversion_set_exception(*ps);
1790Sstevel@tonic-gate }
1800Sstevel@tonic-gate }
1810Sstevel@tonic-gate
1820Sstevel@tonic-gate #elif defined(__i386) || defined(__amd64)
1830Sstevel@tonic-gate
1840Sstevel@tonic-gate void
__hex_to_extended(decimal_record * pd,enum fp_direction_type rd,extended * px,fp_exception_field_type * ps)1850Sstevel@tonic-gate __hex_to_extended(decimal_record *pd, enum fp_direction_type rd, extended *px,
1860Sstevel@tonic-gate fp_exception_field_type *ps)
1870Sstevel@tonic-gate {
1880Sstevel@tonic-gate extended_equivalence kluge;
1890Sstevel@tonic-gate unpacked u;
1900Sstevel@tonic-gate
1910Sstevel@tonic-gate *ps = 0;
1920Sstevel@tonic-gate if (pd->fpclass == fp_zero) {
1930Sstevel@tonic-gate kluge.f.msw.sign = pd->sign? 1 : 0;
1940Sstevel@tonic-gate kluge.f.msw.exponent = 0;
1950Sstevel@tonic-gate kluge.f.significand = 0;
1960Sstevel@tonic-gate kluge.f.significand2 = 0;
1970Sstevel@tonic-gate (*px)[0] = kluge.x[0];
1980Sstevel@tonic-gate (*px)[1] = kluge.x[1];
1990Sstevel@tonic-gate (*px)[2] = kluge.x[2];
2000Sstevel@tonic-gate } else {
2010Sstevel@tonic-gate __hex_to_unpacked(pd, &u);
2020Sstevel@tonic-gate __pack_extended(&u, px, rd, ps);
2030Sstevel@tonic-gate if (*ps != 0)
2040Sstevel@tonic-gate __base_conversion_set_exception(*ps);
2050Sstevel@tonic-gate }
2060Sstevel@tonic-gate }
2070Sstevel@tonic-gate
2080Sstevel@tonic-gate #else
2090Sstevel@tonic-gate #error Unknown architecture
2100Sstevel@tonic-gate #endif
211