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, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 1987, 2000, 2003 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI" /* SunOS-4.1 */
28
29 /* Unpack procedures for Sparc FPU simulator. */
30
31 #include <sys/fpu/fpu_simulator.h>
32 #include <sys/fpu/globals.h>
33
34 static void
unpackint32(unpacked * pu,int32_t x)35 unpackint32(
36 unpacked *pu, /* unpacked result */
37 int32_t x) /* packed int32_t */
38 {
39 uint_t ux;
40
41 pu->sticky = pu->rounded = 0;
42 if (x == 0) {
43 pu->sign = 0;
44 pu->fpclass = fp_zero;
45 } else {
46 (*pu).sign = x < 0;
47 (*pu).fpclass = fp_normal;
48 (*pu).exponent = INTEGER_BIAS;
49 if (x < 0) ux = -x; else ux = x;
50 (*pu).significand[0] = ux>>15;
51 (*pu).significand[1] = (ux&0x7fff)<<17;
52 (*pu).significand[2] = 0;
53 (*pu).significand[3] = 0;
54 fpu_normalize(pu);
55 }
56 }
57
58
59 /*
60 * Workaround for bug 4287443--- we have to convince the compiler
61 * that unpackint64 isn't a leaf routine.
62 */
63 static void
subroutine(void)64 subroutine(void)
65 {
66 }
67
68 static void
unpackint64(unpacked * pu,int64_t x)69 unpackint64(
70 unpacked *pu, /* unpacked result */
71 int64_t x) /* packed int64_t */
72 {
73 union {
74 uint64_t ll;
75 uint32_t i[2];
76 } ux;
77
78 subroutine();
79
80 pu->sticky = pu->rounded = 0;
81 if (x == 0) {
82 pu->sign = 0;
83 pu->fpclass = fp_zero;
84 } else {
85 (*pu).sign = x < 0;
86 (*pu).fpclass = fp_normal;
87 (*pu).exponent = LONGLONG_BIAS;
88 if (x < 0) ux.ll = -x; else ux.ll = x;
89 (*pu).significand[0] = ux.i[0]>>15;
90 (*pu).significand[1] = (((ux.i[0]&0x7fff)<<17) | (ux.i[1]>>15));
91 (*pu).significand[2] = (ux.i[1]&0x7fff)<<17;
92 (*pu).significand[3] = 0;
93 fpu_normalize(pu);
94 }
95 }
96
97 void
unpacksingle(fp_simd_type * pfpsd,unpacked * pu,single_type x)98 unpacksingle(
99 fp_simd_type *pfpsd, /* simulator data */
100 unpacked *pu, /* unpacked result */
101 single_type x) /* packed single */
102 {
103 uint_t U;
104
105 pu->sticky = pu->rounded = 0;
106 U = x.significand;
107 (*pu).sign = x.sign;
108 pu->significand[1] = 0;
109 pu->significand[2] = 0;
110 pu->significand[3] = 0;
111 if (x.exponent == 0) { /* zero or sub */
112 if (x.significand == 0) { /* zero */
113 pu->fpclass = fp_zero;
114 return;
115 } else { /* subnormal */
116 pu->fpclass = fp_normal;
117 pu->exponent = -SINGLE_BIAS-6;
118 pu->significand[0] = U;
119 fpu_normalize(pu);
120 return;
121 }
122 } else if (x.exponent == 0xff) { /* inf or nan */
123 if (x.significand == 0) { /* inf */
124 pu->fpclass = fp_infinity;
125 return;
126 } else { /* nan */
127 if ((U & 0x400000) != 0) { /* quiet */
128 pu->fpclass = fp_quiet;
129 } else { /* signaling */
130 pu->fpclass = fp_signaling;
131 fpu_set_exception(pfpsd, fp_invalid);
132 }
133 pu->significand[0] = 0x18000 | (U >> 7);
134 (*pu).significand[1] = ((U&0x7f)<<25);
135 return;
136 }
137 }
138 (*pu).exponent = x.exponent - SINGLE_BIAS;
139 (*pu).fpclass = fp_normal;
140 (*pu).significand[0] = 0x10000|(U>>7);
141 (*pu).significand[1] = ((U&0x7f)<<25);
142 }
143
144 void
unpackdouble(fp_simd_type * pfpsd,unpacked * pu,double_type x,uint_t y)145 unpackdouble(
146 fp_simd_type *pfpsd, /* simulator data */
147 unpacked *pu, /* unpacked result */
148 double_type x, /* packed double, sign/exponent/upper 20 bits */
149 uint_t y) /* and the lower 32 bits of the significand */
150 {
151 uint_t U;
152
153 pu->sticky = pu->rounded = 0;
154 U = x.significand;
155 (*pu).sign = x.sign;
156 pu->significand[1] = y;
157 pu->significand[2] = 0;
158 pu->significand[3] = 0;
159 if (x.exponent == 0) { /* zero or sub */
160 if ((x.significand == 0) && (y == 0)) { /* zero */
161 pu->fpclass = fp_zero;
162 return;
163 } else { /* subnormal */
164 pu->fpclass = fp_normal;
165 pu->exponent = -DOUBLE_BIAS-3;
166 pu->significand[0] = U;
167 fpu_normalize(pu);
168 return;
169 }
170 } else if (x.exponent == 0x7ff) { /* inf or nan */
171 if ((U|y) == 0) { /* inf */
172 pu->fpclass = fp_infinity;
173 return;
174 } else { /* nan */
175 if ((U & 0x80000) != 0) { /* quiet */
176 pu->fpclass = fp_quiet;
177 } else { /* signaling */
178 pu->fpclass = fp_signaling;
179 fpu_set_exception(pfpsd, fp_invalid);
180 }
181 pu->significand[0] = 0x18000 | (U >> 4);
182 (*pu).significand[1] = ((U&0xf)<<28)|(y>>4);
183 (*pu).significand[2] = ((y&0xf)<<28);
184 return;
185 }
186 }
187 (*pu).exponent = x.exponent - DOUBLE_BIAS;
188 (*pu).fpclass = fp_normal;
189 (*pu).significand[0] = 0x10000|(U>>4);
190 (*pu).significand[1] = ((U&0xf)<<28)|(y>>4);
191 (*pu).significand[2] = ((y&0xf)<<28);
192 }
193
194 static void
unpackextended(fp_simd_type * pfpsd,unpacked * pu,extended_type x,uint32_t y,uint32_t z,uint32_t w)195 unpackextended(
196 fp_simd_type *pfpsd, /* simulator data */
197 unpacked *pu, /* unpacked result */
198 extended_type x, /* packed extended, sign/exponent/16 bits */
199 uint32_t y, /* 2nd word of extended significand */
200 uint32_t z, /* 3rd word of extended significand */
201 uint32_t w) /* 4th word of extended significand */
202 {
203 uint_t U;
204
205 pu->sticky = pu->rounded = 0;
206 U = x.significand;
207 (*pu).sign = x.sign;
208 (*pu).fpclass = fp_normal;
209 (*pu).exponent = x.exponent - EXTENDED_BIAS;
210 (*pu).significand[0] = (x.exponent == 0) ? U : 0x10000|U;
211 (*pu).significand[1] = y;
212 (*pu).significand[2] = z;
213 (*pu).significand[3] = w;
214 if (x.exponent < 0x7fff) { /* zero, normal, or subnormal */
215 if ((z|y|w|pu->significand[0]) == 0) { /* zero */
216 pu->fpclass = fp_zero;
217 return;
218 } else { /* normal or subnormal */
219 if (x.exponent == 0) {
220 fpu_normalize(pu);
221 pu->exponent += 1;
222 }
223 return;
224 }
225 } else { /* inf or nan */
226 if ((U|z|y|w) == 0) { /* inf */
227 pu->fpclass = fp_infinity;
228 return;
229 } else { /* nan */
230 if ((U & 0x00008000) != 0) { /* quiet */
231 pu->fpclass = fp_quiet;
232 } else { /* signaling */
233 pu->fpclass = fp_signaling;
234 fpu_set_exception(pfpsd, fp_invalid);
235 }
236 pu->significand[0] |= 0x8000; /* make quiet */
237 return;
238 }
239 }
240 }
241
242 void
_fp_unpack(fp_simd_type * pfpsd,unpacked * pu,uint_t n,enum fp_op_type dtype)243 _fp_unpack(
244 fp_simd_type *pfpsd, /* simulator data */
245 unpacked *pu, /* unpacked result */
246 uint_t n, /* register where data starts */
247 enum fp_op_type dtype) /* type of datum */
248 {
249 freg_type f;
250 union {
251 uint32_t y[4];
252 uint64_t ll[2];
253 freg_type f;
254 } fp;
255
256 switch (dtype) {
257 case fp_op_int32:
258 pfpsd->fp_current_read_freg(&f, n, pfpsd);
259 unpackint32(pu, f.int32_reg);
260 break;
261 case fp_op_int64:
262
263 if ((n & 0x1) == 1) /* fix register encoding */
264 n = (n & 0x1e) | 0x20;
265 pfpsd->fp_current_read_dreg(&fp.ll[0], DOUBLE(n), pfpsd);
266 unpackint64(pu, fp.f.int64_reg);
267 break;
268 case fp_op_single:
269 pfpsd->fp_current_read_freg(&f, n, pfpsd);
270 unpacksingle(pfpsd, pu, f.single_reg);
271 break;
272 case fp_op_double:
273 if ((n & 0x1) == 1) /* fix register encoding */
274 n = (n & 0x1e) | 0x20;
275 pfpsd->fp_current_read_dreg(&fp.ll[0], DOUBLE(n), pfpsd);
276 unpackdouble(pfpsd, pu, fp.f.double_reg, fp.y[1]);
277 break;
278 case fp_op_extended:
279 if ((n & 0x1) == 1) /* fix register encoding */
280 n = (n & 0x1e) | 0x20;
281 pfpsd->fp_current_read_dreg(&fp.ll[0], QUAD_E(n), pfpsd);
282 pfpsd->fp_current_read_dreg(&fp.ll[1], QUAD_F(n), pfpsd);
283 unpackextended(pfpsd, pu, fp.f.extended_reg, fp.y[1],
284 fp.y[2], fp.y[3]);
285 break;
286 }
287 }
288
289 void
_fp_unpack_word(fp_simd_type * pfpsd,uint32_t * pu,uint_t n)290 _fp_unpack_word(
291 fp_simd_type *pfpsd, /* simulator data */
292 uint32_t *pu, /* unpacked result */
293 uint_t n) /* register where data starts */
294 {
295 pfpsd->fp_current_read_freg(pu, n, pfpsd);
296 }
297
298 void
_fp_unpack_extword(fp_simd_type * pfpsd,uint64_t * pu,uint_t n)299 _fp_unpack_extword(
300 fp_simd_type *pfpsd, /* simulator data */
301 uint64_t *pu, /* unpacked result */
302 uint_t n) /* register where data starts */
303 {
304 if ((n & 0x1) == 1) /* fix register encoding */
305 n = (n & 0x1e) | 0x20;
306 pfpsd->fp_current_read_dreg(pu, DOUBLE(n), pfpsd);
307 }
308