Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5564 serge 1
/*
2
 * Copyright (c) 2012 Rob Clark 
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 
25
#include 
26
#include 
27
#include 
28
#include 
29
#include 
30
#include 
31
#include 
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
 
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
 
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
 
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
	}
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
 
123
struct {
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
 
212
static 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
 
292
struct {
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
 
313
static 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
 
323
static 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
 
359
static 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
 
433
struct {
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
 
451
static 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
 
473
static 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
 
485
static 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
 
495
static void print_cf_nop(instr_cf_t *cf)
496
{
497
}
498
 
499
static 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
 
514
static 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
 
521
static 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
 
534
static 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
 
549
struct {
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
 
573
static 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
 
593
int 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
 
629
void disasm_set_debug(enum debug_t d)
630
{
631
	debug = d;
632
}