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