xref: /aosp_15_r20/external/mesa3d/src/freedreno/ir2/disasm-a2xx.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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