• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
36 static 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 
54 static enum debug_t debug;
55 
56 /*
57  * ALU instructions:
58  */
59 
60 static 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 
72 static void
print_srcreg(uint32_t num,uint32_t type,uint32_t swiz,uint32_t negate,uint32_t abs)73 print_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 
93 static void
print_dstreg(uint32_t num,uint32_t mask,uint32_t dst_exp)94 print_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 
107 static void
print_export_comment(uint32_t num,gl_shader_stage type)108 print_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 
140 struct {
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 
229 static int
disasm_alu(uint32_t * dwords,uint32_t alu_off,int level,int sync,gl_shader_stage type)230 disasm_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 
309 struct {
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 
330 static void
print_fetch_dst(uint32_t dst_reg,uint32_t dst_swiz)331 print_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 
341 static void
print_fetch_vtx(instr_fetch_t * fetch)342 print_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 
378 static void
print_fetch_tex(instr_fetch_t * fetch)379 print_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 
456 struct {
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 
474 static int
disasm_fetch(uint32_t * dwords,uint32_t alu_off,int level,int sync)475 disasm_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 
497 static int
cf_exec(instr_cf_t * cf)498 cf_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 
507 static int
cf_cond_exec(instr_cf_t * cf)508 cf_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 
516 static void
print_cf_nop(instr_cf_t * cf)517 print_cf_nop(instr_cf_t *cf)
518 {
519 }
520 
521 static void
print_cf_exec(instr_cf_t * cf)522 print_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 
537 static void
print_cf_loop(instr_cf_t * cf)538 print_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 
545 static void
print_cf_jmp_call(instr_cf_t * cf)546 print_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 
559 static void
print_cf_alloc(instr_cf_t * cf)560 print_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 
575 struct {
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 
599 static void
print_cf(instr_cf_t * cf,int level)600 print_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 
620 int
disasm_a2xx(uint32_t * dwords,int sizedwords,int level,gl_shader_stage type)621 disasm_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 
659 void
disasm_a2xx_set_debug(enum debug_t d)660 disasm_a2xx_set_debug(enum debug_t d)
661 {
662    debug = d;
663 }
664