freedreno: prepare for a3xx
[mesa.git] / src / gallium / drivers / freedreno / a2xx / disasm-a2xx.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_a2xx(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 }