OSDN Git Service

gallivm: work around slow code generated for interleaving 128bit vectors
[android-x86/external-mesa.git] / src / gallium / drivers / freedreno / disasm.c
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
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', 'y', 'z', 'w',
62                 /* these only apply to FETCH dst's: */
63                 '0', '1', '?', '_',
64 };
65
66 static 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
86 static 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
99 static 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
123 struct {
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
212 static 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
292 struct {
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
313 static 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
323 static 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
359 static 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
433 struct {
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
451 static 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
473 static 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
485 static 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
495 static void print_cf_nop(instr_cf_t *cf)
496 {
497 }
498
499 static 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
514 static 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
521 static 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
534 static 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
549 struct {
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
573 static 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
593 int disasm(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
629 void disasm_set_debug(enum debug_t d)
630 {
631         debug= d;
632 }