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 1988,1995-1996,2003 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 /* Pack procedures for Sparc FPU simulator. */
30
31 #include <sys/fpu/fpu_simulator.h>
32 #include <sys/fpu/globals.h>
33
34 /*
35 * Returns 1 if overflow should go to infinity, 0 if to max finite.
36 */
37 static int
overflow_to_infinity(fp_simd_type * pfpsd,int sign)38 overflow_to_infinity(
39 fp_simd_type *pfpsd, /* Pointer to simulator data */
40 int sign) /* negative or positive */
41 {
42 int inf;
43
44 switch (pfpsd->fp_direction) {
45 case fp_nearest:
46 inf = 1;
47 break;
48 case fp_tozero:
49 inf = 0;
50 break;
51 case fp_positive:
52 inf = !sign;
53 break;
54 case fp_negative:
55 inf = sign;
56 break;
57 }
58 return (inf);
59 }
60
61 /*
62 * Round according to current rounding mode.
63 */
64 static void
round(fp_simd_type * pfpsd,unpacked * pu)65 round(
66 fp_simd_type *pfpsd, /* Pointer to simulator data */
67 unpacked *pu) /* unpacked result */
68 {
69 int increment; /* boolean to indicate round up */
70 int sr;
71
72 sr = pu->sticky|pu->rounded;
73
74 if (sr == 0)
75 return;
76 fpu_set_exception(pfpsd, fp_inexact);
77 switch (pfpsd->fp_direction) {
78 case fp_nearest:
79 increment = pu->rounded;
80 break;
81 case fp_tozero:
82 increment = 0;
83 break;
84 case fp_positive:
85 increment = (pu->sign == 0) & (sr != 0);
86 break;
87 case fp_negative:
88 increment = (pu->sign != 0) & (sr != 0);
89 break;
90 }
91 if (increment) {
92 pu->significand[3]++;
93 if (pu->significand[3] == 0) {
94 pu->significand[2]++;
95 if (pu->significand[2] == 0) {
96 pu->significand[1]++;
97 if (pu->significand[1] == 0) {
98 pu->significand[0]++; /* rounding carried out */
99 if (pu->significand[0] == 0x20000) {
100 pu->exponent++;
101 pu->significand[0] = 0x10000;
102 }
103 }
104 }
105 }
106 }
107 if ((pfpsd->fp_direction == fp_nearest) &&
108 (pu->sticky == 0) && increment != 0) { /* ambiguous case */
109 pu->significand[3] &= 0xfffffffe; /* force round to even */
110 }
111 }
112
113 static void
packint32(fp_simd_type * pfpsd,unpacked * pu,int32_t * px)114 packint32(
115 fp_simd_type *pfpsd, /* Pointer to simulator data */
116 unpacked *pu, /* unpacked result */
117 int32_t *px) /* packed int32_t */
118 {
119 switch (pu->fpclass) {
120 case fp_zero:
121 *px = 0;
122 break;
123 case fp_normal:
124 if (pu->exponent >= 32)
125 goto overflow;
126 fpu_rightshift(pu, 112 - pu->exponent);
127 round(pfpsd, pu);
128 if (pu->significand[3] >= 0x80000000)
129 if ((pu->sign == 0)||(pu->significand[3] > 0x80000000))
130 goto overflow;
131 *px = pu->significand[3];
132 if (pu->sign)
133 *px = -*px;
134 break;
135 case fp_infinity:
136 case fp_quiet:
137 case fp_signaling:
138 overflow:
139 if (pu->sign)
140 *px = 0x80000000;
141 else
142 *px = 0x7fffffff;
143 pfpsd->fp_current_exceptions &= ~(1 << (int)fp_inexact);
144 fpu_set_exception(pfpsd, fp_invalid);
145 break;
146 }
147 }
148
149 static void
packint64(fp_simd_type * pfpsd,unpacked * pu,int64_t * px)150 packint64(
151 fp_simd_type *pfpsd, /* Pointer to simulator data */
152 unpacked *pu, /* unpacked result */
153 int64_t *px) /* packed int64_t */
154 {
155 union {
156 uint64_t ll;
157 uint32_t i[2];
158 } x;
159
160 switch (pu->fpclass) {
161 case fp_zero:
162 *px = 0;
163 break;
164 case fp_normal:
165 if (pu->exponent >= 64)
166 goto overflow;
167 fpu_rightshift(pu, 112 - pu->exponent);
168 round(pfpsd, pu);
169 if (pu->significand[2] >= 0x80000000)
170 if ((pu->sign == 0) ||
171 (pu->significand[2] > 0x80000000) ||
172 (((pu->significand[2] == 0x80000000) &&
173 (pu->significand[3] > 0))))
174 goto overflow;
175 x.i[0] = pu->significand[2];
176 x.i[1] = pu->significand[3];
177 *px = x.ll;
178 if (pu->sign)
179 *px = -*px;
180 break;
181 case fp_infinity:
182 case fp_quiet:
183 case fp_signaling:
184 overflow:
185 if (pu->sign)
186 *px = (int64_t)0x8000000000000000;
187 else
188 *px = (int64_t)0x7fffffffffffffff;
189 pfpsd->fp_current_exceptions &= ~(1 << (int)fp_inexact);
190 fpu_set_exception(pfpsd, fp_invalid);
191 break;
192 }
193 }
194
195 static void
packsingle(fp_simd_type * pfpsd,unpacked * pu,single_type * px)196 packsingle(
197 fp_simd_type *pfpsd, /* Pointer to simulator data */
198 unpacked *pu, /* unpacked result */
199 single_type *px) /* packed single */
200 {
201 px->sign = pu->sign;
202 switch (pu->fpclass) {
203 case fp_zero:
204 px->exponent = 0;
205 px->significand = 0;
206 break;
207 case fp_infinity:
208 infinity:
209 px->exponent = 0xff;
210 px->significand = 0;
211 break;
212 case fp_quiet:
213 case fp_signaling:
214 fpu_rightshift(pu, 113-24);
215 px->exponent = 0xff;
216 px->significand = 0x400000|(0x3fffff&pu->significand[3]);
217 break;
218 case fp_normal:
219 fpu_rightshift(pu, 113-24);
220 pu->exponent += SINGLE_BIAS;
221 if (pu->exponent <= 0) {
222 px->exponent = 0;
223 fpu_rightshift(pu, 1 - pu->exponent);
224 round(pfpsd, pu);
225 if (pu->significand[3] == 0x800000) {
226 /*
227 * rounded
228 * back up to
229 * normal
230 */
231 px->exponent = 1;
232 px->significand = 0;
233 fpu_set_exception(pfpsd, fp_inexact);
234 } else
235 px->significand = 0x7fffff & pu->significand[3];
236
237 if (pfpsd->fp_current_exceptions & (1 << fp_inexact))
238 fpu_set_exception(pfpsd, fp_underflow);
239 if (pfpsd->fp_fsrtem & (1<<fp_underflow)) {
240 fpu_set_exception(pfpsd, fp_underflow);
241 pfpsd->fp_current_exceptions &=
242 ~(1 << (int)fp_inexact);
243 }
244 return;
245 }
246 round(pfpsd, pu);
247 if (pu->significand[3] == 0x1000000) { /* rounding overflow */
248 pu->significand[3] = 0x800000;
249 pu->exponent += 1;
250 }
251 if (pu->exponent >= 0xff) {
252 fpu_set_exception(pfpsd, fp_overflow);
253 fpu_set_exception(pfpsd, fp_inexact);
254 if (pfpsd->fp_fsrtem & (1<<fp_overflow)) {
255 pfpsd->fp_current_exceptions &=
256 ~(1 << (int)fp_inexact);
257 }
258 if (overflow_to_infinity(pfpsd, pu->sign))
259 goto infinity;
260 px->exponent = 0xfe;
261 px->significand = 0x7fffff;
262 return;
263 }
264 px->exponent = pu->exponent;
265 px->significand = 0x7fffff & pu->significand[3];
266 }
267 }
268
269 static void
packdouble(fp_simd_type * pfpsd,unpacked * pu,double_type * px,uint_t * py)270 packdouble(
271 fp_simd_type *pfpsd, /* Pointer to simulator data */
272 unpacked *pu, /* unpacked result */
273 double_type *px, /* packed double, sign/exponent/upper 20 bits */
274 uint_t *py) /* and the lower 32 bits of the significand */
275 {
276 px->sign = pu->sign;
277 switch (pu->fpclass) {
278 case fp_zero:
279 px->exponent = 0;
280 px->significand = 0;
281 *py = 0;
282 break;
283 case fp_infinity:
284 infinity:
285 px->exponent = 0x7ff;
286 px->significand = 0;
287 *py = 0;
288 break;
289 case fp_quiet:
290 case fp_signaling:
291 fpu_rightshift(pu, 113-53);
292 px->exponent = 0x7ff;
293 px->significand = 0x80000 | (0x7ffff & pu->significand[2]);
294 *py = pu->significand[3];
295 break;
296 case fp_normal:
297 fpu_rightshift(pu, 113-53);
298 pu->exponent += DOUBLE_BIAS;
299 if (pu->exponent <= 0) { /* underflow */
300 px->exponent = 0;
301 fpu_rightshift(pu, 1 - pu->exponent);
302 round(pfpsd, pu);
303 if (pu->significand[2] == 0x100000) {
304 /*
305 * rounded
306 * back up to
307 * normal
308 */
309 px->exponent = 1;
310 px->significand = 0;
311 *py = 0;
312 fpu_set_exception(pfpsd, fp_inexact);
313 } else {
314 px->exponent = 0;
315 px->significand = 0xfffff & pu->significand[2];
316 *py = pu->significand[3];
317 }
318 if (pfpsd->fp_current_exceptions & (1 << fp_inexact))
319 fpu_set_exception(pfpsd, fp_underflow);
320 if (pfpsd->fp_fsrtem & (1<<fp_underflow)) {
321 fpu_set_exception(pfpsd, fp_underflow);
322 pfpsd->fp_current_exceptions &=
323 ~(1 << (int)fp_inexact);
324 }
325 return;
326 }
327 round(pfpsd, pu);
328 if (pu->significand[2] == 0x200000) { /* rounding overflow */
329 pu->significand[2] = 0x100000;
330 pu->exponent += 1;
331 }
332 if (pu->exponent >= 0x7ff) { /* overflow */
333 fpu_set_exception(pfpsd, fp_overflow);
334 fpu_set_exception(pfpsd, fp_inexact);
335 if (pfpsd->fp_fsrtem & (1<<fp_overflow)) {
336 pfpsd->fp_current_exceptions &=
337 ~(1 << (int)fp_inexact);
338 }
339 if (overflow_to_infinity(pfpsd, pu->sign))
340 goto infinity;
341 px->exponent = 0x7fe;
342 px->significand = 0xfffff;
343 *py = 0xffffffffU;
344 return;
345 }
346 px->exponent = pu->exponent;
347 px->significand = 0xfffff & pu->significand[2];
348 *py = pu->significand[3];
349 break;
350 }
351 }
352
353 static void
packextended(fp_simd_type * pfpsd,unpacked * pu,extended_type * px,uint_t * py,uint_t * pz,uint_t * pw)354 packextended(
355 fp_simd_type *pfpsd, /* Pointer to simulator data */
356 unpacked *pu, /* unpacked result */
357 extended_type *px, /* packed extended, sign/exponent/16 bits */
358 uint_t *py, /* 2nd word of extended significand */
359 uint_t *pz, /* 3rd word of extended significand */
360 uint_t *pw) /* 4th word of extended significand */
361 {
362 px->sign = pu->sign;
363 switch (pu->fpclass) {
364 case fp_zero:
365 px->exponent = 0;
366 px->significand = 0;
367 *pz = 0;
368 *py = 0;
369 *pw = 0;
370 break;
371 case fp_infinity:
372 infinity:
373 px->exponent = 0x7fff;
374 px->significand = 0;
375 *pz = 0;
376 *py = 0;
377 *pw = 0;
378 break;
379 case fp_quiet:
380 case fp_signaling:
381 px->exponent = 0x7fff;
382 px->significand = 0x8000 | pu->significand[0];
383 /*
384 * Insure quiet
385 * nan.
386 */
387 *py = pu->significand[1];
388 *pz = pu->significand[2];
389 *pw = pu->significand[3];
390 break;
391 case fp_normal:
392 pu->exponent += EXTENDED_BIAS;
393 if (pu->exponent <= 0) { /* underflow */
394 fpu_rightshift(pu, 1-pu->exponent);
395 round(pfpsd, pu);
396 if (pu->significand[0] < 0x00010000) {
397 /*
398 * not rounded
399 * back up
400 * to normal
401 */
402 px->exponent = 0;
403 } else {
404 px->exponent = 1;
405 fpu_set_exception(pfpsd, fp_inexact);
406 }
407 if (pfpsd->fp_current_exceptions & (1 << fp_inexact))
408 fpu_set_exception(pfpsd, fp_underflow);
409 if (pfpsd->fp_fsrtem & (1<<fp_underflow)) {
410 fpu_set_exception(pfpsd, fp_underflow);
411 pfpsd->fp_current_exceptions &=
412 ~(1 << (int)fp_inexact);
413 }
414 px->significand = pu->significand[0];
415 *py = pu->significand[1];
416 *pz = pu->significand[2];
417 *pw = pu->significand[3];
418 return;
419 }
420 round(pfpsd, pu); /* rounding overflow handled in round() */
421 if (pu->exponent >= 0x7fff) { /* overflow */
422 fpu_set_exception(pfpsd, fp_overflow);
423 fpu_set_exception(pfpsd, fp_inexact);
424 if (pfpsd->fp_fsrtem & (1<<fp_overflow)) {
425 pfpsd->fp_current_exceptions &=
426 ~(1 << (int)fp_inexact);
427 }
428 if (overflow_to_infinity(pfpsd, pu->sign))
429 goto infinity;
430 px->exponent = 0x7ffe; /* overflow to max norm */
431 px->significand = 0xffff;
432 *py = 0xffffffffU;
433 *pz = 0xffffffffU;
434 *pw = 0xffffffffU;
435 return;
436 }
437 px->exponent = pu->exponent;
438 px->significand = pu->significand[0];
439 *py = pu->significand[1];
440 *pz = pu->significand[2];
441 *pw = pu->significand[3];
442 break;
443 }
444 }
445
446 void
_fp_pack(fp_simd_type * pfpsd,unpacked * pu,uint_t n,enum fp_op_type type)447 _fp_pack(
448 fp_simd_type *pfpsd, /* Pointer to simulator data */
449 unpacked *pu, /* unpacked operand */
450 uint_t n, /* register where datum starts */
451 enum fp_op_type type) /* type of datum */
452
453 {
454 switch (type) {
455 case fp_op_int32:
456 {
457 int32_t x;
458
459 packint32(pfpsd, pu, &x);
460 if (!(pfpsd->fp_current_exceptions & pfpsd->fp_fsrtem))
461 pfpsd->fp_current_write_freg(&x, n, pfpsd);
462 break;
463 }
464 case fp_op_int64:
465 {
466 int64_t x;
467
468 packint64(pfpsd, pu, &x);
469 if ((n & 0x1) == 1) /* fix register encoding */
470 n = (n & 0x1e) | 0x20;
471 if (!(pfpsd->fp_current_exceptions & pfpsd->fp_fsrtem))
472 pfpsd->fp_current_write_dreg(&x, DOUBLE(n), pfpsd);
473 break;
474 }
475 case fp_op_single:
476 {
477 single_type x;
478
479 packsingle(pfpsd, pu, &x);
480 if (!(pfpsd->fp_current_exceptions & pfpsd->fp_fsrtem))
481 pfpsd->fp_current_write_freg(&x, n, pfpsd);
482 break;
483 }
484 case fp_op_double:
485 {
486 union {
487 double_type x[2];
488 uint32_t y[2];
489 uint64_t ll;
490 } db;
491
492 packdouble(pfpsd, pu, &db.x[0], &db.y[1]);
493 if (!(pfpsd->fp_current_exceptions &
494 pfpsd->fp_fsrtem)) {
495 if ((n & 0x1) == 1) /* fix register encoding */
496 n = (n & 0x1e) | 0x20;
497 pfpsd->fp_current_write_dreg(&db.ll, DOUBLE(n),
498 pfpsd);
499 }
500 break;
501 }
502 case fp_op_extended:
503 {
504 union {
505 extended_type x;
506 uint32_t y[4];
507 uint64_t ll[2];
508 } ex;
509 unpacked U;
510 int k;
511 switch (pfpsd->fp_precision) {
512 /*
513 * Implement extended
514 * rounding precision
515 * mode.
516 */
517 case fp_single:
518 {
519 single_type tx;
520
521 packsingle(pfpsd, pu, &tx);
522 pu = &U;
523 unpacksingle(pfpsd, pu, tx);
524 break;
525 }
526 case fp_double:
527 {
528 double_type tx;
529 uint_t ty;
530
531 packdouble(pfpsd, pu, &tx, &ty);
532 pu = &U;
533 unpackdouble(pfpsd, pu, tx, ty);
534 break;
535 }
536 case fp_precision_3: /* rounded to 64 bits */
537 {
538 k = pu->exponent + EXTENDED_BIAS;
539 if (k >= 0) k = 113-64;
540 else k = 113-64-k;
541 fpu_rightshift(pu, 113-64);
542 round(pfpsd, pu);
543 pu->sticky = pu->rounded = 0;
544 pu->exponent += k;
545 fpu_normalize(pu);
546 break;
547 }
548 }
549 packextended(pfpsd, pu, &ex.x, &ex.y[1],
550 &ex.y[2], &ex.y[3]);
551 if (!(pfpsd->fp_current_exceptions &
552 pfpsd->fp_fsrtem)) {
553 if ((n & 0x1) == 1) /* fix register encoding */
554 n = (n & 0x1e) | 0x20;
555 pfpsd->fp_current_write_dreg(&ex.ll[0],
556 QUAD_E(n), pfpsd);
557 pfpsd->fp_current_write_dreg(&ex.ll[1],
558 QUAD_F(n), pfpsd);
559 }
560
561 break;
562 }
563 }
564 }
565
566 void
_fp_pack_word(fp_simd_type * pfpsd,uint32_t * pu,uint_t n)567 _fp_pack_word(
568 fp_simd_type *pfpsd, /* Pointer to simulator data */
569 uint32_t *pu, /* unpacked operand */
570 uint_t n) /* register where datum starts */
571 {
572 pfpsd->fp_current_write_freg(pu, n, pfpsd);
573 }
574
575 void
_fp_pack_extword(fp_simd_type * pfpsd,uint64_t * pu,uint_t n)576 _fp_pack_extword(
577 fp_simd_type *pfpsd, /* Pointer to simulator data */
578 uint64_t *pu, /* unpacked operand */
579 uint_t n) /* register where datum starts */
580 {
581 if ((n & 1) == 1) /* fix register encoding */
582 n = (n & 0x1e) | 0x20;
583 pfpsd->fp_current_write_dreg(pu, DOUBLE(n), pfpsd);
584 }
585