1/* 2 * Copyright (c) 2018 Lima Project 3 * 4 * Copyright (c) 2013 Codethink (http://www.codethink.co.uk) 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sub license, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the 14 * next paragraph) shall be included in all copies or substantial portions 15 * of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 * DEALINGS IN THE SOFTWARE. 24 * 25 */ 26 27#include "util/u_half.h" 28 29#include "ppir.h" 30#include "codegen.h" 31 32typedef struct { 33 char *name; 34 unsigned srcs; 35} asm_op; 36 37static void 38print_swizzle(uint8_t swizzle) 39{ 40 if (swizzle == 0xE4) 41 return; 42 43 printf("."); 44 for (unsigned i = 0; i < 4; i++, swizzle >>= 2) 45 printf("%c", "xyzw"[swizzle & 3]); 46} 47 48static void 49print_mask(uint8_t mask) 50{ 51 if (mask == 0xF) 52 return; 53 54 printf("."); 55 if (mask & 1) printf("x"); 56 if (mask & 2) printf("y"); 57 if (mask & 4) printf("z"); 58 if (mask & 8) printf("w"); 59} 60 61static void 62print_reg(ppir_codegen_vec4_reg reg, const char *special) 63{ 64 if (special) { 65 printf("%s", special); 66 } else { 67 switch (reg) 68 { 69 case ppir_codegen_vec4_reg_constant0: 70 printf("^const0"); 71 break; 72 case ppir_codegen_vec4_reg_constant1: 73 printf("^const1"); 74 break; 75 case ppir_codegen_vec4_reg_texture: 76 printf("^texture"); 77 break; 78 case ppir_codegen_vec4_reg_uniform: 79 printf("^uniform"); 80 break; 81 default: 82 printf("$%u", reg); 83 break; 84 } 85 } 86} 87 88static void 89print_vector_source(ppir_codegen_vec4_reg reg, const char *special, 90 uint8_t swizzle, bool abs, bool neg) 91{ 92 if (neg) 93 printf("-"); 94 if (abs) 95 printf("abs("); 96 97 print_reg(reg, special); 98 print_swizzle(swizzle); 99 100 if (abs) 101 printf(")"); 102} 103 104static void 105print_source_scalar(unsigned reg, const char *special, bool abs, bool neg) 106{ 107 if (neg) 108 printf("-"); 109 if (abs) 110 printf("abs("); 111 112 print_reg(reg >> 2, special); 113 if (!special) 114 printf(".%c", "xyzw"[reg & 3]); 115 116 if (abs) 117 printf(")"); 118} 119 120static void 121print_outmod(ppir_codegen_outmod modifier) 122{ 123 switch (modifier) 124 { 125 case ppir_codegen_outmod_clamp_fraction: 126 printf(".sat"); 127 break; 128 case ppir_codegen_outmod_clamp_positive: 129 printf(".pos"); 130 break; 131 case ppir_codegen_outmod_round: 132 printf(".int"); 133 break; 134 default: 135 break; 136 } 137} 138 139static void 140print_dest_scalar(unsigned reg) 141{ 142 printf("$%u", reg >> 2); 143 printf(".%c ", "xyzw"[reg & 3]); 144} 145 146static void 147print_const(unsigned const_num, uint16_t *val) 148{ 149 printf("const%u", const_num); 150 for (unsigned i = 0; i < 4; i++) 151 printf(" %f", util_half_to_float(val[i])); 152} 153 154static void 155print_const0(void *code, unsigned offset) 156{ 157 (void) offset; 158 159 print_const(0, code); 160} 161 162static void 163print_const1(void *code, unsigned offset) 164{ 165 (void) offset; 166 167 print_const(1, code); 168} 169 170static void 171print_varying(void *code, unsigned offset) 172{ 173 (void) offset; 174 ppir_codegen_field_varying *varying = code; 175 176 printf("load"); 177 178 bool perspective = varying->imm.source_type < 2 && varying->imm.perspective; 179 if (perspective) 180 { 181 printf(".perspective"); 182 switch (varying->imm.perspective) 183 { 184 case 2: 185 printf(".z"); 186 break; 187 case 3: 188 printf(".w"); 189 break; 190 default: 191 printf(".unknown"); 192 break; 193 } 194 } 195 196 printf(".v "); 197 198 switch (varying->imm.dest) 199 { 200 case ppir_codegen_vec4_reg_discard: 201 printf("^discard"); 202 break; 203 default: 204 printf("$%u", varying->imm.dest); 205 break; 206 } 207 print_mask(varying->imm.mask); 208 printf(" "); 209 210 switch (varying->imm.source_type) { 211 case 1: 212 print_vector_source(varying->reg.source, NULL, varying->reg.swizzle, 213 varying->reg.absolute, varying->reg.negate); 214 break; 215 case 2: 216 printf("gl_FragCoord"); 217 break; 218 case 3: 219 if (varying->imm.perspective) 220 printf("gl_FrontFacing"); 221 else 222 printf("gl_PointCoord"); 223 break; 224 default: 225 switch (varying->imm.alignment) { 226 case 0: 227 printf("%u.%c", varying->imm.index >> 2, 228 "xyzw"[varying->imm.index & 3]); 229 break; 230 case 1: { 231 const char *c[2] = {"xy", "zw"}; 232 printf("%u.%s", varying->imm.index >> 1, c[varying->imm.index & 1]); 233 break; 234 } 235 default: 236 printf("%u", varying->imm.index); 237 break; 238 } 239 240 if (varying->imm.offset_vector != 15) { 241 unsigned reg = (varying->imm.offset_vector << 2) + 242 varying->imm.offset_scalar; 243 printf("+"); 244 print_source_scalar(reg, NULL, false, false); 245 } 246 break; 247 } 248} 249 250static void 251print_sampler(void *code, unsigned offset) 252{ 253 (void) offset; 254 ppir_codegen_field_sampler *sampler = code; 255 256 printf("texld"); 257 if (sampler->lod_bias_en) 258 printf(".b"); 259 260 switch (sampler->type) { 261 case ppir_codegen_sampler_type_2d: 262 printf(".2d"); 263 break; 264 case ppir_codegen_sampler_type_cube: 265 printf(".cube"); 266 break; 267 default: 268 printf("_t%u", sampler->type); 269 break; 270 } 271 272 printf(" %u", sampler->index); 273 274 if (sampler->offset_en) 275 { 276 printf("+"); 277 print_source_scalar(sampler->index_offset, NULL, false, false); 278 } 279 280 if (sampler->lod_bias_en) 281 { 282 printf(" "); 283 print_source_scalar(sampler->lod_bias, NULL, false, false); 284 } 285} 286 287static void 288print_uniform(void *code, unsigned offset) 289{ 290 (void) offset; 291 ppir_codegen_field_uniform *uniform = code; 292 293 printf("load."); 294 295 switch (uniform->source) { 296 case ppir_codegen_uniform_src_uniform: 297 printf("u"); 298 break; 299 case ppir_codegen_uniform_src_temporary: 300 printf("t"); 301 break; 302 default: 303 printf(".u%u", uniform->source); 304 break; 305 } 306 307 if (uniform->alignment) 308 printf(" %u", uniform->index); 309 else 310 printf(" %u.%c", uniform->index >> 2, "xyzw"[uniform->index & 3]); 311 312 if (uniform->offset_en) { 313 printf(" "); 314 print_source_scalar(uniform->offset_reg, NULL, false, false); 315 } 316} 317 318#define CASE(_name, _srcs) \ 319[ppir_codegen_vec4_mul_op_##_name] = { \ 320 .name = #_name, \ 321 .srcs = _srcs \ 322} 323 324static const asm_op vec4_mul_ops[] = { 325 [0 ... 7] = { 326 .name = "mul", 327 .srcs = 2 328 }, 329 CASE(not, 1), 330 CASE(and, 2), 331 CASE(or, 2), 332 CASE(xor, 2), 333 CASE(ne, 2), 334 CASE(gt, 2), 335 CASE(ge, 2), 336 CASE(eq, 2), 337 CASE(min, 2), 338 CASE(max, 2), 339 CASE(mov, 1), 340}; 341 342#undef CASE 343 344static void 345print_vec4_mul(void *code, unsigned offset) 346{ 347 (void) offset; 348 ppir_codegen_field_vec4_mul *vec4_mul = code; 349 350 asm_op op = vec4_mul_ops[vec4_mul->op]; 351 352 if (op.name) 353 printf("%s", op.name); 354 else 355 printf("op%u", vec4_mul->op); 356 print_outmod(vec4_mul->dest_modifier); 357 printf(".v0 "); 358 359 if (vec4_mul->mask) { 360 printf("$%u", vec4_mul->dest); 361 print_mask(vec4_mul->mask); 362 printf(" "); 363 } 364 365 print_vector_source(vec4_mul->arg0_source, NULL, 366 vec4_mul->arg0_swizzle, 367 vec4_mul->arg0_absolute, 368 vec4_mul->arg0_negate); 369 370 if (vec4_mul->op < 8 && vec4_mul->op != 0) { 371 printf("<<%u", vec4_mul->op); 372 } 373 374 printf(" "); 375 376 if (op.srcs > 1) { 377 print_vector_source(vec4_mul->arg1_source, NULL, 378 vec4_mul->arg1_swizzle, 379 vec4_mul->arg1_absolute, 380 vec4_mul->arg1_negate); 381 } 382} 383 384#define CASE(_name, _srcs) \ 385[ppir_codegen_vec4_acc_op_##_name] = { \ 386 .name = #_name, \ 387 .srcs = _srcs \ 388} 389 390static const asm_op vec4_acc_ops[] = { 391 CASE(add, 2), 392 CASE(fract, 1), 393 CASE(ne, 2), 394 CASE(gt, 2), 395 CASE(ge, 2), 396 CASE(eq, 2), 397 CASE(floor, 1), 398 CASE(ceil, 1), 399 CASE(min, 2), 400 CASE(max, 2), 401 CASE(sum3, 1), 402 CASE(sum4, 1), 403 CASE(dFdx, 2), 404 CASE(dFdy, 2), 405 CASE(sel, 2), 406 CASE(mov, 1), 407}; 408 409#undef CASE 410 411static void 412print_vec4_acc(void *code, unsigned offset) 413{ 414 (void) offset; 415 ppir_codegen_field_vec4_acc *vec4_acc = code; 416 417 asm_op op = vec4_acc_ops[vec4_acc->op]; 418 419 if (op.name) 420 printf("%s", op.name); 421 else 422 printf("op%u", vec4_acc->op); 423 print_outmod(vec4_acc->dest_modifier); 424 printf(".v1 "); 425 426 if (vec4_acc->mask) { 427 printf("$%u", vec4_acc->dest); 428 print_mask(vec4_acc->mask); 429 printf(" "); 430 } 431 432 print_vector_source(vec4_acc->arg0_source, vec4_acc->mul_in ? "^v0" : NULL, 433 vec4_acc->arg0_swizzle, 434 vec4_acc->arg0_absolute, 435 vec4_acc->arg0_negate); 436 437 if (op.srcs > 1) { 438 printf(" "); 439 print_vector_source(vec4_acc->arg1_source, NULL, 440 vec4_acc->arg1_swizzle, 441 vec4_acc->arg1_absolute, 442 vec4_acc->arg1_negate); 443 } 444} 445 446#define CASE(_name, _srcs) \ 447[ppir_codegen_float_mul_op_##_name] = { \ 448 .name = #_name, \ 449 .srcs = _srcs \ 450} 451 452static const asm_op float_mul_ops[] = { 453 [0 ... 7] = { 454 .name = "mul", 455 .srcs = 2 456 }, 457 CASE(not, 1), 458 CASE(and, 2), 459 CASE(or, 2), 460 CASE(xor, 2), 461 CASE(ne, 2), 462 CASE(gt, 2), 463 CASE(ge, 2), 464 CASE(eq, 2), 465 CASE(min, 2), 466 CASE(max, 2), 467 CASE(mov, 1), 468}; 469 470#undef CASE 471 472static void 473print_float_mul(void *code, unsigned offset) 474{ 475 (void) offset; 476 ppir_codegen_field_float_mul *float_mul = code; 477 478 asm_op op = float_mul_ops[float_mul->op]; 479 480 if (op.name) 481 printf("%s", op.name); 482 else 483 printf("op%u", float_mul->op); 484 print_outmod(float_mul->dest_modifier); 485 printf(".s0 "); 486 487 if (float_mul->output_en) 488 print_dest_scalar(float_mul->dest); 489 490 print_source_scalar(float_mul->arg0_source, NULL, 491 float_mul->arg0_absolute, 492 float_mul->arg0_negate); 493 494 if (float_mul->op < 8 && float_mul->op != 0) { 495 printf("<<%u", float_mul->op); 496 } 497 498 if (op.srcs > 1) { 499 printf(" "); 500 501 print_source_scalar(float_mul->arg1_source, NULL, 502 float_mul->arg1_absolute, 503 float_mul->arg1_negate); 504 } 505} 506 507#define CASE(_name, _srcs) \ 508[ppir_codegen_float_acc_op_##_name] = { \ 509 .name = #_name, \ 510 .srcs = _srcs \ 511} 512 513static const asm_op float_acc_ops[] = { 514 CASE(add, 2), 515 CASE(fract, 1), 516 CASE(ne, 2), 517 CASE(gt, 2), 518 CASE(ge, 2), 519 CASE(eq, 2), 520 CASE(floor, 1), 521 CASE(ceil, 1), 522 CASE(min, 2), 523 CASE(max, 2), 524 CASE(dFdx, 2), 525 CASE(dFdy, 2), 526 CASE(sel, 2), 527 CASE(mov, 1), 528}; 529 530#undef CASE 531 532static void 533print_float_acc(void *code, unsigned offset) 534{ 535 (void) offset; 536 ppir_codegen_field_float_acc *float_acc = code; 537 538 asm_op op = float_acc_ops[float_acc->op]; 539 540 if (op.name) 541 printf("%s", op.name); 542 else 543 printf("op%u", float_acc->op); 544 print_outmod(float_acc->dest_modifier); 545 printf(".s1 "); 546 547 if (float_acc->output_en) 548 print_dest_scalar(float_acc->dest); 549 550 print_source_scalar(float_acc->arg0_source, float_acc->mul_in ? "^s0" : NULL, 551 float_acc->arg0_absolute, 552 float_acc->arg0_negate); 553 554 if (op.srcs > 1) { 555 printf(" "); 556 print_source_scalar(float_acc->arg1_source, NULL, 557 float_acc->arg1_absolute, 558 float_acc->arg1_negate); 559 } 560} 561 562#define CASE(_name, _srcs) \ 563[ppir_codegen_combine_scalar_op_##_name] = { \ 564 .name = #_name, \ 565 .srcs = _srcs \ 566} 567 568static const asm_op combine_ops[] = { 569 CASE(rcp, 1), 570 CASE(mov, 1), 571 CASE(sqrt, 1), 572 CASE(rsqrt, 1), 573 CASE(exp2, 1), 574 CASE(log2, 1), 575 CASE(sin, 1), 576 CASE(cos, 1), 577 CASE(atan, 1), 578 CASE(atan2, 1), 579}; 580 581#undef CASE 582 583static void 584print_combine(void *code, unsigned offset) 585{ 586 (void) offset; 587 ppir_codegen_field_combine *combine = code; 588 589 if (combine->scalar.dest_vec && 590 combine->scalar.arg1_en) { 591 /* This particular combination can only be valid for scalar * vector 592 * multiplies, and the opcode field is reused for something else. 593 */ 594 printf("mul"); 595 } else { 596 asm_op op = combine_ops[combine->scalar.op]; 597 598 if (op.name) 599 printf("%s", op.name); 600 else 601 printf("op%u", combine->scalar.op); 602 } 603 604 if (!combine->scalar.dest_vec) 605 print_outmod(combine->scalar.dest_modifier); 606 printf(".s2 "); 607 608 if (combine->scalar.dest_vec) { 609 printf("$%u", combine->vector.dest); 610 print_mask(combine->vector.mask); 611 } else { 612 print_dest_scalar(combine->scalar.dest); 613 } 614 printf(" "); 615 616 print_source_scalar(combine->scalar.arg0_src, NULL, 617 combine->scalar.arg0_absolute, 618 combine->scalar.arg0_negate); 619 printf(" "); 620 621 if (combine->scalar.arg1_en) { 622 if (combine->scalar.dest_vec) { 623 print_vector_source(combine->vector.arg1_source, NULL, 624 combine->vector.arg1_swizzle, 625 false, false); 626 } else { 627 print_source_scalar(combine->scalar.arg1_src, NULL, 628 combine->scalar.arg1_absolute, 629 combine->scalar.arg1_negate); 630 } 631 } 632} 633 634static void 635print_temp_write(void *code, unsigned offset) 636{ 637 (void) offset; 638 ppir_codegen_field_temp_write *temp_write = code; 639 640 if (temp_write->fb_read.unknown_0 == 0x7) { 641 if (temp_write->fb_read.source) 642 printf("fb_color"); 643 else 644 printf("fb_depth"); 645 printf(" $%u", temp_write->fb_read.dest); 646 647 return; 648 } 649 650 printf("store.t"); 651 652 if (temp_write->temp_write.alignment) { 653 printf(" %u", temp_write->temp_write.index); 654 } else { 655 printf(" %u.%c", temp_write->temp_write.index >> 2, 656 "xyzw"[temp_write->temp_write.index & 3]); 657 } 658 659 if (temp_write->temp_write.offset_en) { 660 printf("+"); 661 print_source_scalar(temp_write->temp_write.offset_reg, 662 NULL, false, false); 663 } 664 665 printf(" "); 666 667 if (temp_write->temp_write.alignment) { 668 print_reg(temp_write->temp_write.source >> 2, NULL); 669 } else { 670 print_source_scalar(temp_write->temp_write.source, NULL, false, false); 671 } 672} 673 674static void 675print_branch(void *code, unsigned offset) 676{ 677 ppir_codegen_field_branch *branch = code; 678 679 if (branch->discard.word0 == PPIR_CODEGEN_DISCARD_WORD0 && 680 branch->discard.word1 == PPIR_CODEGEN_DISCARD_WORD1 && 681 branch->discard.word2 == PPIR_CODEGEN_DISCARD_WORD2) { 682 printf("discard"); 683 return; 684 } 685 686 687 const char* cond[] = { 688 "nv", "lt", "eq", "le", 689 "gt", "ne", "ge", "" , 690 }; 691 692 unsigned cond_mask = 0; 693 cond_mask |= (branch->branch.cond_lt ? 1 : 0); 694 cond_mask |= (branch->branch.cond_eq ? 2 : 0); 695 cond_mask |= (branch->branch.cond_gt ? 4 : 0); 696 printf("branch"); 697 if (cond_mask != 0x7) { 698 printf(".%s ", cond[cond_mask]); 699 print_source_scalar(branch->branch.arg0_source, NULL, false, false); 700 printf(" "); 701 print_source_scalar(branch->branch.arg1_source, NULL, false, false); 702 } 703 704 printf(" %d", branch->branch.target + offset); 705} 706 707typedef void (*print_field_func)(void *, unsigned); 708 709static const print_field_func print_field[ppir_codegen_field_shift_count] = { 710 [ppir_codegen_field_shift_varying] = print_varying, 711 [ppir_codegen_field_shift_sampler] = print_sampler, 712 [ppir_codegen_field_shift_uniform] = print_uniform, 713 [ppir_codegen_field_shift_vec4_mul] = print_vec4_mul, 714 [ppir_codegen_field_shift_float_mul] = print_float_mul, 715 [ppir_codegen_field_shift_vec4_acc] = print_vec4_acc, 716 [ppir_codegen_field_shift_float_acc] = print_float_acc, 717 [ppir_codegen_field_shift_combine] = print_combine, 718 [ppir_codegen_field_shift_temp_write] = print_temp_write, 719 [ppir_codegen_field_shift_branch] = print_branch, 720 [ppir_codegen_field_shift_vec4_const_0] = print_const0, 721 [ppir_codegen_field_shift_vec4_const_1] = print_const1, 722}; 723 724static const int ppir_codegen_field_size[] = { 725 34, 62, 41, 43, 30, 44, 31, 30, 41, 73, 64, 64 726}; 727 728static void 729bitcopy(char *src, char *dst, unsigned bits, unsigned src_offset) 730{ 731 src += src_offset / 8; 732 src_offset %= 8; 733 734 for (int b = bits; b > 0; b -= 8, src++, dst++) { 735 unsigned char out = ((unsigned char) *src) >> src_offset; 736 if (src_offset > 0 && src_offset + b > 8) 737 out |= ((unsigned char) *(src + 1)) << (8 - src_offset); 738 *dst = (char) out; 739 } 740} 741 742void 743ppir_disassemble_instr(uint32_t *instr, unsigned offset) 744{ 745 ppir_codegen_ctrl *ctrl = (ppir_codegen_ctrl *) instr; 746 747 char *instr_code = (char *) (instr + 1); 748 unsigned bit_offset = 0; 749 bool first = true; 750 for (unsigned i = 0; i < ppir_codegen_field_shift_count; i++) { 751 char code[12]; 752 753 if (!((ctrl->fields >> i) & 1)) 754 continue; 755 756 unsigned bits = ppir_codegen_field_size[i]; 757 bitcopy(instr_code, code, bits, bit_offset); 758 759 if (first) 760 first = false; 761 else 762 printf(", "); 763 764 print_field[i](code, offset); 765 766 bit_offset += bits; 767 } 768 769 if (ctrl->sync) 770 printf(", sync"); 771 if (ctrl->stop) 772 printf(", stop"); 773 774 printf("\n"); 775} 776 777