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
print_srcreg(uint32_t num,uint32_t type,uint32_t swiz,uint32_t negate,uint32_t abs)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
print_dstreg(uint32_t num,uint32_t mask,uint32_t dst_exp)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
print_export_comment(uint32_t num,gl_shader_stage type)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 assert(!"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
disasm_alu(uint32_t * dwords,uint32_t alu_off,int level,int sync,gl_shader_stage type)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
print_fetch_dst(uint32_t dst_reg,uint32_t dst_swiz)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
print_fetch_vtx(instr_fetch_t * fetch)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
print_fetch_tex(instr_fetch_t * fetch)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_lod) {
429 printf(" REG_LOD(%u)", tex->use_reg_lod);
430 }
431 if (tex->use_reg_gradients)
432 printf(" USE_REG_GRADIENTS");
433 printf(" LOCATION(%s)", sample_loc[tex->sample_location]);
434 if (tex->offset_x || tex->offset_y || tex->offset_z)
435 printf(" OFFSET(%u,%u,%u)", tex->offset_x, tex->offset_y, tex->offset_z);
436 }
437
438 struct {
439 const char *name;
440 void (*fxn)(instr_fetch_t *cf);
441 } fetch_instructions[] = {
442 #define INSTR(opc, name, fxn) [opc] = { name, fxn }
443 INSTR(VTX_FETCH, "VERTEX", print_fetch_vtx),
444 INSTR(TEX_FETCH, "SAMPLE", print_fetch_tex),
445 INSTR(TEX_GET_BORDER_COLOR_FRAC, "?", print_fetch_tex),
446 INSTR(TEX_GET_COMP_TEX_LOD, "?", print_fetch_tex),
447 INSTR(TEX_GET_GRADIENTS, "?", print_fetch_tex),
448 INSTR(TEX_GET_WEIGHTS, "?", print_fetch_tex),
449 INSTR(TEX_SET_TEX_LOD, "SET_TEX_LOD", print_fetch_tex),
450 INSTR(TEX_SET_GRADIENTS_H, "?", print_fetch_tex),
451 INSTR(TEX_SET_GRADIENTS_V, "?", print_fetch_tex),
452 INSTR(TEX_RESERVED_4, "?", print_fetch_tex),
453 #undef INSTR
454 };
455
disasm_fetch(uint32_t * dwords,uint32_t alu_off,int level,int sync)456 static int disasm_fetch(uint32_t *dwords, uint32_t alu_off, int level, int sync)
457 {
458 instr_fetch_t *fetch = (instr_fetch_t *)dwords;
459
460 printf("%s", levels[level]);
461 if (debug & PRINT_RAW) {
462 printf("%02x: %08x %08x %08x\t", alu_off,
463 dwords[0], dwords[1], dwords[2]);
464 }
465
466 printf(" %sFETCH:\t", sync ? "(S)" : " ");
467 printf("%s", fetch_instructions[fetch->opc].name);
468 fetch_instructions[fetch->opc].fxn(fetch);
469 printf("\n");
470
471 return 0;
472 }
473
474 /*
475 * CF instructions:
476 */
477
cf_exec(instr_cf_t * cf)478 static int cf_exec(instr_cf_t *cf)
479 {
480 return (cf->opc == EXEC) ||
481 (cf->opc == EXEC_END) ||
482 (cf->opc == COND_EXEC) ||
483 (cf->opc == COND_EXEC_END) ||
484 (cf->opc == COND_PRED_EXEC) ||
485 (cf->opc == COND_PRED_EXEC_END) ||
486 (cf->opc == COND_EXEC_PRED_CLEAN) ||
487 (cf->opc == COND_EXEC_PRED_CLEAN_END);
488 }
489
cf_cond_exec(instr_cf_t * cf)490 static int cf_cond_exec(instr_cf_t *cf)
491 {
492 return (cf->opc == COND_EXEC) ||
493 (cf->opc == COND_EXEC_END) ||
494 (cf->opc == COND_PRED_EXEC) ||
495 (cf->opc == COND_PRED_EXEC_END) ||
496 (cf->opc == COND_EXEC_PRED_CLEAN) ||
497 (cf->opc == COND_EXEC_PRED_CLEAN_END);
498 }
499
print_cf_nop(instr_cf_t * cf)500 static void print_cf_nop(instr_cf_t *cf)
501 {
502 }
503
print_cf_exec(instr_cf_t * cf)504 static void print_cf_exec(instr_cf_t *cf)
505 {
506 printf(" ADDR(0x%x) CNT(0x%x)", cf->exec.address, cf->exec.count);
507 if (cf->exec.yeild)
508 printf(" YIELD");
509 if (cf->exec.vc)
510 printf(" VC(0x%x)", cf->exec.vc);
511 if (cf->exec.bool_addr)
512 printf(" BOOL_ADDR(0x%x)", cf->exec.bool_addr);
513 if (cf->exec.address_mode == ABSOLUTE_ADDR)
514 printf(" ABSOLUTE_ADDR");
515 if (cf_cond_exec(cf))
516 printf(" COND(%d)", cf->exec.condition);
517 }
518
print_cf_loop(instr_cf_t * cf)519 static void print_cf_loop(instr_cf_t *cf)
520 {
521 printf(" ADDR(0x%x) LOOP_ID(%d)", cf->loop.address, cf->loop.loop_id);
522 if (cf->loop.address_mode == ABSOLUTE_ADDR)
523 printf(" ABSOLUTE_ADDR");
524 }
525
print_cf_jmp_call(instr_cf_t * cf)526 static void print_cf_jmp_call(instr_cf_t *cf)
527 {
528 printf(" ADDR(0x%x) DIR(%d)", cf->jmp_call.address, cf->jmp_call.direction);
529 if (cf->jmp_call.force_call)
530 printf(" FORCE_CALL");
531 if (cf->jmp_call.predicated_jmp)
532 printf(" COND(%d)", cf->jmp_call.condition);
533 if (cf->jmp_call.bool_addr)
534 printf(" BOOL_ADDR(0x%x)", cf->jmp_call.bool_addr);
535 if (cf->jmp_call.address_mode == ABSOLUTE_ADDR)
536 printf(" ABSOLUTE_ADDR");
537 }
538
print_cf_alloc(instr_cf_t * cf)539 static void print_cf_alloc(instr_cf_t *cf)
540 {
541 static const char *bufname[] = {
542 [SQ_NO_ALLOC] = "NO ALLOC",
543 [SQ_POSITION] = "POSITION",
544 [SQ_PARAMETER_PIXEL] = "PARAM/PIXEL",
545 [SQ_MEMORY] = "MEMORY",
546 };
547 printf(" %s SIZE(0x%x)", bufname[cf->alloc.buffer_select], cf->alloc.size);
548 if (cf->alloc.no_serial)
549 printf(" NO_SERIAL");
550 if (cf->alloc.alloc_mode) // ???
551 printf(" ALLOC_MODE");
552 }
553
554 struct {
555 const char *name;
556 void (*fxn)(instr_cf_t *cf);
557 } cf_instructions[] = {
558 #define INSTR(opc, fxn) [opc] = { #opc, fxn }
559 INSTR(NOP, print_cf_nop),
560 INSTR(EXEC, print_cf_exec),
561 INSTR(EXEC_END, print_cf_exec),
562 INSTR(COND_EXEC, print_cf_exec),
563 INSTR(COND_EXEC_END, print_cf_exec),
564 INSTR(COND_PRED_EXEC, print_cf_exec),
565 INSTR(COND_PRED_EXEC_END, print_cf_exec),
566 INSTR(LOOP_START, print_cf_loop),
567 INSTR(LOOP_END, print_cf_loop),
568 INSTR(COND_CALL, print_cf_jmp_call),
569 INSTR(RETURN, print_cf_jmp_call),
570 INSTR(COND_JMP, print_cf_jmp_call),
571 INSTR(ALLOC, print_cf_alloc),
572 INSTR(COND_EXEC_PRED_CLEAN, print_cf_exec),
573 INSTR(COND_EXEC_PRED_CLEAN_END, print_cf_exec),
574 INSTR(MARK_VS_FETCH_DONE, print_cf_nop), // ??
575 #undef INSTR
576 };
577
print_cf(instr_cf_t * cf,int level)578 static void print_cf(instr_cf_t *cf, int level)
579 {
580 printf("%s", levels[level]);
581 if (debug & PRINT_RAW) {
582 uint16_t words[3];
583 memcpy(&words, cf, sizeof(words));
584 printf(" %04x %04x %04x \t",
585 words[0], words[1], words[2]);
586 }
587 printf("%s", cf_instructions[cf->opc].name);
588 cf_instructions[cf->opc].fxn(cf);
589 printf("\n");
590 }
591
592 /*
593 * The adreno shader microcode consists of two parts:
594 * 1) A CF (control-flow) program, at the header of the compiled shader,
595 * which refers to ALU/FETCH instructions that follow it by address.
596 * 2) ALU and FETCH instructions
597 */
598
disasm_a2xx(uint32_t * dwords,int sizedwords,int level,gl_shader_stage type)599 int disasm_a2xx(uint32_t *dwords, int sizedwords, int level, gl_shader_stage type)
600 {
601 instr_cf_t *cfs = (instr_cf_t *)dwords;
602 int idx, max_idx;
603
604 for (idx = 0; ; idx++) {
605 instr_cf_t *cf = &cfs[idx];
606 if (cf_exec(cf)) {
607 max_idx = 2 * cf->exec.address;
608 break;
609 }
610 }
611
612 for (idx = 0; idx < max_idx; idx++) {
613 instr_cf_t *cf = &cfs[idx];
614
615 print_cf(cf, level);
616
617 if (cf_exec(cf)) {
618 uint32_t sequence = cf->exec.serialize;
619 uint32_t i;
620 for (i = 0; i < cf->exec.count; i++) {
621 uint32_t alu_off = (cf->exec.address + i);
622 if (sequence & 0x1) {
623 disasm_fetch(dwords + alu_off * 3, alu_off, level, sequence & 0x2);
624 } else {
625 disasm_alu(dwords + alu_off * 3, alu_off, level, sequence & 0x2, type);
626 }
627 sequence >>= 2;
628 }
629 }
630 }
631
632 return 0;
633 }
634
disasm_a2xx_set_debug(enum debug_t d)635 void disasm_a2xx_set_debug(enum debug_t d)
636 {
637 debug = d;
638 }
639