1 /*
2 * Copyright © 2012 Rob Clark <[email protected]>
3 * SPDX-License-Identifier: MIT
4 */
5
6 #include <fcntl.h>
7 #include <stdint.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <unistd.h>
12 #include <sys/stat.h>
13 #include <sys/types.h>
14
15 #include "disasm.h"
16 #include "instr-a2xx.h"
17
18 static const char *levels[] = {
19 "\t",
20 "\t\t",
21 "\t\t\t",
22 "\t\t\t\t",
23 "\t\t\t\t\t",
24 "\t\t\t\t\t\t",
25 "\t\t\t\t\t\t\t",
26 "\t\t\t\t\t\t\t\t",
27 "\t\t\t\t\t\t\t\t\t",
28 "x",
29 "x",
30 "x",
31 "x",
32 "x",
33 "x",
34 };
35
36 static enum debug_t debug;
37
38 /*
39 * ALU instructions:
40 */
41
42 static const char chan_names[] = {
43 'x',
44 'y',
45 'z',
46 'w',
47 /* these only apply to FETCH dst's: */
48 '0',
49 '1',
50 '?',
51 '_',
52 };
53
54 static void
print_srcreg(uint32_t num,uint32_t type,uint32_t swiz,uint32_t negate,uint32_t abs)55 print_srcreg(uint32_t num, uint32_t type, uint32_t swiz, uint32_t negate,
56 uint32_t abs)
57 {
58 if (negate)
59 printf("-");
60 if (abs)
61 printf("|");
62 printf("%c%u", type ? 'R' : 'C', num);
63 if (swiz) {
64 int i;
65 printf(".");
66 for (i = 0; i < 4; i++) {
67 printf("%c", chan_names[(swiz + i) & 0x3]);
68 swiz >>= 2;
69 }
70 }
71 if (abs)
72 printf("|");
73 }
74
75 static void
print_dstreg(uint32_t num,uint32_t mask,uint32_t dst_exp)76 print_dstreg(uint32_t num, uint32_t mask, uint32_t dst_exp)
77 {
78 printf("%s%u", dst_exp ? "export" : "R", num);
79 if (mask != 0xf) {
80 int i;
81 printf(".");
82 for (i = 0; i < 4; i++) {
83 printf("%c", (mask & 0x1) ? chan_names[i] : '_');
84 mask >>= 1;
85 }
86 }
87 }
88
89 static void
print_export_comment(uint32_t num,gl_shader_stage type)90 print_export_comment(uint32_t num, gl_shader_stage type)
91 {
92 const char *name = NULL;
93 switch (type) {
94 case MESA_SHADER_VERTEX:
95 switch (num) {
96 case 62:
97 name = "gl_Position";
98 break;
99 case 63:
100 name = "gl_PointSize";
101 break;
102 }
103 break;
104 case MESA_SHADER_FRAGMENT:
105 switch (num) {
106 case 0:
107 name = "gl_FragColor";
108 break;
109 }
110 break;
111 default:
112 assert(!"not reached");
113 }
114 /* if we had a symbol table here, we could look
115 * up the name of the varying..
116 */
117 if (name) {
118 printf("\t; %s", name);
119 }
120 }
121
122 struct {
123 uint32_t num_srcs;
124 const char *name;
125 } vector_instructions[0x20] = {
126 #define INSTR(opc, num_srcs) [opc] = {num_srcs, #opc}
127 INSTR(ADDv, 2),
128 INSTR(MULv, 2),
129 INSTR(MAXv, 2),
130 INSTR(MINv, 2),
131 INSTR(SETEv, 2),
132 INSTR(SETGTv, 2),
133 INSTR(SETGTEv, 2),
134 INSTR(SETNEv, 2),
135 INSTR(FRACv, 1),
136 INSTR(TRUNCv, 1),
137 INSTR(FLOORv, 1),
138 INSTR(MULADDv, 3),
139 INSTR(CNDEv, 3),
140 INSTR(CNDGTEv, 3),
141 INSTR(CNDGTv, 3),
142 INSTR(DOT4v, 2),
143 INSTR(DOT3v, 2),
144 INSTR(DOT2ADDv, 3), // ???
145 INSTR(CUBEv, 2),
146 INSTR(MAX4v, 1),
147 INSTR(PRED_SETE_PUSHv, 2),
148 INSTR(PRED_SETNE_PUSHv, 2),
149 INSTR(PRED_SETGT_PUSHv, 2),
150 INSTR(PRED_SETGTE_PUSHv, 2),
151 INSTR(KILLEv, 2),
152 INSTR(KILLGTv, 2),
153 INSTR(KILLGTEv, 2),
154 INSTR(KILLNEv, 2),
155 INSTR(DSTv, 2),
156 INSTR(MOVAv, 1),
157 }, scalar_instructions[0x40] = {
158 INSTR(ADDs, 1),
159 INSTR(ADD_PREVs, 1),
160 INSTR(MULs, 1),
161 INSTR(MUL_PREVs, 1),
162 INSTR(MUL_PREV2s, 1),
163 INSTR(MAXs, 1),
164 INSTR(MINs, 1),
165 INSTR(SETEs, 1),
166 INSTR(SETGTs, 1),
167 INSTR(SETGTEs, 1),
168 INSTR(SETNEs, 1),
169 INSTR(FRACs, 1),
170 INSTR(TRUNCs, 1),
171 INSTR(FLOORs, 1),
172 INSTR(EXP_IEEE, 1),
173 INSTR(LOG_CLAMP, 1),
174 INSTR(LOG_IEEE, 1),
175 INSTR(RECIP_CLAMP, 1),
176 INSTR(RECIP_FF, 1),
177 INSTR(RECIP_IEEE, 1),
178 INSTR(RECIPSQ_CLAMP, 1),
179 INSTR(RECIPSQ_FF, 1),
180 INSTR(RECIPSQ_IEEE, 1),
181 INSTR(MOVAs, 1),
182 INSTR(MOVA_FLOORs, 1),
183 INSTR(SUBs, 1),
184 INSTR(SUB_PREVs, 1),
185 INSTR(PRED_SETEs, 1),
186 INSTR(PRED_SETNEs, 1),
187 INSTR(PRED_SETGTs, 1),
188 INSTR(PRED_SETGTEs, 1),
189 INSTR(PRED_SET_INVs, 1),
190 INSTR(PRED_SET_POPs, 1),
191 INSTR(PRED_SET_CLRs, 1),
192 INSTR(PRED_SET_RESTOREs, 1),
193 INSTR(KILLEs, 1),
194 INSTR(KILLGTs, 1),
195 INSTR(KILLGTEs, 1),
196 INSTR(KILLNEs, 1),
197 INSTR(KILLONEs, 1),
198 INSTR(SQRT_IEEE, 1),
199 INSTR(MUL_CONST_0, 1),
200 INSTR(MUL_CONST_1, 1),
201 INSTR(ADD_CONST_0, 1),
202 INSTR(ADD_CONST_1, 1),
203 INSTR(SUB_CONST_0, 1),
204 INSTR(SUB_CONST_1, 1),
205 INSTR(SIN, 1),
206 INSTR(COS, 1),
207 INSTR(RETAIN_PREV, 1),
208 #undef INSTR
209 };
210
211 static int
disasm_alu(uint32_t * dwords,uint32_t alu_off,int level,int sync,gl_shader_stage type)212 disasm_alu(uint32_t *dwords, uint32_t alu_off, int level, int sync,
213 gl_shader_stage 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, dwords[0], dwords[1],
220 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 * FETCH instructions:
289 */
290
291 struct {
292 const char *name;
293 } fetch_types[0xff] = {
294 #define TYPE(id) [id] = {#id}
295 TYPE(FMT_1_REVERSE),
296 TYPE(FMT_32_FLOAT),
297 TYPE(FMT_32_32_FLOAT),
298 TYPE(FMT_32_32_32_FLOAT),
299 TYPE(FMT_32_32_32_32_FLOAT),
300 TYPE(FMT_16),
301 TYPE(FMT_16_16),
302 TYPE(FMT_16_16_16_16),
303 TYPE(FMT_8),
304 TYPE(FMT_8_8),
305 TYPE(FMT_8_8_8_8),
306 TYPE(FMT_32),
307 TYPE(FMT_32_32),
308 TYPE(FMT_32_32_32_32),
309 #undef TYPE
310 };
311
312 static void
print_fetch_dst(uint32_t dst_reg,uint32_t dst_swiz)313 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
323 static void
print_fetch_vtx(instr_fetch_t * fetch)324 print_fetch_vtx(instr_fetch_t *fetch)
325 {
326 instr_fetch_vtx_t *vtx = &fetch->vtx;
327
328 if (vtx->pred_select) {
329 /* seems to work similar to conditional execution in ARM instruction
330 * set, so let's use a similar syntax for now:
331 */
332 printf(vtx->pred_condition ? "EQ" : "NE");
333 }
334
335 print_fetch_dst(vtx->dst_reg, vtx->dst_swiz);
336 printf(" = R%u.", vtx->src_reg);
337 printf("%c", chan_names[vtx->src_swiz & 0x3]);
338 if (fetch_types[vtx->format].name) {
339 printf(" %s", fetch_types[vtx->format].name);
340 } else {
341 printf(" TYPE(0x%x)", vtx->format);
342 }
343 printf(" %s", vtx->format_comp_all ? "SIGNED" : "UNSIGNED");
344 if (!vtx->num_format_all)
345 printf(" NORMALIZED");
346 printf(" STRIDE(%u)", vtx->stride);
347 if (vtx->offset)
348 printf(" OFFSET(%u)", vtx->offset);
349 printf(" CONST(%u, %u)", vtx->const_index, vtx->const_index_sel);
350 if (0) {
351 // XXX
352 printf(" src_reg_am=%u", vtx->src_reg_am);
353 printf(" dst_reg_am=%u", vtx->dst_reg_am);
354 printf(" num_format_all=%u", vtx->num_format_all);
355 printf(" signed_rf_mode_all=%u", vtx->signed_rf_mode_all);
356 printf(" exp_adjust_all=%u", vtx->exp_adjust_all);
357 }
358 }
359
360 static void
print_fetch_tex(instr_fetch_t * fetch)361 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_lod) {
429 printf(" REG_LOD(%u)", tex->use_reg_lod);
430 }
431 if (tex->use_reg_gradients)
432 printf(" USE_REG_GRADIENTS");
433 printf(" LOCATION(%s)", sample_loc[tex->sample_location]);
434 if (tex->offset_x || tex->offset_y || tex->offset_z)
435 printf(" OFFSET(%u,%u,%u)", tex->offset_x, tex->offset_y, tex->offset_z);
436 }
437
438 struct {
439 const char *name;
440 void (*fxn)(instr_fetch_t *cf);
441 } fetch_instructions[] = {
442 #define INSTR(opc, name, fxn) [opc] = {name, fxn}
443 INSTR(VTX_FETCH, "VERTEX", print_fetch_vtx),
444 INSTR(TEX_FETCH, "SAMPLE", print_fetch_tex),
445 INSTR(TEX_GET_BORDER_COLOR_FRAC, "?", print_fetch_tex),
446 INSTR(TEX_GET_COMP_TEX_LOD, "?", print_fetch_tex),
447 INSTR(TEX_GET_GRADIENTS, "?", print_fetch_tex),
448 INSTR(TEX_GET_WEIGHTS, "?", print_fetch_tex),
449 INSTR(TEX_SET_TEX_LOD, "SET_TEX_LOD", print_fetch_tex),
450 INSTR(TEX_SET_GRADIENTS_H, "?", print_fetch_tex),
451 INSTR(TEX_SET_GRADIENTS_V, "?", print_fetch_tex),
452 INSTR(TEX_RESERVED_4, "?", print_fetch_tex),
453 #undef INSTR
454 };
455
456 static int
disasm_fetch(uint32_t * dwords,uint32_t alu_off,int level,int sync)457 disasm_fetch(uint32_t *dwords, uint32_t alu_off, int level, int sync)
458 {
459 instr_fetch_t *fetch = (instr_fetch_t *)dwords;
460
461 printf("%s", levels[level]);
462 if (debug & PRINT_RAW) {
463 printf("%02x: %08x %08x %08x\t", alu_off, dwords[0], dwords[1],
464 dwords[2]);
465 }
466
467 printf(" %sFETCH:\t", sync ? "(S)" : " ");
468 printf("%s", fetch_instructions[fetch->opc].name);
469 fetch_instructions[fetch->opc].fxn(fetch);
470 printf("\n");
471
472 return 0;
473 }
474
475 /*
476 * CF instructions:
477 */
478
479 static int
cf_exec(instr_cf_t * cf)480 cf_exec(instr_cf_t *cf)
481 {
482 return (cf->opc == EXEC) || (cf->opc == EXEC_END) ||
483 (cf->opc == COND_EXEC) || (cf->opc == COND_EXEC_END) ||
484 (cf->opc == COND_PRED_EXEC) || (cf->opc == COND_PRED_EXEC_END) ||
485 (cf->opc == COND_EXEC_PRED_CLEAN) ||
486 (cf->opc == COND_EXEC_PRED_CLEAN_END);
487 }
488
489 static int
cf_cond_exec(instr_cf_t * cf)490 cf_cond_exec(instr_cf_t *cf)
491 {
492 return (cf->opc == COND_EXEC) || (cf->opc == COND_EXEC_END) ||
493 (cf->opc == COND_PRED_EXEC) || (cf->opc == COND_PRED_EXEC_END) ||
494 (cf->opc == COND_EXEC_PRED_CLEAN) ||
495 (cf->opc == COND_EXEC_PRED_CLEAN_END);
496 }
497
498 static void
print_cf_nop(instr_cf_t * cf)499 print_cf_nop(instr_cf_t *cf)
500 {
501 }
502
503 static void
print_cf_exec(instr_cf_t * cf)504 print_cf_exec(instr_cf_t *cf)
505 {
506 printf(" ADDR(0x%x) CNT(0x%x)", cf->exec.address, cf->exec.count);
507 if (cf->exec.yeild)
508 printf(" YIELD");
509 if (cf->exec.vc)
510 printf(" VC(0x%x)", cf->exec.vc);
511 if (cf->exec.bool_addr)
512 printf(" BOOL_ADDR(0x%x)", cf->exec.bool_addr);
513 if (cf->exec.address_mode == ABSOLUTE_ADDR)
514 printf(" ABSOLUTE_ADDR");
515 if (cf_cond_exec(cf))
516 printf(" COND(%d)", cf->exec.condition);
517 }
518
519 static void
print_cf_loop(instr_cf_t * cf)520 print_cf_loop(instr_cf_t *cf)
521 {
522 printf(" ADDR(0x%x) LOOP_ID(%d)", cf->loop.address, cf->loop.loop_id);
523 if (cf->loop.address_mode == ABSOLUTE_ADDR)
524 printf(" ABSOLUTE_ADDR");
525 }
526
527 static void
print_cf_jmp_call(instr_cf_t * cf)528 print_cf_jmp_call(instr_cf_t *cf)
529 {
530 printf(" ADDR(0x%x) DIR(%d)", cf->jmp_call.address, cf->jmp_call.direction);
531 if (cf->jmp_call.force_call)
532 printf(" FORCE_CALL");
533 if (cf->jmp_call.predicated_jmp)
534 printf(" COND(%d)", cf->jmp_call.condition);
535 if (cf->jmp_call.bool_addr)
536 printf(" BOOL_ADDR(0x%x)", cf->jmp_call.bool_addr);
537 if (cf->jmp_call.address_mode == ABSOLUTE_ADDR)
538 printf(" ABSOLUTE_ADDR");
539 }
540
541 static void
print_cf_alloc(instr_cf_t * cf)542 print_cf_alloc(instr_cf_t *cf)
543 {
544 static const char *bufname[] = {
545 [SQ_NO_ALLOC] = "NO ALLOC",
546 [SQ_POSITION] = "POSITION",
547 [SQ_PARAMETER_PIXEL] = "PARAM/PIXEL",
548 [SQ_MEMORY] = "MEMORY",
549 };
550 printf(" %s SIZE(0x%x)", bufname[cf->alloc.buffer_select], cf->alloc.size);
551 if (cf->alloc.no_serial)
552 printf(" NO_SERIAL");
553 if (cf->alloc.alloc_mode) // ???
554 printf(" ALLOC_MODE");
555 }
556
557 struct {
558 const char *name;
559 void (*fxn)(instr_cf_t *cf);
560 } cf_instructions[] = {
561 #define INSTR(opc, fxn) [opc] = {#opc, fxn}
562 INSTR(NOP, print_cf_nop),
563 INSTR(EXEC, print_cf_exec),
564 INSTR(EXEC_END, print_cf_exec),
565 INSTR(COND_EXEC, print_cf_exec),
566 INSTR(COND_EXEC_END, print_cf_exec),
567 INSTR(COND_PRED_EXEC, print_cf_exec),
568 INSTR(COND_PRED_EXEC_END, print_cf_exec),
569 INSTR(LOOP_START, print_cf_loop),
570 INSTR(LOOP_END, print_cf_loop),
571 INSTR(COND_CALL, print_cf_jmp_call),
572 INSTR(RETURN, print_cf_jmp_call),
573 INSTR(COND_JMP, print_cf_jmp_call),
574 INSTR(ALLOC, print_cf_alloc),
575 INSTR(COND_EXEC_PRED_CLEAN, print_cf_exec),
576 INSTR(COND_EXEC_PRED_CLEAN_END, print_cf_exec),
577 INSTR(MARK_VS_FETCH_DONE, print_cf_nop), // ??
578 #undef INSTR
579 };
580
581 static void
print_cf(instr_cf_t * cf,int level)582 print_cf(instr_cf_t *cf, int level)
583 {
584 printf("%s", levels[level]);
585 if (debug & PRINT_RAW) {
586 uint16_t words[3];
587 memcpy(&words, cf, sizeof(words));
588 printf(" %04x %04x %04x \t", words[0], words[1], words[2]);
589 }
590 printf("%s", cf_instructions[cf->opc].name);
591 cf_instructions[cf->opc].fxn(cf);
592 printf("\n");
593 }
594
595 /*
596 * The adreno shader microcode consists of two parts:
597 * 1) A CF (control-flow) program, at the header of the compiled shader,
598 * which refers to ALU/FETCH instructions that follow it by address.
599 * 2) ALU and FETCH instructions
600 */
601
602 int
disasm_a2xx(uint32_t * dwords,int sizedwords,int level,gl_shader_stage type)603 disasm_a2xx(uint32_t *dwords, int sizedwords, int level, gl_shader_stage type)
604 {
605 instr_cf_t *cfs = (instr_cf_t *)dwords;
606 int idx, max_idx;
607
608 for (idx = 0;; idx++) {
609 instr_cf_t *cf = &cfs[idx];
610 if (cf_exec(cf)) {
611 max_idx = 2 * cf->exec.address;
612 break;
613 }
614 }
615
616 for (idx = 0; idx < max_idx; idx++) {
617 instr_cf_t *cf = &cfs[idx];
618
619 print_cf(cf, level);
620
621 if (cf_exec(cf)) {
622 uint32_t sequence = cf->exec.serialize;
623 uint32_t i;
624 for (i = 0; i < cf->exec.count; i++) {
625 uint32_t alu_off = (cf->exec.address + i);
626 if (sequence & 0x1) {
627 disasm_fetch(dwords + alu_off * 3, alu_off, level,
628 sequence & 0x2);
629 } else {
630 disasm_alu(dwords + alu_off * 3, alu_off, level, sequence & 0x2,
631 type);
632 }
633 sequence >>= 2;
634 }
635 }
636 }
637
638 return 0;
639 }
640
641 void
disasm_a2xx_set_debug(enum debug_t d)642 disasm_a2xx_set_debug(enum debug_t d)
643 {
644 debug = d;
645 }
646