• 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,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