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