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 #ifndef __powerpc64__ 83 typedef uint32_t HWord_t; 84 #else 85 typedef uint64_t HWord_t; 86 #endif /* __powerpc64__ */ 87 88 enum BF_vals { BF_val1 = 0, BF_val2 = 1, BF_val3 =6}; 89 90 // The assembly-level instructions being tested 91 static void _test_dtstsf(unsigned int BF, unsigned int ref_sig, dfp_val_t valB) 92 { 93 _Decimal64 f16 = valB.dec_val; 94 register HWord_t r14 __asm__ ("r14"); 95 double f14; 96 r14 = (HWord_t)&ref_sig; 97 98 __asm __volatile__ ("lfiwax %0, 0, %1" : "=f" (f14): "r" (r14)); 99 switch (BF) { 100 case BF_val1: 101 __asm__ __volatile__ ("dtstsf %0, %1, %2" : : "i" (BF_val1), "f" (f14), "f" (f16)); 102 break; 103 case BF_val2: 104 __asm__ __volatile__ ("dtstsf %0, %1, %2" : : "i" (BF_val2), "f" (f14), "f" (f16)); 105 break; 106 case BF_val3: 107 __asm__ __volatile__ ("dtstsf %0, %1, %2" : : "i" (BF_val3), "f" (f14), "f" (f16)); 108 break; 109 default: 110 fprintf(stderr, "Invalid value %d for BF\n", BF); 111 break; 112 } 113 } 114 115 static void _test_dtstsfq(unsigned int BF, unsigned int ref_sig, dfp_val_t valB) 116 { 117 _Decimal128 f16 = valB.dec_val128; 118 register HWord_t r14 __asm__ ("r14"); 119 double f14; 120 r14 = (HWord_t)&ref_sig; 121 122 __asm __volatile__ ("lfiwax %0, 0, %1" : "=f" (f14): "r" (r14)); 123 switch (BF) { 124 case BF_val1: 125 __asm__ __volatile__ ("dtstsfq %0, %1, %2" : : "i" (BF_val1), "f" (f14), "f" (f16)); 126 break; 127 case BF_val2: 128 __asm__ __volatile__ ("dtstsfq %0, %1, %2" : : "i" (BF_val2), "f" (f14), "f" (f16)); 129 break; 130 case BF_val3: 131 __asm__ __volatile__ ("dtstsfq %0, %1, %2" : : "i" (BF_val3), "f" (f14), "f" (f16)); 132 break; 133 default: 134 fprintf(stderr, "Invalid value %d for BF\n", BF); 135 break; 136 } 137 } 138 139 static dfp_val_t _test_ddedpd(unsigned int SP, dfp_val_t valB) 140 { 141 _Decimal64 ret = 0; 142 dfp_val_t result; 143 _Decimal64 f16 = valB.dec_val; 144 switch (SP) { 145 case 0: 146 __asm__ __volatile__ ("ddedpd. 0, %0, %1" : "=f" (ret) : "f" (f16)); 147 break; 148 case 1: 149 __asm__ __volatile__ ("ddedpd. 1, %0, %1" : "=f" (ret) : "f" (f16)); 150 break; 151 case 2: 152 __asm__ __volatile__ ("ddedpd. 2, %0, %1" : "=f" (ret) : "f" (f16)); 153 break; 154 case 3: 155 __asm__ __volatile__ ("ddedpd. 3, %0, %1" : "=f" (ret) : "f" (f16)); 156 break; 157 default: 158 fprintf(stderr, "Invalid value %d for SP\n", SP); 159 break; 160 } 161 result.dec_val = ret; 162 return result; 163 } 164 165 166 static dfp_val_t _test_ddedpdq(unsigned int SP, dfp_val_t valB) 167 { 168 _Decimal128 ret = 0; 169 dfp_val_t result; 170 _Decimal128 f16 = valB.dec_val128; 171 switch (SP) { 172 case 0: 173 __asm__ __volatile__ ("ddedpdq 0, %0, %1" : "=f" (ret) : "f" (f16)); 174 break; 175 case 1: 176 __asm__ __volatile__ ("ddedpdq 1, %0, %1" : "=f" (ret) : "f" (f16)); 177 break; 178 case 2: 179 __asm__ __volatile__ ("ddedpdq 2, %0, %1" : "=f" (ret) : "f" (f16)); 180 break; 181 case 3: 182 __asm__ __volatile__ ("ddedpdq 3, %0, %1" : "=f" (ret) : "f" (f16)); 183 break; 184 default: 185 fprintf(stderr, "Invalid value %d for SP\n", SP); 186 break; 187 } 188 result.dec_val128 = ret; 189 return result; 190 } 191 192 static dfp_val_t _test_denbcd(unsigned int S, dfp_val_t valB) 193 { 194 _Decimal64 ret = 0; 195 dfp_val_t result; 196 _Decimal64 f16 = valB.dec_val; 197 switch (S) { 198 case 0: 199 __asm__ __volatile__ ("denbcd. 0, %0, %1" : "=f" (ret) : "f" (f16)); 200 break; 201 case 1: 202 __asm__ __volatile__ ("denbcd. 1, %0, %1" : "=f" (ret) : "f" (f16)); 203 break; 204 default: 205 fprintf(stderr, "Invalid value %d for S\n", S); 206 break; 207 } 208 result.dec_val = ret; 209 return result; 210 } 211 212 213 static dfp_val_t _test_denbcdq(unsigned int S, dfp_val_t valB) 214 { 215 _Decimal128 ret = 0; 216 dfp_val_t result; 217 _Decimal128 f16 = valB.dec_val128; 218 switch (S) { 219 case 0: 220 __asm__ __volatile__ ("denbcdq 0, %0, %1" : "=f" (ret) : "f" (f16)); 221 break; 222 case 1: 223 __asm__ __volatile__ ("denbcdq 1, %0, %1" : "=f" (ret) : "f" (f16)); 224 break; 225 default: 226 fprintf(stderr, "Invalid value %d for S\n", S); 227 break; 228 } 229 result.dec_val128 = ret; 230 return result; 231 } 232 233 234 typedef void (*test_func_t)(unsigned int imm, unsigned int imm2, dfp_val_t valB); 235 typedef dfp_val_t (*test_func_bcd_t)(unsigned int imm, dfp_val_t valB); 236 typedef void (*test_driver_func_t)(void); 237 typedef struct test_table 238 { 239 test_driver_func_t test_category; 240 char * name; 241 } test_table_t; 242 243 /* 244 * 345.0DD (0x2207c00000000000 0xe50) 245 * 1.2300e+5DD (0x2207c00000000000 0x14c000) 246 * -16.0DD (0xa207c00000000000 0xe0) 247 * 0.00189DD (0x2206c00000000000 0xcf) 248 * -4.1235DD (0xa205c00000000000 0x10a395bcf) 249 * 9.8399e+20DD (0x2209400000000000 0x253f1f534acdd4) 250 * 0DD (0x2208000000000000 0x0) 251 * 0DD (0x2208000000000000 0x0) 252 * infDD (0x7800000000000000 0x0) 253 * nanDD (0x7c00000000000000 0x0 254 */ 255 static unsigned long long dfp128_vals[] = { 256 // Some finite numbers 257 0x2207c00000000000ULL, 0x0000000000000e50ULL, 258 0x2207c00000000000ULL, 0x000000000014c000ULL, 259 0xa207c00000000000ULL, 0x00000000000000e0ULL, 260 0x2206c00000000000ULL, 0x00000000000000cfULL, 261 0xa205c00000000000ULL, 0x000000010a395bcfULL, 262 0x6209400000fd0000ULL, 0x00253f1f534acdd4ULL, // huge number 263 0x000400000089b000ULL, 0x0a6000d000000049ULL, // very small number 264 // flavors of zero 265 0x2208000000000000ULL, 0x0000000000000000ULL, 266 0xa208000000000000ULL, 0x0000000000000000ULL, // negative 267 0xa248000000000000ULL, 0x0000000000000000ULL, 268 // flavors of NAN 269 0x7c00000000000000ULL, 0x0000000000000000ULL, // quiet 270 0xfc00000000000000ULL, 0xc00100035b007700ULL, 271 0x7e00000000000000ULL, 0xfe000000d0e0a0d0ULL, // signaling 272 // flavors of Infinity 273 0x7800000000000000ULL, 0x0000000000000000ULL, 274 0xf800000000000000ULL, 0x0000000000000000ULL, // negative 275 0xf900000000000000ULL, 0x0000000000000000ULL 276 }; 277 278 static unsigned long long dfp64_vals[] = { 279 // various finite numbers 280 0x2234000000000e50ULL, 281 0x223400000014c000ULL, 282 0xa2340000000000e0ULL,// negative 283 0x22240000000000cfULL, 284 0xa21400010a395bcfULL,// negative 285 0x6e4d3f1f534acdd4ULL,// huge number 286 0x000400000089b000ULL,// very small number 287 // flavors of zero 288 0x2238000000000000ULL, 289 0xa238000000000000ULL, 290 0x4248000000000000ULL, 291 // flavors of NAN 292 0x7e34000000000111ULL, 293 0xfe000000d0e0a0d0ULL,//signaling 294 0xfc00000000000000ULL,//quiet 295 // flavors of Infinity 296 0x7800000000000000ULL, 297 0xf800000000000000ULL,//negative 298 0x7a34000000000000ULL, 299 }; 300 301 /* The bcd64_vals and bdc128_vals hold the unique results of executing 302 * the ddedpd instruction on the basic dfp64 and dfp128 array values. 303 * Executing the inverse operation (denbcd) on these values with the 304 * appropriate S (signed) value should yield values approximating the 305 * original dfp values (except being 2^4 in magnitude since the decoding 306 * operation shifted the value one hex digit to the left to make room 307 * for signedness info). 308 */ 309 static unsigned long long bcd64_vals[] = { 310 0x0000000000003450ULL, 311 0x000000000003450cULL, 312 0x000000000003450fULL, 313 0x0000000001230000ULL, 314 0x000000001230000cULL, 315 0x000000001230000fULL, 316 0x0000000000000160ULL, 317 0x000000000000160dULL, 318 0x0000000000000189ULL, 319 0x000000000000189cULL, 320 0x000000000000189fULL, 321 0x0000004123456789ULL, 322 0x000004123456789dULL, 323 0x9839871234533354ULL, 324 0x839871234533354cULL, 325 0x839871234533354fULL, 326 0x0000000008864000ULL, 327 0x000000008864000cULL, 328 0x000000008864000fULL, 329 0x0000000000000000ULL, 330 0x000000000000000cULL, 331 0x000000000000000fULL, 332 0x000000000000000dULL, 333 0x0000000000000211ULL, 334 0x000000000000211cULL, 335 0x000000000000211fULL, 336 0x0000003882028150ULL, 337 0x000003882028150dULL 338 }; 339 340 static unsigned long long bcd128_vals[] = { 341 0x0000000000000000ULL, 0x0000000000003450ULL, 342 0x0000000000000000ULL, 0x000000000003450cULL, 343 0x0000000000000000ULL, 0x000000000003450fULL, 344 0x0000000000000000ULL, 0x0000000001230000ULL, 345 0x0000000000000000ULL, 0x000000001230000cULL, 346 0x0000000000000000ULL, 0x000000001230000fULL, 347 0x0000000000000000ULL, 0x0000000000000160ULL, 348 0x0000000000000000ULL, 0x000000000000160dULL, 349 0x0000000000000000ULL, 0x0000000000000189ULL, 350 0x0000000000000000ULL, 0x000000000000189cULL, 351 0x0000000000000000ULL, 0x000000000000189fULL, 352 0x0000000000000000ULL, 0x0000004123456789ULL, 353 0x0000000000000000ULL, 0x000004123456789dULL, 354 0x0000097100000000ULL, 0x9839871234533354ULL, 355 0x0000971000000009ULL, 0x839871234533354cULL, 356 0x0000971000000009ULL, 0x839871234533354fULL, 357 0x0000010954000051ULL, 0x8000640000000049ULL, 358 0x0000109540000518ULL, 0x000640000000049cULL, 359 0x0000109540000518ULL, 0x000640000000049fULL, 360 0x0000000000000000ULL, 0x0000000000000000ULL, 361 0x0000000000000000ULL, 0x000000000000000cULL, 362 0x0000000000000000ULL, 0x000000000000000fULL, 363 0x0000000000000000ULL, 0x000000000000000dULL, 364 0x0000000000080000ULL, 0x0200801330811600ULL, 365 0x0000000000800000ULL, 0x200801330811600dULL, 366 0x0000000000088170ULL, 0x0000003882028150ULL, 367 0x0000000000881700ULL, 0x000003882028150cULL, 368 0x0000000000881700ULL, 0x000003882028150fULL 369 }; 370 371 // Both Long and Quad arrays of DFP values should have the same length, so it 372 // doesn't matter which array I use for calculating the following #define. 373 #define NUM_DFP_VALS (sizeof(dfp64_vals)/8) 374 375 typedef enum { 376 LONG_TEST, 377 QUAD_TEST 378 } precision_type_t; 379 380 typedef struct dfp_one_arg_test 381 { 382 test_func_t test_func; 383 const char * name; 384 precision_type_t precision; 385 const char * op; 386 } dfp_one_arg_test_t; 387 388 typedef struct dfp_one_arg_bcd_test 389 { 390 test_func_bcd_t test_func; 391 const char * name; 392 precision_type_t precision; 393 const char * op; 394 } dfp_one_arg_bcd_test_t; 395 396 static dfp_one_arg_bcd_test_t 397 dfp_test_dfp_ddedpd_tests[] = { 398 { &_test_ddedpd, "ddedpd", LONG_TEST, "[D->B]"}, 399 { &_test_ddedpdq, "ddedpdq", QUAD_TEST, "[D->B]"}, 400 { NULL, NULL, 0, NULL} 401 }; 402 403 static void test_dfp_ddedpd_ops(void) 404 { 405 test_func_bcd_t func; 406 dfp_val_t test_val; 407 408 int k = 0; 409 410 while ((func = dfp_test_dfp_ddedpd_tests[k].test_func)) { 411 int i; 412 dfp_one_arg_bcd_test_t test_def = dfp_test_dfp_ddedpd_tests[k]; 413 414 for (i = 0; i < NUM_DFP_VALS; i++) { 415 unsigned int SP; 416 417 if (test_def.precision == LONG_TEST) { 418 test_val.u64_val = dfp64_vals[i]; 419 } else { 420 test_val.u128.valu = dfp128_vals[i * 2]; 421 test_val.u64_val = test_val.u128.valu; 422 test_val.u128.vall = dfp128_vals[(i * 2) + 1]; 423 } 424 425 for (SP = 0; SP < 4; SP++) { 426 dfp_val_t result; 427 result = (*func)(SP, test_val); 428 printf("%s (SP=%d) %s%016llx", test_def.name, SP, 429 test_def.op, test_val.u64_val); 430 if (test_def.precision == QUAD_TEST) { 431 printf(" %016llx", test_val.u128.vall); 432 } 433 if (test_def.precision == LONG_TEST) 434 printf(" ==> %016llx\n", result.u64_val); 435 else 436 printf(" ==> %016llx %016llx\n", result.u128.valu, result.u128.vall); 437 } 438 } 439 k++; 440 printf( "\n" ); 441 } 442 } 443 444 static dfp_one_arg_bcd_test_t 445 dfp_test_dfp_denbcd_tests[] = { 446 { &_test_denbcd, "denbcd", LONG_TEST, "[B->D]"}, 447 { &_test_denbcdq, "denbcdq", QUAD_TEST, "[B->D]"}, 448 { NULL, NULL, 0, NULL} 449 }; 450 451 static void test_dfp_denbcd_ops(void) 452 { 453 test_func_bcd_t func; 454 dfp_val_t test_val; 455 int num_test_vals; 456 457 int k = 0; 458 459 while ((func = dfp_test_dfp_denbcd_tests[k].test_func)) { 460 int i; 461 dfp_one_arg_bcd_test_t test_def = dfp_test_dfp_denbcd_tests[k]; 462 if (test_def.precision == LONG_TEST) 463 num_test_vals = sizeof(bcd64_vals)/sizeof(unsigned long long); 464 else 465 num_test_vals = sizeof(bcd128_vals)/(2 * sizeof(unsigned long long)); 466 467 for (i = 0; i < num_test_vals; i++) { 468 unsigned int S; 469 dfp_val_t result; 470 /* The DPD-to-BCD decodings may contain up to 3 decodings for each normal DFP 471 * value: the first is an unsigned decoding, and the other two are 472 * signed decodings, with SP[1] set to '0' and '1' respectively at decode 473 * time. But some of the results of decodings were duplicates, so they were 474 * not included in the bcd64_vals and bcd128_vals arrays. 475 * 476 * When doing the encoding operation (denbcd), we'll attempt both S=0 and 477 * S=1; one or the other should encode the BCD value to something close to 478 * its original DFP value (except being 2^4 in magnitude since the decoding 479 * operation shifted the value one hex digit to the left to make room 480 * for signedness info). 481 */ 482 for (S = 0; S < 2; S++) { 483 if (test_def.precision == LONG_TEST) { 484 test_val.u64_val = bcd64_vals[i]; 485 } else { 486 test_val.u128.valu = bcd128_vals[i * 2]; 487 test_val.u64_val = test_val.u128.valu; 488 test_val.u128.vall = bcd128_vals[(i * 2) + 1]; 489 } 490 491 result = (*func)(S, test_val); 492 printf("%s (S=%d) %s%016llx", test_def.name, S, 493 test_def.op, test_val.u64_val); 494 if (test_def.precision == QUAD_TEST) { 495 printf(" %016llx", test_val.u128.vall); 496 } 497 if (test_def.precision == LONG_TEST) 498 printf(" ==> %016llx\n", result.u64_val); 499 else 500 printf(" ==> %016llx %016llx\n", result.u128.valu, result.u128.vall); 501 } 502 } 503 k++; 504 printf( "\n" ); 505 } 506 } 507 508 509 static dfp_one_arg_test_t 510 dfp_test_significance_tests[] = { 511 { &_test_dtstsf, "dtstsf", LONG_TEST, "[tSig]"}, 512 { &_test_dtstsfq, "dtstsfq", QUAD_TEST, "[tSig]"}, 513 { NULL, NULL, 0, NULL} 514 }; 515 516 static void test_dfp_test_significance_ops(void) 517 { 518 test_func_t func; 519 dfp_val_t test_valB; 520 int k = 0; 521 unsigned int BF_vals[] = {BF_val1, BF_val2, BF_val3}; 522 unsigned int reference_sig, reference_sig_vals[] = {0U, 1U, 2U, 4U, 6U, 63U}; 523 int num_reference_sig_vals = sizeof(reference_sig_vals)/sizeof(unsigned int); 524 525 while ((func = dfp_test_significance_tests[k].test_func)) { 526 int i; 527 dfp_one_arg_test_t test_def = dfp_test_significance_tests[k]; 528 529 for (i = 0; i < NUM_DFP_VALS; i++) { 530 int j; 531 if (test_def.precision == LONG_TEST) { 532 test_valB.u64_val = dfp64_vals[i]; 533 } else { 534 test_valB.u128.valu = dfp128_vals[i * 2]; 535 test_valB.u64_val = test_valB.u128.valu; 536 test_valB.u128.vall = dfp128_vals[(i * 2) + 1]; 537 } 538 539 for (j = 0; j < num_reference_sig_vals; j++) { 540 int bf_idx, BF; 541 reference_sig = reference_sig_vals[j]; 542 for (bf_idx = 0; bf_idx < sizeof(BF_vals)/sizeof(unsigned int); bf_idx++) { 543 unsigned int condreg; 544 unsigned int flags; 545 BF = BF_vals[bf_idx]; 546 SET_FPSCR_ZERO; 547 SET_CR_XER_ZERO; 548 (*func)(BF, reference_sig, test_valB); 549 GET_CR(flags); 550 551 condreg = ((flags >> (4 * (7-BF)))) & 0xf; 552 printf("%s (ref_sig=%d) %s%016llx", test_def.name, reference_sig, 553 test_def.op, test_valB.u64_val); 554 if (test_def.precision == QUAD_TEST) { 555 printf(" %016llx", test_valB.u128.vall); 556 } 557 printf(" => %x (BF=%d)\n", condreg, BF); 558 } 559 } 560 printf( "\n" ); 561 } 562 k++; 563 } 564 } 565 566 static test_table_t 567 all_tests[] = 568 { 569 { &test_dfp_test_significance_ops, 570 "Test DFP test significance instructions"}, 571 { &test_dfp_ddedpd_ops, 572 "Test DFP DPD-to-BCD instructions"}, 573 { &test_dfp_denbcd_ops, 574 "Test DFP BCD-to-DPD instructions"}, 575 { NULL, NULL } 576 }; 577 #endif // HAS_DFP 578 579 int main() { 580 #if defined(HAS_DFP) 581 582 test_table_t aTest; 583 test_driver_func_t func; 584 int i = 0; 585 586 while ((func = all_tests[i].test_category)) { 587 aTest = all_tests[i]; 588 printf( "%s\n", aTest.name ); 589 (*func)(); 590 i++; 591 } 592 593 #endif // HAS_DFP 594 return 0; 595 } 596