disasm-a2xx.c revision 848b8605
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	}
115	/* if we had a symbol table here, we could look
116	 * up the name of the varying..
117	 */
118	if (name) {
119		printf("\t; %s", name);
120	}
121}
122
123struct {
124	uint32_t num_srcs;
125	const char *name;
126} vector_instructions[0x20] = {
127#define INSTR(opc, num_srcs) [opc] = { num_srcs, #opc }
128		INSTR(ADDv, 2),
129		INSTR(MULv, 2),
130		INSTR(MAXv, 2),
131		INSTR(MINv, 2),
132		INSTR(SETEv, 2),
133		INSTR(SETGTv, 2),
134		INSTR(SETGTEv, 2),
135		INSTR(SETNEv, 2),
136		INSTR(FRACv, 1),
137		INSTR(TRUNCv, 1),
138		INSTR(FLOORv, 1),
139		INSTR(MULADDv, 3),
140		INSTR(CNDEv, 3),
141		INSTR(CNDGTEv, 3),
142		INSTR(CNDGTv, 3),
143		INSTR(DOT4v, 2),
144		INSTR(DOT3v, 2),
145		INSTR(DOT2ADDv, 3),  // ???
146		INSTR(CUBEv, 2),
147		INSTR(MAX4v, 1),
148		INSTR(PRED_SETE_PUSHv, 2),
149		INSTR(PRED_SETNE_PUSHv, 2),
150		INSTR(PRED_SETGT_PUSHv, 2),
151		INSTR(PRED_SETGTE_PUSHv, 2),
152		INSTR(KILLEv, 2),
153		INSTR(KILLGTv, 2),
154		INSTR(KILLGTEv, 2),
155		INSTR(KILLNEv, 2),
156		INSTR(DSTv, 2),
157		INSTR(MOVAv, 1),
158}, scalar_instructions[0x40] = {
159		INSTR(ADDs, 1),
160		INSTR(ADD_PREVs, 1),
161		INSTR(MULs, 1),
162		INSTR(MUL_PREVs, 1),
163		INSTR(MUL_PREV2s, 1),
164		INSTR(MAXs, 1),
165		INSTR(MINs, 1),
166		INSTR(SETEs, 1),
167		INSTR(SETGTs, 1),
168		INSTR(SETGTEs, 1),
169		INSTR(SETNEs, 1),
170		INSTR(FRACs, 1),
171		INSTR(TRUNCs, 1),
172		INSTR(FLOORs, 1),
173		INSTR(EXP_IEEE, 1),
174		INSTR(LOG_CLAMP, 1),
175		INSTR(LOG_IEEE, 1),
176		INSTR(RECIP_CLAMP, 1),
177		INSTR(RECIP_FF, 1),
178		INSTR(RECIP_IEEE, 1),
179		INSTR(RECIPSQ_CLAMP, 1),
180		INSTR(RECIPSQ_FF, 1),
181		INSTR(RECIPSQ_IEEE, 1),
182		INSTR(MOVAs, 1),
183		INSTR(MOVA_FLOORs, 1),
184		INSTR(SUBs, 1),
185		INSTR(SUB_PREVs, 1),
186		INSTR(PRED_SETEs, 1),
187		INSTR(PRED_SETNEs, 1),
188		INSTR(PRED_SETGTs, 1),
189		INSTR(PRED_SETGTEs, 1),
190		INSTR(PRED_SET_INVs, 1),
191		INSTR(PRED_SET_POPs, 1),
192		INSTR(PRED_SET_CLRs, 1),
193		INSTR(PRED_SET_RESTOREs, 1),
194		INSTR(KILLEs, 1),
195		INSTR(KILLGTs, 1),
196		INSTR(KILLGTEs, 1),
197		INSTR(KILLNEs, 1),
198		INSTR(KILLONEs, 1),
199		INSTR(SQRT_IEEE, 1),
200		INSTR(MUL_CONST_0, 1),
201		INSTR(MUL_CONST_1, 1),
202		INSTR(ADD_CONST_0, 1),
203		INSTR(ADD_CONST_1, 1),
204		INSTR(SUB_CONST_0, 1),
205		INSTR(SUB_CONST_1, 1),
206		INSTR(SIN, 1),
207		INSTR(COS, 1),
208		INSTR(RETAIN_PREV, 1),
209#undef INSTR
210};
211
212static int disasm_alu(uint32_t *dwords, uint32_t alu_off,
213		int level, int sync, enum shader_t type)
214{
215	instr_alu_t *alu = (instr_alu_t *)dwords;
216
217	printf("%s", levels[level]);
218	if (debug & PRINT_RAW) {
219		printf("%02x: %08x %08x %08x\t", alu_off,
220				dwords[0], dwords[1], dwords[2]);
221	}
222
223	printf("   %sALU:\t", sync ? "(S)" : "   ");
224
225	printf("%s", vector_instructions[alu->vector_opc].name);
226
227	if (alu->pred_select & 0x2) {
228		/* seems to work similar to conditional execution in ARM instruction
229		 * set, so let's use a similar syntax for now:
230		 */
231		printf((alu->pred_select & 0x1) ? "EQ" : "NE");
232	}
233
234	printf("\t");
235
236	print_dstreg(alu->vector_dest, alu->vector_write_mask, alu->export_data);
237	printf(" = ");
238	if (vector_instructions[alu->vector_opc].num_srcs == 3) {
239		print_srcreg(alu->src3_reg, alu->src3_sel, alu->src3_swiz,
240				alu->src3_reg_negate, alu->src3_reg_abs);
241		printf(", ");
242	}
243	print_srcreg(alu->src1_reg, alu->src1_sel, alu->src1_swiz,
244			alu->src1_reg_negate, alu->src1_reg_abs);
245	if (vector_instructions[alu->vector_opc].num_srcs > 1) {
246		printf(", ");
247		print_srcreg(alu->src2_reg, alu->src2_sel, alu->src2_swiz,
248				alu->src2_reg_negate, alu->src2_reg_abs);
249	}
250
251	if (alu->vector_clamp)
252		printf(" CLAMP");
253
254	if (alu->export_data)
255		print_export_comment(alu->vector_dest, type);
256
257	printf("\n");
258
259	if (alu->scalar_write_mask || !alu->vector_write_mask) {
260		/* 2nd optional scalar op: */
261
262		printf("%s", levels[level]);
263		if (debug & PRINT_RAW)
264			printf("                          \t");
265
266		if (scalar_instructions[alu->scalar_opc].name) {
267			printf("\t    \t%s\t", scalar_instructions[alu->scalar_opc].name);
268		} else {
269			printf("\t    \tOP(%u)\t", alu->scalar_opc);
270		}
271
272		print_dstreg(alu->scalar_dest, alu->scalar_write_mask, alu->export_data);
273		printf(" = ");
274		print_srcreg(alu->src3_reg, alu->src3_sel, alu->src3_swiz,
275				alu->src3_reg_negate, alu->src3_reg_abs);
276		// TODO ADD/MUL must have another src?!?
277		if (alu->scalar_clamp)
278			printf(" CLAMP");
279		if (alu->export_data)
280			print_export_comment(alu->scalar_dest, type);
281		printf("\n");
282	}
283
284	return 0;
285}
286
287
288/*
289 * FETCH instructions:
290 */
291
292struct {
293	const char *name;
294} fetch_types[0xff] = {
295#define TYPE(id) [id] = { #id }
296		TYPE(FMT_1_REVERSE),
297		TYPE(FMT_32_FLOAT),
298		TYPE(FMT_32_32_FLOAT),
299		TYPE(FMT_32_32_32_FLOAT),
300		TYPE(FMT_32_32_32_32_FLOAT),
301		TYPE(FMT_16),
302		TYPE(FMT_16_16),
303		TYPE(FMT_16_16_16_16),
304		TYPE(FMT_8),
305		TYPE(FMT_8_8),
306		TYPE(FMT_8_8_8_8),
307		TYPE(FMT_32),
308		TYPE(FMT_32_32),
309		TYPE(FMT_32_32_32_32),
310#undef TYPE
311};
312
313static void print_fetch_dst(uint32_t dst_reg, uint32_t dst_swiz)
314{
315	int i;
316	printf("\tR%u.", dst_reg);
317	for (i = 0; i < 4; i++) {
318		printf("%c", chan_names[dst_swiz & 0x7]);
319		dst_swiz >>= 3;
320	}
321}
322
323static void print_fetch_vtx(instr_fetch_t *fetch)
324{
325	instr_fetch_vtx_t *vtx = &fetch->vtx;
326
327	if (vtx->pred_select) {
328		/* seems to work similar to conditional execution in ARM instruction
329		 * set, so let's use a similar syntax for now:
330		 */
331		printf(vtx->pred_condition ? "EQ" : "NE");
332	}
333
334	print_fetch_dst(vtx->dst_reg, vtx->dst_swiz);
335	printf(" = R%u.", vtx->src_reg);
336	printf("%c", chan_names[vtx->src_swiz & 0x3]);
337	if (fetch_types[vtx->format].name) {
338		printf(" %s", fetch_types[vtx->format].name);
339	} else  {
340		printf(" TYPE(0x%x)", vtx->format);
341	}
342	printf(" %s", vtx->format_comp_all ? "SIGNED" : "UNSIGNED");
343	if (!vtx->num_format_all)
344		printf(" NORMALIZED");
345	printf(" STRIDE(%u)", vtx->stride);
346	if (vtx->offset)
347		printf(" OFFSET(%u)", vtx->offset);
348	printf(" CONST(%u, %u)", vtx->const_index, vtx->const_index_sel);
349	if (0) {
350		// XXX
351		printf(" src_reg_am=%u", vtx->src_reg_am);
352		printf(" dst_reg_am=%u", vtx->dst_reg_am);
353		printf(" num_format_all=%u", vtx->num_format_all);
354		printf(" signed_rf_mode_all=%u", vtx->signed_rf_mode_all);
355		printf(" exp_adjust_all=%u", vtx->exp_adjust_all);
356	}
357}
358
359static void print_fetch_tex(instr_fetch_t *fetch)
360{
361	static const char *filter[] = {
362			[TEX_FILTER_POINT] = "POINT",
363			[TEX_FILTER_LINEAR] = "LINEAR",
364			[TEX_FILTER_BASEMAP] = "BASEMAP",
365	};
366	static const char *aniso_filter[] = {
367			[ANISO_FILTER_DISABLED] = "DISABLED",
368			[ANISO_FILTER_MAX_1_1] = "MAX_1_1",
369			[ANISO_FILTER_MAX_2_1] = "MAX_2_1",
370			[ANISO_FILTER_MAX_4_1] = "MAX_4_1",
371			[ANISO_FILTER_MAX_8_1] = "MAX_8_1",
372			[ANISO_FILTER_MAX_16_1] = "MAX_16_1",
373	};
374	static const char *arbitrary_filter[] = {
375			[ARBITRARY_FILTER_2X4_SYM] = "2x4_SYM",
376			[ARBITRARY_FILTER_2X4_ASYM] = "2x4_ASYM",
377			[ARBITRARY_FILTER_4X2_SYM] = "4x2_SYM",
378			[ARBITRARY_FILTER_4X2_ASYM] = "4x2_ASYM",
379			[ARBITRARY_FILTER_4X4_SYM] = "4x4_SYM",
380			[ARBITRARY_FILTER_4X4_ASYM] = "4x4_ASYM",
381	};
382	static const char *sample_loc[] = {
383			[SAMPLE_CENTROID] = "CENTROID",
384			[SAMPLE_CENTER] = "CENTER",
385	};
386	instr_fetch_tex_t *tex = &fetch->tex;
387	uint32_t src_swiz = tex->src_swiz;
388	int i;
389
390	if (tex->pred_select) {
391		/* seems to work similar to conditional execution in ARM instruction
392		 * set, so let's use a similar syntax for now:
393		 */
394		printf(tex->pred_condition ? "EQ" : "NE");
395	}
396
397	print_fetch_dst(tex->dst_reg, tex->dst_swiz);
398	printf(" = R%u.", tex->src_reg);
399	for (i = 0; i < 3; i++) {
400		printf("%c", chan_names[src_swiz & 0x3]);
401		src_swiz >>= 2;
402	}
403	printf(" CONST(%u)", tex->const_idx);
404	if (tex->fetch_valid_only)
405		printf(" VALID_ONLY");
406	if (tex->tx_coord_denorm)
407		printf(" DENORM");
408	if (tex->mag_filter != TEX_FILTER_USE_FETCH_CONST)
409		printf(" MAG(%s)", filter[tex->mag_filter]);
410	if (tex->min_filter != TEX_FILTER_USE_FETCH_CONST)
411		printf(" MIN(%s)", filter[tex->min_filter]);
412	if (tex->mip_filter != TEX_FILTER_USE_FETCH_CONST)
413		printf(" MIP(%s)", filter[tex->mip_filter]);
414	if (tex->aniso_filter != ANISO_FILTER_USE_FETCH_CONST)
415		printf(" ANISO(%s)", aniso_filter[tex->aniso_filter]);
416	if (tex->arbitrary_filter != ARBITRARY_FILTER_USE_FETCH_CONST)
417		printf(" ARBITRARY(%s)", arbitrary_filter[tex->arbitrary_filter]);
418	if (tex->vol_mag_filter != TEX_FILTER_USE_FETCH_CONST)
419		printf(" VOL_MAG(%s)", filter[tex->vol_mag_filter]);
420	if (tex->vol_min_filter != TEX_FILTER_USE_FETCH_CONST)
421		printf(" VOL_MIN(%s)", filter[tex->vol_min_filter]);
422	if (!tex->use_comp_lod) {
423		printf(" LOD(%u)", tex->use_comp_lod);
424		printf(" LOD_BIAS(%u)", tex->lod_bias);
425	}
426	if (tex->use_reg_gradients)
427		printf(" USE_REG_GRADIENTS");
428	printf(" LOCATION(%s)", sample_loc[tex->sample_location]);
429	if (tex->offset_x || tex->offset_y || tex->offset_z)
430		printf(" OFFSET(%u,%u,%u)", tex->offset_x, tex->offset_y, tex->offset_z);
431}
432
433struct {
434	const char *name;
435	void (*fxn)(instr_fetch_t *cf);
436} fetch_instructions[] = {
437#define INSTR(opc, name, fxn) [opc] = { name, fxn }
438		INSTR(VTX_FETCH, "VERTEX", print_fetch_vtx),
439		INSTR(TEX_FETCH, "SAMPLE", print_fetch_tex),
440		INSTR(TEX_GET_BORDER_COLOR_FRAC, "?", print_fetch_tex),
441		INSTR(TEX_GET_COMP_TEX_LOD, "?", print_fetch_tex),
442		INSTR(TEX_GET_GRADIENTS, "?", print_fetch_tex),
443		INSTR(TEX_GET_WEIGHTS, "?", print_fetch_tex),
444		INSTR(TEX_SET_TEX_LOD, "SET_TEX_LOD", print_fetch_tex),
445		INSTR(TEX_SET_GRADIENTS_H, "?", print_fetch_tex),
446		INSTR(TEX_SET_GRADIENTS_V, "?", print_fetch_tex),
447		INSTR(TEX_RESERVED_4, "?", print_fetch_tex),
448#undef INSTR
449};
450
451static int disasm_fetch(uint32_t *dwords, uint32_t alu_off, int level, int sync)
452{
453	instr_fetch_t *fetch = (instr_fetch_t *)dwords;
454
455	printf("%s", levels[level]);
456	if (debug & PRINT_RAW) {
457		printf("%02x: %08x %08x %08x\t", alu_off,
458				dwords[0], dwords[1], dwords[2]);
459	}
460
461	printf("   %sFETCH:\t", sync ? "(S)" : "   ");
462	printf("%s", fetch_instructions[fetch->opc].name);
463	fetch_instructions[fetch->opc].fxn(fetch);
464	printf("\n");
465
466	return 0;
467}
468
469/*
470 * CF instructions:
471 */
472
473static int cf_exec(instr_cf_t *cf)
474{
475	return (cf->opc == EXEC) ||
476			(cf->opc == EXEC_END) ||
477			(cf->opc == COND_EXEC) ||
478			(cf->opc == COND_EXEC_END) ||
479			(cf->opc == COND_PRED_EXEC) ||
480			(cf->opc == COND_PRED_EXEC_END) ||
481			(cf->opc == COND_EXEC_PRED_CLEAN) ||
482			(cf->opc == COND_EXEC_PRED_CLEAN_END);
483}
484
485static int cf_cond_exec(instr_cf_t *cf)
486{
487	return (cf->opc == COND_EXEC) ||
488			(cf->opc == COND_EXEC_END) ||
489			(cf->opc == COND_PRED_EXEC) ||
490			(cf->opc == COND_PRED_EXEC_END) ||
491			(cf->opc == COND_EXEC_PRED_CLEAN) ||
492			(cf->opc == COND_EXEC_PRED_CLEAN_END);
493}
494
495static void print_cf_nop(instr_cf_t *cf)
496{
497}
498
499static void print_cf_exec(instr_cf_t *cf)
500{
501	printf(" ADDR(0x%x) CNT(0x%x)", cf->exec.address, cf->exec.count);
502	if (cf->exec.yeild)
503		printf(" YIELD");
504	if (cf->exec.vc)
505		printf(" VC(0x%x)", cf->exec.vc);
506	if (cf->exec.bool_addr)
507		printf(" BOOL_ADDR(0x%x)", cf->exec.bool_addr);
508	if (cf->exec.address_mode == ABSOLUTE_ADDR)
509		printf(" ABSOLUTE_ADDR");
510	if (cf_cond_exec(cf))
511		printf(" COND(%d)", cf->exec.condition);
512}
513
514static void print_cf_loop(instr_cf_t *cf)
515{
516	printf(" ADDR(0x%x) LOOP_ID(%d)", cf->loop.address, cf->loop.loop_id);
517	if (cf->loop.address_mode == ABSOLUTE_ADDR)
518		printf(" ABSOLUTE_ADDR");
519}
520
521static void print_cf_jmp_call(instr_cf_t *cf)
522{
523	printf(" ADDR(0x%x) DIR(%d)", cf->jmp_call.address, cf->jmp_call.direction);
524	if (cf->jmp_call.force_call)
525		printf(" FORCE_CALL");
526	if (cf->jmp_call.predicated_jmp)
527		printf(" COND(%d)", cf->jmp_call.condition);
528	if (cf->jmp_call.bool_addr)
529		printf(" BOOL_ADDR(0x%x)", cf->jmp_call.bool_addr);
530	if (cf->jmp_call.address_mode == ABSOLUTE_ADDR)
531		printf(" ABSOLUTE_ADDR");
532}
533
534static void print_cf_alloc(instr_cf_t *cf)
535{
536	static const char *bufname[] = {
537			[SQ_NO_ALLOC] = "NO ALLOC",
538			[SQ_POSITION] = "POSITION",
539			[SQ_PARAMETER_PIXEL] = "PARAM/PIXEL",
540			[SQ_MEMORY] = "MEMORY",
541	};
542	printf(" %s SIZE(0x%x)", bufname[cf->alloc.buffer_select], cf->alloc.size);
543	if (cf->alloc.no_serial)
544		printf(" NO_SERIAL");
545	if (cf->alloc.alloc_mode) // ???
546		printf(" ALLOC_MODE");
547}
548
549struct {
550	const char *name;
551	void (*fxn)(instr_cf_t *cf);
552} cf_instructions[] = {
553#define INSTR(opc, fxn) [opc] = { #opc, fxn }
554		INSTR(NOP, print_cf_nop),
555		INSTR(EXEC, print_cf_exec),
556		INSTR(EXEC_END, print_cf_exec),
557		INSTR(COND_EXEC, print_cf_exec),
558		INSTR(COND_EXEC_END, print_cf_exec),
559		INSTR(COND_PRED_EXEC, print_cf_exec),
560		INSTR(COND_PRED_EXEC_END, print_cf_exec),
561		INSTR(LOOP_START, print_cf_loop),
562		INSTR(LOOP_END, print_cf_loop),
563		INSTR(COND_CALL, print_cf_jmp_call),
564		INSTR(RETURN, print_cf_jmp_call),
565		INSTR(COND_JMP, print_cf_jmp_call),
566		INSTR(ALLOC, print_cf_alloc),
567		INSTR(COND_EXEC_PRED_CLEAN, print_cf_exec),
568		INSTR(COND_EXEC_PRED_CLEAN_END, print_cf_exec),
569		INSTR(MARK_VS_FETCH_DONE, print_cf_nop),  // ??
570#undef INSTR
571};
572
573static void print_cf(instr_cf_t *cf, int level)
574{
575	printf("%s", levels[level]);
576	if (debug & PRINT_RAW) {
577		uint16_t *words = (uint16_t *)cf;
578		printf("    %04x %04x %04x            \t",
579				words[0], words[1], words[2]);
580	}
581	printf("%s", cf_instructions[cf->opc].name);
582	cf_instructions[cf->opc].fxn(cf);
583	printf("\n");
584}
585
586/*
587 * The adreno shader microcode consists of two parts:
588 *   1) A CF (control-flow) program, at the header of the compiled shader,
589 *      which refers to ALU/FETCH instructions that follow it by address.
590 *   2) ALU and FETCH instructions
591 */
592
593int disasm_a2xx(uint32_t *dwords, int sizedwords, int level, enum shader_t type)
594{
595	instr_cf_t *cfs = (instr_cf_t *)dwords;
596	int idx, max_idx;
597
598	for (idx = 0; ; idx++) {
599		instr_cf_t *cf = &cfs[idx];
600		if (cf_exec(cf)) {
601			max_idx = 2 * cf->exec.address;
602			break;
603		}
604	}
605
606	for (idx = 0; idx < max_idx; idx++) {
607		instr_cf_t *cf = &cfs[idx];
608
609		print_cf(cf, level);
610
611		if (cf_exec(cf)) {
612			uint32_t sequence = cf->exec.serialize;
613			uint32_t i;
614			for (i = 0; i < cf->exec.count; i++) {
615				uint32_t alu_off = (cf->exec.address + i);
616				if (sequence & 0x1) {
617					disasm_fetch(dwords + alu_off * 3, alu_off, level, sequence & 0x2);
618				} else {
619					disasm_alu(dwords + alu_off * 3, alu_off, level, sequence & 0x2, type);
620				}
621				sequence >>= 2;
622			}
623		}
624	}
625
626	return 0;
627}
628
629void disasm_set_debug(enum debug_t d)
630{
631	debug = d;
632}
633