16429Svs195195 /*
26429Svs195195 * CDDL HEADER START
36429Svs195195 *
46429Svs195195 * The contents of this file are subject to the terms of the
56429Svs195195 * Common Development and Distribution License (the "License").
66429Svs195195 * You may not use this file except in compliance with the License.
76429Svs195195 *
86429Svs195195 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96429Svs195195 * or http://www.opensolaris.org/os/licensing.
106429Svs195195 * See the License for the specific language governing permissions
116429Svs195195 * and limitations under the License.
126429Svs195195 *
136429Svs195195 * When distributing Covered Code, include this CDDL HEADER in each
146429Svs195195 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156429Svs195195 * If applicable, add the following below this CDDL HEADER, with the
166429Svs195195 * fields enclosed by brackets "[]" replaced with your own identifying
176429Svs195195 * information: Portions Copyright [yyyy] [name of copyright owner]
186429Svs195195 *
196429Svs195195 * CDDL HEADER END
206429Svs195195 */
216429Svs195195
226429Svs195195 /*
236491Sia112686 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
246429Svs195195 * Use is subject to license terms.
256429Svs195195 */
266429Svs195195
276429Svs195195 #pragma ident "%Z%%M% %I% %E% SMI"
286429Svs195195
296429Svs195195 #ifdef __lint
306429Svs195195 #pragma error_messages(off, E_VALUE_TYPE)
316429Svs195195 #endif
326429Svs195195
336429Svs195195 #include <stdlib.h>
346429Svs195195 #include <unistd.h>
356429Svs195195 #include <fp.h>
366429Svs195195 #include <fps_ereport.h>
376429Svs195195
386429Svs195195 #define EXPECTED 1.9999999999999998E+00
396429Svs195195
406429Svs195195 static void fdivd(double *f22, double *f2, double *f12);
416429Svs195195 static void fmuld(double *x, double *y, double *z, double *z1);
426429Svs195195 static void fmulx(uint64_t *rs1, uint64_t *rs2, uint64_t *rd);
436429Svs195195 int fpu_fdivd(int rloop, struct fps_test_ereport *report);
446429Svs195195 int fpu_fmuld(int rloop, struct fps_test_ereport *report);
456429Svs195195 int fpu_fmulx(int rloop, struct fps_test_ereport *report);
466429Svs195195
476429Svs195195 #ifdef V9B
486429Svs195195
49*7186Skk158166 /* Lint doesn't recognize .il files where these are defined */
50*7186Skk158166 #ifdef __lint
51*7186Skk158166
52*7186Skk158166 unsigned long fcmpgt16(double in1, double in2);
53*7186Skk158166 unsigned long fcmpne16(double in1, double in2);
54*7186Skk158166 unsigned long setgsr(unsigned long);
55*7186Skk158166
56*7186Skk158166 #else
57*7186Skk158166
586429Svs195195 extern float fpackfix(double num);
596429Svs195195 extern unsigned long fcmpgt16(double in1, double in2);
606429Svs195195 extern unsigned long fcmpne16(double in1, double in2);
61*7186Skk158166 extern unsigned long setgsr(unsigned long);
626429Svs195195
63*7186Skk158166 #endif
64*7186Skk158166
65*7186Skk158166 int align_data(int loop,
666429Svs195195 struct fps_test_ereport *report);
67*7186Skk158166 int vis_test(struct fps_test_ereport *report);
68*7186Skk158166 static int align_error_create(char *err, uint32_t start, uint32_t offest,
69*7186Skk158166 int loop, uint32_t count);
706429Svs195195 static int do_aligndata(uchar_t *from, uint32_t *offset, size_t sz,
716429Svs195195 uchar_t *f0, uchar_t *f2, uint32_t bmask);
72*7186Skk158166 static int visgt16(struct fps_test_ereport *report);
73*7186Skk158166 static int visne16(struct fps_test_ereport *report);
74*7186Skk158166 static int vispackfix(struct fps_test_ereport *report);
756429Svs195195
766429Svs195195 #endif
776429Svs195195
786429Svs195195
796429Svs195195 /*
806429Svs195195 * fpu_fdivd(int rloop, int unit, struct fps_test_ereport *report)
816429Svs195195 * returns whether the correct value is calculated each time
826429Svs195195 * rloop times. If an error is found, the relevant data is stored
836429Svs195195 * in report. The test uses internally generated random double
846429Svs195195 * precision within a certain range to conduct the following test:
856429Svs195195 *
866429Svs195195 * (a * 2^1022) / ((a+e) * 2^1021)
876429Svs195195 *
886429Svs195195 * which is guaranteed to fill the resulting mantissa with all ones.
896429Svs195195 *
906429Svs195195 */
916429Svs195195 int
fpu_fdivd(int rloop,struct fps_test_ereport * report)926429Svs195195 fpu_fdivd(int rloop, struct fps_test_ereport *report)
936429Svs195195 {
946429Svs195195
956429Svs195195 char err_data[MAX_INFO_SIZE];
966429Svs195195 double expect_ans = EXPECTED;
976429Svs195195 double f12 = 0;
986429Svs195195 double f2;
996429Svs195195 double f22;
1006429Svs195195 int loop = 0;
1016429Svs195195 uint64_t expect;
1026429Svs195195 uint64_t observe;
1036429Svs195195
1046429Svs195195 srand48(1L);
1056429Svs195195
1066429Svs195195 while (loop < rloop) {
1076429Svs195195 loop++;
1086429Svs195195
1096429Svs195195 *(uint32_t *)& f22 = mrand48();
1106429Svs195195 *(uint32_t *)& f22 &= 0x80069fff;
1116429Svs195195 *(uint32_t *)& f22 |= 0x7fd69f00;
1126429Svs195195
1136429Svs195195 #ifdef __lint
1146429Svs195195 (void) f22;
1156429Svs195195 #endif
1166429Svs195195
1176429Svs195195 *((uint32_t *)& f22 + 1) = mrand48();
1186429Svs195195 *((uint32_t *)& f22 + 1) |= 0x00000001;
1196429Svs195195
1206429Svs195195 *(uint64_t *)& f2 = *(uint64_t *)& f22 + 1;
1216429Svs195195 *(uint32_t *)& f2 &= 0x800FFFFF;
1226429Svs195195 *(uint32_t *)& f2 |= 0x7FC00000;
1236429Svs195195 #ifdef __lint
1246429Svs195195 (void) f2;
1256429Svs195195 #endif
1266429Svs195195
1276429Svs195195 fdivd(&f22, &f2, &f12);
1286429Svs195195
1296429Svs195195 if (f12 != expect_ans) {
130*7186Skk158166 (void) snprintf(err_data, sizeof (err_data),
1316429Svs195195 "\nExpected: %.16e,\nObserved: %.16e",
1326429Svs195195 expect_ans, f12);
1336429Svs195195 expect = *(uint64_t *)&expect_ans;
1346429Svs195195 observe = *(uint64_t *)&f12;
1356429Svs195195 setup_fps_test_struct(IS_EREPORT_INFO, report,
1366429Svs195195 6340, &observe, &expect, 1, 1, err_data);
1376429Svs195195
1386429Svs195195 return (-1);
1396429Svs195195 }
1406429Svs195195 }
1416429Svs195195
1426429Svs195195 return (0);
1436429Svs195195 }
1446429Svs195195
1456429Svs195195 /*
1466429Svs195195 * fdivd(uint64_t *rs1, uint64_t *rs2, uint64_t *rd)
1476429Svs195195 * performs the assembly level instructions for
1486429Svs195195 * fpu_fdivd.
1496429Svs195195 */
1506429Svs195195 /* ARGSUSED */
1516429Svs195195 static void
fdivd(double * f22,double * f2,double * f12)1526429Svs195195 fdivd(double *f22, double *f2, double *f12)
1536429Svs195195 {
1546429Svs195195 asm("ldd [%i0], %f22");
1556429Svs195195 asm("ldd [%i1], %f2");
1566429Svs195195 asm("fdivd %f22, %f2, %f12");
1576429Svs195195 asm("std %f12,[%i2]");
1586429Svs195195 asm("membar #Sync");
1596429Svs195195 }
1606429Svs195195
1616429Svs195195 /*
1626429Svs195195 * fpu_fmuld(int rloop, int unit, struct fps_test_ereport *report)
1636429Svs195195 * returns whether the correct value is calculated each time
1646429Svs195195 * rloop times. If an error is found, the relevant data is stored
1656429Svs195195 * in report. The goal is to check if (x * y) == (y * x). The
1666429Svs195195 * data pattern is important, and the back-to-back fmuld's are
1676429Svs195195 * important.
1686429Svs195195 */
1696429Svs195195 int
fpu_fmuld(int rloop,struct fps_test_ereport * report)1706429Svs195195 fpu_fmuld(int rloop, struct fps_test_ereport *report)
1716429Svs195195 {
1726429Svs195195 char err_data[MAX_INFO_SIZE];
1736429Svs195195 double x;
1746429Svs195195 double y;
1756429Svs195195 double z;
1766429Svs195195 double z1;
1776429Svs195195 int loop;
1786429Svs195195 uint64_t expect;
1796429Svs195195 uint64_t observe;
1806429Svs195195 uint64_t *px;
1816429Svs195195 uint64_t *py;
1826429Svs195195
1836429Svs195195 loop = 0;
1846429Svs195195 px = (uint64_t *)& x;
1856429Svs195195 py = (uint64_t *)& y;
1866429Svs195195 *px = 0x2FEBD8507111CDE5UL; /* 4865027 */
1876429Svs195195 *py = 0x2FE284A9A98EAA26UL;
1886429Svs195195
1896429Svs195195 #ifdef __lint
1906429Svs195195 (void) x;
1916429Svs195195 (void) y;
1926429Svs195195 #endif
1936429Svs195195
1946429Svs195195 while (loop < rloop) {
1956429Svs195195 loop++;
1966429Svs195195 z = z1 = 0.0;
1976429Svs195195
1986429Svs195195 /*
1996429Svs195195 * Data pattern and back-to-back fmuld() are
2006429Svs195195 * important
2016429Svs195195 */
2026429Svs195195 fmuld(&x, &y, &z, &z1);
2036429Svs195195
2046429Svs195195 if (*(uint64_t *)&z != *(uint64_t *)&z1) {
205*7186Skk158166 (void) snprintf(err_data, sizeof (err_data),
2066429Svs195195 "\nExpected: %.16e,\nObserved: %.16e",
2076429Svs195195 *(uint64_t *)&z, *(uint64_t *)&z1);
2086429Svs195195 expect = *(uint64_t *)&z;
2096429Svs195195 observe = *(uint64_t *)&z1;
2106429Svs195195 setup_fps_test_struct(IS_EREPORT_INFO, report,
2116429Svs195195 6341, &observe, &expect, 1, 1, err_data);
2126429Svs195195
2136429Svs195195 return (-1);
2146429Svs195195 }
2156429Svs195195 }
2166429Svs195195
2176429Svs195195 return (0);
2186429Svs195195 }
2196429Svs195195
2206429Svs195195 /*
2216429Svs195195 * fmuld(double *x,double *y, double *z, double *z1)
2226429Svs195195 * performs the assembly level instructions for
2236429Svs195195 * fpu_fmuld.
2246429Svs195195 */
2256429Svs195195 /* ARGSUSED */
2266429Svs195195 static void
fmuld(double * x,double * y,double * z,double * z1)2276429Svs195195 fmuld(double *x, double *y, double *z, double *z1)
2286429Svs195195 {
2296429Svs195195 asm("ldd[%i0], %f0");
2306429Svs195195 asm("ldd[%i1], %f4");
2316429Svs195195 asm("fmuld%f0, %f4, %f2");
2326429Svs195195 asm("fmuld%f4, %f0, %f6");
2336429Svs195195 asm("std%f2, [%i2]");
2346429Svs195195 asm("std%f6, [%i3]");
2356429Svs195195 asm("membar #Sync");
2366429Svs195195 }
2376429Svs195195
2386429Svs195195
2396429Svs195195 /*
2406429Svs195195 * fpu_fmulx(int rloop, int unit, struct fps_test_ereport *report)
2416429Svs195195 * returns whether the correct value is calculated each time
2426429Svs195195 * rloop times. If an error is found, the relevant data is stored
2436429Svs195195 * in report. The goal is to check if (x * y) == (y * x) with
2446429Svs195195 * 64-bit intgers.
2456429Svs195195 */
2466429Svs195195 int
fpu_fmulx(int rloop,struct fps_test_ereport * report)2476429Svs195195 fpu_fmulx(int rloop, struct fps_test_ereport *report)
2486429Svs195195 {
2496429Svs195195 char err_data[MAX_INFO_SIZE];
2506429Svs195195 int loop;
2516429Svs195195 int loop_lim;
2526429Svs195195 uint32_t *rs1;
2536429Svs195195 uint32_t *rs2;
2546429Svs195195 uint64_t expect;
2556429Svs195195 uint64_t observe;
2566429Svs195195 uint64_t v1;
2576429Svs195195 uint64_t v2;
2586429Svs195195 uint64_t vd1;
2596429Svs195195 uint64_t vd2;
2606429Svs195195 uint64_t *rd1;
2616429Svs195195 uint64_t *rd2;
2626429Svs195195
2636429Svs195195 v1 = v2 = vd1 = vd2 = 0;
2646429Svs195195 loop = 0;
2656429Svs195195 loop_lim = rloop;
2666429Svs195195
2676429Svs195195 if (loop_lim < 10)
2686429Svs195195 loop_lim = 10;
2696429Svs195195
2706429Svs195195 if (loop_lim > 100000)
2716429Svs195195 loop_lim = 100000;
2726429Svs195195
2736429Svs195195 rs1 = (uint32_t *)& v1;
2746429Svs195195 rs2 = (uint32_t *)& v2;
2756429Svs195195 rd1 = &vd1;
2766429Svs195195 rd2 = &vd2;
2776429Svs195195
2786429Svs195195 #ifdef __lint
2796429Svs195195 (void) v1;
2806429Svs195195 (void) v2;
2816429Svs195195 #endif
2826429Svs195195
2836429Svs195195 srand(0l);
2846429Svs195195 while (loop < loop_lim) {
2856429Svs195195 loop++;
2866429Svs195195
2876429Svs195195 #ifndef __lint
2886429Svs195195
2896429Svs195195 *rs1 = mrand48();
2906429Svs195195 *(rs1 + 1) = mrand48();
2916429Svs195195 *rs2 = mrand48();
2926429Svs195195 *(rs2 + 1) = mrand48();
2936429Svs195195 #endif
2946429Svs195195
2956429Svs195195 /* LINTED */
2966429Svs195195 fmulx((uint64_t *)rs1, (uint64_t *)rs2, rd1);
2976429Svs195195
2986429Svs195195 /* LINTED */
2996429Svs195195 fmulx((uint64_t *)rs2, (uint64_t *)rs1, rd2);
3006429Svs195195
3016429Svs195195 if (*rd1 != *rd2) {
3026429Svs195195 expect = (uint64_t)*rd1;
3036429Svs195195 observe = (uint64_t)*rd2;
304*7186Skk158166 (void) snprintf(err_data, sizeof (err_data),
3056429Svs195195 "\nExpected: %lld\nObserved: %lld", *rd1, *rd2);
3066429Svs195195 setup_fps_test_struct(IS_EREPORT_INFO, report,
3076429Svs195195 6356, &observe, &expect, 1, 1, err_data);
3086429Svs195195
3096429Svs195195 return (-1);
3106429Svs195195 }
3116429Svs195195 }
3126429Svs195195
3136429Svs195195 return (0);
3146429Svs195195 }
3156429Svs195195
3166429Svs195195 /*
3176429Svs195195 * fmulx(uint64_t *rs1, uint64_t *rs2, uint64_t *rd)
3186429Svs195195 * performs the assembly level instructions for
3196429Svs195195 * fpu_fmulx.
3206429Svs195195 */
3216429Svs195195 /* ARGSUSED */
3226429Svs195195 static void
fmulx(uint64_t * rs1,uint64_t * rs2,uint64_t * rd)3236429Svs195195 fmulx(uint64_t *rs1, uint64_t *rs2, uint64_t *rd)
3246429Svs195195 {
3256429Svs195195 asm("ldx [%i0], %l0");
3266429Svs195195 asm("ldx [%i1], %l1");
3276429Svs195195 asm("mulx %l0, %l1, %l2");
3286429Svs195195 asm("stx %l2, [%i2]");
3296429Svs195195 asm("membar #Sync");
3306429Svs195195
3316429Svs195195 }
3326429Svs195195
3336429Svs195195
3346429Svs195195
3356429Svs195195 #ifdef V9B
3366429Svs195195
3376429Svs195195 #pragma align 64 (f0)
3386429Svs195195 #pragma align 8 (f2)
3396429Svs195195
3406429Svs195195 #define MEMSIZE 2048*3
3416429Svs195195
3426429Svs195195 static uchar_t f0[64];
3436429Svs195195 static uchar_t f2[8];
3446429Svs195195
3456429Svs195195 static uint32_t bmask[] = {0x01234567, 0x12345678,
3466429Svs195195 0x23456789, 0x3456789a,
3476429Svs195195 0x456789ab, 0x56789abc,
3486429Svs195195 0x6789abcd, 0x789abcde,
3496429Svs195195 0x89abcdef, 0x9abcdef0,
3506429Svs195195 0xabcdef01, 0xbcdef012,
3516429Svs195195 0xcdef0123, 0xdef01234,
3526429Svs195195 0xef012345, 0xf0123456,
3536429Svs195195 0x55555555, 0xaaaaaaaa,
3546429Svs195195 0x00000000, 0xffffffff};
3556429Svs195195
356*7186Skk158166 #ifdef __lint
357*7186Skk158166
358*7186Skk158166 /*ARGSUSED*/
359*7186Skk158166 unsigned long
setgsr(unsigned long arg1)360*7186Skk158166 setgsr(unsigned long arg1)
361*7186Skk158166 {
362*7186Skk158166 return (0);
363*7186Skk158166 }
364*7186Skk158166
365*7186Skk158166 /*ARGSUSED*/
366*7186Skk158166 float
fpackfix(double arg1)367*7186Skk158166 fpackfix(double arg1)
368*7186Skk158166 {
369*7186Skk158166 return (0.0);
370*7186Skk158166 }
371*7186Skk158166
372*7186Skk158166 /*ARGSUSED*/
373*7186Skk158166 unsigned long
fcmpne16(double arg1,double arg2)374*7186Skk158166 fcmpne16(double arg1, double arg2)
375*7186Skk158166 {
376*7186Skk158166 return (0);
377*7186Skk158166 }
378*7186Skk158166
379*7186Skk158166 /*ARGSUSED*/
380*7186Skk158166 unsigned long
fcmpgt16(double arg1,double arg2)381*7186Skk158166 fcmpgt16(double arg1, double arg2)
382*7186Skk158166 {
383*7186Skk158166 return (0);
384*7186Skk158166 }
385*7186Skk158166
386*7186Skk158166 #endif /* LINT */
387*7186Skk158166
3886429Svs195195 /*
389*7186Skk158166 * align_data(int loop, struct fps_test_ereport *report)
3906429Svs195195 * returns whether a miscompare was found after running alignment tests
3916429Svs195195 * loop amount of times. If an error is found, relevant data is stored
3926429Svs195195 * in report. This test exercises the alignaddr and aligndata
3936429Svs195195 * instructions with different byte alignments to ensure proper
3946429Svs195195 * operation. These two instructions are used extensively by the kernel
3956429Svs195195 * to move data size greater than 512 bytes. User level memcpy and
3966429Svs195195 * memmove library also use these instructions for data size
3976429Svs195195 * greater than 256 bytes.
3986429Svs195195 */
3996429Svs195195 int
align_data(int loop,struct fps_test_ereport * report)400*7186Skk158166 align_data(int loop, struct fps_test_ereport *report)
4016429Svs195195 {
4026429Svs195195 char err[MAX_INFO_SIZE];
4036429Svs195195 int test_ret;
4046429Svs195195 int nr_malloc;
4056429Svs195195 size_t memsize;
4066429Svs195195 struct timeval timeout;
4076429Svs195195 uchar_t c;
4086429Svs195195 uchar_t *pf0;
4096429Svs195195 uchar_t *pf2;
4106429Svs195195 uchar_t *src;
4116429Svs195195 uint32_t cnt;
4126429Svs195195 uint32_t i;
4136429Svs195195 uint32_t offset;
4146429Svs195195 uint32_t start;
4156429Svs195195 uint64_t expect[2];
4166429Svs195195 uint64_t observe[2];
4176429Svs195195
4186429Svs195195 timeout.tv_sec = 0;
4196429Svs195195 timeout.tv_usec = 10000;
4206429Svs195195 nr_malloc = 0;
4216429Svs195195 err[0] = '\0';
4226429Svs195195
4236429Svs195195 /* Make sure memsize is 64 bytes aligned with minimum of 64 bytes */
4246429Svs195195 memsize = MEMSIZE;
4256429Svs195195 memsize = memsize / 64 * 64;
4266429Svs195195
4276429Svs195195 if (memsize < 64)
4286429Svs195195 memsize = 64;
4296429Svs195195
4306429Svs195195 src = (uchar_t *)memalign(64, memsize + 64);
4316429Svs195195
4326429Svs195195 while (src == NULL && nr_malloc < 10) {
433*7186Skk158166 (void) select(1, NULL, NULL, NULL, &timeout);
4346429Svs195195 nr_malloc++;
4356429Svs195195 src = (uchar_t *)memalign(64, memsize + 64);
4366429Svs195195 }
4376429Svs195195
4386429Svs195195 if (src == NULL)
4396429Svs195195 _exit(FPU_SYSCALL_FAIL);
4406429Svs195195
4416429Svs195195 /* Initialize source array with sequential data */
4426429Svs195195 c = 0;
4436429Svs195195
4446429Svs195195 for (i = 0; i < memsize + 64; i++)
4456429Svs195195 *(src + i) = c++;
4466429Svs195195
4476429Svs195195 for (cnt = 0; cnt < loop; cnt++) {
4486429Svs195195 for (start = 1; start < 64; start += 1) {
4496429Svs195195 offset = 0;
4506429Svs195195
4516429Svs195195 test_ret = do_aligndata(src + start, &offset,
4526429Svs195195 memsize, f0, f2, bmask[cnt % 20]);
4536429Svs195195
4546429Svs195195 /*
4556429Svs195195 * Miscompare on the two aligndata
4566429Svs195195 * instructions. Calculate offset to source
4576429Svs195195 * array and get miscompare data
4586429Svs195195 */
4596429Svs195195
4606429Svs195195 if (test_ret != 0) {
4616429Svs195195 pf0 = f0 + offset % 64;
4626429Svs195195 pf2 = f2;
4636429Svs195195
4646429Svs195195 for (i = 0; i < 8; i++) {
4656429Svs195195 if (*(pf0 + i) != *(pf2 + i))
4666429Svs195195 break;
4676429Svs195195 }
4686429Svs195195
469*7186Skk158166 (void) align_error_create(err, start,
4706429Svs195195 offset + start + i, loop, cnt);
4716429Svs195195 expect[0] =
4726429Svs195195 (uint64_t)(*(uint8_t *)
4736429Svs195195 (src + offset + start + i));
4746429Svs195195 expect[1] = (uint64_t)0;
4756429Svs195195 observe[0] = (uint64_t)(*(uint8_t *)(pf0 + i));
4766429Svs195195 observe[1] = (uint64_t)(*(uint8_t *)(pf2 + i));
4776429Svs195195 setup_fps_test_struct(
4786429Svs195195 IS_EREPORT_INFO,
4796429Svs195195 report, 6344, observe,
4806429Svs195195 expect, 1, 2, err);
4816429Svs195195
4826429Svs195195 free(src);
4836429Svs195195
4846429Svs195195 return (-1);
4856429Svs195195 }
4866429Svs195195
4876429Svs195195 /*
4886429Svs195195 * No miscompare on the aligndata
4896429Svs195195 * instructions. Check to see whether the
4906429Svs195195 * last 64 bytes matches the input
4916429Svs195195 */
4926429Svs195195 if (test_ret == 0) {
4936429Svs195195 pf2 = src + offset + start;
4946429Svs195195
4956429Svs195195 for (i = 0; i < 64; i++) {
4966429Svs195195 if (f0[i] != *(pf2 + i)) {
4976429Svs195195
498*7186Skk158166 (void) align_error_create(err,
4996429Svs195195 start,
5006429Svs195195 offset + start + i,
5016429Svs195195 loop, cnt);
5026429Svs195195 expect[0] =
5036429Svs195195 (uint64_t)(*(uint8_t *)
5046429Svs195195 (pf2 + i));
5056429Svs195195 expect[1] = (uint64_t)0;
5066429Svs195195 observe[0] = (uint64_t)f0[i];
5076429Svs195195 observe[1] = (uint64_t)0;
5086429Svs195195 setup_fps_test_struct(
5096429Svs195195 IS_EREPORT_INFO,
5106429Svs195195 report, 6343, observe,
5116429Svs195195 expect, 1, 1, err);
5126429Svs195195
5136429Svs195195 free(src);
5146429Svs195195 return (-1);
5156429Svs195195 }
5166429Svs195195 }
5176429Svs195195 }
5186429Svs195195 }
5196429Svs195195 }
5206429Svs195195
5216429Svs195195 free(src);
5226429Svs195195
5236429Svs195195 return (0);
5246429Svs195195 }
5256429Svs195195
5266429Svs195195 /*
5276429Svs195195 * align_error_create(char *err, int start, int offset, int loop, int count)
5286429Svs195195 * returns if a successful snprintf was performed when creating an align_data
5296429Svs195195 * error message for align_data.
5306429Svs195195 */
5316429Svs195195 static int
align_error_create(char * err,uint32_t start,uint32_t offset,int loop,uint32_t count)532*7186Skk158166 align_error_create(char *err, uint32_t start,
533*7186Skk158166 uint32_t offset, int loop, uint32_t count)
5346429Svs195195 {
5356429Svs195195 if (err == NULL)
5366429Svs195195 return (-1);
5376429Svs195195
5386429Svs195195 return snprintf(err, sizeof (err),
5396429Svs195195 "Start = %2.2d offset = %2.2d loop = %d cnt = %d",
5406429Svs195195 start, offset, loop, count);
5416429Svs195195 }
5426429Svs195195
5436429Svs195195 /*
5446429Svs195195 * do_aligndata(uchar_t *from, uint32_t *offset, size_t sz,
5456429Svs195195 * uchar_t *f0, uchar_t *f2, uint32_t bmask) performs
5466429Svs195195 * the assembly lvl routines for align_data.
5476429Svs195195 */
548*7186Skk158166 /*ARGSUSED*/
5496429Svs195195 static int
do_aligndata(uchar_t * from,uint32_t * offset,size_t sz,uchar_t * f0,uchar_t * f2,uint32_t bmask)5506429Svs195195 do_aligndata(uchar_t *from, uint32_t *offset, size_t sz,
5516429Svs195195 uchar_t *f0, uchar_t *f2, uint32_t bmask)
5526429Svs195195 {
553*7186Skk158166 int ret = 1;
554*7186Skk158166
5556429Svs195195 asm("bmask %i5,%g0,%g0");
5566429Svs195195 /* produce GSR.offset and align %l0 to 8 bytes boundary */
5576429Svs195195 asm("alignaddr %i0, %g0, %l0");
5586429Svs195195 /* %i0 then used as error register, assume error */
5596429Svs195195 asm("mov 1,%i0");
5606429Svs195195 /* %l1 used as offset counter */
5616429Svs195195 asm("mov -8,%l1");
5626429Svs195195 asm("ldd [%l0], %f0");
5636429Svs195195
5646429Svs195195 asm("next_read:");
5656429Svs195195
5666429Svs195195 asm("ldd [%l0+8], %f2");
5676429Svs195195 asm("ldd [%l0+0x10], %f4");
5686429Svs195195 asm("faligndata %f0, %f2, %f32");
5696429Svs195195 asm("faligndata %f0, %f2, %f48");
5706429Svs195195 asm("fcmpd %fcc0,%f32,%f48");
5716429Svs195195 asm("fblg,pn %fcc0,error");
5726429Svs195195 /* %l1 contains offset value */
5736429Svs195195 asm("add %l1,8,%l1");
5746429Svs195195 /* 0 - 7 */
5756429Svs195195
5766429Svs195195 asm("ldd [%l0+0x18], %f6");
5776429Svs195195 asm("faligndata %f2, %f4, %f34");
5786429Svs195195 asm("faligndata %f2, %f4, %f48");
5796429Svs195195 asm("fcmpd %fcc0,%f34,%f48");
5806429Svs195195 asm("fblg,pn %fcc0,error");
5816429Svs195195 /* %l1 contains offset value */
5826429Svs195195 asm("add %l1,8,%l1");
5836429Svs195195 /* 9 - 15 */
5846429Svs195195
5856429Svs195195 asm("ldd [%l0+0x20], %f8");
5866429Svs195195 asm("faligndata %f4, %f6, %f36");
5876429Svs195195 asm("faligndata %f4, %f6, %f48");
5886429Svs195195 asm("fcmpd %fcc0,%f36,%f48");
5896429Svs195195 asm("fblg,pn %fcc0,error");
5906429Svs195195 /* %l1 contains offset value */
5916429Svs195195 asm("add %l1,8,%l1");
5926429Svs195195 /* 16 - 23 */
5936429Svs195195
5946429Svs195195 asm("ldd [%l0+0x28], %f10");
5956429Svs195195 asm("faligndata %f6, %f8, %f38");
5966429Svs195195 asm("faligndata %f6, %f8, %f48");
5976429Svs195195 asm("fcmpd %fcc0,%f38,%f48");
5986429Svs195195 asm("fblg,pn %fcc0,error");
5996429Svs195195 /* contains offset value */
6006429Svs195195 asm("add %l1,8,%l1");
6016429Svs195195 /* 24 - 31 */
6026429Svs195195
6036429Svs195195 asm("ldd [%l0+0x28], %f10");
6046429Svs195195 asm("faligndata %f8, %f10, %f40");
6056429Svs195195 asm("faligndata %f8, %f10, %f48");
6066429Svs195195 asm("fcmpd %fcc0,%f40,%f48");
6076429Svs195195 asm("fblg,pn %fcc0,error");
6086429Svs195195 /* %l1 contains offset value */
6096429Svs195195 asm("add %l1,8,%l1");
6106429Svs195195 /* 32 - 39 */
6116429Svs195195
6126429Svs195195 asm("ldd [%l0+0x30], %f12");
6136429Svs195195 asm("faligndata %f10, %f12, %f42");
6146429Svs195195 asm("faligndata %f10, %f12, %f48");
6156429Svs195195 asm("fcmpd %fcc0,%f42,%f48");
6166429Svs195195 asm("fblg,pn %fcc0,error");
6176429Svs195195 /* %l1 contains offset value */
6186429Svs195195 asm("add %l1,8,%l1");
6196429Svs195195 /* 40 - 47 */
6206429Svs195195
6216429Svs195195 asm("ldd [%l0+0x38], %f14");
6226429Svs195195 asm("faligndata %f12, %f14, %f44");
6236429Svs195195 asm("faligndata %f12, %f14, %f48");
6246429Svs195195 asm("fcmpd %fcc0,%f44,%f48");
6256429Svs195195 asm("fblg,pn %fcc0,error");
6266429Svs195195 /* %l1 contains offset value */
6276429Svs195195 asm("add %l1,8,%l1");
6286429Svs195195 /* 48 - 55 */
6296429Svs195195
6306429Svs195195 asm("ldd [%l0+0x40], %f0");
6316429Svs195195 asm("faligndata %f14, %f0, %f46");
6326429Svs195195 asm("faligndata %f14, %f0, %f48");
6336429Svs195195 asm("fcmpd %fcc0,%f46,%f48");
6346429Svs195195 asm("fblg,pn %fcc0,error");
6356429Svs195195 /* %l1 contains offset value */
6366429Svs195195 asm("add %l1,8,%l1");
6376429Svs195195 /* 56 - 63 */
6386429Svs195195
6396429Svs195195 asm("subcc %i2,64,%i2");
6406429Svs195195 asm("bg next_read");
6416429Svs195195 asm("add %l0,64,%l0");
6426429Svs195195
6436429Svs195195 /* no miscompare error */
6446429Svs195195 asm("mov 0,%i0");
645*7186Skk158166 ret = 0;
6466429Svs195195 /* no error, move back to last 64 bytes boundary */
6476429Svs195195 asm("sub %l1,56,%l1");
6486429Svs195195
6496429Svs195195 asm("error:");
6506429Svs195195 asm("stda %f32,[%i3]0xf0");
6516429Svs195195 asm("std %f48,[%i4]");
6526429Svs195195 /* store offset value */
6536429Svs195195 asm("st %l1,[%i1]");
6546429Svs195195 asm("membar #Sync");
6556429Svs195195
656*7186Skk158166 return (ret);
6576429Svs195195 }
6586429Svs195195
6596429Svs195195 /*
660*7186Skk158166 * vis_test(struct fps_test_ereport *report)
6616429Svs195195 * checks if various RISC operations are performed
6626429Svs195195 * succesfully. If an error is found, relevant data
6636429Svs195195 * is stored in report.
6646429Svs195195 */
6656429Svs195195 int
vis_test(struct fps_test_ereport * report)666*7186Skk158166 vis_test(struct fps_test_ereport *report)
6676429Svs195195 {
6686429Svs195195 int v1;
6696429Svs195195 int v2;
6706429Svs195195 int v3;
6716429Svs195195
672*7186Skk158166 v1 = visgt16(report);
673*7186Skk158166 v2 = visne16(report);
674*7186Skk158166 v3 = vispackfix(report);
6756429Svs195195
6766429Svs195195 if ((0 != v1) || (0 != v2) || (0 != v3))
6776429Svs195195 return (-1);
6786429Svs195195
6796429Svs195195 return (0);
6806429Svs195195 }
6816429Svs195195
6826429Svs195195 /*
683*7186Skk158166 * visgt16(struct fps_test_ereport *report)
6846429Svs195195 * does a greater-than compare instruction and returns if
6856429Svs195195 * successful or not. If an error, relevant data is
6866429Svs195195 * stored in report.
6876429Svs195195 */
6886429Svs195195 static int
visgt16(struct fps_test_ereport * report)689*7186Skk158166 visgt16(struct fps_test_ereport *report)
6906429Svs195195 {
6916429Svs195195 uint64_t expected;
6926429Svs195195 uint64_t observed;
6936429Svs195195 unsigned long a = 0x0000000000000001;
6946429Svs195195 unsigned long b = 0x8000000008000008;
6956429Svs195195 unsigned long c = fcmpgt16(*((double *)&a), *((double *)&b));
6966429Svs195195
6976429Svs195195 if (c == 0x8)
6986429Svs195195 return (0);
6996429Svs195195 else {
7006429Svs195195 expected = (uint64_t)0x8;
7016429Svs195195 observed = (*(uint64_t *)&c);
7026429Svs195195 setup_fps_test_struct(NO_EREPORT_INFO, report,
7036429Svs195195 6364, &observed, &expected, 1, 1);
7046429Svs195195
7056429Svs195195 return (-1);
7066429Svs195195 }
7076429Svs195195 }
7086429Svs195195
7096429Svs195195 /*
710*7186Skk158166 * visne16(struct fps_test_ereport *report)
7116429Svs195195 * does a not-equal compare instruction and returns if
7126429Svs195195 * successful or not. If an error, relevant data is
7136429Svs195195 * stored in report.
7146429Svs195195 */
7156429Svs195195 static int
visne16(struct fps_test_ereport * report)716*7186Skk158166 visne16(struct fps_test_ereport *report)
7176429Svs195195 {
7186429Svs195195 uint64_t expected;
7196429Svs195195 uint64_t observed;
7206429Svs195195 unsigned long a = 0x0000000000000001;
7216429Svs195195 unsigned long b = 0x0001000000001001;
7226429Svs195195 unsigned long c = fcmpne16(*((double *)&a), *((double *)&b));
7236429Svs195195
7246429Svs195195 if (c == 0x9)
7256429Svs195195 return (0);
7266429Svs195195 else {
7276429Svs195195 expected = (uint64_t)0x9;
7286429Svs195195 observed = (*(uint64_t *)&c);
7296429Svs195195 setup_fps_test_struct(NO_EREPORT_INFO, report,
7306429Svs195195 6365, &observed, &expected, 1, 1);
7316429Svs195195
7326429Svs195195 return (-1);
7336429Svs195195 }
7346429Svs195195 }
7356429Svs195195
7366429Svs195195 /*
737*7186Skk158166 * vispackfix(struct fps_test_ereport *report)
7386429Svs195195 * does four 16-bit pack conversions to a lower precsion
7396429Svs195195 * format and returns if successful or not. If an error,
7406429Svs195195 * relevant data is stored in report.
7416429Svs195195 */
7426429Svs195195 static int
vispackfix(struct fps_test_ereport * report)743*7186Skk158166 vispackfix(struct fps_test_ereport *report)
7446429Svs195195 {
7456429Svs195195 float b;
7466429Svs195195 uint64_t expected;
7476429Svs195195 uint64_t observed;
7486429Svs195195 unsigned int c;
7496429Svs195195 unsigned long a = 0x8008000008008008;
7506429Svs195195 unsigned long gsr = 0;
7516429Svs195195
7526429Svs195195 (void) setgsr(gsr);
7536429Svs195195
7546429Svs195195 b = fpackfix(*((double *)&a));
7556429Svs195195 c = *((unsigned int *)&b);
7566429Svs195195
7576429Svs195195 if (c == 0x80080800)
7586429Svs195195 return (0);
7596429Svs195195 else {
7606429Svs195195 expected = (uint64_t)0x80080800;
7616429Svs195195 observed = (uint64_t)c;
7626429Svs195195 setup_fps_test_struct(NO_EREPORT_INFO, report,
7636429Svs195195 6366, &observed, &expected, 1, 1);
7646429Svs195195
7656429Svs195195 return (-1);
7666429Svs195195 }
7676429Svs195195 }
7686429Svs195195
7696429Svs195195 #endif
770