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 #include <string.h> 27 28 #if defined(HAS_DFP) 29 30 register double f14 __asm__ ("fr14"); 31 register double f15 __asm__ ("fr15"); 32 register double f16 __asm__ ("fr16"); 33 register double f17 __asm__ ("fr17"); 34 register double f18 __asm__ ("fr18"); 35 register double f19 __asm__ ("fr19"); 36 37 38 typedef unsigned char Bool; 39 #define True 1 40 #define False 0 41 42 43 #define ALLCR "cr0","cr1","cr2","cr3","cr4","cr5","cr6","cr7" 44 45 #define SET_CR(_arg) \ 46 __asm__ __volatile__ ("mtcr %0" : : "b"(_arg) : ALLCR ); 47 48 #define SET_XER(_arg) \ 49 __asm__ __volatile__ ("mtxer %0" : : "b"(_arg) : "xer" ); 50 51 #define GET_CR(_lval) \ 52 __asm__ __volatile__ ("mfcr %0" : "=b"(_lval) ) 53 54 #define GET_XER(_lval) \ 55 __asm__ __volatile__ ("mfxer %0" : "=b"(_lval) ) 56 57 #define GET_CR_XER(_lval_cr,_lval_xer) \ 58 do { GET_CR(_lval_cr); GET_XER(_lval_xer); } while (0) 59 60 #define SET_CR_ZERO \ 61 SET_CR(0) 62 63 #define SET_XER_ZERO \ 64 SET_XER(0) 65 66 #define SET_CR_XER_ZERO \ 67 do { SET_CR_ZERO; SET_XER_ZERO; } while (0) 68 69 #define SET_FPSCR_ZERO \ 70 do { double _d = 0.0; \ 71 __asm__ __volatile__ ("mtfsf 0xFF, %0" : : "f"(_d) ); \ 72 } while (0) 73 74 #define GET_FPSCR(_arg) \ 75 __asm__ __volatile__ ("mffs %0" : "=f"(_arg) ) 76 77 #define SET_FPSCR_DRN \ 78 __asm__ __volatile__ ("mtfsf 1, %0, 0, 1" : : "f"(f14) ) 79 80 81 // The assembly-level instructions being tested 82 static void _test_drintx(int R, int RMC) 83 { 84 if (RMC < 0 || RMC > 3 || R < 0 || R > 1) { 85 fprintf(stderr, "Invalid inputs to asm test: a=%d, b=%d\n", R, RMC); 86 return; 87 } 88 switch (RMC) { 89 case 0: 90 if (R) 91 __asm__ __volatile__ ("drintx 1, %0, %1, 0" : "=f" (f18) : "f" (f16)); 92 else 93 __asm__ __volatile__ ("drintx 0, %0, %1, 0" : "=f" (f18) : "f" (f16)); 94 break; 95 case 1: 96 if (R) 97 __asm__ __volatile__ ("drintx 1, %0, %1, 1" : "=f" (f18) : "f" (f16)); 98 else 99 __asm__ __volatile__ ("drintx 0, %0, %1, 1" : "=f" (f18) : "f" (f16)); 100 break; 101 case 2: 102 if (R) 103 __asm__ __volatile__ ("drintx 1, %0, %1, 2" : "=f" (f18) : "f" (f16)); 104 else 105 __asm__ __volatile__ ("drintx 0, %0, %1, 2" : "=f" (f18) : "f" (f16)); 106 break; 107 case 3: 108 if (R) 109 __asm__ __volatile__ ("drintx 1, %0, %1, 3" : "=f" (f18) : "f" (f16)); 110 else 111 __asm__ __volatile__ ("drintx 0, %0, %1, 3" : "=f" (f18) : "f" (f16)); 112 break; 113 default: 114 break; 115 } 116 } 117 118 static void _test_drintn(int R, int RMC) 119 { 120 if (RMC < 0 || RMC > 3 || R < 0 || R > 1) { 121 fprintf(stderr, "Invalid inputs to asm test: a=%d, b=%d\n", R, RMC); 122 return; 123 } 124 switch (RMC) { 125 case 0: 126 if (R) 127 __asm__ __volatile__ ("drintn 1, %0, %1, 0" : "=f" (f18) : "f" (f16)); 128 else 129 __asm__ __volatile__ ("drintn 0, %0, %1, 0" : "=f" (f18) : "f" (f16)); 130 break; 131 case 1: 132 if (R) 133 __asm__ __volatile__ ("drintn 1, %0, %1, 1" : "=f" (f18) : "f" (f16)); 134 else 135 __asm__ __volatile__ ("drintn 0, %0, %1, 1" : "=f" (f18) : "f" (f16)); 136 break; 137 case 2: 138 if (R) 139 __asm__ __volatile__ ("drintn 1, %0, %1, 2" : "=f" (f18) : "f" (f16)); 140 else 141 __asm__ __volatile__ ("drintn 0, %0, %1, 2" : "=f" (f18) : "f" (f16)); 142 break; 143 case 3: 144 if (R) 145 __asm__ __volatile__ ("drintn 1, %0, %1, 3" : "=f" (f18) : "f" (f16)); 146 else 147 __asm__ __volatile__ ("drintn 0, %0, %1, 3" : "=f" (f18) : "f" (f16)); 148 break; 149 default: 150 break; 151 } 152 } 153 154 155 static void _test_diex(int a __attribute__((unused)), int b __attribute__((unused))) 156 { 157 __asm__ __volatile__ ("diex %0, %1, %2" : "=f" (f18) : "f" (f14),"f" (f16)); 158 } 159 160 static void _test_dxex(int a __attribute__((unused)), int b __attribute__((unused))) 161 { 162 __asm__ __volatile__ ("dxex %0, %1" : "=f" (f18) : "f" (f16)); 163 } 164 165 static void _test_dcmpo(int BF, int x __attribute__((unused))) 166 { 167 if (BF < 0 || BF > 7) { 168 fprintf(stderr, "Invalid input to asm test: a=%d\n", BF); 169 return; 170 } 171 switch (BF) { 172 case 0: 173 __asm__ __volatile__ ("dcmpo 0, %0, %1" : : "f" (f14),"f" (f16)); 174 break; 175 case 1: 176 __asm__ __volatile__ ("dcmpo 1, %0, %1" : : "f" (f14),"f" (f16)); 177 break; 178 case 2: 179 __asm__ __volatile__ ("dcmpo 2, %0, %1" : : "f" (f14),"f" (f16)); 180 break; 181 case 3: 182 __asm__ __volatile__ ("dcmpo 3, %0, %1" : : "f" (f14),"f" (f16)); 183 break; 184 case 4: 185 __asm__ __volatile__ ("dcmpo 4, %0, %1" : : "f" (f14),"f" (f16)); 186 break; 187 case 5: 188 __asm__ __volatile__ ("dcmpo 5, %0, %1" : : "f" (f14),"f" (f16)); 189 break; 190 case 6: 191 __asm__ __volatile__ ("dcmpo 6, %0, %1" : : "f" (f14),"f" (f16)); 192 break; 193 case 7: 194 __asm__ __volatile__ ("dcmpo 7, %0, %1" : : "f" (f14),"f" (f16)); 195 break; 196 default: 197 break; 198 } 199 } 200 201 static void _test_dcmpu(int BF, int x __attribute__((unused))) 202 { 203 if (BF < 0 || BF > 7) { 204 fprintf(stderr, "Invalid input to asm test: a=%d\n", BF); 205 return; 206 } 207 switch (BF) { 208 case 0: 209 __asm__ __volatile__ ("dcmpu 0, %0, %1" : : "f" (f14),"f" (f16)); 210 break; 211 case 1: 212 __asm__ __volatile__ ("dcmpu 1, %0, %1" : : "f" (f14),"f" (f16)); 213 break; 214 case 2: 215 __asm__ __volatile__ ("dcmpu 2, %0, %1" : : "f" (f14),"f" (f16)); 216 break; 217 case 3: 218 __asm__ __volatile__ ("dcmpu 3, %0, %1" : : "f" (f14),"f" (f16)); 219 break; 220 case 4: 221 __asm__ __volatile__ ("dcmpu 4, %0, %1" : : "f" (f14),"f" (f16)); 222 break; 223 case 5: 224 __asm__ __volatile__ ("dcmpu 5, %0, %1" : : "f" (f14),"f" (f16)); 225 break; 226 case 6: 227 __asm__ __volatile__ ("dcmpu 6, %0, %1" : : "f" (f14),"f" (f16)); 228 break; 229 case 7: 230 __asm__ __volatile__ ("dcmpu 7, %0, %1" : : "f" (f14),"f" (f16)); 231 break; 232 default: 233 break; 234 } 235 } 236 237 // Quad instruction testing 238 static void _test_drintxq(int R, int RMC) 239 { 240 if (RMC < 0 || RMC > 3 || R < 0 || R > 1) { 241 fprintf(stderr, "Invalid inputs to asm test: a=%d, b=%d\n", R, RMC); 242 return; 243 } 244 switch (RMC) { 245 case 0: 246 if (R) 247 __asm__ __volatile__ ("drintxq 1, %0, %1, 0" : "=f" (f18) : "f" (f16)); 248 else 249 __asm__ __volatile__ ("drintxq 0, %0, %1, 0" : "=f" (f18) : "f" (f16)); 250 break; 251 case 1: 252 if (R) 253 __asm__ __volatile__ ("drintxq 1, %0, %1, 1" : "=f" (f18) : "f" (f16)); 254 else 255 __asm__ __volatile__ ("drintxq 0, %0, %1, 1" : "=f" (f18) : "f" (f16)); 256 break; 257 case 2: 258 if (R) 259 __asm__ __volatile__ ("drintxq 1, %0, %1, 2" : "=f" (f18) : "f" (f16)); 260 else 261 __asm__ __volatile__ ("drintxq 0, %0, %1, 2" : "=f" (f18) : "f" (f16)); 262 break; 263 case 3: 264 if (R) 265 __asm__ __volatile__ ("drintxq 1, %0, %1, 3" : "=f" (f18) : "f" (f16)); 266 else 267 __asm__ __volatile__ ("drintxq 0, %0, %1, 3" : "=f" (f18) : "f" (f16)); 268 break; 269 default: 270 break; 271 } 272 } 273 274 static void _test_drintnq(int R, int RMC) 275 { 276 if (RMC < 0 || RMC > 3 || R < 0 || R > 1) { 277 fprintf(stderr, "Invalid inputs to asm test: a=%d, b=%d\n", R, RMC); 278 return; 279 } 280 switch (RMC) { 281 case 0: 282 if (R) 283 __asm__ __volatile__ ("drintnq 1, %0, %1, 0" : "=f" (f18) : "f" (f16)); 284 else 285 __asm__ __volatile__ ("drintnq 0, %0, %1, 0" : "=f" (f18) : "f" (f16)); 286 break; 287 case 1: 288 if (R) 289 __asm__ __volatile__ ("drintnq 1, %0, %1, 1" : "=f" (f18) : "f" (f16)); 290 else 291 __asm__ __volatile__ ("drintnq 0, %0, %1, 1" : "=f" (f18) : "f" (f16)); 292 break; 293 case 2: 294 if (R) 295 __asm__ __volatile__ ("drintnq 1, %0, %1, 2" : "=f" (f18) : "f" (f16)); 296 else 297 __asm__ __volatile__ ("drintnq 0, %0, %1, 2" : "=f" (f18) : "f" (f16)); 298 break; 299 case 3: 300 if (R) 301 __asm__ __volatile__ ("drintnq 1, %0, %1, 3" : "=f" (f18) : "f" (f16)); 302 else 303 __asm__ __volatile__ ("drintnq 0, %0, %1, 3" : "=f" (f18) : "f" (f16)); 304 break; 305 default: 306 break; 307 } 308 } 309 310 static void _test_diexq(int a __attribute__((unused)), int b __attribute__((unused))) 311 { 312 __asm__ __volatile__ ("diexq %0, %1, %2" : "=f" (f18) : "f" (f14),"f" (f16)); 313 } 314 315 static void _test_dxexq(int a __attribute__((unused)), int b __attribute__((unused))) 316 { 317 __asm__ __volatile__ ("dxexq %0, %1" : "=f" (f18) : "f" (f16)); 318 } 319 320 static void _test_dcmpoq(int BF, int x __attribute__((unused))) 321 { 322 if (BF < 0 || BF > 7) { 323 fprintf(stderr, "Invalid input to asm test: a=%d\n", BF ); 324 return; 325 } 326 switch (BF) { 327 case 0: 328 __asm__ __volatile__ ("dcmpoq 0, %0, %1" : : "f" (f14),"f" (f16)); 329 break; 330 case 1: 331 __asm__ __volatile__ ("dcmpoq 1, %0, %1" : : "f" (f14),"f" (f16)); 332 break; 333 case 2: 334 __asm__ __volatile__ ("dcmpoq 2, %0, %1" : : "f" (f14),"f" (f16)); 335 break; 336 case 3: 337 __asm__ __volatile__ ("dcmpoq 3, %0, %1" : : "f" (f14),"f" (f16)); 338 break; 339 case 4: 340 __asm__ __volatile__ ("dcmpoq 4, %0, %1" : : "f" (f14),"f" (f16)); 341 break; 342 case 5: 343 __asm__ __volatile__ ("dcmpoq 5, %0, %1" : : "f" (f14),"f" (f16)); 344 break; 345 case 6: 346 __asm__ __volatile__ ("dcmpoq 6, %0, %1" : : "f" (f14),"f" (f16)); 347 break; 348 case 7: 349 __asm__ __volatile__ ("dcmpoq 7, %0, %1" : : "f" (f14),"f" (f16)); 350 break; 351 default: 352 break; 353 } 354 } 355 356 static void _test_dcmpuq(int BF, int x __attribute__((unused))) 357 { 358 if (BF < 0 || BF > 7) { 359 fprintf(stderr, "Invalid input to asm test: a=%d\n", BF); 360 return; 361 } 362 switch (BF) { 363 case 0: 364 __asm__ __volatile__ ("dcmpuq 0, %0, %1" : : "f" (f14),"f" (f16)); 365 break; 366 case 1: 367 __asm__ __volatile__ ("dcmpuq 1, %0, %1" : : "f" (f14),"f" (f16)); 368 break; 369 case 2: 370 __asm__ __volatile__ ("dcmpuq 2, %0, %1" : : "f" (f14),"f" (f16)); 371 break; 372 case 3: 373 __asm__ __volatile__ ("dcmpuq 3, %0, %1" : : "f" (f14),"f" (f16)); 374 break; 375 case 4: 376 __asm__ __volatile__ ("dcmpuq 4, %0, %1" : : "f" (f14),"f" (f16)); 377 break; 378 case 5: 379 __asm__ __volatile__ ("dcmpuq 5, %0, %1" : : "f" (f14),"f" (f16)); 380 break; 381 case 6: 382 __asm__ __volatile__ ("dcmpuq 6, %0, %1" : : "f" (f14),"f" (f16)); 383 break; 384 case 7: 385 __asm__ __volatile__ ("dcmpuq 7, %0, %1" : : "f" (f14),"f" (f16)); 386 break; 387 default: 388 break; 389 } 390 } 391 392 static void _test_drrnd(int x __attribute__((unused)), int RMC) 393 { 394 if (RMC < 0 || RMC > 31) { 395 fprintf(stderr, "Invalid input to asm test: a=%d\n", RMC); 396 return; 397 } 398 switch (RMC) { 399 case 0: 400 __asm__ __volatile__ ("drrnd %0, %1, %2, 0" : "=f" (f18) : "f" (f14), "f" (f16)); 401 break; 402 case 1: 403 __asm__ __volatile__ ("drrnd %0, %1, %2, 1" : "=f" (f18) : "f" (f14), "f" (f16)); 404 break; 405 case 2: 406 __asm__ __volatile__ ("drrnd %0, %1, %2, 2" : "=f" (f18) : "f" (f14), "f" (f16)); 407 break; 408 case 3: 409 __asm__ __volatile__ ("drrnd %0, %1, %2, 3" : "=f" (f18) : "f" (f14), "f" (f16)); 410 break; 411 default: 412 break; 413 } 414 } 415 416 static void _test_drrndq(int x __attribute__((unused)), int RMC) 417 { 418 if (RMC < 0 || RMC > 3) { 419 fprintf(stderr, "Invalid input to asm test: a=%dn", RMC); 420 return; 421 } 422 switch (RMC) { 423 case 0: 424 __asm__ __volatile__ ("drrndq %0, %1, %2, 0" : "=f" (f18) : "f" (f14), "f" (f16)); 425 break; 426 case 1: 427 __asm__ __volatile__ ("drrndq %0, %1, %2, 1" : "=f" (f18) : "f" (f14), "f" (f16)); 428 break; 429 case 2: 430 __asm__ __volatile__ ("drrndq %0, %1, %2, 2" : "=f" (f18) : "f" (f14), "f" (f16)); 431 break; 432 case 3: 433 __asm__ __volatile__ ("drrndq %0, %1, %2, 3" : "=f" (f18) : "f" (f14), "f" (f16)); 434 break; 435 default: 436 break; 437 } 438 } 439 440 static void _test_dqua(int x __attribute__((unused)), int RMC) 441 { 442 if (RMC < 0 || RMC > 3) { 443 fprintf(stderr, "Invalid input to asm test: a=%d\n", RMC); 444 return; 445 } 446 switch (RMC) { 447 case 0: 448 __asm__ __volatile__ ("dqua %0, %1, %2, 0" : "=f" (f18) : "f" (f14), "f" (f16)); 449 break; 450 case 1: 451 __asm__ __volatile__ ("dqua %0, %1, %2, 1" : "=f" (f18) : "f" (f14), "f" (f16)); 452 break; 453 case 2: 454 __asm__ __volatile__ ("dqua %0, %1, %2, 2" : "=f" (f18) : "f" (f14), "f" (f16)); 455 break; 456 case 3: 457 __asm__ __volatile__ ("dqua %0, %1, %2, 3" : "=f" (f18) : "f" (f14), "f" (f16)); 458 break; 459 default: 460 break; 461 } 462 } 463 464 static void _test_dquaq(int x __attribute__((unused)), int RMC) 465 { 466 if (RMC < 0 || RMC > 3) { 467 fprintf(stderr, "Invalid input to asm test: a=%d\n", RMC); 468 return; 469 } 470 switch (RMC) { 471 case 0: 472 __asm__ __volatile__ ("dquaq %0, %1, %2, 0" : "=f" (f18) : "f" (f14), "f" (f16)); 473 break; 474 case 1: 475 __asm__ __volatile__ ("dquaq %0, %1, %2, 1" : "=f" (f18) : "f" (f14), "f" (f16)); 476 break; 477 case 2: 478 __asm__ __volatile__ ("dquaq %0, %1, %2, 2" : "=f" (f18) : "f" (f14), "f" (f16)); 479 break; 480 case 3: 481 __asm__ __volatile__ ("dquaq %0, %1, %2, 3" : "=f" (f18) : "f" (f14), "f" (f16)); 482 break; 483 default: 484 break; 485 } 486 } 487 488 static int TE_vals[] = { -16, -2, 0, 5}; 489 #define TE_VAL_LEN sizeof(TE_vals)/sizeof(int) 490 static Bool __is_TE_val(int x) 491 { 492 int i; 493 for (i = 0; i < TE_VAL_LEN; i++) { 494 if (x==TE_vals[i]) 495 return True; 496 } 497 return False; 498 } 499 500 static void _test_dquai(int TE, int RMC) 501 { 502 if (RMC < 0 || RMC > 3 || !__is_TE_val(TE)) { 503 fprintf(stderr, "Invalid inputs to asm test: a=%d, b=%d\n", TE, RMC); 504 return; 505 } 506 switch (RMC) { 507 case 0: 508 switch (TE) { 509 case -16: 510 __asm__ __volatile__ ("dquai -16, %0, %1, 0" : "=f" (f18) : "f" (f16)); 511 break; 512 case -2: 513 __asm__ __volatile__ ("dquai -2, %0, %1, 0" : "=f" (f18) : "f" (f16)); 514 break; 515 case 0: 516 __asm__ __volatile__ ("dquai 0, %0, %1, 0" : "=f" (f18) : "f" (f16)); 517 break; 518 case 5: 519 __asm__ __volatile__ ("dquai 5, %0, %1, 0" : "=f" (f18) : "f" (f16)); 520 break; 521 default: 522 break; 523 } 524 break; 525 case 1: 526 switch (TE) { 527 case -16: 528 __asm__ __volatile__ ("dquai -16, %0, %1, 1" : "=f" (f18) : "f" (f16)); 529 break; 530 case -2: 531 __asm__ __volatile__ ("dquai -2, %0, %1, 1" : "=f" (f18) : "f" (f16)); 532 break; 533 case 0: 534 __asm__ __volatile__ ("dquai 0, %0, %1, 1" : "=f" (f18) : "f" (f16)); 535 break; 536 case 5: 537 __asm__ __volatile__ ("dquai 5, %0, %1, 1" : "=f" (f18) : "f" (f16)); 538 break; 539 default: 540 break; 541 } 542 break; 543 case 2: 544 switch (TE) { 545 case -16: 546 __asm__ __volatile__ ("dquai -16, %0, %1, 2" : "=f" (f18) : "f" (f16)); 547 break; 548 case -2: 549 __asm__ __volatile__ ("dquai -2, %0, %1, 2" : "=f" (f18) : "f" (f16)); 550 break; 551 case 0: 552 __asm__ __volatile__ ("dquai 0, %0, %1, 2" : "=f" (f18) : "f" (f16)); 553 break; 554 case 5: 555 __asm__ __volatile__ ("dquai 5, %0, %1, 2" : "=f" (f18) : "f" (f16)); 556 break; 557 default: 558 break; 559 } 560 break; 561 case 3: 562 switch (TE) { 563 case -16: 564 __asm__ __volatile__ ("dquai -16, %0, %1, 3" : "=f" (f18) : "f" (f16)); 565 break; 566 case -2: 567 __asm__ __volatile__ ("dquai -2, %0, %1, 3" : "=f" (f18) : "f" (f16)); 568 break; 569 case 0: 570 __asm__ __volatile__ ("dquai 0, %0, %1, 3" : "=f" (f18) : "f" (f16)); 571 break; 572 case 5: 573 __asm__ __volatile__ ("dquai 5, %0, %1, 3" : "=f" (f18) : "f" (f16)); 574 break; 575 default: 576 break; 577 } 578 break; 579 default: 580 break; 581 } 582 } 583 584 static void _test_dquaiq(int TE, int RMC) 585 { 586 if (RMC < 0 || RMC > 3 || !__is_TE_val(TE)) { 587 fprintf(stderr, "Invalid inputs to asm test: a=%d, b=%d\n", TE, RMC); 588 return; 589 } 590 switch (RMC) { 591 case 0: 592 switch (TE) { 593 case -16: 594 __asm__ __volatile__ ("dquaiq -16, %0, %1, 0" : "=f" (f18) : "f" (f16)); 595 break; 596 case -2: 597 __asm__ __volatile__ ("dquaiq -2, %0, %1, 0" : "=f" (f18) : "f" (f16)); 598 break; 599 case 0: 600 __asm__ __volatile__ ("dquaiq 0, %0, %1, 0" : "=f" (f18) : "f" (f16)); 601 break; 602 case 5: 603 __asm__ __volatile__ ("dquaiq 5, %0, %1, 0" : "=f" (f18) : "f" (f16)); 604 break; 605 default: 606 break; 607 } 608 break; 609 case 1: 610 switch (TE) { 611 case -16: 612 __asm__ __volatile__ ("dquaiq -16, %0, %1, 1" : "=f" (f18) : "f" (f16)); 613 break; 614 case -2: 615 __asm__ __volatile__ ("dquaiq -2, %0, %1, 1" : "=f" (f18) : "f" (f16)); 616 break; 617 case 0: 618 __asm__ __volatile__ ("dquaiq 0, %0, %1, 1" : "=f" (f18) : "f" (f16)); 619 break; 620 case 5: 621 __asm__ __volatile__ ("dquaiq 5, %0, %1, 1" : "=f" (f18) : "f" (f16)); 622 break; 623 default: 624 break; 625 } 626 break; 627 case 2: 628 switch (TE) { 629 case -16: 630 __asm__ __volatile__ ("dquaiq -16, %0, %1, 2" : "=f" (f18) : "f" (f16)); 631 break; 632 case -2: 633 __asm__ __volatile__ ("dquaiq -2, %0, %1, 2" : "=f" (f18) : "f" (f16)); 634 break; 635 case 0: 636 __asm__ __volatile__ ("dquaiq 0, %0, %1, 2" : "=f" (f18) : "f" (f16)); 637 break; 638 case 5: 639 __asm__ __volatile__ ("dquaiq 5, %0, %1, 2" : "=f" (f18) : "f" (f16)); 640 break; 641 default: 642 break; 643 } 644 break; 645 case 3: 646 switch (TE) { 647 case -16: 648 __asm__ __volatile__ ("dquaiq -16, %0, %1, 3" : "=f" (f18) : "f" (f16)); 649 break; 650 case -2: 651 __asm__ __volatile__ ("dquaiq -2, %0, %1, 3" : "=f" (f18) : "f" (f16)); 652 break; 653 case 0: 654 __asm__ __volatile__ ("dquaiq 0, %0, %1, 3" : "=f" (f18) : "f" (f16)); 655 break; 656 case 5: 657 __asm__ __volatile__ ("dquaiq 5, %0, %1, 3" : "=f" (f18) : "f" (f16)); 658 break; 659 default: 660 break; 661 } 662 break; 663 default: 664 break; 665 } 666 } 667 668 669 typedef void (*test_func_t)(int a, int b); 670 typedef void (*test_driver_func_t)(void); 671 typedef struct test_table 672 { 673 test_driver_func_t test_category; 674 char * name; 675 } test_table_t; 676 677 /* 678 * 345.0DD (0x2207c00000000000 0xe50) 679 * 1.2300e+5DD (0x2207c00000000000 0x14c000) 680 * -16.0DD (0xa207c00000000000 0xe0) 681 * 0.00189DD (0x2206c00000000000 0xcf) 682 * -4.1235DD (0xa205c00000000000 0x10a395bcf) 683 * 9.8399e+20DD (0x2209400000000000 0x253f1f534acdd4) 684 * 0DD (0x2208000000000000 0x0) 685 * 0DD (0x2208000000000000 0x0) 686 * infDD (0x7800000000000000 0x0) 687 * nanDD (0x7c00000000000000 0x0 688 */ 689 static unsigned long long dfp128_vals[] = { 690 // Some finite numbers 691 0x2207c00000000000ULL, 0x0000000000000e50ULL, 692 0x2207c00000000000ULL, 0x000000000014c000ULL, 693 0xa207c00000000000ULL, 0x00000000000000e0ULL, 694 0x2206c00000000000ULL, 0x00000000000000cfULL, 695 0xa205c00000000000ULL, 0x000000010a395bcfULL, 696 0x6209400000fd0000ULL, 0x00253f1f534acdd4ULL, // huge number 697 0x000400000089b000ULL, 0x0a6000d000000049ULL, // very small number 698 // flavors of zero 699 0x2208000000000000ULL, 0x0000000000000000ULL, 700 0xa208000000000000ULL, 0x0000000000000000ULL, // negative 701 0xa248000000000000ULL, 0x0000000000000000ULL, 702 // flavors of NAN 703 0x7c00000000000000ULL, 0x0000000000000000ULL, // quiet 704 0xfc00000000000000ULL, 0xc00100035b007700ULL, 705 0x7e00000000000000ULL, 0xfe000000d0e0a0d0ULL, // signaling 706 // flavors of Infinity 707 0x7800000000000000ULL, 0x0000000000000000ULL, 708 0xf800000000000000ULL, 0x0000000000000000ULL, // negative 709 0xf900000000000000ULL, 0x0000000000000000ULL 710 }; 711 712 static unsigned long long dfp64_vals[] = { 713 // various finite numbers 714 0x2234000000000e50ULL, 715 0x223400000014c000ULL, 716 0xa2340000000000e0ULL,// negative 717 0x22240000000000cfULL, 718 0xa21400010a395bcfULL,// negative 719 0x6e4d3f1f534acdd4ULL,// huge number 720 0x000400000089b000ULL,// very small number 721 // flavors of zero 722 0x2238000000000000ULL, 723 0xa238000000000000ULL, 724 0x4248000000000000ULL, 725 // flavors of NAN 726 0x7e34000000000111ULL, 727 0xfe000000d0e0a0d0ULL,//signaling 728 0xfc00000000000000ULL,//quiet 729 // flavors of Infinity 730 0x7800000000000000ULL, 731 0xf800000000000000ULL,//negative 732 0x7a34000000000000ULL, 733 }; 734 735 // Both Long and Quad arrays of DFP values should have the same length. 736 // If that length is changed, t 737 #define NUM_DFP_VALS (sizeof(dfp64_vals)/8) 738 739 typedef struct dfp_test_args { 740 int fra_idx; 741 int frb_idx; 742 } dfp_test_args_t; 743 744 745 // Index pairs from dfp64_vals array to be used with dfp_two_arg_tests 746 static dfp_test_args_t dfp_2args_x1[] = { 747 {0, 1}, 748 {2, 1}, 749 {3, 4}, 750 {0, 6}, 751 {2, 4}, 752 {5, 1}, 753 {5, 2}, 754 {7, 1}, 755 {7, 2}, 756 {8, 0}, 757 {8, 1}, 758 {8, 2}, 759 {7, 8}, 760 {12, 14}, 761 {12, 1}, 762 {12, 13}, 763 {12, 12}, 764 {12, 11}, 765 {11, 14}, 766 {11, 0}, 767 {11, 13}, 768 {11, 11}, 769 {14, 14}, 770 {14, 3}, 771 {14, 15}, 772 }; 773 774 typedef enum { 775 LONG_TEST, 776 QUAD_TEST 777 } precision_type_t; 778 779 typedef struct dfp_test 780 { 781 test_func_t test_func; 782 const char * name; 783 dfp_test_args_t * targs; 784 int num_tests; 785 precision_type_t precision; 786 const char * op; 787 } dfp_test_t; 788 789 typedef struct dfp_one_arg_test 790 { 791 test_func_t test_func; 792 const char * name; 793 precision_type_t precision; 794 const char * op; 795 } dfp_one_arg_test_t; 796 797 798 static dfp_one_arg_test_t 799 dfp_quai_tests[] = { 800 { &_test_dquai, "dquai", LONG_TEST, "[QI]"}, 801 { &_test_dquaiq, "dquaiq", QUAD_TEST, "[QI]"}, 802 { NULL, NULL, 0, NULL} 803 }; 804 805 static void test_dfp_quai_ops(void) 806 { 807 test_func_t func; 808 unsigned long long u0, u0x; 809 double res, d0, *d0p, d0x, *d0xp; 810 811 int k = 0; 812 u0 = u0x = 0; 813 d0p = &d0; 814 d0xp = &d0x; 815 816 while ((func = dfp_quai_tests[k].test_func)) { 817 int i; 818 dfp_one_arg_test_t test_def = dfp_quai_tests[k]; 819 820 for (i = 0; i < NUM_DFP_VALS; i++) { 821 int TE, RMC; 822 823 if (test_def.precision == LONG_TEST) { 824 u0 = dfp64_vals[i]; 825 } else { 826 u0 = dfp128_vals[i * 2]; 827 u0x = dfp128_vals[(i * 2) + 1]; 828 } 829 *(unsigned long long *)d0p = u0; 830 f16 = d0; 831 if (test_def.precision == QUAD_TEST) { 832 *(unsigned long long *)d0xp = u0x; 833 f17 = d0x; 834 } 835 836 for (TE = 0; TE < TE_VAL_LEN; TE++) { 837 for (RMC = 0; RMC < 4; RMC++) { 838 (*func)(TE_vals[TE], RMC); 839 res = f18; 840 printf("%s (RMC=%2d, TE=%3d) %s %016llx", test_def.name, RMC, 841 TE_vals[TE], test_def.op, u0); 842 if (test_def.precision == LONG_TEST) { 843 printf(" => %016llx\n", 844 *((unsigned long long *)(&res))); 845 } else { 846 double resx = f19; 847 printf(" %016llx ==> %016llx %016llx\n", 848 u0x, *((unsigned long long *)(&res)), *((unsigned long long *)(&resx))); 849 } 850 } 851 } 852 } 853 k++; 854 printf( "\n" ); 855 } 856 } 857 858 859 static dfp_test_t 860 dfp_qua_tests[] = { 861 { &_test_dqua, "dqua", dfp_2args_x1, 25, LONG_TEST, "[Q]"}, 862 { &_test_dquaq, "dquaq", dfp_2args_x1, 25, QUAD_TEST, "[Q]"}, 863 { NULL, NULL, NULL, 0, 0, NULL} 864 }; 865 866 static void test_dfp_qua_ops(void) 867 { 868 test_func_t func; 869 unsigned long long u0, u0x, u1, u1x; 870 double res, d0, d1, *d0p, *d1p; 871 double d0x, d1x, *d0xp, *d1xp; 872 int k = 0; 873 u0x = u1x = 0; 874 d0p = &d0; 875 d0xp = &d0x; 876 d1p = &d1; 877 d1xp = &d1x; 878 879 while ((func = dfp_qua_tests[k].test_func)) { 880 int i, RMC; 881 dfp_test_t test_def = dfp_qua_tests[k]; 882 883 for (i = 0; i < test_def.num_tests; i++) { 884 if (test_def.precision == LONG_TEST) { 885 u0 = dfp64_vals[test_def.targs[i].fra_idx]; 886 u1 = dfp64_vals[test_def.targs[i].frb_idx]; 887 } else { 888 u0 = dfp128_vals[test_def.targs[i].fra_idx * 2]; 889 u0x = dfp128_vals[(test_def.targs[i].fra_idx * 2) + 1]; 890 u1 = dfp128_vals[test_def.targs[i].frb_idx * 2]; 891 u1x = dfp128_vals[(test_def.targs[i].frb_idx * 2) + 1]; 892 } 893 *(unsigned long long *)d0p = u0; 894 *(unsigned long long *)d1p = u1; 895 f14 = d0; 896 f16 = d1; 897 if (test_def.precision == QUAD_TEST) { 898 *(unsigned long long *)d0xp = u0x; 899 *(unsigned long long *)d1xp = u1x; 900 f15 = d0x; 901 f17 = d1x; 902 } 903 for (RMC = 0; RMC < 4; RMC++) { 904 (*func)(-1, RMC); 905 res = f18; 906 printf("%s (RMC=%2d) %s %016llx", test_def.name, RMC, test_def.op, u0); 907 if (test_def.precision == LONG_TEST) { 908 printf(", %016llx => %016llx\n", u1, *((unsigned long long *)(&res))); 909 } else { 910 double resx = f19; 911 printf(" %016llx, %016llx %016llx ==> %016llx %016llx\n",u0x, u1, u1x, 912 *((unsigned long long *)(&res)), *((unsigned long long *)(&resx))); 913 } 914 } 915 } 916 k++; 917 printf( "\n" ); 918 } 919 } 920 921 922 static dfp_one_arg_test_t 923 dfp_rrnd_tests[] = { 924 { &_test_drrnd, "drrnd", LONG_TEST, "[RR]"}, 925 { &_test_drrndq, "drrndq", QUAD_TEST, "[RR]"}, 926 { NULL, NULL, 0, NULL} 927 }; 928 929 static void test_dfp_rrnd_ops(void) 930 { 931 test_func_t func; 932 unsigned long long u0, u0x; 933 double res, d0, *d0p, d0x, *d0xp, reference_sig, *reference_sig_p; 934 long long reference_sig_vals[] = {0ULL, 2ULL, 6ULL, 63ULL}; 935 int num_reference_sig_vals = sizeof(reference_sig_vals)/sizeof(long long); 936 937 int k = 0; 938 u0 = u0x = 0; 939 d0p = &d0; 940 d0xp = &d0x; 941 reference_sig_p = &reference_sig; 942 943 while ((func = dfp_rrnd_tests[k].test_func)) { 944 int i, j; 945 dfp_one_arg_test_t test_def = dfp_rrnd_tests[k]; 946 947 for (i = 0; i < NUM_DFP_VALS; i++) { 948 int RMC; 949 950 if (test_def.precision == LONG_TEST) { 951 u0 = dfp64_vals[i]; 952 } else { 953 u0 = dfp128_vals[i * 2]; 954 u0x = dfp128_vals[(i * 2) + 1]; 955 } 956 *(unsigned long long *)d0p = u0; 957 f16 = d0; 958 if (test_def.precision == QUAD_TEST) { 959 *(unsigned long long *)d0xp = u0x; 960 f17 = d0x; 961 } 962 963 for (j = 0; j < num_reference_sig_vals; j++) { 964 *(long long *)reference_sig_p = reference_sig_vals[j]; 965 f14 = reference_sig; 966 for (RMC = 0; RMC < 4; RMC++) { 967 (*func)(-1, RMC); 968 res = f18; 969 printf("%s (RMC=%d, ref sig=%d) %s%016llx", test_def.name, RMC, 970 (int)reference_sig_vals[j], test_def.op, u0); 971 if (test_def.precision == LONG_TEST) { 972 printf(" => %016llx\n", 973 *((unsigned long long *)(&res))); 974 } else { 975 double resx = f19; 976 printf(" %016llx ==> %016llx %016llx\n", 977 u0x, *((unsigned long long *)(&res)), *((unsigned long long *)(&resx))); 978 } 979 } 980 } 981 } 982 k++; 983 printf( "\n" ); 984 } 985 } 986 987 988 static dfp_one_arg_test_t 989 dfp_xiex_tests[] = { 990 { &_test_diex, "diex", LONG_TEST, ">>"}, 991 { &_test_diexq, "diexq", QUAD_TEST, ">>"}, 992 { &_test_dxex, "dxex", LONG_TEST, "<<"}, 993 { &_test_dxexq, "dxexq", QUAD_TEST, "<<"}, 994 { NULL, NULL, 0, NULL} 995 }; 996 997 static void test_dfp_xiex_ops(void) 998 { 999 test_func_t func; 1000 unsigned long long u0, u0x; 1001 double res, d0, *d0p, d0x, *d0xp, target_exp, *target_exp_p; 1002 /* The first two positions are placeholders and will be filled in later, 1003 * based on the precision of the DFP argument. 1004 */ 1005 long long target_exp_vals[] = {0ULL, 0ULL, 0ULL, -1ULL, -2ULL, -3ULL, -4ULL, -5ULL}; 1006 int num_exp_vals = sizeof(target_exp_vals)/sizeof(long long); 1007 int k = 0; 1008 u0 = u0x = 0; 1009 d0p = &d0; 1010 d0xp = &d0x; 1011 target_exp_p = &target_exp; 1012 1013 while ((func = dfp_xiex_tests[k].test_func)) { 1014 int i; 1015 Bool insert_insn = False; 1016 dfp_one_arg_test_t test_def = dfp_xiex_tests[k]; 1017 1018 if (!strncmp(test_def.name, "di", 2)) 1019 insert_insn = True; 1020 1021 if (test_def.precision == QUAD_TEST) { 1022 target_exp_vals[0] = 12288ULL; // > max biased exponent 1023 target_exp_vals[1] = 5235ULL; 1024 } else { 1025 target_exp_vals[0] = 768ULL; // > max biased exponent 1026 target_exp_vals[1] = 355ULL; 1027 } 1028 1029 for (i = 0; i < NUM_DFP_VALS; i++) { 1030 unsigned int j; 1031 1032 if (test_def.precision == QUAD_TEST) { 1033 u0 = dfp128_vals[i * 2]; 1034 u0x = dfp128_vals[(i * 2) + 1]; 1035 } else { 1036 u0 = dfp64_vals[i]; 1037 } 1038 *(unsigned long long *)d0p = u0; 1039 f16 = d0; 1040 if (test_def.precision == QUAD_TEST) { 1041 *(unsigned long long *)d0xp = u0x; 1042 f17 = d0x; 1043 } 1044 1045 if (!insert_insn) { 1046 // This is just for extract insns (dexex[q]) 1047 (*func)(0, 0); 1048 res = f18; 1049 printf("%s %s ", test_def.name, test_def.op); 1050 if (test_def.precision == LONG_TEST) { 1051 printf("%016llx => %016llx\n", u0, 1052 *((unsigned long long *)(&res))); 1053 } else { 1054 double resx = f19; 1055 printf("%016llx %016llx ==> %016llx %016llx\n", u0, u0x, 1056 *((unsigned long long *)(&res)), *((unsigned long long *)(&resx))); 1057 } 1058 continue; 1059 } 1060 // The following for-loop is just for insert insns (diex[q]) 1061 for (j = 0; j < num_exp_vals; j++) { 1062 *(long long *)target_exp_p = target_exp_vals[j]; 1063 f14 = target_exp; 1064 (*func)(0, 0); 1065 res = f18; 1066 printf("%s %s %5d, ", test_def.name, test_def.op, (int)target_exp_vals[j]); 1067 1068 if (test_def.precision == LONG_TEST) { 1069 printf("%016llx => %016llx\n", u0, 1070 *((unsigned long long *)(&res))); 1071 } else { 1072 double resx = f19; 1073 printf("%016llx %016llx ==> %016llx %016llx\n", u0, u0x, 1074 *((unsigned long long *)(&res)), *((unsigned long long *)(&resx))); 1075 } 1076 } 1077 } 1078 k++; 1079 printf( "\n" ); 1080 } 1081 } 1082 1083 static dfp_one_arg_test_t 1084 dfp_rint_tests[] = { 1085 { &_test_drintn, "drintn", LONG_TEST, "~"}, 1086 { &_test_drintnq, "drintnq", QUAD_TEST, "~"}, 1087 { &_test_drintx, "drintx", LONG_TEST, "~"}, 1088 { &_test_drintxq, "drintxq", QUAD_TEST, "~"}, 1089 { NULL, NULL, 0, NULL} 1090 }; 1091 1092 static void test_dfp_rint_ops(void) 1093 { 1094 test_func_t func; 1095 unsigned long long u0, u0x; 1096 double res, d0, *d0p, d0x, *d0xp; 1097 int k = 0; 1098 u0 = u0x = 0; 1099 d0p = &d0; 1100 d0xp = &d0x; 1101 1102 while ((func = dfp_rint_tests[k].test_func)) { 1103 int i; 1104 dfp_one_arg_test_t test_def = dfp_rint_tests[k]; 1105 1106 for (i = 0; i < NUM_DFP_VALS; i++) { 1107 int R, RMC; 1108 1109 if (test_def.precision == LONG_TEST) { 1110 u0 = dfp64_vals[i]; 1111 } else { 1112 u0 = dfp128_vals[i * 2]; 1113 u0x = dfp128_vals[(i * 2) + 1]; 1114 } 1115 *(unsigned long long *)d0p = u0; 1116 f16 = d0; 1117 if (test_def.precision == QUAD_TEST) { 1118 *(unsigned long long *)d0xp = u0x; 1119 f17 = d0x; 1120 } 1121 1122 for (R = 0; R < 2; R++) { 1123 for (RMC = 0; RMC < 4; RMC++) { 1124 (*func)(R, RMC); 1125 res = f18; 1126 printf("%s (RM=%d) %s%016llx", test_def.name, (RMC + (R << 2)), test_def.op, u0); 1127 if (test_def.precision == LONG_TEST) { 1128 printf(" => %016llx\n", 1129 *((unsigned long long *)(&res))); 1130 } else { 1131 double resx = f19; 1132 printf(" %016llx ==> %016llx %016llx\n", 1133 u0x, *((unsigned long long *)(&res)), *((unsigned long long *)(&resx))); 1134 } 1135 } 1136 } 1137 } 1138 k++; 1139 printf( "\n" ); 1140 } 1141 } 1142 1143 static dfp_test_t 1144 dfp_cmp_tests[] = { 1145 { &_test_dcmpo, "dcmpo", dfp_2args_x1, 25, LONG_TEST, "<>"}, 1146 { &_test_dcmpoq, "dcmpoq", dfp_2args_x1, 25, QUAD_TEST, "<>"}, 1147 { &_test_dcmpu, "dcmpu", dfp_2args_x1, 25, LONG_TEST, "<>"}, 1148 { &_test_dcmpuq, "dcmpuq", dfp_2args_x1, 25, QUAD_TEST, "<>"}, 1149 { NULL, NULL, NULL, 0, 0, NULL} 1150 }; 1151 1152 static void test_dfp_cmp_ops(void) 1153 { 1154 test_func_t func; 1155 unsigned long long u0, u0x, u1, u1x; 1156 double d0, d1, *d0p, *d1p; 1157 double d0x, d1x, *d0xp, *d1xp; 1158 /* BF is a 3-bit instruction field that indicates the CR field in which the 1159 * result of the compare should be placed. We won't iterate through all 1160 * 8 possible BF values since storing compare results to a given field is 1161 * a well-tested mechanism in VEX. But we will test two BF values, just as 1162 * a sniff-test. 1163 */ 1164 int k = 0, BF; 1165 u0x = u1x = 0; 1166 d0p = &d0; 1167 d0xp = &d0x; 1168 d1p = &d1; 1169 d1xp = &d1x; 1170 1171 while ((func = dfp_cmp_tests[k].test_func)) { 1172 int i, repeat = 1; 1173 dfp_test_t test_def = dfp_cmp_tests[k]; 1174 BF = 0; 1175 1176 again: 1177 for (i = 0; i < test_def.num_tests; i++) { 1178 unsigned int condreg; 1179 unsigned int flags; 1180 1181 if (test_def.precision == LONG_TEST) { 1182 u0 = dfp64_vals[test_def.targs[i].fra_idx]; 1183 u1 = dfp64_vals[test_def.targs[i].frb_idx]; 1184 } else { 1185 u0 = dfp128_vals[test_def.targs[i].fra_idx * 2]; 1186 u0x = dfp128_vals[(test_def.targs[i].fra_idx * 2) + 1]; 1187 u1 = dfp128_vals[test_def.targs[i].frb_idx * 2]; 1188 u1x = dfp128_vals[(test_def.targs[i].frb_idx * 2) + 1]; 1189 } 1190 *(unsigned long long *)d0p = u0; 1191 *(unsigned long long *)d1p = u1; 1192 f14 = d0; 1193 f16 = d1; 1194 if (test_def.precision == QUAD_TEST) { 1195 *(unsigned long long *)d0xp = u0x; 1196 *(unsigned long long *)d1xp = u1x; 1197 f15 = d0x; 1198 f17 = d1x; 1199 } 1200 1201 SET_FPSCR_ZERO; 1202 SET_CR_XER_ZERO; 1203 (*func)(BF, 0); 1204 GET_CR(flags); 1205 1206 condreg = ((flags >> (4 * (7-BF)))) & 0xf; 1207 printf("%s %016llx", test_def.name, u0); 1208 if (test_def.precision == LONG_TEST) { 1209 printf(" %s %016llx => %x (BF=%d)\n", 1210 test_def.op, u1, condreg, BF); 1211 } else { 1212 printf(" %016llx %s %016llx %016llx ==> %x (BF=%d)\n", 1213 u0x, test_def.op, u1, u1x, 1214 condreg, BF); 1215 } 1216 } 1217 if (repeat) { 1218 repeat = 0; 1219 BF = 5; 1220 goto again; 1221 } 1222 k++; 1223 printf( "\n" ); 1224 } 1225 } 1226 1227 1228 static test_table_t 1229 all_tests[] = 1230 { 1231 { &test_dfp_cmp_ops, 1232 "Test DFP compare instructions"}, 1233 { &test_dfp_rint_ops, 1234 "Test DFP round instructions"}, 1235 { &test_dfp_xiex_ops, 1236 "Test DFP insert/extract instructions"}, 1237 { &test_dfp_rrnd_ops, 1238 "Test DFP reround instructions"}, 1239 { &test_dfp_qua_ops, 1240 "Test DFP quantize instructions"}, 1241 { &test_dfp_quai_ops, 1242 "Test DFP quantize immediate instructions"}, 1243 { NULL, NULL } 1244 }; 1245 #endif // HAS_DFP 1246 1247 int main() { 1248 #if defined(HAS_DFP) 1249 1250 test_table_t aTest; 1251 test_driver_func_t func; 1252 int i = 0; 1253 1254 while ((func = all_tests[i].test_category)) { 1255 aTest = all_tests[i]; 1256 printf( "%s\n", aTest.name ); 1257 (*func)(); 1258 i++; 1259 } 1260 1261 #endif // HAS_DFP 1262 return 0; 1263 } 1264