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