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.
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.
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]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 #pragma error_messages(off, E_VALUE_TYPE)
36 #include <fps_ereport.h>
38 #define EXPECTED 1.9999999999999998E+00
40 static void fdivd(double *f22
, double *f2
, double *f12
);
41 static void fmuld(double *x
, double *y
, double *z
, double *z1
);
42 static void fmulx(uint64_t *rs1
, uint64_t *rs2
, uint64_t *rd
);
43 int fpu_fdivd(int rloop
, struct fps_test_ereport
*report
);
44 int fpu_fmuld(int rloop
, struct fps_test_ereport
*report
);
45 int fpu_fmulx(int rloop
, struct fps_test_ereport
*report
);
49 /* Lint doesn't recognize .il files where these are defined */
52 unsigned long fcmpgt16(double in1
, double in2
);
53 unsigned long fcmpne16(double in1
, double in2
);
54 unsigned long setgsr(unsigned long);
58 extern float fpackfix(double num
);
59 extern unsigned long fcmpgt16(double in1
, double in2
);
60 extern unsigned long fcmpne16(double in1
, double in2
);
61 extern unsigned long setgsr(unsigned long);
65 int align_data(int loop
,
66 struct fps_test_ereport
*report
);
67 int vis_test(struct fps_test_ereport
*report
);
68 static int align_error_create(char *err
, uint32_t start
, uint32_t offest
,
69 int loop
, uint32_t count
);
70 static int do_aligndata(uchar_t
*from
, uint32_t *offset
, size_t sz
,
71 uchar_t
*f0
, uchar_t
*f2
, uint32_t bmask
);
72 static int visgt16(struct fps_test_ereport
*report
);
73 static int visne16(struct fps_test_ereport
*report
);
74 static int vispackfix(struct fps_test_ereport
*report
);
80 * fpu_fdivd(int rloop, int unit, struct fps_test_ereport *report)
81 * returns whether the correct value is calculated each time
82 * rloop times. If an error is found, the relevant data is stored
83 * in report. The test uses internally generated random double
84 * precision within a certain range to conduct the following test:
86 * (a * 2^1022) / ((a+e) * 2^1021)
88 * which is guaranteed to fill the resulting mantissa with all ones.
92 fpu_fdivd(int rloop
, struct fps_test_ereport
*report
)
95 char err_data
[MAX_INFO_SIZE
];
96 double expect_ans
= EXPECTED
;
106 while (loop
< rloop
) {
109 *(uint32_t *)& f22
= mrand48();
110 *(uint32_t *)& f22
&= 0x80069fff;
111 *(uint32_t *)& f22
|= 0x7fd69f00;
117 *((uint32_t *)& f22
+ 1) = mrand48();
118 *((uint32_t *)& f22
+ 1) |= 0x00000001;
120 *(uint64_t *)& f2
= *(uint64_t *)& f22
+ 1;
121 *(uint32_t *)& f2
&= 0x800FFFFF;
122 *(uint32_t *)& f2
|= 0x7FC00000;
127 fdivd(&f22
, &f2
, &f12
);
129 if (f12
!= expect_ans
) {
130 (void) snprintf(err_data
, sizeof (err_data
),
131 "\nExpected: %.16e,\nObserved: %.16e",
133 expect
= *(uint64_t *)&expect_ans
;
134 observe
= *(uint64_t *)&f12
;
135 setup_fps_test_struct(IS_EREPORT_INFO
, report
,
136 6340, &observe
, &expect
, 1, 1, err_data
);
146 * fdivd(uint64_t *rs1, uint64_t *rs2, uint64_t *rd)
147 * performs the assembly level instructions for
152 fdivd(double *f22
, double *f2
, double *f12
)
154 asm("ldd [%i0], %f22");
155 asm("ldd [%i1], %f2");
156 asm("fdivd %f22, %f2, %f12");
157 asm("std %f12,[%i2]");
162 * fpu_fmuld(int rloop, int unit, struct fps_test_ereport *report)
163 * returns whether the correct value is calculated each time
164 * rloop times. If an error is found, the relevant data is stored
165 * in report. The goal is to check if (x * y) == (y * x). The
166 * data pattern is important, and the back-to-back fmuld's are
170 fpu_fmuld(int rloop
, struct fps_test_ereport
*report
)
172 char err_data
[MAX_INFO_SIZE
];
184 px
= (uint64_t *)& x
;
185 py
= (uint64_t *)& y
;
186 *px
= 0x2FEBD8507111CDE5UL
; /* 4865027 */
187 *py
= 0x2FE284A9A98EAA26UL
;
194 while (loop
< rloop
) {
199 * Data pattern and back-to-back fmuld() are
202 fmuld(&x
, &y
, &z
, &z1
);
204 if (*(uint64_t *)&z
!= *(uint64_t *)&z1
) {
205 (void) snprintf(err_data
, sizeof (err_data
),
206 "\nExpected: %.16e,\nObserved: %.16e",
207 *(uint64_t *)&z
, *(uint64_t *)&z1
);
208 expect
= *(uint64_t *)&z
;
209 observe
= *(uint64_t *)&z1
;
210 setup_fps_test_struct(IS_EREPORT_INFO
, report
,
211 6341, &observe
, &expect
, 1, 1, err_data
);
221 * fmuld(double *x,double *y, double *z, double *z1)
222 * performs the assembly level instructions for
227 fmuld(double *x
, double *y
, double *z
, double *z1
)
229 asm("ldd[%i0], %f0");
230 asm("ldd[%i1], %f4");
231 asm("fmuld%f0, %f4, %f2");
232 asm("fmuld%f4, %f0, %f6");
233 asm("std%f2, [%i2]");
234 asm("std%f6, [%i3]");
240 * fpu_fmulx(int rloop, int unit, struct fps_test_ereport *report)
241 * returns whether the correct value is calculated each time
242 * rloop times. If an error is found, the relevant data is stored
243 * in report. The goal is to check if (x * y) == (y * x) with
247 fpu_fmulx(int rloop
, struct fps_test_ereport
*report
)
249 char err_data
[MAX_INFO_SIZE
];
263 v1
= v2
= vd1
= vd2
= 0;
270 if (loop_lim
> 100000)
273 rs1
= (uint32_t *)& v1
;
274 rs2
= (uint32_t *)& v2
;
284 while (loop
< loop_lim
) {
290 *(rs1
+ 1) = mrand48();
292 *(rs2
+ 1) = mrand48();
296 fmulx((uint64_t *)rs1
, (uint64_t *)rs2
, rd1
);
299 fmulx((uint64_t *)rs2
, (uint64_t *)rs1
, rd2
);
302 expect
= (uint64_t)*rd1
;
303 observe
= (uint64_t)*rd2
;
304 (void) snprintf(err_data
, sizeof (err_data
),
305 "\nExpected: %lld\nObserved: %lld", *rd1
, *rd2
);
306 setup_fps_test_struct(IS_EREPORT_INFO
, report
,
307 6356, &observe
, &expect
, 1, 1, err_data
);
317 * fmulx(uint64_t *rs1, uint64_t *rs2, uint64_t *rd)
318 * performs the assembly level instructions for
323 fmulx(uint64_t *rs1
, uint64_t *rs2
, uint64_t *rd
)
325 asm("ldx [%i0], %l0");
326 asm("ldx [%i1], %l1");
327 asm("mulx %l0, %l1, %l2");
328 asm("stx %l2, [%i2]");
337 #pragma align 64 (f0)
340 #define MEMSIZE 2048*3
342 static uchar_t f0
[64];
343 static uchar_t f2
[8];
345 static uint32_t bmask
[] = {0x01234567, 0x12345678,
346 0x23456789, 0x3456789a,
347 0x456789ab, 0x56789abc,
348 0x6789abcd, 0x789abcde,
349 0x89abcdef, 0x9abcdef0,
350 0xabcdef01, 0xbcdef012,
351 0xcdef0123, 0xdef01234,
352 0xef012345, 0xf0123456,
353 0x55555555, 0xaaaaaaaa,
354 0x00000000, 0xffffffff};
360 setgsr(unsigned long arg1
)
367 fpackfix(double arg1
)
374 fcmpne16(double arg1
, double arg2
)
381 fcmpgt16(double arg1
, double arg2
)
389 * align_data(int loop, struct fps_test_ereport *report)
390 * returns whether a miscompare was found after running alignment tests
391 * loop amount of times. If an error is found, relevant data is stored
392 * in report. This test exercises the alignaddr and aligndata
393 * instructions with different byte alignments to ensure proper
394 * operation. These two instructions are used extensively by the kernel
395 * to move data size greater than 512 bytes. User level memcpy and
396 * memmove library also use these instructions for data size
397 * greater than 256 bytes.
400 align_data(int loop
, struct fps_test_ereport
*report
)
402 char err
[MAX_INFO_SIZE
];
406 struct timeval timeout
;
419 timeout
.tv_usec
= 10000;
423 /* Make sure memsize is 64 bytes aligned with minimum of 64 bytes */
425 memsize
= memsize
/ 64 * 64;
430 src
= (uchar_t
*)memalign(64, memsize
+ 64);
432 while (src
== NULL
&& nr_malloc
< 10) {
433 (void) select(1, NULL
, NULL
, NULL
, &timeout
);
435 src
= (uchar_t
*)memalign(64, memsize
+ 64);
439 _exit(FPU_SYSCALL_FAIL
);
441 /* Initialize source array with sequential data */
444 for (i
= 0; i
< memsize
+ 64; i
++)
447 for (cnt
= 0; cnt
< loop
; cnt
++) {
448 for (start
= 1; start
< 64; start
+= 1) {
451 test_ret
= do_aligndata(src
+ start
, &offset
,
452 memsize
, f0
, f2
, bmask
[cnt
% 20]);
455 * Miscompare on the two aligndata
456 * instructions. Calculate offset to source
457 * array and get miscompare data
461 pf0
= f0
+ offset
% 64;
464 for (i
= 0; i
< 8; i
++) {
465 if (*(pf0
+ i
) != *(pf2
+ i
))
469 (void) align_error_create(err
, start
,
470 offset
+ start
+ i
, loop
, cnt
);
472 (uint64_t)(*(uint8_t *)
473 (src
+ offset
+ start
+ i
));
474 expect
[1] = (uint64_t)0;
475 observe
[0] = (uint64_t)(*(uint8_t *)(pf0
+ i
));
476 observe
[1] = (uint64_t)(*(uint8_t *)(pf2
+ i
));
477 setup_fps_test_struct(
479 report
, 6344, observe
,
488 * No miscompare on the aligndata
489 * instructions. Check to see whether the
490 * last 64 bytes matches the input
493 pf2
= src
+ offset
+ start
;
495 for (i
= 0; i
< 64; i
++) {
496 if (f0
[i
] != *(pf2
+ i
)) {
498 (void) align_error_create(err
,
503 (uint64_t)(*(uint8_t *)
505 expect
[1] = (uint64_t)0;
506 observe
[0] = (uint64_t)f0
[i
];
507 observe
[1] = (uint64_t)0;
508 setup_fps_test_struct(
510 report
, 6343, observe
,
527 * align_error_create(char *err, int start, int offset, int loop, int count)
528 * returns if a successful snprintf was performed when creating an align_data
529 * error message for align_data.
532 align_error_create(char *err
, uint32_t start
,
533 uint32_t offset
, int loop
, uint32_t count
)
538 return snprintf(err
, sizeof (err
),
539 "Start = %2.2d offset = %2.2d loop = %d cnt = %d",
540 start
, offset
, loop
, count
);
544 * do_aligndata(uchar_t *from, uint32_t *offset, size_t sz,
545 * uchar_t *f0, uchar_t *f2, uint32_t bmask) performs
546 * the assembly lvl routines for align_data.
550 do_aligndata(uchar_t
*from
, uint32_t *offset
, size_t sz
,
551 uchar_t
*f0
, uchar_t
*f2
, uint32_t bmask
)
555 asm("bmask %i5,%g0,%g0");
556 /* produce GSR.offset and align %l0 to 8 bytes boundary */
557 asm("alignaddr %i0, %g0, %l0");
558 /* %i0 then used as error register, assume error */
560 /* %l1 used as offset counter */
562 asm("ldd [%l0], %f0");
566 asm("ldd [%l0+8], %f2");
567 asm("ldd [%l0+0x10], %f4");
568 asm("faligndata %f0, %f2, %f32");
569 asm("faligndata %f0, %f2, %f48");
570 asm("fcmpd %fcc0,%f32,%f48");
571 asm("fblg,pn %fcc0,error");
572 /* %l1 contains offset value */
573 asm("add %l1,8,%l1");
576 asm("ldd [%l0+0x18], %f6");
577 asm("faligndata %f2, %f4, %f34");
578 asm("faligndata %f2, %f4, %f48");
579 asm("fcmpd %fcc0,%f34,%f48");
580 asm("fblg,pn %fcc0,error");
581 /* %l1 contains offset value */
582 asm("add %l1,8,%l1");
585 asm("ldd [%l0+0x20], %f8");
586 asm("faligndata %f4, %f6, %f36");
587 asm("faligndata %f4, %f6, %f48");
588 asm("fcmpd %fcc0,%f36,%f48");
589 asm("fblg,pn %fcc0,error");
590 /* %l1 contains offset value */
591 asm("add %l1,8,%l1");
594 asm("ldd [%l0+0x28], %f10");
595 asm("faligndata %f6, %f8, %f38");
596 asm("faligndata %f6, %f8, %f48");
597 asm("fcmpd %fcc0,%f38,%f48");
598 asm("fblg,pn %fcc0,error");
599 /* contains offset value */
600 asm("add %l1,8,%l1");
603 asm("ldd [%l0+0x28], %f10");
604 asm("faligndata %f8, %f10, %f40");
605 asm("faligndata %f8, %f10, %f48");
606 asm("fcmpd %fcc0,%f40,%f48");
607 asm("fblg,pn %fcc0,error");
608 /* %l1 contains offset value */
609 asm("add %l1,8,%l1");
612 asm("ldd [%l0+0x30], %f12");
613 asm("faligndata %f10, %f12, %f42");
614 asm("faligndata %f10, %f12, %f48");
615 asm("fcmpd %fcc0,%f42,%f48");
616 asm("fblg,pn %fcc0,error");
617 /* %l1 contains offset value */
618 asm("add %l1,8,%l1");
621 asm("ldd [%l0+0x38], %f14");
622 asm("faligndata %f12, %f14, %f44");
623 asm("faligndata %f12, %f14, %f48");
624 asm("fcmpd %fcc0,%f44,%f48");
625 asm("fblg,pn %fcc0,error");
626 /* %l1 contains offset value */
627 asm("add %l1,8,%l1");
630 asm("ldd [%l0+0x40], %f0");
631 asm("faligndata %f14, %f0, %f46");
632 asm("faligndata %f14, %f0, %f48");
633 asm("fcmpd %fcc0,%f46,%f48");
634 asm("fblg,pn %fcc0,error");
635 /* %l1 contains offset value */
636 asm("add %l1,8,%l1");
639 asm("subcc %i2,64,%i2");
641 asm("add %l0,64,%l0");
643 /* no miscompare error */
646 /* no error, move back to last 64 bytes boundary */
647 asm("sub %l1,56,%l1");
650 asm("stda %f32,[%i3]0xf0");
651 asm("std %f48,[%i4]");
652 /* store offset value */
660 * vis_test(struct fps_test_ereport *report)
661 * checks if various RISC operations are performed
662 * succesfully. If an error is found, relevant data
663 * is stored in report.
666 vis_test(struct fps_test_ereport
*report
)
672 v1
= visgt16(report
);
673 v2
= visne16(report
);
674 v3
= vispackfix(report
);
676 if ((0 != v1
) || (0 != v2
) || (0 != v3
))
683 * visgt16(struct fps_test_ereport *report)
684 * does a greater-than compare instruction and returns if
685 * successful or not. If an error, relevant data is
689 visgt16(struct fps_test_ereport
*report
)
693 unsigned long a
= 0x0000000000000001;
694 unsigned long b
= 0x8000000008000008;
695 unsigned long c
= fcmpgt16(*((double *)&a
), *((double *)&b
));
700 expected
= (uint64_t)0x8;
701 observed
= (*(uint64_t *)&c
);
702 setup_fps_test_struct(NO_EREPORT_INFO
, report
,
703 6364, &observed
, &expected
, 1, 1);
710 * visne16(struct fps_test_ereport *report)
711 * does a not-equal compare instruction and returns if
712 * successful or not. If an error, relevant data is
716 visne16(struct fps_test_ereport
*report
)
720 unsigned long a
= 0x0000000000000001;
721 unsigned long b
= 0x0001000000001001;
722 unsigned long c
= fcmpne16(*((double *)&a
), *((double *)&b
));
727 expected
= (uint64_t)0x9;
728 observed
= (*(uint64_t *)&c
);
729 setup_fps_test_struct(NO_EREPORT_INFO
, report
,
730 6365, &observed
, &expected
, 1, 1);
737 * vispackfix(struct fps_test_ereport *report)
738 * does four 16-bit pack conversions to a lower precsion
739 * format and returns if successful or not. If an error,
740 * relevant data is stored in report.
743 vispackfix(struct fps_test_ereport
*report
)
749 unsigned long a
= 0x8008000008008008;
750 unsigned long gsr
= 0;
754 b
= fpackfix(*((double *)&a
));
755 c
= *((unsigned int *)&b
);
760 expected
= (uint64_t)0x80080800;
761 observed
= (uint64_t)c
;
762 setup_fps_test_struct(NO_EREPORT_INFO
, report
,
763 6366, &observed
, &expected
, 1, 1);