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