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
36static 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
54static enum debug_t debug;
55
56/*
57 * ALU instructions:
58 */
59
60static const char chan_names[] = {
61		'x', 'y', 'z', 'w',
62		/* these only apply to FETCH dst's: */
63		'0', '1', '?', '_',
64};
65
66static 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
86static 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
99static 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	case SHADER_COMPUTE:
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
125struct {
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
214static 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
294struct {
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
315static 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
325static 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
361static 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
435struct {
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
453static 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
475static 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
487static 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
497static void print_cf_nop(instr_cf_t *cf)
498{
499}
500
501static 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
516static 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
523static 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
536static 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
551struct {
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
575static 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
595int 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
631void disasm_set_debug(enum debug_t d)
632{
633	debug = d;
634}
635