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#ifdef __lint 30#pragma error_messages(off, E_VALUE_TYPE) 31#endif 32 33#include <stdlib.h> 34#include <unistd.h> 35#include <fp.h> 36#include <fps_ereport.h> 37 38#define EXPECTED 1.9999999999999998E+00 39 40static void fdivd(double *f22, double *f2, double *f12); 41static void fmuld(double *x, double *y, double *z, double *z1); 42static void fmulx(uint64_t *rs1, uint64_t *rs2, uint64_t *rd); 43int fpu_fdivd(int rloop, struct fps_test_ereport *report); 44int fpu_fmuld(int rloop, struct fps_test_ereport *report); 45int fpu_fmulx(int rloop, struct fps_test_ereport *report); 46 47#ifdef V9B 48 49/* Lint doesn't recognize .il files where these are defined */ 50#ifdef __lint 51 52unsigned long fcmpgt16(double in1, double in2); 53unsigned long fcmpne16(double in1, double in2); 54unsigned long setgsr(unsigned long); 55 56#else 57 58extern float fpackfix(double num); 59extern unsigned long fcmpgt16(double in1, double in2); 60extern unsigned long fcmpne16(double in1, double in2); 61extern unsigned long setgsr(unsigned long); 62 63#endif 64 65int align_data(int loop, 66 struct fps_test_ereport *report); 67int vis_test(struct fps_test_ereport *report); 68static int align_error_create(char *err, uint32_t start, uint32_t offest, 69 int loop, uint32_t count); 70static int do_aligndata(uchar_t *from, uint32_t *offset, size_t sz, 71 uchar_t *f0, uchar_t *f2, uint32_t bmask); 72static int visgt16(struct fps_test_ereport *report); 73static int visne16(struct fps_test_ereport *report); 74static int vispackfix(struct fps_test_ereport *report); 75 76#endif 77 78 79/* 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: 85 * 86 * (a * 2^1022) / ((a+e) * 2^1021) 87 * 88 * which is guaranteed to fill the resulting mantissa with all ones. 89 * 90 */ 91int 92fpu_fdivd(int rloop, struct fps_test_ereport *report) 93{ 94 95 char err_data[MAX_INFO_SIZE]; 96 double expect_ans = EXPECTED; 97 double f12 = 0; 98 double f2; 99 double f22; 100 int loop = 0; 101 uint64_t expect; 102 uint64_t observe; 103 104 srand48(1L); 105 106 while (loop < rloop) { 107 loop++; 108 109 *(uint32_t *)& f22 = mrand48(); 110 *(uint32_t *)& f22 &= 0x80069fff; 111 *(uint32_t *)& f22 |= 0x7fd69f00; 112 113#ifdef __lint 114 (void) f22; 115#endif 116 117 *((uint32_t *)& f22 + 1) = mrand48(); 118 *((uint32_t *)& f22 + 1) |= 0x00000001; 119 120 *(uint64_t *)& f2 = *(uint64_t *)& f22 + 1; 121 *(uint32_t *)& f2 &= 0x800FFFFF; 122 *(uint32_t *)& f2 |= 0x7FC00000; 123#ifdef __lint 124 (void) f2; 125#endif 126 127 fdivd(&f22, &f2, &f12); 128 129 if (f12 != expect_ans) { 130 (void) snprintf(err_data, sizeof (err_data), 131 "\nExpected: %.16e,\nObserved: %.16e", 132 expect_ans, f12); 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); 137 138 return (-1); 139 } 140 } 141 142 return (0); 143} 144 145/* 146 * fdivd(uint64_t *rs1, uint64_t *rs2, uint64_t *rd) 147 * performs the assembly level instructions for 148 * fpu_fdivd. 149 */ 150/* ARGSUSED */ 151static void 152fdivd(double *f22, double *f2, double *f12) 153{ 154 asm("ldd [%i0], %f22"); 155 asm("ldd [%i1], %f2"); 156 asm("fdivd %f22, %f2, %f12"); 157 asm("std %f12,[%i2]"); 158 asm("membar #Sync"); 159} 160 161/* 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 167 * important. 168 */ 169int 170fpu_fmuld(int rloop, struct fps_test_ereport *report) 171{ 172 char err_data[MAX_INFO_SIZE]; 173 double x; 174 double y; 175 double z; 176 double z1; 177 int loop; 178 uint64_t expect; 179 uint64_t observe; 180 uint64_t *px; 181 uint64_t *py; 182 183 loop = 0; 184 px = (uint64_t *)& x; 185 py = (uint64_t *)& y; 186 *px = 0x2FEBD8507111CDE5UL; /* 4865027 */ 187 *py = 0x2FE284A9A98EAA26UL; 188 189#ifdef __lint 190 (void) x; 191 (void) y; 192#endif 193 194 while (loop < rloop) { 195 loop++; 196 z = z1 = 0.0; 197 198 /* 199 * Data pattern and back-to-back fmuld() are 200 * important 201 */ 202 fmuld(&x, &y, &z, &z1); 203 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); 212 213 return (-1); 214 } 215 } 216 217 return (0); 218} 219 220/* 221 * fmuld(double *x,double *y, double *z, double *z1) 222 * performs the assembly level instructions for 223 * fpu_fmuld. 224 */ 225/* ARGSUSED */ 226static void 227fmuld(double *x, double *y, double *z, double *z1) 228{ 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]"); 235 asm("membar #Sync"); 236} 237 238 239/* 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 244 * 64-bit intgers. 245 */ 246int 247fpu_fmulx(int rloop, struct fps_test_ereport *report) 248{ 249 char err_data[MAX_INFO_SIZE]; 250 int loop; 251 int loop_lim; 252 uint32_t *rs1; 253 uint32_t *rs2; 254 uint64_t expect; 255 uint64_t observe; 256 uint64_t v1; 257 uint64_t v2; 258 uint64_t vd1; 259 uint64_t vd2; 260 uint64_t *rd1; 261 uint64_t *rd2; 262 263 v1 = v2 = vd1 = vd2 = 0; 264 loop = 0; 265 loop_lim = rloop; 266 267 if (loop_lim < 10) 268 loop_lim = 10; 269 270 if (loop_lim > 100000) 271 loop_lim = 100000; 272 273 rs1 = (uint32_t *)& v1; 274 rs2 = (uint32_t *)& v2; 275 rd1 = &vd1; 276 rd2 = &vd2; 277 278#ifdef __lint 279 (void) v1; 280 (void) v2; 281#endif 282 283 srand(0l); 284 while (loop < loop_lim) { 285 loop++; 286 287#ifndef __lint 288 289 *rs1 = mrand48(); 290 *(rs1 + 1) = mrand48(); 291 *rs2 = mrand48(); 292 *(rs2 + 1) = mrand48(); 293#endif 294 295 /* LINTED */ 296 fmulx((uint64_t *)rs1, (uint64_t *)rs2, rd1); 297 298 /* LINTED */ 299 fmulx((uint64_t *)rs2, (uint64_t *)rs1, rd2); 300 301 if (*rd1 != *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); 308 309 return (-1); 310 } 311 } 312 313 return (0); 314} 315 316/* 317 * fmulx(uint64_t *rs1, uint64_t *rs2, uint64_t *rd) 318 * performs the assembly level instructions for 319 * fpu_fmulx. 320 */ 321/* ARGSUSED */ 322static void 323fmulx(uint64_t *rs1, uint64_t *rs2, uint64_t *rd) 324{ 325 asm("ldx [%i0], %l0"); 326 asm("ldx [%i1], %l1"); 327 asm("mulx %l0, %l1, %l2"); 328 asm("stx %l2, [%i2]"); 329 asm("membar #Sync"); 330 331} 332 333 334 335#ifdef V9B 336 337#pragma align 64 (f0) 338#pragma align 8 (f2) 339 340#define MEMSIZE 2048*3 341 342static uchar_t f0[64]; 343static uchar_t f2[8]; 344 345static 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}; 355 356#ifdef __lint 357 358/*ARGSUSED*/ 359unsigned long 360setgsr(unsigned long arg1) 361{ 362 return (0); 363} 364 365/*ARGSUSED*/ 366float 367fpackfix(double arg1) 368{ 369 return (0.0); 370} 371 372/*ARGSUSED*/ 373unsigned long 374fcmpne16(double arg1, double arg2) 375{ 376 return (0); 377} 378 379/*ARGSUSED*/ 380unsigned long 381fcmpgt16(double arg1, double arg2) 382{ 383 return (0); 384} 385 386#endif /* LINT */ 387 388/* 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. 398 */ 399int 400align_data(int loop, struct fps_test_ereport *report) 401{ 402 char err[MAX_INFO_SIZE]; 403 int test_ret; 404 int nr_malloc; 405 size_t memsize; 406 struct timeval timeout; 407 uchar_t c; 408 uchar_t *pf0; 409 uchar_t *pf2; 410 uchar_t *src; 411 uint32_t cnt; 412 uint32_t i; 413 uint32_t offset; 414 uint32_t start; 415 uint64_t expect[2]; 416 uint64_t observe[2]; 417 418 timeout.tv_sec = 0; 419 timeout.tv_usec = 10000; 420 nr_malloc = 0; 421 err[0] = '\0'; 422 423 /* Make sure memsize is 64 bytes aligned with minimum of 64 bytes */ 424 memsize = MEMSIZE; 425 memsize = memsize / 64 * 64; 426 427 if (memsize < 64) 428 memsize = 64; 429 430 src = (uchar_t *)memalign(64, memsize + 64); 431 432 while (src == NULL && nr_malloc < 10) { 433 (void) select(1, NULL, NULL, NULL, &timeout); 434 nr_malloc++; 435 src = (uchar_t *)memalign(64, memsize + 64); 436 } 437 438 if (src == NULL) 439 _exit(FPU_SYSCALL_FAIL); 440 441 /* Initialize source array with sequential data */ 442 c = 0; 443 444 for (i = 0; i < memsize + 64; i++) 445 *(src + i) = c++; 446 447 for (cnt = 0; cnt < loop; cnt++) { 448 for (start = 1; start < 64; start += 1) { 449 offset = 0; 450 451 test_ret = do_aligndata(src + start, &offset, 452 memsize, f0, f2, bmask[cnt % 20]); 453 454 /* 455 * Miscompare on the two aligndata 456 * instructions. Calculate offset to source 457 * array and get miscompare data 458 */ 459 460 if (test_ret != 0) { 461 pf0 = f0 + offset % 64; 462 pf2 = f2; 463 464 for (i = 0; i < 8; i++) { 465 if (*(pf0 + i) != *(pf2 + i)) 466 break; 467 } 468 469 (void) align_error_create(err, start, 470 offset + start + i, loop, cnt); 471 expect[0] = 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( 478 IS_EREPORT_INFO, 479 report, 6344, observe, 480 expect, 1, 2, err); 481 482 free(src); 483 484 return (-1); 485 } 486 487 /* 488 * No miscompare on the aligndata 489 * instructions. Check to see whether the 490 * last 64 bytes matches the input 491 */ 492 if (test_ret == 0) { 493 pf2 = src + offset + start; 494 495 for (i = 0; i < 64; i++) { 496 if (f0[i] != *(pf2 + i)) { 497 498 (void) align_error_create(err, 499 start, 500 offset + start + i, 501 loop, cnt); 502 expect[0] = 503 (uint64_t)(*(uint8_t *) 504 (pf2 + i)); 505 expect[1] = (uint64_t)0; 506 observe[0] = (uint64_t)f0[i]; 507 observe[1] = (uint64_t)0; 508 setup_fps_test_struct( 509 IS_EREPORT_INFO, 510 report, 6343, observe, 511 expect, 1, 1, err); 512 513 free(src); 514 return (-1); 515 } 516 } 517 } 518 } 519 } 520 521 free(src); 522 523 return (0); 524} 525 526/* 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. 530 */ 531static int 532align_error_create(char *err, uint32_t start, 533 uint32_t offset, int loop, uint32_t count) 534{ 535 if (err == NULL) 536 return (-1); 537 538 return snprintf(err, sizeof (err), 539 "Start = %2.2d offset = %2.2d loop = %d cnt = %d", 540 start, offset, loop, count); 541} 542 543/* 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. 547 */ 548/*ARGSUSED*/ 549static int 550do_aligndata(uchar_t *from, uint32_t *offset, size_t sz, 551 uchar_t *f0, uchar_t *f2, uint32_t bmask) 552{ 553 int ret = 1; 554 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 */ 559 asm("mov 1,%i0"); 560 /* %l1 used as offset counter */ 561 asm("mov -8,%l1"); 562 asm("ldd [%l0], %f0"); 563 564 asm("next_read:"); 565 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"); 574 /* 0 - 7 */ 575 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"); 583 /* 9 - 15 */ 584 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"); 592 /* 16 - 23 */ 593 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"); 601 /* 24 - 31 */ 602 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"); 610 /* 32 - 39 */ 611 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"); 619 /* 40 - 47 */ 620 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"); 628 /* 48 - 55 */ 629 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"); 637 /* 56 - 63 */ 638 639 asm("subcc %i2,64,%i2"); 640 asm("bg next_read"); 641 asm("add %l0,64,%l0"); 642 643 /* no miscompare error */ 644 asm("mov 0,%i0"); 645 ret = 0; 646 /* no error, move back to last 64 bytes boundary */ 647 asm("sub %l1,56,%l1"); 648 649 asm("error:"); 650 asm("stda %f32,[%i3]0xf0"); 651 asm("std %f48,[%i4]"); 652 /* store offset value */ 653 asm("st %l1,[%i1]"); 654 asm("membar #Sync"); 655 656 return (ret); 657} 658 659/* 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. 664 */ 665int 666vis_test(struct fps_test_ereport *report) 667{ 668 int v1; 669 int v2; 670 int v3; 671 672 v1 = visgt16(report); 673 v2 = visne16(report); 674 v3 = vispackfix(report); 675 676 if ((0 != v1) || (0 != v2) || (0 != v3)) 677 return (-1); 678 679 return (0); 680} 681 682/* 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 686 * stored in report. 687 */ 688static int 689visgt16(struct fps_test_ereport *report) 690{ 691 uint64_t expected; 692 uint64_t observed; 693 unsigned long a = 0x0000000000000001; 694 unsigned long b = 0x8000000008000008; 695 unsigned long c = fcmpgt16(*((double *)&a), *((double *)&b)); 696 697 if (c == 0x8) 698 return (0); 699 else { 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); 704 705 return (-1); 706 } 707} 708 709/* 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 713 * stored in report. 714 */ 715static int 716visne16(struct fps_test_ereport *report) 717{ 718 uint64_t expected; 719 uint64_t observed; 720 unsigned long a = 0x0000000000000001; 721 unsigned long b = 0x0001000000001001; 722 unsigned long c = fcmpne16(*((double *)&a), *((double *)&b)); 723 724 if (c == 0x9) 725 return (0); 726 else { 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); 731 732 return (-1); 733 } 734} 735 736/* 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. 741 */ 742static int 743vispackfix(struct fps_test_ereport *report) 744{ 745 float b; 746 uint64_t expected; 747 uint64_t observed; 748 unsigned int c; 749 unsigned long a = 0x8008000008008008; 750 unsigned long gsr = 0; 751 752 (void) setgsr(gsr); 753 754 b = fpackfix(*((double *)&a)); 755 c = *((unsigned int *)&b); 756 757 if (c == 0x80080800) 758 return (0); 759 else { 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); 764 765 return (-1); 766 } 767} 768 769#endif 770