• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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,enum shader_t type)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 	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 
disasm_alu(uint32_t * dwords,uint32_t alu_off,int level,int sync,enum shader_t type)214 static int disasm_alu(uint32_t *dwords, uint32_t alu_off,
215 		int level, int sync, enum shader_t 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_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 
disasm_fetch(uint32_t * dwords,uint32_t alu_off,int level,int sync)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 
cf_exec(instr_cf_t * cf)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 
cf_cond_exec(instr_cf_t * cf)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 
print_cf_nop(instr_cf_t * cf)497 static void print_cf_nop(instr_cf_t *cf)
498 {
499 }
500 
print_cf_exec(instr_cf_t * cf)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 
print_cf_loop(instr_cf_t * cf)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 
print_cf_jmp_call(instr_cf_t * cf)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 
print_cf_alloc(instr_cf_t * cf)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 
print_cf(instr_cf_t * cf,int level)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 = (uint16_t *)cf;
580 		printf("    %04x %04x %04x            \t",
581 				words[0], words[1], words[2]);
582 	}
583 	printf("%s", cf_instructions[cf->opc].name);
584 	cf_instructions[cf->opc].fxn(cf);
585 	printf("\n");
586 }
587 
588 /*
589  * The adreno shader microcode consists of two parts:
590  *   1) A CF (control-flow) program, at the header of the compiled shader,
591  *      which refers to ALU/FETCH instructions that follow it by address.
592  *   2) ALU and FETCH instructions
593  */
594 
disasm_a2xx(uint32_t * dwords,int sizedwords,int level,enum shader_t type)595 int disasm_a2xx(uint32_t *dwords, int sizedwords, int level, enum shader_t type)
596 {
597 	instr_cf_t *cfs = (instr_cf_t *)dwords;
598 	int idx, max_idx;
599 
600 	for (idx = 0; ; idx++) {
601 		instr_cf_t *cf = &cfs[idx];
602 		if (cf_exec(cf)) {
603 			max_idx = 2 * cf->exec.address;
604 			break;
605 		}
606 	}
607 
608 	for (idx = 0; idx < max_idx; idx++) {
609 		instr_cf_t *cf = &cfs[idx];
610 
611 		print_cf(cf, level);
612 
613 		if (cf_exec(cf)) {
614 			uint32_t sequence = cf->exec.serialize;
615 			uint32_t i;
616 			for (i = 0; i < cf->exec.count; i++) {
617 				uint32_t alu_off = (cf->exec.address + i);
618 				if (sequence & 0x1) {
619 					disasm_fetch(dwords + alu_off * 3, alu_off, level, sequence & 0x2);
620 				} else {
621 					disasm_alu(dwords + alu_off * 3, alu_off, level, sequence & 0x2, type);
622 				}
623 				sequence >>= 2;
624 			}
625 		}
626 	}
627 
628 	return 0;
629 }
630 
disasm_set_debug(enum debug_t d)631 void disasm_set_debug(enum debug_t d)
632 {
633 	debug = d;
634 }
635