1 /* Copyright (C) 2012 IBM 2 3 Author: Maynard Johnson <maynardj (at) us.ibm.com> 4 5 This program is free software; you can redistribute it and/or 6 modify it under the terms of the GNU General Public License as 7 published by the Free Software Foundation; either version 2 of the 8 License, or (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, but 11 WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, write to the Free Software 17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 18 02111-1307, USA. 19 20 The GNU General Public License is contained in the file COPYING. 21 */ 22 23 #include <stdio.h> 24 #include <stdlib.h> 25 #include <stdint.h> 26 27 #if defined(HAS_DFP) 28 29 typedef union stuff { 30 _Decimal64 dec_val; 31 _Decimal128 dec_val128; 32 unsigned long long u64_val; 33 struct { 34 unsigned long long valu; 35 unsigned long long vall; 36 } u128; 37 } dfp_val_t; 38 39 40 typedef unsigned char Bool; 41 #define True 1 42 #define False 0 43 44 45 #define ALLCR "cr0","cr1","cr2","cr3","cr4","cr5","cr6","cr7" 46 47 #define SET_CR(_arg) \ 48 __asm__ __volatile__ ("mtcr %0" : : "b"(_arg) : ALLCR ); 49 50 #define SET_XER(_arg) \ 51 __asm__ __volatile__ ("mtxer %0" : : "b"(_arg) : "xer" ); 52 53 #define GET_CR(_lval) \ 54 __asm__ __volatile__ ("mfcr %0" : "=b"(_lval) ) 55 56 #define GET_XER(_lval) \ 57 __asm__ __volatile__ ("mfxer %0" : "=b"(_lval) ) 58 59 #define GET_CR_XER(_lval_cr,_lval_xer) \ 60 do { GET_CR(_lval_cr); GET_XER(_lval_xer); } while (0) 61 62 #define SET_CR_ZERO \ 63 SET_CR(0) 64 65 #define SET_XER_ZERO \ 66 SET_XER(0) 67 68 #define SET_CR_XER_ZERO \ 69 do { SET_CR_ZERO; SET_XER_ZERO; } while (0) 70 71 #define SET_FPSCR_ZERO \ 72 do { double _d = 0.0; \ 73 __asm__ __volatile__ ("mtfsf 0xFF, %0" : : "f"(_d) ); \ 74 } while (0) 75 76 #define GET_FPSCR(_arg) \ 77 __asm__ __volatile__ ("mffs %0" : "=f"(_arg) ) 78 79 #define SET_FPSCR_DRN \ 80 __asm__ __volatile__ ("mtfsf 1, %0, 0, 1" : : "f"(f14) ) 81 82 83 // The assembly-level instructions being tested 84 85 /* In _test_dtstdc[q], DCM can be one of 6 possible data classes, numbered 0-5. 86 * In reality, DCM is a 6-bit mask field. We just test the individual values 87 * and assume that masking multiple values would work OK. 88 * BF is the condition register bit field which can range from 0-7. But for 89 * testing purposes, we only use BF values of '0' and '5'. 90 */ 91 static void _test_dtstdc(int BF, int DCM, dfp_val_t val1, dfp_val_t x1 __attribute__((unused))) 92 { 93 _Decimal64 f14 = val1.dec_val; 94 if (DCM < 0 || DCM > 5 || !(BF == 0 || BF == 5)) { 95 fprintf(stderr, "Invalid inputs to asm test: a=%d, b=%d\n", BF, DCM); 96 return; 97 } 98 switch (DCM) { 99 case 0: 100 if (BF) 101 __asm__ __volatile__ ("dtstdc 5, %0, 1" : : "f" (f14)); 102 else 103 __asm__ __volatile__ ("dtstdc 0, %0, 1" : : "f" (f14)); 104 break; 105 case 1: 106 if (BF) 107 __asm__ __volatile__ ("dtstdc 5, %0, 2" : : "f" (f14)); 108 else 109 __asm__ __volatile__ ("dtstdc 0, %0, 2" : : "f" (f14)); 110 break; 111 case 2: 112 if (BF) 113 __asm__ __volatile__ ("dtstdc 5, %0, 4" : : "f" (f14)); 114 else 115 __asm__ __volatile__ ("dtstdc 0, %0, 4" : : "f" (f14)); 116 break; 117 case 3: 118 if (BF) 119 __asm__ __volatile__ ("dtstdc 5, %0, 8" : : "f" (f14)); 120 else 121 __asm__ __volatile__ ("dtstdc 0, %0, 8" : : "f" (f14)); 122 break; 123 case 4: 124 if (BF) 125 __asm__ __volatile__ ("dtstdc 5, %0, 16" : : "f" (f14)); 126 else 127 __asm__ __volatile__ ("dtstdc 0, %0, 16" : : "f" (f14)); 128 break; 129 case 5: 130 if (BF) 131 __asm__ __volatile__ ("dtstdc 5, %0, 32" : : "f" (f14)); 132 else 133 __asm__ __volatile__ ("dtstdc 0, %0, 32" : : "f" (f14)); 134 break; 135 default: 136 break; 137 } 138 } 139 140 static void _test_dtstdcq(int BF, int DCM, dfp_val_t val1, dfp_val_t x1 __attribute__((unused))) 141 { 142 _Decimal128 f14 = val1.dec_val128; 143 if (DCM < 0 || DCM > 5 || !(BF == 0 || BF == 5)) { 144 fprintf(stderr, "Invalid inputs to asm test: a=%d, b=%d\n", BF, DCM); 145 return; 146 } 147 switch (DCM) { 148 case 0: 149 if (BF) 150 __asm__ __volatile__ ("dtstdcq 5, %0, 1" : : "f" (f14)); 151 else 152 __asm__ __volatile__ ("dtstdcq 0, %0, 1" : : "f" (f14)); 153 break; 154 case 1: 155 if (BF) 156 __asm__ __volatile__ ("dtstdcq 5, %0, 2" : : "f" (f14)); 157 else 158 __asm__ __volatile__ ("dtstdcq 0, %0, 2" : : "f" (f14)); 159 break; 160 case 2: 161 if (BF) 162 __asm__ __volatile__ ("dtstdcq 5, %0, 4" : : "f" (f14)); 163 else 164 __asm__ __volatile__ ("dtstdcq 0, %0, 4" : : "f" (f14)); 165 break; 166 case 3: 167 if (BF) 168 __asm__ __volatile__ ("dtstdcq 5, %0, 8" : : "f" (f14)); 169 else 170 __asm__ __volatile__ ("dtstdcq 0, %0, 8" : : "f" (f14)); 171 break; 172 case 4: 173 if (BF) 174 __asm__ __volatile__ ("dtstdcq 5, %0, 16" : : "f" (f14)); 175 else 176 __asm__ __volatile__ ("dtstdcq 0, %0, 16" : : "f" (f14)); 177 break; 178 case 5: 179 if (BF) 180 __asm__ __volatile__ ("dtstdcq 5, %0, 32" : : "f" (f14)); 181 else 182 __asm__ __volatile__ ("dtstdcq 0, %0, 32" : : "f" (f14)); 183 break; 184 default: 185 break; 186 } 187 } 188 189 /* In _test_dtstdg[q], DGM can be one of 6 possible data groups, numbered 0-5. 190 * In reality, DGM is a 6-bit mask field. We just test the individual values 191 * and assume that masking multiple values would work OK. 192 * BF is the condition register bit field which can range from 0-7. But for 193 * testing purposes, we only use BF values of '0' and '5'. 194 */ 195 static void _test_dtstdg(int BF, int DGM, dfp_val_t val1, dfp_val_t x1 __attribute__((unused))) 196 { 197 _Decimal64 f14 = val1.dec_val; 198 if (DGM < 0 || DGM > 5 || !(BF == 0 || BF == 5)) { 199 fprintf(stderr, "Invalid inputs to asm test: a=%d, b=%d\n", BF, DGM); 200 return; 201 } 202 switch (DGM) { 203 case 0: 204 if (BF) 205 __asm__ __volatile__ ("dtstdg 5, %0, 1" : : "f" (f14)); 206 else 207 __asm__ __volatile__ ("dtstdg 0, %0, 1" : : "f" (f14)); 208 break; 209 case 1: 210 if (BF) 211 __asm__ __volatile__ ("dtstdg 5, %0, 2" : : "f" (f14)); 212 else 213 __asm__ __volatile__ ("dtstdg 0, %0, 2" : : "f" (f14)); 214 break; 215 case 2: 216 if (BF) 217 __asm__ __volatile__ ("dtstdg 5, %0, 4" : : "f" (f14)); 218 else 219 __asm__ __volatile__ ("dtstdg 0, %0, 4" : : "f" (f14)); 220 break; 221 case 3: 222 if (BF) 223 __asm__ __volatile__ ("dtstdg 5, %0, 8" : : "f" (f14)); 224 else 225 __asm__ __volatile__ ("dtstdg 0, %0, 8" : : "f" (f14)); 226 break; 227 case 4: 228 if (BF) 229 __asm__ __volatile__ ("dtstdg 5, %0, 16" : : "f" (f14)); 230 else 231 __asm__ __volatile__ ("dtstdg 0, %0, 16" : : "f" (f14)); 232 break; 233 case 5: 234 if (BF) 235 __asm__ __volatile__ ("dtstdg 5, %0, 32" : : "f" (f14)); 236 else 237 __asm__ __volatile__ ("dtstdg 0, %0, 32" : : "f" (f14)); 238 break; 239 default: 240 break; 241 } 242 } 243 244 static void _test_dtstdgq(int BF, int DGM, dfp_val_t val1, dfp_val_t x1 __attribute__((unused))) 245 { 246 _Decimal128 f14 = val1.dec_val128; 247 if (DGM < 0 || DGM > 5 || !(BF == 0 || BF == 5)) { 248 fprintf(stderr, "Invalid inputs to asm test: a=%d, b=%d\n", BF, DGM); 249 return; 250 } 251 switch (DGM) { 252 case 0: 253 if (BF) 254 __asm__ __volatile__ ("dtstdgq 5, %0, 1" : : "f" (f14)); 255 else 256 __asm__ __volatile__ ("dtstdgq 0, %0, 1" : : "f" (f14)); 257 break; 258 case 1: 259 if (BF) 260 __asm__ __volatile__ ("dtstdgq 5, %0, 2" : : "f" (f14)); 261 else 262 __asm__ __volatile__ ("dtstdgq 0, %0, 2" : : "f" (f14)); 263 break; 264 case 2: 265 if (BF) 266 __asm__ __volatile__ ("dtstdgq 5, %0, 4" : : "f" (f14)); 267 else 268 __asm__ __volatile__ ("dtstdgq 0, %0, 4" : : "f" (f14)); 269 break; 270 case 3: 271 if (BF) 272 __asm__ __volatile__ ("dtstdgq 5, %0, 8" : : "f" (f14)); 273 else 274 __asm__ __volatile__ ("dtstdgq 0, %0, 8" : : "f" (f14)); 275 break; 276 case 4: 277 if (BF) 278 __asm__ __volatile__ ("dtstdgq 5, %0, 16" : : "f" (f14)); 279 else 280 __asm__ __volatile__ ("dtstdgq 0, %0, 16" : : "f" (f14)); 281 break; 282 case 5: 283 if (BF) 284 __asm__ __volatile__ ("dtstdgq 5, %0, 32" : : "f" (f14)); 285 else 286 __asm__ __volatile__ ("dtstdgq 0, %0, 32" : : "f" (f14)); 287 break; 288 default: 289 break; 290 } 291 } 292 293 /* In _test_dtstex[q], BF is the condition register bit field indicating the 294 * CR field in which the result of the test should be placed. BF can range 295 * from 0-7, but for testing purposes, we only use BF values of '4' and '7'. 296 */ 297 static void 298 _test_dtstex(int BF, int x __attribute__((unused)), dfp_val_t val1, dfp_val_t val2) 299 { 300 _Decimal64 f14 = val1.dec_val; 301 _Decimal64 f16 = val2.dec_val; 302 if (!(BF == 4 || BF == 7)) { 303 fprintf(stderr, "Invalid input to asm test: a=%d\n", BF); 304 return; 305 } 306 switch (BF) { 307 case 4: 308 __asm__ __volatile__ ("dtstex 4, %0, %1" : : "f" (f14),"f" (f16)); 309 break; 310 case 7: 311 __asm__ __volatile__ ("dtstex 7, %0, %1" : : "f" (f14),"f" (f16)); 312 break; 313 default: 314 break; 315 } 316 } 317 318 static void _test_dtstexq(int BF, int x __attribute__((unused)), dfp_val_t val1, dfp_val_t val2) 319 { 320 _Decimal128 f14 = val1.dec_val128; 321 _Decimal128 f16 = val2.dec_val128; 322 if (!(BF == 4 || BF == 7)) { 323 fprintf(stderr, "Invalid input to asm test: a=%d\n", BF); 324 return; 325 } 326 switch (BF) { 327 case 4: 328 __asm__ __volatile__ ("dtstexq 4, %0, %1" : : "f" (f14),"f" (f16)); 329 break; 330 case 7: 331 __asm__ __volatile__ ("dtstexq 7, %0, %1" : : "f" (f14),"f" (f16)); 332 break; 333 default: 334 break; 335 } 336 } 337 338 339 340 typedef void (*test_func_t)(int a, int b, dfp_val_t val1, dfp_val_t val2); 341 typedef void (*test_driver_func_t)(void); 342 typedef struct test_table 343 { 344 test_driver_func_t test_category; 345 char * name; 346 } test_table_t; 347 348 /* 349 * 345.0DD (0x2207c00000000000 0xe50) 350 * 1.2300e+5DD (0x2207c00000000000 0x14c000) 351 * -16.0DD (0xa207c00000000000 0xe0) 352 * 0.00189DD (0x2206c00000000000 0xcf) 353 * -4.1235DD (0xa205c00000000000 0x10a395bcf) 354 * 9.8399e+20DD (0x2209400000000000 0x253f1f534acdd4) 355 * 0DD (0x2208000000000000 0x0) 356 * 0DD (0x2208000000000000 0x0) 357 * infDD (0x7800000000000000 0x0) 358 * nanDD (0x7c00000000000000 0x0 359 */ 360 static unsigned long long dfp128_vals[] = { 361 // Some finite numbers 362 0x2207c00000000000ULL, 0x0000000000000e50ULL, 363 0x2207c00000000000ULL, 0x000000000014c000ULL, 364 0xa207c00000000000ULL, 0x00000000000000e0ULL, 365 0x2206c00000000000ULL, 0x00000000000000cfULL, 366 0xa205c00000000000ULL, 0x000000010a395bcfULL, 367 0x6209400000fd0000ULL, 0x00253f1f534acdd4ULL, // huge number 368 0x000400000089b000ULL, 0x0a6000d000000049ULL, // very small number 369 // flavors of zero 370 0x2208000000000000ULL, 0x0000000000000000ULL, 371 0xa208000000000000ULL, 0x0000000000000000ULL, // negative 372 0xa248000000000000ULL, 0x0000000000000000ULL, 373 // flavors of NAN 374 0x7c00000000000000ULL, 0x0000000000000000ULL, // quiet 375 0xfc00000000000000ULL, 0xc00100035b007700ULL, 376 0x7e00000000000000ULL, 0xfe000000d0e0a0d0ULL, // signaling 377 // flavors of Infinity 378 0x7800000000000000ULL, 0x0000000000000000ULL, 379 0xf800000000000000ULL, 0x0000000000000000ULL, // negative 380 0xf900000000000000ULL, 0x0000000000000000ULL 381 }; 382 383 static unsigned long long dfp64_vals[] = { 384 // various finite numbers 385 0x2234000000000e50ULL, 386 0x223400000014c000ULL, 387 0xa2340000000000e0ULL,// negative 388 0x22240000000000cfULL, 389 0xa21400010a395bcfULL,// negative 390 0x6e4d3f1f534acdd4ULL,// huge number 391 0x000400000089b000ULL,// very small number 392 // flavors of zero 393 0x2238000000000000ULL, 394 0xa238000000000000ULL, 395 0x4248000000000000ULL, 396 // flavors of NAN 397 0x7e34000000000111ULL, 398 0xfe000000d0e0a0d0ULL,//signaling 399 0xfc00000000000000ULL,//quiet 400 // flavors of Infinity 401 0x7800000000000000ULL, 402 0xf800000000000000ULL,//negative 403 0x7a34000000000000ULL, 404 }; 405 406 // Both Long and Quad arrays of DFP values should have the same length, so it 407 // doesn't matter which array I use for calculating the following #define. 408 #define NUM_DFP_VALS (sizeof(dfp64_vals)/8) 409 410 typedef struct dfp_test_args { 411 int fra_idx; 412 int frb_idx; 413 } dfp_test_args_t; 414 415 416 // Index pairs from dfp64_vals array to be used with dfp_two_arg_tests 417 static dfp_test_args_t dfp_2args_x1[] = { 418 {0, 1}, 419 {2, 1}, 420 {4, 3}, 421 {6, 0}, 422 {2, 4}, 423 {5, 1}, 424 {5, 2}, 425 {7, 1}, 426 {7, 2}, 427 {8, 0}, 428 {8, 1}, 429 {8, 2}, 430 {7, 8}, 431 {12, 14}, 432 {12, 1}, 433 {12, 13}, 434 {12, 12}, 435 {12, 11}, 436 {11, 14}, 437 {11, 0}, 438 {11, 13}, 439 {11, 11}, 440 {14, 14}, 441 {14, 3}, 442 {14, 15}, 443 }; 444 445 typedef enum { 446 LONG_TEST, 447 QUAD_TEST 448 } precision_type_t; 449 450 typedef struct dfp_test 451 { 452 test_func_t test_func; 453 const char * name; 454 dfp_test_args_t * targs; 455 int num_tests; 456 precision_type_t precision; 457 const char * op; 458 } dfp_test_t; 459 460 typedef struct dfp_one_arg_test 461 { 462 test_func_t test_func; 463 const char * name; 464 precision_type_t precision; 465 const char * op; 466 } dfp_one_arg_test_t; 467 468 469 470 static dfp_one_arg_test_t 471 dfp_ClassAndGroupTest_tests[] = { 472 { &_test_dtstdc, "dtstdc", LONG_TEST, "[tCls]"}, 473 { &_test_dtstdcq, "dtstdcq", QUAD_TEST, "[tCls]"}, 474 { &_test_dtstdg, "dtstdg", LONG_TEST, "[tGrp]"}, 475 { &_test_dtstdgq, "dtstdgq", QUAD_TEST, "[tGrp]"}, 476 { NULL, NULL, 0, NULL} 477 }; 478 479 static void test_dfp_ClassAndGroupTest_ops(void) 480 { 481 test_func_t func; 482 dfp_val_t test_val, dummy; 483 484 int k = 0; 485 486 while ((func = dfp_ClassAndGroupTest_tests[k].test_func)) { 487 int i; 488 dfp_one_arg_test_t test_def = dfp_ClassAndGroupTest_tests[k]; 489 490 for (i = 0; i < NUM_DFP_VALS; i++) { 491 int data_class_OR_group, BF = 0; 492 Bool repeat = True; 493 494 if (test_def.precision == LONG_TEST) { 495 test_val.u64_val = dfp64_vals[i]; 496 } else { 497 test_val.u128.valu = dfp128_vals[i * 2]; 498 test_val.u64_val = test_val.u128.valu; 499 test_val.u128.vall = dfp128_vals[(i * 2) + 1]; 500 } 501 502 again: 503 for (data_class_OR_group = 0; data_class_OR_group < 6; data_class_OR_group++) { 504 unsigned int condreg; 505 unsigned int flags; 506 SET_FPSCR_ZERO; 507 SET_CR_XER_ZERO; 508 (*func)(BF, data_class_OR_group, test_val, dummy); 509 GET_CR(flags); 510 511 condreg = ((flags >> (4 * (7-BF)))) & 0xf; 512 printf("%s (DC/DG=%d) %s%016llx", test_def.name, data_class_OR_group, 513 test_def.op, test_val.u64_val); 514 if (test_def.precision == QUAD_TEST) { 515 printf(" %016llx", test_val.u128.vall); 516 } 517 printf(" => %x (BF=%d)\n", condreg, BF); 518 } 519 if (repeat) { 520 repeat = False; 521 BF = 5; 522 goto again; 523 } 524 } 525 k++; 526 printf( "\n" ); 527 } 528 } 529 530 531 static dfp_test_t 532 dfp_ExpTest_tests[] = { 533 { &_test_dtstex, "dtstex", dfp_2args_x1, 25, LONG_TEST, "[tExp]"}, 534 { &_test_dtstexq, "dtstexq", dfp_2args_x1, 25, QUAD_TEST, "[tExp]"}, 535 { NULL, NULL, NULL, 0, 0, NULL} 536 }; 537 538 539 static void test_dfp_ExpTest_ops(void) 540 { 541 dfp_val_t test_val1, test_val2; 542 test_func_t func; 543 int k = 0; 544 545 while ((func = dfp_ExpTest_tests[k].test_func)) { 546 /* BF is a 3-bit instruction field that indicates the CR field in which the 547 * result of the test should be placed. We won't iterate through all 548 * 8 possible BF values since storing compare results to a given field is 549 * a well-tested mechanism in VEX. But we will test two BF values, just as 550 * a sniff-test. 551 */ 552 int i, repeat = 1, BF = 4; 553 dfp_test_t test_def = dfp_ExpTest_tests[k]; 554 555 again: 556 for (i = 0; i < test_def.num_tests; i++) { 557 unsigned int condreg; 558 unsigned int flags; 559 560 if (test_def.precision == LONG_TEST) { 561 test_val1.u64_val = dfp64_vals[test_def.targs[i].fra_idx]; 562 test_val2.u64_val = dfp64_vals[test_def.targs[i].frb_idx]; 563 } else { 564 test_val1.u128.valu = dfp128_vals[test_def.targs[i].fra_idx * 2]; 565 test_val1.u64_val = test_val1.u128.valu; 566 test_val1.u128.vall = dfp128_vals[(test_def.targs[i].fra_idx * 2) + 1]; 567 test_val2.u128.valu = dfp128_vals[test_def.targs[i].frb_idx * 2]; 568 test_val2.u64_val = test_val2.u128.valu; 569 test_val2.u128.vall = dfp128_vals[(test_def.targs[i].frb_idx * 2) + 1]; 570 } 571 572 SET_FPSCR_ZERO; 573 SET_CR_XER_ZERO; 574 (*func)(BF, 0, test_val1, test_val2); 575 GET_CR(flags); 576 577 condreg = ((flags >> (4 * (7-BF)))) & 0xf; 578 printf("%s %016llx", test_def.name, test_val1.u64_val); 579 if (test_def.precision == LONG_TEST) { 580 printf(" %s %016llx ", 581 test_def.op, test_val2.u64_val); 582 } else { 583 printf(" %016llx %s %016llx %016llx ", 584 test_val1.u128.vall, test_def.op, test_val2.u128.valu, test_val2.u128.vall); 585 } 586 printf(" => %x (BF=%d)\n", condreg, BF); 587 } 588 if (repeat) { 589 repeat = 0; 590 BF = 7; 591 goto again; 592 } 593 k++; 594 printf( "\n" ); 595 } 596 } 597 598 599 static test_table_t 600 all_tests[] = 601 { 602 { &test_dfp_ExpTest_ops, 603 "Test DFP exponent test instructions"}, 604 { &test_dfp_ClassAndGroupTest_ops, 605 "Test DFP class and group test instructions"}, 606 { NULL, NULL } 607 }; 608 #endif // HAS_DFP 609 610 int main() { 611 #if defined(HAS_DFP) 612 613 test_table_t aTest; 614 test_driver_func_t func; 615 int i = 0; 616 617 while ((func = all_tests[i].test_category)) { 618 aTest = all_tests[i]; 619 printf( "%s\n", aTest.name ); 620 (*func)(); 621 i++; 622 } 623 624 #endif // HAS_DFP 625 return 0; 626 } 627