1/* 2 * Copyright © 2022 Imagination Technologies Ltd. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a copy 5 * of this software and associated documentation files (the "Software"), to deal 6 * in the Software without restriction, including without limitation the rights 7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 * copies of the Software, and to permit persons to whom the Software is 9 * furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 * SOFTWARE. 22 */ 23 24#include <stdbool.h> 25#include <stdint.h> 26#include <stdio.h> 27#include <stdlib.h> 28 29#include "pvr_rogue_pds_defs.h" 30#include "pvr_rogue_pds_disasm.h" 31#include "pvr_rogue_pds_encode.h" 32#include "util/log.h" 33 34#define X(lop, str) #str, 35static const char *const LOP[] = { PVR_PDS_LOP }; 36#undef X 37 38static void pvr_pds_disassemble_operand(struct pvr_operand *op, 39 char *instr_str, 40 size_t instr_len) 41{ 42#define X(enum, str, size) { #str, #size }, 43 static const char *const regs[][2] = { PVR_PDS_OPERAND_TYPES }; 44#undef X 45 46 if (op->type == LITERAL_NUM) { 47 snprintf(instr_str, 48 instr_len, 49 "%s (%llu)", 50 regs[op->type][0], 51 (unsigned long long)op->literal); 52 } else if (op->type == UNRESOLVED) { 53 snprintf(instr_str, instr_len, "UNRESOLVED"); 54 } else { 55 snprintf(instr_str, 56 instr_len, 57 "%s[%u].%s", 58 regs[op->type][0], 59 op->absolute_address, 60 regs[op->type][1]); 61 } 62} 63 64static void pvr_pds_disassemble_instruction_add64(struct pvr_add *add, 65 char *instr_str, 66 size_t instr_len) 67{ 68 char dst[32]; 69 char src0[32]; 70 char src1[32]; 71 72 pvr_pds_disassemble_operand(add->src0, src0, sizeof(src0)); 73 pvr_pds_disassemble_operand(add->src1, src1, sizeof(src1)); 74 pvr_pds_disassemble_operand(add->dst, dst, sizeof(dst)); 75 76 snprintf(instr_str, 77 instr_len, 78 "%-16s%s%s = %s %s %s %s", 79 "ADD64", 80 add->cc ? "? " : "", 81 dst, 82 src0, 83 add->sna ? "-" : "+", 84 src1, 85 add->alum ? "[signed]" : ""); 86} 87 88static void pvr_pds_disassemble_instruction_add32(struct pvr_add *add, 89 char *instr_str, 90 size_t instr_len) 91{ 92 char dst[32]; 93 char src0[32]; 94 char src1[32]; 95 96 pvr_pds_disassemble_operand(add->src0, src0, sizeof(src0)); 97 pvr_pds_disassemble_operand(add->src1, src1, sizeof(src1)); 98 pvr_pds_disassemble_operand(add->dst, dst, sizeof(dst)); 99 100 snprintf(instr_str, 101 instr_len, 102 "%-16s%s%s = %s %s %s %s", 103 "ADD32", 104 add->cc ? "? " : "", 105 dst, 106 src0, 107 add->sna ? "-" : "+", 108 src1, 109 add->alum ? "[signed]" : ""); 110} 111 112static void 113pvr_pds_disassemble_instruction_sftlp32(struct pvr_sftlp *instruction, 114 char *instr_str, 115 size_t instr_len) 116{ 117 char dst[32]; 118 char src0[32]; 119 char src1[32]; 120 char src2[32]; 121 122 pvr_pds_disassemble_operand(instruction->src0, src0, sizeof(src0)); 123 pvr_pds_disassemble_operand(instruction->src1, src1, sizeof(src1)); 124 pvr_pds_disassemble_operand(instruction->dst, dst, sizeof(dst)); 125 126 if (instruction->IM) 127 snprintf(src2, sizeof(src2), "%u", (uint32_t)instruction->src2->literal); 128 else 129 pvr_pds_disassemble_operand(instruction->src2, src2, sizeof(src2)); 130 131 if (instruction->lop == LOP_NONE) { 132 snprintf(instr_str, 133 instr_len, 134 "%-16s%s%s = %s %s %s", 135 "SFTLP32", 136 instruction->cc ? "? " : "", 137 dst, 138 src0, 139 instruction->IM ? instruction->src2->negate ? ">>" : "<<" : "<<", 140 src2); 141 } else if (instruction->lop == LOP_NOT) { 142 snprintf(instr_str, 143 instr_len, 144 "%-16s%s%s = (~%s) %s %s", 145 "SFTLP32", 146 instruction->cc ? "? " : "", 147 dst, 148 src0, 149 instruction->IM ? instruction->src2->negate ? ">>" : "<<" : "<<", 150 src2); 151 } else { 152 snprintf(instr_str, 153 instr_len, 154 "%-16s%s%s = (%s %s %s) %s %s", 155 "SFTLP32", 156 instruction->cc ? "? " : "", 157 dst, 158 src0, 159 LOP[instruction->lop], 160 src1, 161 instruction->IM ? instruction->src2->negate ? ">>" : "<<" : "<<", 162 src2); 163 } 164} 165 166static void pvr_pds_disassemble_instruction_stm(struct pvr_stm *instruction, 167 char *instr_str, 168 size_t instr_len) 169{ 170 char src0[32]; 171 char src1[32]; 172 char src2[32]; 173 char src3[32]; 174 175 char stm_pred[64]; 176 177 pvr_pds_disassemble_operand(instruction->src0, src0, sizeof(src0)); 178 pvr_pds_disassemble_operand(instruction->src1, src1, sizeof(src1)); 179 pvr_pds_disassemble_operand(instruction->src2, src2, sizeof(src2)); 180 pvr_pds_disassemble_operand(instruction->src3, src3, sizeof(src3)); 181 182 if (instruction->ccs_global) 183 snprintf(stm_pred, sizeof(stm_pred), "overflow_any"); 184 else if (instruction->ccs_so) 185 snprintf(stm_pred, sizeof(stm_pred), "overflow_current"); 186 else 187 stm_pred[0] = 0; 188 189 snprintf(instr_str, 190 instr_len, 191 "%-16s%s%s%s stm%u = %s, %s, %s, %s", 192 "STM", 193 instruction->cc ? "? " : "", 194 stm_pred, 195 instruction->tst ? " (TST only)" : "", 196 instruction->stream_out, 197 src0, 198 src1, 199 src2, 200 src3); 201} 202 203static void pds_disassemble_instruction_stmc(struct pvr_stmc *instruction, 204 char *instr_str, 205 size_t instr_len) 206{ 207 char src0[32]; 208 209 pvr_pds_disassemble_operand(instruction->src0, src0, sizeof(src0)); 210 211 snprintf(instr_str, 212 instr_len, 213 "%-16s%s %s", 214 "STMC", 215 instruction->cc ? "? " : "", 216 src0); 217} 218 219static void 220pvr_pds_disassemble_instruction_sftlp64(struct pvr_sftlp *instruction, 221 char *instr_str, 222 size_t instr_len) 223{ 224 char dst[32]; 225 char src0[32]; 226 char src1[32]; 227 char src2[32]; 228 229 pvr_pds_disassemble_operand(instruction->src0, src0, sizeof(src0)); 230 pvr_pds_disassemble_operand(instruction->src1, src1, sizeof(src1)); 231 pvr_pds_disassemble_operand(instruction->dst, dst, sizeof(dst)); 232 233 if (instruction->IM) 234 snprintf(src2, sizeof(src2), "%u", (uint32_t)instruction->src2->literal); 235 else 236 pvr_pds_disassemble_operand(instruction->src2, src2, sizeof(src2)); 237 238 if (instruction->lop == LOP_NONE) { 239 snprintf(instr_str, 240 instr_len, 241 "%-16s%s%s = %s %s %s", 242 "SFTLP64", 243 instruction->cc ? "? " : "", 244 dst, 245 src0, 246 instruction->IM ? instruction->src2->negate ? ">>" : "<<" : "<<", 247 src2); 248 } else if (instruction->lop == LOP_NOT) { 249 snprintf(instr_str, 250 instr_len, 251 "%-16s%s%s = (~%s) %s %s", 252 "SFTLP64", 253 instruction->cc ? "? " : "", 254 dst, 255 src0, 256 instruction->IM ? instruction->src2->negate ? ">>" : "<<" : "<<", 257 src2); 258 } else { 259 snprintf(instr_str, 260 instr_len, 261 "%-16s%s%s = (%s %s %s) %s %s", 262 "SFTLP64", 263 instruction->cc ? "? " : "", 264 dst, 265 src0, 266 LOP[instruction->lop], 267 src1, 268 instruction->IM ? instruction->src2->negate ? ">>" : "<<" : "<<", 269 src2); 270 } 271} 272 273static void pvr_pds_disassemble_instruction_cmp(struct pvr_cmp *cmp, 274 char *instr_str, 275 size_t instr_len) 276{ 277 char src0[32]; 278 char src1[32]; 279 static const char *const COP[] = { "=", ">", "<", "!=" }; 280 281 pvr_pds_disassemble_operand(cmp->src0, src0, sizeof(src0)); 282 283 if (cmp->IM) { 284 snprintf(src1, 285 sizeof(src1), 286 "%#04llx", 287 (unsigned long long)cmp->src1->literal); 288 } else { 289 pvr_pds_disassemble_operand(cmp->src1, src1, sizeof(src1)); 290 } 291 292 snprintf(instr_str, 293 instr_len, 294 "%-16s%sP0 = (%s %s %s)", 295 "CMP", 296 cmp->cc ? "? " : "", 297 src0, 298 COP[cmp->cop], 299 src1); 300} 301 302static void pvr_pds_disassemble_instruction_ldst(struct pvr_ldst *ins, 303 char *instr_str, 304 size_t instr_len) 305{ 306 char src0[PVR_PDS_MAX_INST_STR_LEN]; 307 308 pvr_pds_disassemble_operand(ins->src0, src0, sizeof(src0)); 309 310 if (ins->st) { 311 snprintf(instr_str, 312 instr_len, 313 "%-16s%s%s: mem(%s) <= src(%s)", 314 "ST", 315 ins->cc ? "? " : "", 316 src0, 317 "?", 318 "?"); 319 } else { 320 snprintf(instr_str, 321 instr_len, 322 "%-16s%s%s: dst(%s) <= mem(%s)", 323 "ld", 324 ins->cc ? "? " : "", 325 src0, 326 "?", 327 "?"); 328 } 329} 330 331static void pvr_pds_disassemble_simple(struct pvr_simple *simple, 332 const char *type, 333 char *instr_str, 334 size_t instr_len) 335{ 336 snprintf(instr_str, instr_len, "%-16s%s", type, simple->cc ? "? " : ""); 337} 338 339static void pvr_pds_disassemble_instruction_limm(struct pvr_limm *limm, 340 char *instr_str, 341 size_t instr_len) 342{ 343 int32_t imm = (uint32_t)limm->src0->literal; 344 char dst[PVR_PDS_MAX_INST_STR_LEN]; 345 346 pvr_pds_disassemble_operand(limm->dst, dst, sizeof(dst)); 347 348 if (limm->GR) { 349 char *pchGReg; 350 351 switch (imm) { 352 case 0: 353 pchGReg = "cluster"; 354 break; 355 case 1: 356 pchGReg = "instance"; 357 break; 358 default: 359 pchGReg = "unknown"; 360 } 361 362 snprintf(instr_str, 363 instr_len, 364 "%-16s%s%s = G%d (%s)", 365 "LIMM", 366 limm->cc ? "? " : "", 367 dst, 368 imm, 369 pchGReg); 370 } else { 371 snprintf(instr_str, 372 instr_len, 373 "%-16s%s%s = %#04x", 374 "LIMM", 375 limm->cc ? "? " : "", 376 dst, 377 imm); 378 } 379} 380 381static void pvr_pds_disassemble_instruction_ddmad(struct pvr_ddmad *ddmad, 382 char *instr_str, 383 size_t instr_len) 384{ 385 char src0[PVR_PDS_MAX_INST_STR_LEN]; 386 char src1[PVR_PDS_MAX_INST_STR_LEN]; 387 char src2[PVR_PDS_MAX_INST_STR_LEN]; 388 char src3[PVR_PDS_MAX_INST_STR_LEN]; 389 390 pvr_pds_disassemble_operand(ddmad->src0, src0, sizeof(src0)); 391 pvr_pds_disassemble_operand(ddmad->src1, src1, sizeof(src1)); 392 pvr_pds_disassemble_operand(ddmad->src2, src2, sizeof(src2)); 393 pvr_pds_disassemble_operand(ddmad->src3, src3, sizeof(src3)); 394 395 snprintf(instr_str, 396 instr_len, 397 "%-16s%sdoutd = (%s * %s) + %s, %s%s", 398 "DDMAD", 399 ddmad->cc ? "? " : "", 400 src0, 401 src1, 402 src2, 403 src3, 404 ddmad->END ? "; HALT" : ""); 405} 406 407static void pvr_pds_disassemble_predicate(uint32_t predicate, 408 char *buffer, 409 size_t buffer_length) 410{ 411 switch (predicate) { 412 case PVR_ROGUE_PDSINST_PREDICATE_P0: 413 snprintf(buffer, buffer_length, "%s", "p0"); 414 break; 415 case PVR_ROGUE_PDSINST_PREDICATE_IF0: 416 snprintf(buffer, buffer_length, "%s", "if0"); 417 break; 418 case PVR_ROGUE_PDSINST_PREDICATE_IF1: 419 snprintf(buffer, buffer_length, "%s", "if1"); 420 break; 421 case PVR_ROGUE_PDSINST_PREDICATE_SO_OVERFLOW_PREDICATE_0: 422 snprintf(buffer, buffer_length, "%s", "so_overflow_0"); 423 break; 424 case PVR_ROGUE_PDSINST_PREDICATE_SO_OVERFLOW_PREDICATE_1: 425 snprintf(buffer, buffer_length, "%s", "so_overflow_1"); 426 break; 427 case PVR_ROGUE_PDSINST_PREDICATE_SO_OVERFLOW_PREDICATE_2: 428 snprintf(buffer, buffer_length, "%s", "so_overflow_2"); 429 break; 430 case PVR_ROGUE_PDSINST_PREDICATE_SO_OVERFLOW_PREDICATE_3: 431 snprintf(buffer, buffer_length, "%s", "so_overflow_3"); 432 break; 433 case PVR_ROGUE_PDSINST_PREDICATE_SO_OVERFLOW_PREDICATE_GLOBAL: 434 snprintf(buffer, buffer_length, "%s", "so_overflow_any"); 435 break; 436 case PVR_ROGUE_PDSINST_PREDICATE_KEEP: 437 snprintf(buffer, buffer_length, "%s", "keep"); 438 break; 439 case PVR_ROGUE_PDSINST_PREDICATE_OOB: 440 snprintf(buffer, buffer_length, "%s", "oob"); 441 break; 442 default: 443 snprintf(buffer, buffer_length, "%s", "<ERROR>"); 444 break; 445 } 446} 447 448static void pvr_pds_disassemble_instruction_bra(struct pvr_bra *bra, 449 char *instr_str, 450 size_t instr_len) 451{ 452 char setc_pred[32]; 453 char srcc_pred[32]; 454 455 pvr_pds_disassemble_predicate(bra->srcc->predicate, 456 srcc_pred, 457 sizeof(srcc_pred)); 458 pvr_pds_disassemble_predicate(bra->setc->predicate, 459 setc_pred, 460 sizeof(setc_pred)); 461 462 if (bra->setc->predicate != PVR_ROGUE_PDSINST_PREDICATE_KEEP) { 463 snprintf(instr_str, 464 instr_len, 465 "%-16sif %s%s %d ( setc = %s )", 466 "BRA", 467 bra->srcc->negate ? "! " : "", 468 srcc_pred, 469 bra->address, 470 setc_pred); 471 } else { 472 snprintf(instr_str, 473 instr_len, 474 "%-16sif %s%s %d", 475 "BRA", 476 bra->srcc->negate ? "! " : "", 477 srcc_pred, 478 bra->address); 479 } 480} 481 482static void pvr_pds_disassemble_instruction_mad(struct pvr_mad *mad, 483 char *instr_str, 484 size_t instr_len) 485{ 486 char src0[PVR_PDS_MAX_INST_STR_LEN]; 487 char src1[PVR_PDS_MAX_INST_STR_LEN]; 488 char src2[PVR_PDS_MAX_INST_STR_LEN]; 489 char dst[PVR_PDS_MAX_INST_STR_LEN]; 490 491 pvr_pds_disassemble_operand(mad->src0, src0, sizeof(src0)); 492 pvr_pds_disassemble_operand(mad->src1, src1, sizeof(src1)); 493 pvr_pds_disassemble_operand(mad->src2, src2, sizeof(src2)); 494 pvr_pds_disassemble_operand(mad->dst, dst, sizeof(dst)); 495 496 snprintf(instr_str, 497 instr_len, 498 "%-16s%s%s = (%s * %s) %s %s%s", 499 "MAD", 500 mad->cc ? "? " : "", 501 dst, 502 src0, 503 src1, 504 mad->sna ? "-" : "+", 505 src2, 506 mad->alum ? " [signed]" : ""); 507} 508 509static void pvr_pds_disassemble_instruction_dout(struct pvr_dout *dout, 510 char *instr_str, 511 size_t instr_len) 512{ 513 char src0[PVR_PDS_MAX_INST_STR_LEN]; 514 char src1[PVR_PDS_MAX_INST_STR_LEN]; 515 516#define X(dout_dst, str) #str, 517 static const char *const dst[] = { PVR_PDS_DOUT_DSTS }; 518#undef X 519 520 pvr_pds_disassemble_operand(dout->src0, src0, sizeof(src0)); 521 pvr_pds_disassemble_operand(dout->src1, src1, sizeof(src1)); 522 523 { 524 snprintf(instr_str, 525 instr_len, 526 "%-16s%s%s = %s, %s%s", 527 "DOUT", 528 dout->cc ? "? " : "", 529 dst[dout->dst], 530 src0, 531 src1, 532 dout->END ? "; HALT" : ""); 533 } 534} 535 536void pvr_pds_disassemble_instruction(char *instr_str, 537 size_t instr_len, 538 struct pvr_instruction *instruction) 539{ 540 if (!instruction) { 541 snprintf(instr_str, 542 instr_len, 543 "Instruction was not disassembled properly\n"); 544 return; 545 } 546 547 switch (instruction->type) { 548 case INS_LIMM: 549 pvr_pds_disassemble_instruction_limm((struct pvr_limm *)instruction, 550 instr_str, 551 instr_len); 552 break; 553 case INS_ADD64: 554 pvr_pds_disassemble_instruction_add64((struct pvr_add *)instruction, 555 instr_str, 556 instr_len); 557 break; 558 case INS_ADD32: 559 pvr_pds_disassemble_instruction_add32((struct pvr_add *)instruction, 560 instr_str, 561 instr_len); 562 break; 563 case INS_CMP: 564 pvr_pds_disassemble_instruction_cmp((struct pvr_cmp *)instruction, 565 instr_str, 566 instr_len); 567 break; 568 case INS_MAD: 569 pvr_pds_disassemble_instruction_mad((struct pvr_mad *)instruction, 570 instr_str, 571 instr_len); 572 break; 573 case INS_BRA: 574 pvr_pds_disassemble_instruction_bra((struct pvr_bra *)instruction, 575 instr_str, 576 instr_len); 577 break; 578 case INS_DDMAD: 579 pvr_pds_disassemble_instruction_ddmad((struct pvr_ddmad *)instruction, 580 instr_str, 581 instr_len); 582 break; 583 case INS_DOUT: 584 pvr_pds_disassemble_instruction_dout((struct pvr_dout *)instruction, 585 instr_str, 586 instr_len); 587 break; 588 case INS_LD: 589 case INS_ST: 590 pvr_pds_disassemble_instruction_ldst((struct pvr_ldst *)instruction, 591 instr_str, 592 instr_len); 593 break; 594 case INS_WDF: 595 pvr_pds_disassemble_simple((struct pvr_simple *)instruction, 596 "WDF", 597 instr_str, 598 instr_len); 599 break; 600 case INS_LOCK: 601 pvr_pds_disassemble_simple((struct pvr_simple *)instruction, 602 "LOCK", 603 instr_str, 604 instr_len); 605 break; 606 case INS_RELEASE: 607 pvr_pds_disassemble_simple((struct pvr_simple *)instruction, 608 "RELEASE", 609 instr_str, 610 instr_len); 611 break; 612 case INS_HALT: 613 pvr_pds_disassemble_simple((struct pvr_simple *)instruction, 614 "HALT", 615 instr_str, 616 instr_len); 617 break; 618 case INS_NOP: 619 pvr_pds_disassemble_simple((struct pvr_simple *)instruction, 620 "NOP", 621 instr_str, 622 instr_len); 623 break; 624 case INS_SFTLP32: 625 pvr_pds_disassemble_instruction_sftlp32((struct pvr_sftlp *)instruction, 626 instr_str, 627 instr_len); 628 break; 629 case INS_SFTLP64: 630 pvr_pds_disassemble_instruction_sftlp64((struct pvr_sftlp *)instruction, 631 instr_str, 632 instr_len); 633 break; 634 case INS_STM: 635 pvr_pds_disassemble_instruction_stm((struct pvr_stm *)instruction, 636 instr_str, 637 instr_len); 638 break; 639 case INS_STMC: 640 pds_disassemble_instruction_stmc((struct pvr_stmc *)instruction, 641 instr_str, 642 instr_len); 643 break; 644 default: 645 snprintf(instr_str, instr_len, "Printing not implemented\n"); 646 break; 647 } 648} 649 650#if defined(DUMP_PDS) 651void pvr_pds_print_instruction(uint32_t instr) 652{ 653 char instruction_str[1024]; 654 struct pvr_instruction *decoded = 655 pvr_pds_disassemble_instruction2(0, 0, instr); 656 657 if (!decoded) { 658 mesa_logd("%X\n", instr); 659 } else { 660 pvr_pds_disassemble_instruction(instruction_str, 661 sizeof(instruction_str), 662 decoded); 663 mesa_logd("\t0x%08x, /* %s */\n", instr, instruction_str); 664 } 665} 666#endif 667