1/* 2 * Copyright (c) 2012 Rob Clark <robdclark@gmail.com> 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, sublicense, 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 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 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 FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 * SOFTWARE. 22 */ 23 24#include <fcntl.h> 25#include <stdint.h> 26#include <stdio.h> 27#include <stdlib.h> 28#include <string.h> 29#include <unistd.h> 30#include <sys/stat.h> 31#include <sys/types.h> 32 33#include "disasm.h" 34#include "instr-a2xx.h" 35 36static const char *levels[] = { 37 "\t", 38 "\t\t", 39 "\t\t\t", 40 "\t\t\t\t", 41 "\t\t\t\t\t", 42 "\t\t\t\t\t\t", 43 "\t\t\t\t\t\t\t", 44 "\t\t\t\t\t\t\t\t", 45 "\t\t\t\t\t\t\t\t\t", 46 "x", 47 "x", 48 "x", 49 "x", 50 "x", 51 "x", 52}; 53 54static enum debug_t debug; 55 56/* 57 * ALU instructions: 58 */ 59 60static const char chan_names[] = { 61 'x', 62 'y', 63 'z', 64 'w', 65 /* these only apply to FETCH dst's: */ 66 '0', 67 '1', 68 '?', 69 '_', 70}; 71 72static void 73print_srcreg(uint32_t num, uint32_t type, uint32_t swiz, uint32_t negate, 74 uint32_t abs) 75{ 76 if (negate) 77 printf("-"); 78 if (abs) 79 printf("|"); 80 printf("%c%u", type ? 'R' : 'C', num); 81 if (swiz) { 82 int i; 83 printf("."); 84 for (i = 0; i < 4; i++) { 85 printf("%c", chan_names[(swiz + i) & 0x3]); 86 swiz >>= 2; 87 } 88 } 89 if (abs) 90 printf("|"); 91} 92 93static void 94print_dstreg(uint32_t num, uint32_t mask, uint32_t dst_exp) 95{ 96 printf("%s%u", dst_exp ? "export" : "R", num); 97 if (mask != 0xf) { 98 int i; 99 printf("."); 100 for (i = 0; i < 4; i++) { 101 printf("%c", (mask & 0x1) ? chan_names[i] : '_'); 102 mask >>= 1; 103 } 104 } 105} 106 107static void 108print_export_comment(uint32_t num, gl_shader_stage type) 109{ 110 const char *name = NULL; 111 switch (type) { 112 case MESA_SHADER_VERTEX: 113 switch (num) { 114 case 62: 115 name = "gl_Position"; 116 break; 117 case 63: 118 name = "gl_PointSize"; 119 break; 120 } 121 break; 122 case MESA_SHADER_FRAGMENT: 123 switch (num) { 124 case 0: 125 name = "gl_FragColor"; 126 break; 127 } 128 break; 129 default: 130 assert(!"not reached"); 131 } 132 /* if we had a symbol table here, we could look 133 * up the name of the varying.. 134 */ 135 if (name) { 136 printf("\t; %s", name); 137 } 138} 139 140struct { 141 uint32_t num_srcs; 142 const char *name; 143} vector_instructions[0x20] = { 144#define INSTR(opc, num_srcs) [opc] = {num_srcs, #opc} 145 INSTR(ADDv, 2), 146 INSTR(MULv, 2), 147 INSTR(MAXv, 2), 148 INSTR(MINv, 2), 149 INSTR(SETEv, 2), 150 INSTR(SETGTv, 2), 151 INSTR(SETGTEv, 2), 152 INSTR(SETNEv, 2), 153 INSTR(FRACv, 1), 154 INSTR(TRUNCv, 1), 155 INSTR(FLOORv, 1), 156 INSTR(MULADDv, 3), 157 INSTR(CNDEv, 3), 158 INSTR(CNDGTEv, 3), 159 INSTR(CNDGTv, 3), 160 INSTR(DOT4v, 2), 161 INSTR(DOT3v, 2), 162 INSTR(DOT2ADDv, 3), // ??? 163 INSTR(CUBEv, 2), 164 INSTR(MAX4v, 1), 165 INSTR(PRED_SETE_PUSHv, 2), 166 INSTR(PRED_SETNE_PUSHv, 2), 167 INSTR(PRED_SETGT_PUSHv, 2), 168 INSTR(PRED_SETGTE_PUSHv, 2), 169 INSTR(KILLEv, 2), 170 INSTR(KILLGTv, 2), 171 INSTR(KILLGTEv, 2), 172 INSTR(KILLNEv, 2), 173 INSTR(DSTv, 2), 174 INSTR(MOVAv, 1), 175}, scalar_instructions[0x40] = { 176 INSTR(ADDs, 1), 177 INSTR(ADD_PREVs, 1), 178 INSTR(MULs, 1), 179 INSTR(MUL_PREVs, 1), 180 INSTR(MUL_PREV2s, 1), 181 INSTR(MAXs, 1), 182 INSTR(MINs, 1), 183 INSTR(SETEs, 1), 184 INSTR(SETGTs, 1), 185 INSTR(SETGTEs, 1), 186 INSTR(SETNEs, 1), 187 INSTR(FRACs, 1), 188 INSTR(TRUNCs, 1), 189 INSTR(FLOORs, 1), 190 INSTR(EXP_IEEE, 1), 191 INSTR(LOG_CLAMP, 1), 192 INSTR(LOG_IEEE, 1), 193 INSTR(RECIP_CLAMP, 1), 194 INSTR(RECIP_FF, 1), 195 INSTR(RECIP_IEEE, 1), 196 INSTR(RECIPSQ_CLAMP, 1), 197 INSTR(RECIPSQ_FF, 1), 198 INSTR(RECIPSQ_IEEE, 1), 199 INSTR(MOVAs, 1), 200 INSTR(MOVA_FLOORs, 1), 201 INSTR(SUBs, 1), 202 INSTR(SUB_PREVs, 1), 203 INSTR(PRED_SETEs, 1), 204 INSTR(PRED_SETNEs, 1), 205 INSTR(PRED_SETGTs, 1), 206 INSTR(PRED_SETGTEs, 1), 207 INSTR(PRED_SET_INVs, 1), 208 INSTR(PRED_SET_POPs, 1), 209 INSTR(PRED_SET_CLRs, 1), 210 INSTR(PRED_SET_RESTOREs, 1), 211 INSTR(KILLEs, 1), 212 INSTR(KILLGTs, 1), 213 INSTR(KILLGTEs, 1), 214 INSTR(KILLNEs, 1), 215 INSTR(KILLONEs, 1), 216 INSTR(SQRT_IEEE, 1), 217 INSTR(MUL_CONST_0, 1), 218 INSTR(MUL_CONST_1, 1), 219 INSTR(ADD_CONST_0, 1), 220 INSTR(ADD_CONST_1, 1), 221 INSTR(SUB_CONST_0, 1), 222 INSTR(SUB_CONST_1, 1), 223 INSTR(SIN, 1), 224 INSTR(COS, 1), 225 INSTR(RETAIN_PREV, 1), 226#undef INSTR 227}; 228 229static int 230disasm_alu(uint32_t *dwords, uint32_t alu_off, int level, int sync, 231 gl_shader_stage type) 232{ 233 instr_alu_t *alu = (instr_alu_t *)dwords; 234 235 printf("%s", levels[level]); 236 if (debug & PRINT_RAW) { 237 printf("%02x: %08x %08x %08x\t", alu_off, dwords[0], dwords[1], 238 dwords[2]); 239 } 240 241 printf(" %sALU:\t", sync ? "(S)" : " "); 242 243 printf("%s", vector_instructions[alu->vector_opc].name); 244 245 if (alu->pred_select & 0x2) { 246 /* seems to work similar to conditional execution in ARM instruction 247 * set, so let's use a similar syntax for now: 248 */ 249 printf((alu->pred_select & 0x1) ? "EQ" : "NE"); 250 } 251 252 printf("\t"); 253 254 print_dstreg(alu->vector_dest, alu->vector_write_mask, alu->export_data); 255 printf(" = "); 256 if (vector_instructions[alu->vector_opc].num_srcs == 3) { 257 print_srcreg(alu->src3_reg, alu->src3_sel, alu->src3_swiz, 258 alu->src3_reg_negate, alu->src3_reg_abs); 259 printf(", "); 260 } 261 print_srcreg(alu->src1_reg, alu->src1_sel, alu->src1_swiz, 262 alu->src1_reg_negate, alu->src1_reg_abs); 263 if (vector_instructions[alu->vector_opc].num_srcs > 1) { 264 printf(", "); 265 print_srcreg(alu->src2_reg, alu->src2_sel, alu->src2_swiz, 266 alu->src2_reg_negate, alu->src2_reg_abs); 267 } 268 269 if (alu->vector_clamp) 270 printf(" CLAMP"); 271 272 if (alu->export_data) 273 print_export_comment(alu->vector_dest, type); 274 275 printf("\n"); 276 277 if (alu->scalar_write_mask || !alu->vector_write_mask) { 278 /* 2nd optional scalar op: */ 279 280 printf("%s", levels[level]); 281 if (debug & PRINT_RAW) 282 printf(" \t"); 283 284 if (scalar_instructions[alu->scalar_opc].name) { 285 printf("\t \t%s\t", scalar_instructions[alu->scalar_opc].name); 286 } else { 287 printf("\t \tOP(%u)\t", alu->scalar_opc); 288 } 289 290 print_dstreg(alu->scalar_dest, alu->scalar_write_mask, alu->export_data); 291 printf(" = "); 292 print_srcreg(alu->src3_reg, alu->src3_sel, alu->src3_swiz, 293 alu->src3_reg_negate, alu->src3_reg_abs); 294 // TODO ADD/MUL must have another src?!? 295 if (alu->scalar_clamp) 296 printf(" CLAMP"); 297 if (alu->export_data) 298 print_export_comment(alu->scalar_dest, type); 299 printf("\n"); 300 } 301 302 return 0; 303} 304 305/* 306 * FETCH instructions: 307 */ 308 309struct { 310 const char *name; 311} fetch_types[0xff] = { 312#define TYPE(id) [id] = {#id} 313 TYPE(FMT_1_REVERSE), 314 TYPE(FMT_32_FLOAT), 315 TYPE(FMT_32_32_FLOAT), 316 TYPE(FMT_32_32_32_FLOAT), 317 TYPE(FMT_32_32_32_32_FLOAT), 318 TYPE(FMT_16), 319 TYPE(FMT_16_16), 320 TYPE(FMT_16_16_16_16), 321 TYPE(FMT_8), 322 TYPE(FMT_8_8), 323 TYPE(FMT_8_8_8_8), 324 TYPE(FMT_32), 325 TYPE(FMT_32_32), 326 TYPE(FMT_32_32_32_32), 327#undef TYPE 328}; 329 330static void 331print_fetch_dst(uint32_t dst_reg, uint32_t dst_swiz) 332{ 333 int i; 334 printf("\tR%u.", dst_reg); 335 for (i = 0; i < 4; i++) { 336 printf("%c", chan_names[dst_swiz & 0x7]); 337 dst_swiz >>= 3; 338 } 339} 340 341static void 342print_fetch_vtx(instr_fetch_t *fetch) 343{ 344 instr_fetch_vtx_t *vtx = &fetch->vtx; 345 346 if (vtx->pred_select) { 347 /* seems to work similar to conditional execution in ARM instruction 348 * set, so let's use a similar syntax for now: 349 */ 350 printf(vtx->pred_condition ? "EQ" : "NE"); 351 } 352 353 print_fetch_dst(vtx->dst_reg, vtx->dst_swiz); 354 printf(" = R%u.", vtx->src_reg); 355 printf("%c", chan_names[vtx->src_swiz & 0x3]); 356 if (fetch_types[vtx->format].name) { 357 printf(" %s", fetch_types[vtx->format].name); 358 } else { 359 printf(" TYPE(0x%x)", vtx->format); 360 } 361 printf(" %s", vtx->format_comp_all ? "SIGNED" : "UNSIGNED"); 362 if (!vtx->num_format_all) 363 printf(" NORMALIZED"); 364 printf(" STRIDE(%u)", vtx->stride); 365 if (vtx->offset) 366 printf(" OFFSET(%u)", vtx->offset); 367 printf(" CONST(%u, %u)", vtx->const_index, vtx->const_index_sel); 368 if (0) { 369 // XXX 370 printf(" src_reg_am=%u", vtx->src_reg_am); 371 printf(" dst_reg_am=%u", vtx->dst_reg_am); 372 printf(" num_format_all=%u", vtx->num_format_all); 373 printf(" signed_rf_mode_all=%u", vtx->signed_rf_mode_all); 374 printf(" exp_adjust_all=%u", vtx->exp_adjust_all); 375 } 376} 377 378static void 379print_fetch_tex(instr_fetch_t *fetch) 380{ 381 static const char *filter[] = { 382 [TEX_FILTER_POINT] = "POINT", 383 [TEX_FILTER_LINEAR] = "LINEAR", 384 [TEX_FILTER_BASEMAP] = "BASEMAP", 385 }; 386 static const char *aniso_filter[] = { 387 [ANISO_FILTER_DISABLED] = "DISABLED", 388 [ANISO_FILTER_MAX_1_1] = "MAX_1_1", 389 [ANISO_FILTER_MAX_2_1] = "MAX_2_1", 390 [ANISO_FILTER_MAX_4_1] = "MAX_4_1", 391 [ANISO_FILTER_MAX_8_1] = "MAX_8_1", 392 [ANISO_FILTER_MAX_16_1] = "MAX_16_1", 393 }; 394 static const char *arbitrary_filter[] = { 395 [ARBITRARY_FILTER_2X4_SYM] = "2x4_SYM", 396 [ARBITRARY_FILTER_2X4_ASYM] = "2x4_ASYM", 397 [ARBITRARY_FILTER_4X2_SYM] = "4x2_SYM", 398 [ARBITRARY_FILTER_4X2_ASYM] = "4x2_ASYM", 399 [ARBITRARY_FILTER_4X4_SYM] = "4x4_SYM", 400 [ARBITRARY_FILTER_4X4_ASYM] = "4x4_ASYM", 401 }; 402 static const char *sample_loc[] = { 403 [SAMPLE_CENTROID] = "CENTROID", 404 [SAMPLE_CENTER] = "CENTER", 405 }; 406 instr_fetch_tex_t *tex = &fetch->tex; 407 uint32_t src_swiz = tex->src_swiz; 408 int i; 409 410 if (tex->pred_select) { 411 /* seems to work similar to conditional execution in ARM instruction 412 * set, so let's use a similar syntax for now: 413 */ 414 printf(tex->pred_condition ? "EQ" : "NE"); 415 } 416 417 print_fetch_dst(tex->dst_reg, tex->dst_swiz); 418 printf(" = R%u.", tex->src_reg); 419 for (i = 0; i < 3; i++) { 420 printf("%c", chan_names[src_swiz & 0x3]); 421 src_swiz >>= 2; 422 } 423 printf(" CONST(%u)", tex->const_idx); 424 if (tex->fetch_valid_only) 425 printf(" VALID_ONLY"); 426 if (tex->tx_coord_denorm) 427 printf(" DENORM"); 428 if (tex->mag_filter != TEX_FILTER_USE_FETCH_CONST) 429 printf(" MAG(%s)", filter[tex->mag_filter]); 430 if (tex->min_filter != TEX_FILTER_USE_FETCH_CONST) 431 printf(" MIN(%s)", filter[tex->min_filter]); 432 if (tex->mip_filter != TEX_FILTER_USE_FETCH_CONST) 433 printf(" MIP(%s)", filter[tex->mip_filter]); 434 if (tex->aniso_filter != ANISO_FILTER_USE_FETCH_CONST) 435 printf(" ANISO(%s)", aniso_filter[tex->aniso_filter]); 436 if (tex->arbitrary_filter != ARBITRARY_FILTER_USE_FETCH_CONST) 437 printf(" ARBITRARY(%s)", arbitrary_filter[tex->arbitrary_filter]); 438 if (tex->vol_mag_filter != TEX_FILTER_USE_FETCH_CONST) 439 printf(" VOL_MAG(%s)", filter[tex->vol_mag_filter]); 440 if (tex->vol_min_filter != TEX_FILTER_USE_FETCH_CONST) 441 printf(" VOL_MIN(%s)", filter[tex->vol_min_filter]); 442 if (!tex->use_comp_lod) { 443 printf(" LOD(%u)", tex->use_comp_lod); 444 printf(" LOD_BIAS(%u)", tex->lod_bias); 445 } 446 if (tex->use_reg_lod) { 447 printf(" REG_LOD(%u)", tex->use_reg_lod); 448 } 449 if (tex->use_reg_gradients) 450 printf(" USE_REG_GRADIENTS"); 451 printf(" LOCATION(%s)", sample_loc[tex->sample_location]); 452 if (tex->offset_x || tex->offset_y || tex->offset_z) 453 printf(" OFFSET(%u,%u,%u)", tex->offset_x, tex->offset_y, tex->offset_z); 454} 455 456struct { 457 const char *name; 458 void (*fxn)(instr_fetch_t *cf); 459} fetch_instructions[] = { 460#define INSTR(opc, name, fxn) [opc] = {name, fxn} 461 INSTR(VTX_FETCH, "VERTEX", print_fetch_vtx), 462 INSTR(TEX_FETCH, "SAMPLE", print_fetch_tex), 463 INSTR(TEX_GET_BORDER_COLOR_FRAC, "?", print_fetch_tex), 464 INSTR(TEX_GET_COMP_TEX_LOD, "?", print_fetch_tex), 465 INSTR(TEX_GET_GRADIENTS, "?", print_fetch_tex), 466 INSTR(TEX_GET_WEIGHTS, "?", print_fetch_tex), 467 INSTR(TEX_SET_TEX_LOD, "SET_TEX_LOD", print_fetch_tex), 468 INSTR(TEX_SET_GRADIENTS_H, "?", print_fetch_tex), 469 INSTR(TEX_SET_GRADIENTS_V, "?", print_fetch_tex), 470 INSTR(TEX_RESERVED_4, "?", print_fetch_tex), 471#undef INSTR 472}; 473 474static int 475disasm_fetch(uint32_t *dwords, uint32_t alu_off, int level, int sync) 476{ 477 instr_fetch_t *fetch = (instr_fetch_t *)dwords; 478 479 printf("%s", levels[level]); 480 if (debug & PRINT_RAW) { 481 printf("%02x: %08x %08x %08x\t", alu_off, dwords[0], dwords[1], 482 dwords[2]); 483 } 484 485 printf(" %sFETCH:\t", sync ? "(S)" : " "); 486 printf("%s", fetch_instructions[fetch->opc].name); 487 fetch_instructions[fetch->opc].fxn(fetch); 488 printf("\n"); 489 490 return 0; 491} 492 493/* 494 * CF instructions: 495 */ 496 497static int 498cf_exec(instr_cf_t *cf) 499{ 500 return (cf->opc == EXEC) || (cf->opc == EXEC_END) || 501 (cf->opc == COND_EXEC) || (cf->opc == COND_EXEC_END) || 502 (cf->opc == COND_PRED_EXEC) || (cf->opc == COND_PRED_EXEC_END) || 503 (cf->opc == COND_EXEC_PRED_CLEAN) || 504 (cf->opc == COND_EXEC_PRED_CLEAN_END); 505} 506 507static int 508cf_cond_exec(instr_cf_t *cf) 509{ 510 return (cf->opc == COND_EXEC) || (cf->opc == COND_EXEC_END) || 511 (cf->opc == COND_PRED_EXEC) || (cf->opc == COND_PRED_EXEC_END) || 512 (cf->opc == COND_EXEC_PRED_CLEAN) || 513 (cf->opc == COND_EXEC_PRED_CLEAN_END); 514} 515 516static void 517print_cf_nop(instr_cf_t *cf) 518{ 519} 520 521static void 522print_cf_exec(instr_cf_t *cf) 523{ 524 printf(" ADDR(0x%x) CNT(0x%x)", cf->exec.address, cf->exec.count); 525 if (cf->exec.yeild) 526 printf(" YIELD"); 527 if (cf->exec.vc) 528 printf(" VC(0x%x)", cf->exec.vc); 529 if (cf->exec.bool_addr) 530 printf(" BOOL_ADDR(0x%x)", cf->exec.bool_addr); 531 if (cf->exec.address_mode == ABSOLUTE_ADDR) 532 printf(" ABSOLUTE_ADDR"); 533 if (cf_cond_exec(cf)) 534 printf(" COND(%d)", cf->exec.condition); 535} 536 537static void 538print_cf_loop(instr_cf_t *cf) 539{ 540 printf(" ADDR(0x%x) LOOP_ID(%d)", cf->loop.address, cf->loop.loop_id); 541 if (cf->loop.address_mode == ABSOLUTE_ADDR) 542 printf(" ABSOLUTE_ADDR"); 543} 544 545static void 546print_cf_jmp_call(instr_cf_t *cf) 547{ 548 printf(" ADDR(0x%x) DIR(%d)", cf->jmp_call.address, cf->jmp_call.direction); 549 if (cf->jmp_call.force_call) 550 printf(" FORCE_CALL"); 551 if (cf->jmp_call.predicated_jmp) 552 printf(" COND(%d)", cf->jmp_call.condition); 553 if (cf->jmp_call.bool_addr) 554 printf(" BOOL_ADDR(0x%x)", cf->jmp_call.bool_addr); 555 if (cf->jmp_call.address_mode == ABSOLUTE_ADDR) 556 printf(" ABSOLUTE_ADDR"); 557} 558 559static void 560print_cf_alloc(instr_cf_t *cf) 561{ 562 static const char *bufname[] = { 563 [SQ_NO_ALLOC] = "NO ALLOC", 564 [SQ_POSITION] = "POSITION", 565 [SQ_PARAMETER_PIXEL] = "PARAM/PIXEL", 566 [SQ_MEMORY] = "MEMORY", 567 }; 568 printf(" %s SIZE(0x%x)", bufname[cf->alloc.buffer_select], cf->alloc.size); 569 if (cf->alloc.no_serial) 570 printf(" NO_SERIAL"); 571 if (cf->alloc.alloc_mode) // ??? 572 printf(" ALLOC_MODE"); 573} 574 575struct { 576 const char *name; 577 void (*fxn)(instr_cf_t *cf); 578} cf_instructions[] = { 579#define INSTR(opc, fxn) [opc] = {#opc, fxn} 580 INSTR(NOP, print_cf_nop), 581 INSTR(EXEC, print_cf_exec), 582 INSTR(EXEC_END, print_cf_exec), 583 INSTR(COND_EXEC, print_cf_exec), 584 INSTR(COND_EXEC_END, print_cf_exec), 585 INSTR(COND_PRED_EXEC, print_cf_exec), 586 INSTR(COND_PRED_EXEC_END, print_cf_exec), 587 INSTR(LOOP_START, print_cf_loop), 588 INSTR(LOOP_END, print_cf_loop), 589 INSTR(COND_CALL, print_cf_jmp_call), 590 INSTR(RETURN, print_cf_jmp_call), 591 INSTR(COND_JMP, print_cf_jmp_call), 592 INSTR(ALLOC, print_cf_alloc), 593 INSTR(COND_EXEC_PRED_CLEAN, print_cf_exec), 594 INSTR(COND_EXEC_PRED_CLEAN_END, print_cf_exec), 595 INSTR(MARK_VS_FETCH_DONE, print_cf_nop), // ?? 596#undef INSTR 597}; 598 599static void 600print_cf(instr_cf_t *cf, int level) 601{ 602 printf("%s", levels[level]); 603 if (debug & PRINT_RAW) { 604 uint16_t words[3]; 605 memcpy(&words, cf, sizeof(words)); 606 printf(" %04x %04x %04x \t", words[0], words[1], words[2]); 607 } 608 printf("%s", cf_instructions[cf->opc].name); 609 cf_instructions[cf->opc].fxn(cf); 610 printf("\n"); 611} 612 613/* 614 * The adreno shader microcode consists of two parts: 615 * 1) A CF (control-flow) program, at the header of the compiled shader, 616 * which refers to ALU/FETCH instructions that follow it by address. 617 * 2) ALU and FETCH instructions 618 */ 619 620int 621disasm_a2xx(uint32_t *dwords, int sizedwords, int level, gl_shader_stage type) 622{ 623 instr_cf_t *cfs = (instr_cf_t *)dwords; 624 int idx, max_idx; 625 626 for (idx = 0;; idx++) { 627 instr_cf_t *cf = &cfs[idx]; 628 if (cf_exec(cf)) { 629 max_idx = 2 * cf->exec.address; 630 break; 631 } 632 } 633 634 for (idx = 0; idx < max_idx; idx++) { 635 instr_cf_t *cf = &cfs[idx]; 636 637 print_cf(cf, level); 638 639 if (cf_exec(cf)) { 640 uint32_t sequence = cf->exec.serialize; 641 uint32_t i; 642 for (i = 0; i < cf->exec.count; i++) { 643 uint32_t alu_off = (cf->exec.address + i); 644 if (sequence & 0x1) { 645 disasm_fetch(dwords + alu_off * 3, alu_off, level, 646 sequence & 0x2); 647 } else { 648 disasm_alu(dwords + alu_off * 3, alu_off, level, sequence & 0x2, 649 type); 650 } 651 sequence >>= 2; 652 } 653 } 654 } 655 656 return 0; 657} 658 659void 660disasm_a2xx_set_debug(enum debug_t d) 661{ 662 debug = d; 663} 664