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