1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 #include "lint.h"
30 #include "base_conversion.h"
31
32 /* conversion from hex chars to hex values */
33 #define HEXVAL(c) (('0' <= c && c <= '9')? c - '0' : \
34 10 + (('a' <= c && c <= 'f')? c - 'a' : c - 'A'))
35
36 /*
37 * Convert a hexadecimal record in *pd to unpacked form in *pu.
38 *
39 * Up to 30 hexadecimal digits from pd->ds are converted to a binary
40 * value in px->significand, which is then normalized so that the most
41 * significant bit is 1. If there are additional, unused digits in
42 * pd->ds, the least significant bit of px->significand will be set.
43 */
44 static void
__hex_to_unpacked(decimal_record * pd,unpacked * pu)45 __hex_to_unpacked(decimal_record *pd, unpacked *pu)
46 {
47 int i, n;
48
49 pu->sign = pd->sign;
50 pu->fpclass = pd->fpclass;
51
52 /*
53 * Adjust the (base two) exponent to reflect the fact that the
54 * radix point in *pd lies to the right of the last (base sixteen)
55 * digit while the radix point in *pu lies to the right of the
56 * most significant bit.
57 */
58 pu->exponent = pd->exponent + (pd->ndigits << 2) - 1;
59
60 /* fill in the significand */
61 for (i = 0; i < 5; i++)
62 pu->significand[i] = 0;
63
64 n = pd->ndigits;
65 if (n > 30)
66 n = 30;
67 for (i = 0; i < n; i++) {
68 pu->significand[i >> 3] |= HEXVAL(pd->ds[i]) <<
69 ((7 - (i & 7)) << 2);
70 }
71
72 /* sanity check */
73 if (pu->significand[0] == 0) {
74 pu->fpclass = fp_zero;
75 return;
76 }
77
78 /* normalize so the most significant bit is set */
79 while (pu->significand[0] < 0x80000000u) {
80 pu->significand[0] = (pu->significand[0] << 1) |
81 (pu->significand[1] >> 31);
82 pu->significand[1] = (pu->significand[1] << 1) |
83 (pu->significand[2] >> 31);
84 pu->significand[2] = (pu->significand[2] << 1) |
85 (pu->significand[3] >> 31);
86 pu->significand[3] <<= 1;
87 pu->exponent--;
88 }
89
90 /* if there are any unused digits, set a sticky bit */
91 if (pd->ndigits > 30 || pd->more)
92 pu->significand[4] = 1;
93 }
94
95 /*
96 * The following routines convert the hexadecimal value encoded in the
97 * decimal record *pd to a floating point value *px observing the round-
98 * ing mode specified in rd and passing back any exceptions raised via
99 * *ps.
100 *
101 * These routines assume pd->fpclass is either fp_zero or fp_normal.
102 * If pd->fpclass is fp_zero, *px is set to zero with the sign indicated
103 * by pd->sign and no exceptions are raised. Otherwise, pd->ds must
104 * contain a string of hexadecimal digits of length pd->ndigits > 0, and
105 * the first digit must be nonzero. Let m be the integer represented by
106 * this string. Then *px is set to a correctly rounded approximation to
107 *
108 * (-1)^(pd->sign) * m * 2^(pd->exponent)
109 *
110 * with inexact, underflow, and/or overflow raised as appropriate.
111 */
112
113 void
__hex_to_single(decimal_record * pd,enum fp_direction_type rd,single * px,fp_exception_field_type * ps)114 __hex_to_single(decimal_record *pd, enum fp_direction_type rd, single *px,
115 fp_exception_field_type *ps)
116 {
117 single_equivalence kluge;
118 unpacked u;
119
120 *ps = 0;
121 if (pd->fpclass == fp_zero) {
122 kluge.f.msw.sign = pd->sign? 1 : 0;
123 kluge.f.msw.exponent = 0;
124 kluge.f.msw.significand = 0;
125 *px = kluge.x;
126 } else {
127 __hex_to_unpacked(pd, &u);
128 __pack_single(&u, px, rd, ps);
129 if (*ps != 0)
130 __base_conversion_set_exception(*ps);
131 }
132 }
133
134 void
__hex_to_double(decimal_record * pd,enum fp_direction_type rd,double * px,fp_exception_field_type * ps)135 __hex_to_double(decimal_record *pd, enum fp_direction_type rd, double *px,
136 fp_exception_field_type *ps)
137 {
138 double_equivalence kluge;
139 unpacked u;
140
141 *ps = 0;
142 if (pd->fpclass == fp_zero) {
143 kluge.f.msw.sign = pd->sign? 1 : 0;
144 kluge.f.msw.exponent = 0;
145 kluge.f.msw.significand = 0;
146 kluge.f.significand2 = 0;
147 *px = kluge.x;
148 } else {
149 __hex_to_unpacked(pd, &u);
150 __pack_double(&u, px, rd, ps);
151 if (*ps != 0)
152 __base_conversion_set_exception(*ps);
153 }
154 }
155
156 #if defined(__sparc)
157
158 void
__hex_to_quadruple(decimal_record * pd,enum fp_direction_type rd,quadruple * px,fp_exception_field_type * ps)159 __hex_to_quadruple(decimal_record *pd, enum fp_direction_type rd, quadruple *px,
160 fp_exception_field_type *ps)
161 {
162 quadruple_equivalence kluge;
163 unpacked u;
164
165 *ps = 0;
166 if (pd->fpclass == fp_zero) {
167 kluge.f.msw.sign = pd->sign? 1 : 0;
168 kluge.f.msw.exponent = 0;
169 kluge.f.msw.significand = 0;
170 kluge.f.significand2 = 0;
171 kluge.f.significand3 = 0;
172 kluge.f.significand4 = 0;
173 *px = kluge.x;
174 } else {
175 __hex_to_unpacked(pd, &u);
176 __pack_quadruple(&u, px, rd, ps);
177 if (*ps != 0)
178 __base_conversion_set_exception(*ps);
179 }
180 }
181
182 #elif defined(__i386) || defined(__amd64)
183
184 void
__hex_to_extended(decimal_record * pd,enum fp_direction_type rd,extended * px,fp_exception_field_type * ps)185 __hex_to_extended(decimal_record *pd, enum fp_direction_type rd, extended *px,
186 fp_exception_field_type *ps)
187 {
188 extended_equivalence kluge;
189 unpacked u;
190
191 *ps = 0;
192 if (pd->fpclass == fp_zero) {
193 kluge.f.msw.sign = pd->sign? 1 : 0;
194 kluge.f.msw.exponent = 0;
195 kluge.f.significand = 0;
196 kluge.f.significand2 = 0;
197 (*px)[0] = kluge.x[0];
198 (*px)[1] = kluge.x[1];
199 (*px)[2] = kluge.x[2];
200 } else {
201 __hex_to_unpacked(pd, &u);
202 __pack_extended(&u, px, rd, ps);
203 if (*ps != 0)
204 __base_conversion_set_exception(*ps);
205 }
206 }
207
208 #else
209 #error Unknown architecture
210 #endif
211