1/* 2 * Copyright (c) 2016 Etnaviv Project 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sub license, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the 12 * next paragraph) shall be included in all copies or substantial portions 13 * of the 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 NON-INFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 * 23 * Authors: 24 * Christian Gmeiner <christian.gmeiner@gmail.com> 25 */ 26 27#include "etnaviv_disasm.h" 28 29#include <assert.h> 30#include <stdbool.h> 31#include <stdio.h> 32#include <stdlib.h> 33 34#include "hw/isa.xml.h" 35 36struct instr { 37 /* dword0: */ 38 uint32_t opc : 6; 39 uint32_t cond : 5; 40 uint32_t sat : 1; 41 uint32_t dst_use : 1; 42 uint32_t dst_amode : 3; 43 uint32_t dst_reg : 7; 44 uint32_t dst_comps : 4; 45 uint32_t tex_id : 5; 46 47 /* dword1: */ 48 uint32_t tex_amode : 3; 49 uint32_t tex_swiz : 8; 50 uint32_t src0_use : 1; 51 uint32_t src0_reg : 9; 52 uint32_t type_bit2 : 1; 53 uint32_t src0_swiz : 8; 54 uint32_t src0_neg : 1; 55 uint32_t src0_abs : 1; 56 57 /* dword2: */ 58 uint32_t src0_amode : 3; 59 uint32_t src0_rgroup : 3; 60 uint32_t src1_use : 1; 61 uint32_t src1_reg : 9; 62 uint32_t opcode_bit6 : 1; 63 uint32_t src1_swiz : 8; 64 uint32_t src1_neg : 1; 65 uint32_t src1_abs : 1; 66 uint32_t src1_amode : 3; 67 uint32_t type_bit01 : 2; 68 69 /* dword3: */ 70 union { 71 struct { 72 uint32_t src1_rgroup : 3; 73 uint32_t src2_use : 1; 74 uint32_t src2_reg : 9; 75 uint32_t unk3_13 : 1; 76 uint32_t src2_swiz : 8; 77 uint32_t src2_neg : 1; 78 uint32_t src2_abs : 1; 79 uint32_t unk3_24 : 1; 80 uint32_t src2_amode : 3; 81 uint32_t src2_rgroup : 3; 82 uint32_t unk3_31 : 1; 83 }; 84 uint32_t dword3; 85 }; 86}; 87 88struct dst_operand { 89 bool use; 90 uint8_t amode; 91 uint16_t reg; 92 uint8_t comps; 93}; 94 95struct src_operand { 96 bool use; 97 bool neg; 98 bool abs; 99 uint8_t rgroup; 100 uint16_t reg; 101 uint8_t swiz; 102 uint8_t amode; 103}; 104 105struct tex_operand { 106 uint8_t id; 107 uint8_t amode; 108 uint8_t swiz; 109}; 110 111struct opc_operands { 112 struct dst_operand *dst; 113 struct tex_operand *tex; 114 struct src_operand *src0; 115 struct src_operand *src1; 116 struct src_operand *src2; 117 118 int imm; 119}; 120 121static void 122printf_type(uint8_t type) 123{ 124 switch(type) { 125 case INST_TYPE_F32: 126 /* as f32 is the default print nothing */ 127 break; 128 129 case INST_TYPE_S32: 130 printf(".s32"); 131 break; 132 133 case INST_TYPE_S8: 134 printf(".s8"); 135 break; 136 137 case INST_TYPE_U16: 138 printf(".u16"); 139 break; 140 141 case INST_TYPE_F16: 142 printf(".f16"); 143 break; 144 145 case INST_TYPE_S16: 146 printf(".s16"); 147 break; 148 149 case INST_TYPE_U32: 150 printf(".u32"); 151 break; 152 153 case INST_TYPE_U8: 154 printf(".u8"); 155 break; 156 157 default: 158 abort(); 159 break; 160 } 161} 162 163static void 164print_condition(uint8_t condition) 165{ 166 switch (condition) { 167 case INST_CONDITION_TRUE: 168 break; 169 170 case INST_CONDITION_GT: 171 printf(".GT"); 172 break; 173 174 case INST_CONDITION_LT: 175 printf(".LT"); 176 break; 177 178 case INST_CONDITION_GE: 179 printf(".GE"); 180 break; 181 182 case INST_CONDITION_LE: 183 printf(".LE"); 184 break; 185 186 case INST_CONDITION_EQ: 187 printf(".EQ"); 188 break; 189 190 case INST_CONDITION_NE: 191 printf(".NE"); 192 break; 193 194 case INST_CONDITION_AND: 195 printf(".AND"); 196 break; 197 198 case INST_CONDITION_OR: 199 printf(".OR"); 200 break; 201 202 case INST_CONDITION_XOR: 203 printf(".XOR"); 204 break; 205 206 case INST_CONDITION_NOT: 207 printf(".NOT"); 208 break; 209 210 case INST_CONDITION_NZ: 211 printf(".NZ"); 212 break; 213 214 case INST_CONDITION_GEZ: 215 printf(".GEZ"); 216 break; 217 218 case INST_CONDITION_GZ: 219 printf(".GZ"); 220 break; 221 222 case INST_CONDITION_LEZ: 223 printf(".LEZ"); 224 break; 225 226 case INST_CONDITION_LZ: 227 printf(".LZ"); 228 break; 229 230 default: 231 abort(); 232 break; 233 } 234} 235 236static void 237print_rgroup(uint8_t rgoup) 238{ 239 switch (rgoup) { 240 case INST_RGROUP_TEMP: 241 printf("t"); 242 break; 243 244 case INST_RGROUP_INTERNAL: 245 printf("i"); 246 break; 247 248 case INST_RGROUP_UNIFORM_0: 249 case INST_RGROUP_UNIFORM_1: 250 printf("u"); 251 break; 252 } 253} 254 255static void 256print_components(uint8_t components) 257{ 258 if (components == 15) 259 return; 260 261 printf("."); 262 if (components & INST_COMPS_X) 263 printf("x"); 264 else 265 printf("_"); 266 267 if (components & INST_COMPS_Y) 268 printf("y"); 269 else 270 printf("_"); 271 272 if (components & INST_COMPS_Z) 273 printf("z"); 274 else 275 printf("_"); 276 277 if (components & INST_COMPS_W) 278 printf("w"); 279 else 280 printf("_"); 281} 282 283static inline void 284print_swiz_comp(uint8_t swiz_comp) 285{ 286 switch (swiz_comp) { 287 case INST_SWIZ_COMP_X: 288 printf("x"); 289 break; 290 291 case INST_SWIZ_COMP_Y: 292 printf("y"); 293 break; 294 295 case INST_SWIZ_COMP_Z: 296 printf("z"); 297 break; 298 299 case INST_SWIZ_COMP_W: 300 printf("w"); 301 break; 302 303 default: 304 abort(); 305 break; 306 } 307} 308 309static void 310print_swiz(uint8_t swiz) 311{ 312 // if a null swizzle 313 if (swiz == 0xe4) 314 return; 315 316 const unsigned x = swiz & 0x3; 317 const unsigned y = (swiz & 0x0C) >> 2; 318 const unsigned z = (swiz & 0x30) >> 4; 319 const unsigned w = (swiz & 0xc0) >> 6; 320 321 printf("."); 322 print_swiz_comp(x); 323 print_swiz_comp(y); 324 print_swiz_comp(z); 325 print_swiz_comp(w); 326} 327 328static void 329print_amode(uint8_t amode) 330{ 331 switch (amode) { 332 case INST_AMODE_DIRECT: 333 /* nothing to output */ 334 break; 335 336 case INST_AMODE_ADD_A_X: 337 printf("[a.x]"); 338 break; 339 340 case INST_AMODE_ADD_A_Y: 341 printf("[a.y]"); 342 break; 343 344 case INST_AMODE_ADD_A_Z: 345 printf("[a.z]"); 346 break; 347 348 case INST_AMODE_ADD_A_W: 349 printf("[a.w]"); 350 break; 351 352 default: 353 abort(); 354 break; 355 } 356} 357 358static void 359print_dst(struct dst_operand *dst, bool sep) 360{ 361 if (dst->use) { 362 printf("t%u", dst->reg); 363 print_amode(dst->amode); 364 print_components(dst->comps); 365 } else { 366 printf("void"); 367 } 368 369 if (sep) 370 printf(", "); 371} 372 373static void 374print_tex(struct tex_operand *tex, bool sep) 375{ 376 printf("tex%u", tex->id); 377 print_amode(tex->amode); 378 print_swiz(tex->swiz); 379 380 if (sep) 381 printf(", "); 382} 383 384static void 385print_src(struct src_operand *src, bool sep) 386{ 387 if (src->use) { 388 if (src->neg) 389 printf("-"); 390 391 if (src->abs) 392 printf("|"); 393 394 if (src->rgroup == INST_RGROUP_UNIFORM_1) 395 src->reg += 128; 396 397 print_rgroup(src->rgroup); 398 printf("%u", src->reg); 399 print_amode(src->amode); 400 print_swiz(src->swiz); 401 402 if (src->abs) 403 printf("|"); 404 } else { 405 printf("void"); 406 } 407 408 if (sep) 409 printf(", "); 410} 411 412static void 413print_opc_default(struct opc_operands *operands) 414{ 415 print_dst(operands->dst, true); 416 print_src(operands->src0, true); 417 print_src(operands->src1, true); 418 print_src(operands->src2, false); 419} 420 421static void 422print_opc_mov(struct opc_operands *operands) 423{ 424 // dst (areg) 425 printf("a%u", operands->dst->reg); 426 print_components(operands->dst->comps); 427 printf(", "); 428 429 print_src(operands->src0, true); 430 print_src(operands->src1, true); 431 print_src(operands->src2, false); 432} 433 434static void 435print_opc_tex(struct opc_operands *operands) 436{ 437 print_dst(operands->dst, true); 438 print_tex(operands->tex, true); 439 print_src(operands->src0, true); 440 print_src(operands->src1, true); 441 print_src(operands->src2, false); 442} 443 444static void 445print_opc_imm(struct opc_operands *operands) 446{ 447 print_dst(operands->dst, true); 448 print_src(operands->src0, true); 449 print_src(operands->src1, true); 450 printf("label_%04d", operands->imm); 451} 452 453#define OPC_BITS 7 454 455static const struct opc_info { 456 const char *name; 457 void (*print)(struct opc_operands *operands); 458} opcs[1 << OPC_BITS] = { 459#define OPC(opc) [INST_OPCODE_##opc] = {#opc, print_opc_default} 460#define OPC_MOV(opc) [INST_OPCODE_##opc] = {#opc, print_opc_mov} 461#define OPC_TEX(opc) [INST_OPCODE_##opc] = {#opc, print_opc_tex} 462#define OPC_IMM(opc) [INST_OPCODE_##opc] = {#opc, print_opc_imm} 463 OPC(NOP), 464 OPC(ADD), 465 OPC(MAD), 466 OPC(MUL), 467 OPC(DST), 468 OPC(DP3), 469 OPC(DP4), 470 OPC(DSX), 471 OPC(DSY), 472 OPC(MOV), 473 OPC_MOV(MOVAR), 474 OPC_MOV(MOVAF), 475 OPC(RCP), 476 OPC(RSQ), 477 OPC(LITP), 478 OPC(SELECT), 479 OPC(SET), 480 OPC(EXP), 481 OPC(LOG), 482 OPC(FRC), 483 OPC_IMM(CALL), 484 OPC(RET), 485 OPC_IMM(BRANCH), 486 OPC_TEX(TEXKILL), 487 OPC_TEX(TEXLD), 488 OPC_TEX(TEXLDB), 489 OPC_TEX(TEXLDD), 490 OPC_TEX(TEXLDL), 491 OPC_TEX(TEXLDPCF), 492 OPC(REP), 493 OPC(ENDREP), 494 OPC(LOOP), 495 OPC(ENDLOOP), 496 OPC(SQRT), 497 OPC(SIN), 498 OPC(COS), 499 OPC(FLOOR), 500 OPC(CEIL), 501 OPC(SIGN), 502 OPC(I2F), 503 OPC(CMP), 504 OPC(LOAD), 505 OPC(STORE), 506 OPC(IMULLO0), 507 OPC(IMULHI0), 508 OPC(LEADZERO), 509 OPC(LSHIFT), 510 OPC(RSHIFT), 511 OPC(ROTATE), 512 OPC(OR), 513 OPC(AND), 514 OPC(XOR), 515 OPC(NOT), 516}; 517 518static void 519print_instr(uint32_t *dwords, int n, enum debug_t debug) 520{ 521 struct instr *instr = (struct instr *)dwords; 522 const unsigned opc = instr->opc | (instr->opcode_bit6 << 6); 523 const char *name = opcs[opc].name; 524 525 printf("%04d: ", n); 526 if (debug & PRINT_RAW) 527 printf("%08x %08x %08x %08x ", dwords[0], dwords[1], dwords[2], 528 dwords[3]); 529 530 if (name) { 531 532 struct dst_operand dst = { 533 .use = instr->dst_use, 534 .amode = instr->dst_amode, 535 .reg = instr->dst_reg, 536 .comps = instr->dst_comps 537 }; 538 539 struct tex_operand tex = { 540 .id = instr->tex_id, 541 .amode = instr->tex_amode, 542 .swiz = instr->tex_swiz, 543 }; 544 545 struct src_operand src0 = { 546 .use = instr->src0_use, 547 .neg = instr->src0_neg, 548 .abs = instr->src0_abs, 549 .rgroup = instr->src0_rgroup, 550 .reg = instr->src0_reg, 551 .swiz = instr->src0_swiz, 552 .amode = instr->src0_amode, 553 }; 554 555 struct src_operand src1 = { 556 .use = instr->src1_use, 557 .neg = instr->src1_neg, 558 .abs = instr->src1_abs, 559 .rgroup = instr->src1_rgroup, 560 .reg = instr->src1_reg, 561 .swiz = instr->src1_swiz, 562 .amode = instr->src1_amode, 563 }; 564 565 struct src_operand src2 = { 566 .use = instr->src2_use, 567 .neg = instr->src2_neg, 568 .abs = instr->src2_abs, 569 .rgroup = instr->src2_rgroup, 570 .reg = instr->src2_reg, 571 .swiz = instr->src2_swiz, 572 .amode = instr->src2_amode, 573 }; 574 575 int imm = (instr->dword3 & VIV_ISA_WORD_3_SRC2_IMM__MASK) 576 >> VIV_ISA_WORD_3_SRC2_IMM__SHIFT; 577 578 struct opc_operands operands = { 579 .dst = &dst, 580 .tex = &tex, 581 .src0 = &src0, 582 .src1 = &src1, 583 .src2 = &src2, 584 .imm = imm, 585 }; 586 587 uint8_t type = instr->type_bit01 | (instr->type_bit2 << 2); 588 589 printf("%s", name); 590 printf_type(type); 591 if (instr->sat) 592 printf(".SAT"); 593 print_condition(instr->cond); 594 printf(" "); 595 opcs[opc].print(&operands); 596 } else { 597 printf("unknown (%d)", instr->opc); 598 } 599 600 printf("\n"); 601} 602 603void 604etna_disasm(uint32_t *dwords, int sizedwords, enum debug_t debug) 605{ 606 unsigned i; 607 608 assert((sizedwords % 2) == 0); 609 610 for (i = 0; i < sizedwords; i += 4) 611 print_instr(&dwords[i], i / 4, debug); 612} 613