b5647307038c7081473fb66b7fa789dd308891fb
[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, gl_shader_stage type)
100 {
101 const char *name = NULL;
102 switch (type) {
103 case MESA_SHADER_VERTEX:
104 switch (num) {
105 case 62: name = "gl_Position"; break;
106 case 63: name = "gl_PointSize"; break;
107 }
108 break;
109 case MESA_SHADER_FRAGMENT:
110 switch (num) {
111 case 0: name = "gl_FragColor"; break;
112 }
113 break;
114 default:
115 unreachable("not reached");
116 }
117 /* if we had a symbol table here, we could look
118 * up the name of the varying..
119 */
120 if (name) {
121 printf("\t; %s", name);
122 }
123 }
124
125 struct {
126 uint32_t num_srcs;
127 const char *name;
128 } vector_instructions[0x20] = {
129 #define INSTR(opc, num_srcs) [opc] = { num_srcs, #opc }
130 INSTR(ADDv, 2),
131 INSTR(MULv, 2),
132 INSTR(MAXv, 2),
133 INSTR(MINv, 2),
134 INSTR(SETEv, 2),
135 INSTR(SETGTv, 2),
136 INSTR(SETGTEv, 2),
137 INSTR(SETNEv, 2),
138 INSTR(FRACv, 1),
139 INSTR(TRUNCv, 1),
140 INSTR(FLOORv, 1),
141 INSTR(MULADDv, 3),
142 INSTR(CNDEv, 3),
143 INSTR(CNDGTEv, 3),
144 INSTR(CNDGTv, 3),
145 INSTR(DOT4v, 2),
146 INSTR(DOT3v, 2),
147 INSTR(DOT2ADDv, 3), // ???
148 INSTR(CUBEv, 2),
149 INSTR(MAX4v, 1),
150 INSTR(PRED_SETE_PUSHv, 2),
151 INSTR(PRED_SETNE_PUSHv, 2),
152 INSTR(PRED_SETGT_PUSHv, 2),
153 INSTR(PRED_SETGTE_PUSHv, 2),
154 INSTR(KILLEv, 2),
155 INSTR(KILLGTv, 2),
156 INSTR(KILLGTEv, 2),
157 INSTR(KILLNEv, 2),
158 INSTR(DSTv, 2),
159 INSTR(MOVAv, 1),
160 }, scalar_instructions[0x40] = {
161 INSTR(ADDs, 1),
162 INSTR(ADD_PREVs, 1),
163 INSTR(MULs, 1),
164 INSTR(MUL_PREVs, 1),
165 INSTR(MUL_PREV2s, 1),
166 INSTR(MAXs, 1),
167 INSTR(MINs, 1),
168 INSTR(SETEs, 1),
169 INSTR(SETGTs, 1),
170 INSTR(SETGTEs, 1),
171 INSTR(SETNEs, 1),
172 INSTR(FRACs, 1),
173 INSTR(TRUNCs, 1),
174 INSTR(FLOORs, 1),
175 INSTR(EXP_IEEE, 1),
176 INSTR(LOG_CLAMP, 1),
177 INSTR(LOG_IEEE, 1),
178 INSTR(RECIP_CLAMP, 1),
179 INSTR(RECIP_FF, 1),
180 INSTR(RECIP_IEEE, 1),
181 INSTR(RECIPSQ_CLAMP, 1),
182 INSTR(RECIPSQ_FF, 1),
183 INSTR(RECIPSQ_IEEE, 1),
184 INSTR(MOVAs, 1),
185 INSTR(MOVA_FLOORs, 1),
186 INSTR(SUBs, 1),
187 INSTR(SUB_PREVs, 1),
188 INSTR(PRED_SETEs, 1),
189 INSTR(PRED_SETNEs, 1),
190 INSTR(PRED_SETGTs, 1),
191 INSTR(PRED_SETGTEs, 1),
192 INSTR(PRED_SET_INVs, 1),
193 INSTR(PRED_SET_POPs, 1),
194 INSTR(PRED_SET_CLRs, 1),
195 INSTR(PRED_SET_RESTOREs, 1),
196 INSTR(KILLEs, 1),
197 INSTR(KILLGTs, 1),
198 INSTR(KILLGTEs, 1),
199 INSTR(KILLNEs, 1),
200 INSTR(KILLONEs, 1),
201 INSTR(SQRT_IEEE, 1),
202 INSTR(MUL_CONST_0, 1),
203 INSTR(MUL_CONST_1, 1),
204 INSTR(ADD_CONST_0, 1),
205 INSTR(ADD_CONST_1, 1),
206 INSTR(SUB_CONST_0, 1),
207 INSTR(SUB_CONST_1, 1),
208 INSTR(SIN, 1),
209 INSTR(COS, 1),
210 INSTR(RETAIN_PREV, 1),
211 #undef INSTR
212 };
213
214 static int disasm_alu(uint32_t *dwords, uint32_t alu_off,
215 int level, int sync, gl_shader_stage type)
216 {
217 instr_alu_t *alu = (instr_alu_t *)dwords;
218
219 printf("%s", levels[level]);
220 if (debug & PRINT_RAW) {
221 printf("%02x: %08x %08x %08x\t", alu_off,
222 dwords[0], dwords[1], dwords[2]);
223 }
224
225 printf(" %sALU:\t", sync ? "(S)" : " ");
226
227 printf("%s", vector_instructions[alu->vector_opc].name);
228
229 if (alu->pred_select & 0x2) {
230 /* seems to work similar to conditional execution in ARM instruction
231 * set, so let's use a similar syntax for now:
232 */
233 printf((alu->pred_select & 0x1) ? "EQ" : "NE");
234 }
235
236 printf("\t");
237
238 print_dstreg(alu->vector_dest, alu->vector_write_mask, alu->export_data);
239 printf(" = ");
240 if (vector_instructions[alu->vector_opc].num_srcs == 3) {
241 print_srcreg(alu->src3_reg, alu->src3_sel, alu->src3_swiz,
242 alu->src3_reg_negate, alu->src3_reg_abs);
243 printf(", ");
244 }
245 print_srcreg(alu->src1_reg, alu->src1_sel, alu->src1_swiz,
246 alu->src1_reg_negate, alu->src1_reg_abs);
247 if (vector_instructions[alu->vector_opc].num_srcs > 1) {
248 printf(", ");
249 print_srcreg(alu->src2_reg, alu->src2_sel, alu->src2_swiz,
250 alu->src2_reg_negate, alu->src2_reg_abs);
251 }
252
253 if (alu->vector_clamp)
254 printf(" CLAMP");
255
256 if (alu->export_data)
257 print_export_comment(alu->vector_dest, type);
258
259 printf("\n");
260
261 if (alu->scalar_write_mask || !alu->vector_write_mask) {
262 /* 2nd optional scalar op: */
263
264 printf("%s", levels[level]);
265 if (debug & PRINT_RAW)
266 printf(" \t");
267
268 if (scalar_instructions[alu->scalar_opc].name) {
269 printf("\t \t%s\t", scalar_instructions[alu->scalar_opc].name);
270 } else {
271 printf("\t \tOP(%u)\t", alu->scalar_opc);
272 }
273
274 print_dstreg(alu->scalar_dest, alu->scalar_write_mask, alu->export_data);
275 printf(" = ");
276 print_srcreg(alu->src3_reg, alu->src3_sel, alu->src3_swiz,
277 alu->src3_reg_negate, alu->src3_reg_abs);
278 // TODO ADD/MUL must have another src?!?
279 if (alu->scalar_clamp)
280 printf(" CLAMP");
281 if (alu->export_data)
282 print_export_comment(alu->scalar_dest, type);
283 printf("\n");
284 }
285
286 return 0;
287 }
288
289
290 /*
291 * FETCH instructions:
292 */
293
294 struct {
295 const char *name;
296 } fetch_types[0xff] = {
297 #define TYPE(id) [id] = { #id }
298 TYPE(FMT_1_REVERSE),
299 TYPE(FMT_32_FLOAT),
300 TYPE(FMT_32_32_FLOAT),
301 TYPE(FMT_32_32_32_FLOAT),
302 TYPE(FMT_32_32_32_32_FLOAT),
303 TYPE(FMT_16),
304 TYPE(FMT_16_16),
305 TYPE(FMT_16_16_16_16),
306 TYPE(FMT_8),
307 TYPE(FMT_8_8),
308 TYPE(FMT_8_8_8_8),
309 TYPE(FMT_32),
310 TYPE(FMT_32_32),
311 TYPE(FMT_32_32_32_32),
312 #undef TYPE
313 };
314
315 static void print_fetch_dst(uint32_t dst_reg, uint32_t dst_swiz)
316 {
317 int i;
318 printf("\tR%u.", dst_reg);
319 for (i = 0; i < 4; i++) {
320 printf("%c", chan_names[dst_swiz & 0x7]);
321 dst_swiz >>= 3;
322 }
323 }
324
325 static void print_fetch_vtx(instr_fetch_t *fetch)
326 {
327 instr_fetch_vtx_t *vtx = &fetch->vtx;
328
329 if (vtx->pred_select) {
330 /* seems to work similar to conditional execution in ARM instruction
331 * set, so let's use a similar syntax for now:
332 */
333 printf(vtx->pred_condition ? "EQ" : "NE");
334 }
335
336 print_fetch_dst(vtx->dst_reg, vtx->dst_swiz);
337 printf(" = R%u.", vtx->src_reg);
338 printf("%c", chan_names[vtx->src_swiz & 0x3]);
339 if (fetch_types[vtx->format].name) {
340 printf(" %s", fetch_types[vtx->format].name);
341 } else {
342 printf(" TYPE(0x%x)", vtx->format);
343 }
344 printf(" %s", vtx->format_comp_all ? "SIGNED" : "UNSIGNED");
345 if (!vtx->num_format_all)
346 printf(" NORMALIZED");
347 printf(" STRIDE(%u)", vtx->stride);
348 if (vtx->offset)
349 printf(" OFFSET(%u)", vtx->offset);
350 printf(" CONST(%u, %u)", vtx->const_index, vtx->const_index_sel);
351 if (0) {
352 // XXX
353 printf(" src_reg_am=%u", vtx->src_reg_am);
354 printf(" dst_reg_am=%u", vtx->dst_reg_am);
355 printf(" num_format_all=%u", vtx->num_format_all);
356 printf(" signed_rf_mode_all=%u", vtx->signed_rf_mode_all);
357 printf(" exp_adjust_all=%u", vtx->exp_adjust_all);
358 }
359 }
360
361 static void 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_gradients)
429 printf(" USE_REG_GRADIENTS");
430 printf(" LOCATION(%s)", sample_loc[tex->sample_location]);
431 if (tex->offset_x || tex->offset_y || tex->offset_z)
432 printf(" OFFSET(%u,%u,%u)", tex->offset_x, tex->offset_y, tex->offset_z);
433 }
434
435 struct {
436 const char *name;
437 void (*fxn)(instr_fetch_t *cf);
438 } fetch_instructions[] = {
439 #define INSTR(opc, name, fxn) [opc] = { name, fxn }
440 INSTR(VTX_FETCH, "VERTEX", print_fetch_vtx),
441 INSTR(TEX_FETCH, "SAMPLE", print_fetch_tex),
442 INSTR(TEX_GET_BORDER_COLOR_FRAC, "?", print_fetch_tex),
443 INSTR(TEX_GET_COMP_TEX_LOD, "?", print_fetch_tex),
444 INSTR(TEX_GET_GRADIENTS, "?", print_fetch_tex),
445 INSTR(TEX_GET_WEIGHTS, "?", print_fetch_tex),
446 INSTR(TEX_SET_TEX_LOD, "SET_TEX_LOD", print_fetch_tex),
447 INSTR(TEX_SET_GRADIENTS_H, "?", print_fetch_tex),
448 INSTR(TEX_SET_GRADIENTS_V, "?", print_fetch_tex),
449 INSTR(TEX_RESERVED_4, "?", print_fetch_tex),
450 #undef INSTR
451 };
452
453 static int disasm_fetch(uint32_t *dwords, uint32_t alu_off, int level, int sync)
454 {
455 instr_fetch_t *fetch = (instr_fetch_t *)dwords;
456
457 printf("%s", levels[level]);
458 if (debug & PRINT_RAW) {
459 printf("%02x: %08x %08x %08x\t", alu_off,
460 dwords[0], dwords[1], dwords[2]);
461 }
462
463 printf(" %sFETCH:\t", sync ? "(S)" : " ");
464 printf("%s", fetch_instructions[fetch->opc].name);
465 fetch_instructions[fetch->opc].fxn(fetch);
466 printf("\n");
467
468 return 0;
469 }
470
471 /*
472 * CF instructions:
473 */
474
475 static int cf_exec(instr_cf_t *cf)
476 {
477 return (cf->opc == EXEC) ||
478 (cf->opc == EXEC_END) ||
479 (cf->opc == COND_EXEC) ||
480 (cf->opc == COND_EXEC_END) ||
481 (cf->opc == COND_PRED_EXEC) ||
482 (cf->opc == COND_PRED_EXEC_END) ||
483 (cf->opc == COND_EXEC_PRED_CLEAN) ||
484 (cf->opc == COND_EXEC_PRED_CLEAN_END);
485 }
486
487 static int cf_cond_exec(instr_cf_t *cf)
488 {
489 return (cf->opc == COND_EXEC) ||
490 (cf->opc == COND_EXEC_END) ||
491 (cf->opc == COND_PRED_EXEC) ||
492 (cf->opc == COND_PRED_EXEC_END) ||
493 (cf->opc == COND_EXEC_PRED_CLEAN) ||
494 (cf->opc == COND_EXEC_PRED_CLEAN_END);
495 }
496
497 static void print_cf_nop(instr_cf_t *cf)
498 {
499 }
500
501 static void print_cf_exec(instr_cf_t *cf)
502 {
503 printf(" ADDR(0x%x) CNT(0x%x)", cf->exec.address, cf->exec.count);
504 if (cf->exec.yeild)
505 printf(" YIELD");
506 if (cf->exec.vc)
507 printf(" VC(0x%x)", cf->exec.vc);
508 if (cf->exec.bool_addr)
509 printf(" BOOL_ADDR(0x%x)", cf->exec.bool_addr);
510 if (cf->exec.address_mode == ABSOLUTE_ADDR)
511 printf(" ABSOLUTE_ADDR");
512 if (cf_cond_exec(cf))
513 printf(" COND(%d)", cf->exec.condition);
514 }
515
516 static void print_cf_loop(instr_cf_t *cf)
517 {
518 printf(" ADDR(0x%x) LOOP_ID(%d)", cf->loop.address, cf->loop.loop_id);
519 if (cf->loop.address_mode == ABSOLUTE_ADDR)
520 printf(" ABSOLUTE_ADDR");
521 }
522
523 static void print_cf_jmp_call(instr_cf_t *cf)
524 {
525 printf(" ADDR(0x%x) DIR(%d)", cf->jmp_call.address, cf->jmp_call.direction);
526 if (cf->jmp_call.force_call)
527 printf(" FORCE_CALL");
528 if (cf->jmp_call.predicated_jmp)
529 printf(" COND(%d)", cf->jmp_call.condition);
530 if (cf->jmp_call.bool_addr)
531 printf(" BOOL_ADDR(0x%x)", cf->jmp_call.bool_addr);
532 if (cf->jmp_call.address_mode == ABSOLUTE_ADDR)
533 printf(" ABSOLUTE_ADDR");
534 }
535
536 static void print_cf_alloc(instr_cf_t *cf)
537 {
538 static const char *bufname[] = {
539 [SQ_NO_ALLOC] = "NO ALLOC",
540 [SQ_POSITION] = "POSITION",
541 [SQ_PARAMETER_PIXEL] = "PARAM/PIXEL",
542 [SQ_MEMORY] = "MEMORY",
543 };
544 printf(" %s SIZE(0x%x)", bufname[cf->alloc.buffer_select], cf->alloc.size);
545 if (cf->alloc.no_serial)
546 printf(" NO_SERIAL");
547 if (cf->alloc.alloc_mode) // ???
548 printf(" ALLOC_MODE");
549 }
550
551 struct {
552 const char *name;
553 void (*fxn)(instr_cf_t *cf);
554 } cf_instructions[] = {
555 #define INSTR(opc, fxn) [opc] = { #opc, fxn }
556 INSTR(NOP, print_cf_nop),
557 INSTR(EXEC, print_cf_exec),
558 INSTR(EXEC_END, print_cf_exec),
559 INSTR(COND_EXEC, print_cf_exec),
560 INSTR(COND_EXEC_END, print_cf_exec),
561 INSTR(COND_PRED_EXEC, print_cf_exec),
562 INSTR(COND_PRED_EXEC_END, print_cf_exec),
563 INSTR(LOOP_START, print_cf_loop),
564 INSTR(LOOP_END, print_cf_loop),
565 INSTR(COND_CALL, print_cf_jmp_call),
566 INSTR(RETURN, print_cf_jmp_call),
567 INSTR(COND_JMP, print_cf_jmp_call),
568 INSTR(ALLOC, print_cf_alloc),
569 INSTR(COND_EXEC_PRED_CLEAN, print_cf_exec),
570 INSTR(COND_EXEC_PRED_CLEAN_END, print_cf_exec),
571 INSTR(MARK_VS_FETCH_DONE, print_cf_nop), // ??
572 #undef INSTR
573 };
574
575 static void print_cf(instr_cf_t *cf, int level)
576 {
577 printf("%s", levels[level]);
578 if (debug & PRINT_RAW) {
579 uint16_t words[3];
580 memcpy(&words, cf, sizeof(words));
581 printf(" %04x %04x %04x \t",
582 words[0], words[1], words[2]);
583 }
584 printf("%s", cf_instructions[cf->opc].name);
585 cf_instructions[cf->opc].fxn(cf);
586 printf("\n");
587 }
588
589 /*
590 * The adreno shader microcode consists of two parts:
591 * 1) A CF (control-flow) program, at the header of the compiled shader,
592 * which refers to ALU/FETCH instructions that follow it by address.
593 * 2) ALU and FETCH instructions
594 */
595
596 int disasm_a2xx(uint32_t *dwords, int sizedwords, int level, gl_shader_stage type)
597 {
598 instr_cf_t *cfs = (instr_cf_t *)dwords;
599 int idx, max_idx;
600
601 for (idx = 0; ; idx++) {
602 instr_cf_t *cf = &cfs[idx];
603 if (cf_exec(cf)) {
604 max_idx = 2 * cf->exec.address;
605 break;
606 }
607 }
608
609 for (idx = 0; idx < max_idx; idx++) {
610 instr_cf_t *cf = &cfs[idx];
611
612 print_cf(cf, level);
613
614 if (cf_exec(cf)) {
615 uint32_t sequence = cf->exec.serialize;
616 uint32_t i;
617 for (i = 0; i < cf->exec.count; i++) {
618 uint32_t alu_off = (cf->exec.address + i);
619 if (sequence & 0x1) {
620 disasm_fetch(dwords + alu_off * 3, alu_off, level, sequence & 0x2);
621 } else {
622 disasm_alu(dwords + alu_off * 3, alu_off, level, sequence & 0x2, type);
623 }
624 sequence >>= 2;
625 }
626 }
627 }
628
629 return 0;
630 }
631
632 void disasm_set_debug(enum debug_t d)
633 {
634 debug = d;
635 }