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
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',
62   'y',
63   'z',
64   'w',
65   /* these only apply to FETCH dst's: */
66   '0',
67   '1',
68   '?',
69   '_',
70};
71
72static void
73print_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
93static void
94print_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
107static void
108print_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
140struct {
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
229static int
230disasm_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
309struct {
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
330static void
331print_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
341static void
342print_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
378static void
379print_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
456struct {
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
474static int
475disasm_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
497static int
498cf_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
507static int
508cf_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
516static void
517print_cf_nop(instr_cf_t *cf)
518{
519}
520
521static void
522print_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
537static void
538print_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
545static void
546print_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
559static void
560print_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
575struct {
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
599static void
600print_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
620int
621disasm_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
659void
660disasm_a2xx_set_debug(enum debug_t d)
661{
662   debug = d;
663}
664