1/*
2 * Copyright © 2008 Keith Packard
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission.  The copyright holders make no representations
11 * about the suitability of this software for any purpose.  It is provided "as
12 * is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20 * OF THIS SOFTWARE.
21 */
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <getopt.h>
27#include <unistd.h>
28#include <stdarg.h>
29
30#include "brw_eu.h"
31
32static const struct {
33	const char *name;
34	int nsrc;
35	int ndst;
36} opcode[128] = {
37	[BRW_OPCODE_MOV] = { .name = "mov", .nsrc = 1, .ndst = 1 },
38	[BRW_OPCODE_FRC] = { .name = "frc", .nsrc = 1, .ndst = 1 },
39	[BRW_OPCODE_RNDU] = { .name = "rndu", .nsrc = 1, .ndst = 1 },
40	[BRW_OPCODE_RNDD] = { .name = "rndd", .nsrc = 1, .ndst = 1 },
41	[BRW_OPCODE_RNDE] = { .name = "rnde", .nsrc = 1, .ndst = 1 },
42	[BRW_OPCODE_RNDZ] = { .name = "rndz", .nsrc = 1, .ndst = 1 },
43	[BRW_OPCODE_NOT] = { .name = "not", .nsrc = 1, .ndst = 1 },
44	[BRW_OPCODE_LZD] = { .name = "lzd", .nsrc = 1, .ndst = 1 },
45
46	[BRW_OPCODE_MUL] = { .name = "mul", .nsrc = 2, .ndst = 1 },
47	[BRW_OPCODE_MAC] = { .name = "mac", .nsrc = 2, .ndst = 1 },
48	[BRW_OPCODE_MACH] = { .name = "mach", .nsrc = 2, .ndst = 1 },
49	[BRW_OPCODE_LINE] = { .name = "line", .nsrc = 2, .ndst = 1 },
50	[BRW_OPCODE_PLN] = { .name = "pln", .nsrc = 2, .ndst = 1 },
51	[BRW_OPCODE_SAD2] = { .name = "sad2", .nsrc = 2, .ndst = 1 },
52	[BRW_OPCODE_SADA2] = { .name = "sada2", .nsrc = 2, .ndst = 1 },
53	[BRW_OPCODE_DP4] = { .name = "dp4", .nsrc = 2, .ndst = 1 },
54	[BRW_OPCODE_DPH] = { .name = "dph", .nsrc = 2, .ndst = 1 },
55	[BRW_OPCODE_DP3] = { .name = "dp3", .nsrc = 2, .ndst = 1 },
56	[BRW_OPCODE_DP2] = { .name = "dp2", .nsrc = 2, .ndst = 1 },
57	[BRW_OPCODE_MATH] = { .name = "math", .nsrc = 2, .ndst = 1 },
58
59	[BRW_OPCODE_AVG] = { .name = "avg", .nsrc = 2, .ndst = 1 },
60	[BRW_OPCODE_ADD] = { .name = "add", .nsrc = 2, .ndst = 1 },
61	[BRW_OPCODE_SEL] = { .name = "sel", .nsrc = 2, .ndst = 1 },
62	[BRW_OPCODE_AND] = { .name = "and", .nsrc = 2, .ndst = 1 },
63	[BRW_OPCODE_OR] = { .name = "or", .nsrc = 2, .ndst = 1 },
64	[BRW_OPCODE_XOR] = { .name = "xor", .nsrc = 2, .ndst = 1 },
65	[BRW_OPCODE_SHR] = { .name = "shr", .nsrc = 2, .ndst = 1 },
66	[BRW_OPCODE_SHL] = { .name = "shl", .nsrc = 2, .ndst = 1 },
67	[BRW_OPCODE_ASR] = { .name = "asr", .nsrc = 2, .ndst = 1 },
68	[BRW_OPCODE_CMP] = { .name = "cmp", .nsrc = 2, .ndst = 1 },
69	[BRW_OPCODE_CMPN] = { .name = "cmpn", .nsrc = 2, .ndst = 1 },
70
71	[BRW_OPCODE_SEND] = { .name = "send", .nsrc = 1, .ndst = 1 },
72	[BRW_OPCODE_SENDC] = { .name = "sendc", .nsrc = 1, .ndst = 1 },
73	[BRW_OPCODE_NOP] = { .name = "nop", .nsrc = 0, .ndst = 0 },
74	[BRW_OPCODE_JMPI] = { .name = "jmpi", .nsrc = 1, .ndst = 0 },
75	[BRW_OPCODE_IF] = { .name = "if", .nsrc = 2, .ndst = 0 },
76	[BRW_OPCODE_IFF] = { .name = "iff", .nsrc = 2, .ndst = 1 },
77	[BRW_OPCODE_WHILE] = { .name = "while", .nsrc = 2, .ndst = 0 },
78	[BRW_OPCODE_ELSE] = { .name = "else", .nsrc = 2, .ndst = 0 },
79	[BRW_OPCODE_BREAK] = { .name = "break", .nsrc = 2, .ndst = 0 },
80	[BRW_OPCODE_CONTINUE] = { .name = "cont", .nsrc = 1, .ndst = 0 },
81	[BRW_OPCODE_HALT] = { .name = "halt", .nsrc = 1, .ndst = 0 },
82	[BRW_OPCODE_MSAVE] = { .name = "msave", .nsrc = 1, .ndst = 1 },
83	[BRW_OPCODE_PUSH] = { .name = "push", .nsrc = 1, .ndst = 1 },
84	[BRW_OPCODE_MRESTORE] = { .name = "mrest", .nsrc = 1, .ndst = 1 },
85	[BRW_OPCODE_POP] = { .name = "pop", .nsrc = 2, .ndst = 0 },
86	[BRW_OPCODE_WAIT] = { .name = "wait", .nsrc = 1, .ndst = 0 },
87	[BRW_OPCODE_DO] = { .name = "do", .nsrc = 0, .ndst = 0 },
88	[BRW_OPCODE_ENDIF] = { .name = "endif", .nsrc = 2, .ndst = 0 },
89};
90
91static const char *conditional_modifier[16] = {
92	[BRW_CONDITIONAL_NONE] = "",
93	[BRW_CONDITIONAL_Z] = ".e",
94	[BRW_CONDITIONAL_NZ] = ".ne",
95	[BRW_CONDITIONAL_G] = ".g",
96	[BRW_CONDITIONAL_GE] = ".ge",
97	[BRW_CONDITIONAL_L] = ".l",
98	[BRW_CONDITIONAL_LE] = ".le",
99	[BRW_CONDITIONAL_R] = ".r",
100	[BRW_CONDITIONAL_O] = ".o",
101	[BRW_CONDITIONAL_U] = ".u",
102};
103
104static const char *negate[2] = {
105	[0] = "",
106	[1] = "-",
107};
108
109static const char *_abs[2] = {
110	[0] = "",
111	[1] = "(abs)",
112};
113
114static const char *vert_stride[16] = {
115	[0] = "0",
116	[1] = "1",
117	[2] = "2",
118	[3] = "4",
119	[4] = "8",
120	[5] = "16",
121	[6] = "32",
122	[15] = "VxH",
123};
124
125static const char *width[8] = {
126	[0] = "1",
127	[1] = "2",
128	[2] = "4",
129	[3] = "8",
130	[4] = "16",
131};
132
133static const char *horiz_stride[4] = {
134	[0] = "0",
135	[1] = "1",
136	[2] = "2",
137	[3] = "4"
138};
139
140static const char *chan_sel[4] = {
141	[0] = "x",
142	[1] = "y",
143	[2] = "z",
144	[3] = "w",
145};
146
147#if 0
148static const char *dest_condmod[16] = {
149};
150
151static const char *imm_encoding[8] = {
152	[0] = "UD",
153	[1] = "D",
154	[2] = "UW",
155	[3] = "W",
156	[5] = "VF",
157	[6] = "V",
158	[7] = "F"
159};
160#endif
161
162static const char *debug_ctrl[2] = {
163	[0] = "",
164	[1] = ".breakpoint"
165};
166
167static const char *saturate[2] = {
168	[0] = "",
169	[1] = ".sat"
170};
171
172static const char *accwr[2] = {
173	[0] = "",
174	[1] = "AccWrEnable"
175};
176
177static const char *wectrl[2] = {
178	[0] = "WE_normal",
179	[1] = "WE_all"
180};
181
182static const char *exec_size[8] = {
183	[0] = "1",
184	[1] = "2",
185	[2] = "4",
186	[3] = "8",
187	[4] = "16",
188	[5] = "32"
189};
190
191static const char *pred_inv[2] = {
192	[0] = "+",
193	[1] = "-"
194};
195
196static const char *pred_ctrl_align16[16] = {
197	[1] = "",
198	[2] = ".x",
199	[3] = ".y",
200	[4] = ".z",
201	[5] = ".w",
202	[6] = ".any4h",
203	[7] = ".all4h",
204};
205
206static const char *pred_ctrl_align1[16] = {
207	[1] = "",
208	[2] = ".anyv",
209	[3] = ".allv",
210	[4] = ".any2h",
211	[5] = ".all2h",
212	[6] = ".any4h",
213	[7] = ".all4h",
214	[8] = ".any8h",
215	[9] = ".all8h",
216	[10] = ".any16h",
217	[11] = ".all16h",
218};
219
220static const char *thread_ctrl[4] = {
221	[0] = "",
222	[2] = "switch"
223};
224
225static const char *compr_ctrl[4] = {
226	[0] = "",
227	[1] = "sechalf",
228	[2] = "compr",
229	[3] = "compr4",
230};
231
232static const char *dep_ctrl[4] = {
233	[0] = "",
234	[1] = "NoDDClr",
235	[2] = "NoDDChk",
236	[3] = "NoDDClr,NoDDChk",
237};
238
239static const char *mask_ctrl[4] = {
240	[0] = "",
241	[1] = "nomask",
242};
243
244static const char *access_mode[2] = {
245	[0] = "align1",
246	[1] = "align16",
247};
248
249static const char *reg_encoding[8] = {
250	[0] = "UD",
251	[1] = "D",
252	[2] = "UW",
253	[3] = "W",
254	[4] = "UB",
255	[5] = "B",
256	[7] = "F"
257};
258
259static const int reg_type_size[8] = {
260	[0] = 4,
261	[1] = 4,
262	[2] = 2,
263	[3] = 2,
264	[4] = 1,
265	[5] = 1,
266	[7] = 4
267};
268
269static const char *reg_file[4] = {
270	[0] = "A",
271	[1] = "g",
272	[2] = "m",
273	[3] = "imm",
274};
275
276static const char *writemask[16] = {
277	[0x0] = ".",
278	[0x1] = ".x",
279	[0x2] = ".y",
280	[0x3] = ".xy",
281	[0x4] = ".z",
282	[0x5] = ".xz",
283	[0x6] = ".yz",
284	[0x7] = ".xyz",
285	[0x8] = ".w",
286	[0x9] = ".xw",
287	[0xa] = ".yw",
288	[0xb] = ".xyw",
289	[0xc] = ".zw",
290	[0xd] = ".xzw",
291	[0xe] = ".yzw",
292	[0xf] = "",
293};
294
295static const char *end_of_thread[2] = {
296	[0] = "",
297	[1] = "EOT"
298};
299
300static const char *target_function[16] = {
301	[BRW_SFID_NULL] = "null",
302	[BRW_SFID_MATH] = "math",
303	[BRW_SFID_SAMPLER] = "sampler",
304	[BRW_SFID_MESSAGE_GATEWAY] = "gateway",
305	[BRW_SFID_DATAPORT_READ] = "read",
306	[BRW_SFID_DATAPORT_WRITE] = "write",
307	[BRW_SFID_URB] = "urb",
308	[BRW_SFID_THREAD_SPAWNER] = "thread_spawner"
309};
310
311static const char *target_function_gen6[16] = {
312	[BRW_SFID_NULL] = "null",
313	[BRW_SFID_MATH] = "math",
314	[BRW_SFID_SAMPLER] = "sampler",
315	[BRW_SFID_MESSAGE_GATEWAY] = "gateway",
316	[BRW_SFID_URB] = "urb",
317	[BRW_SFID_THREAD_SPAWNER] = "thread_spawner",
318	[GEN6_SFID_DATAPORT_SAMPLER_CACHE] = "sampler",
319	[GEN6_SFID_DATAPORT_RENDER_CACHE] = "render",
320	[GEN6_SFID_DATAPORT_CONSTANT_CACHE] = "const",
321	[GEN7_SFID_DATAPORT_DATA_CACHE] = "data"
322};
323
324static const char *dp_rc_msg_type_gen6[16] = {
325	[BRW_DATAPORT_READ_MESSAGE_OWORD_BLOCK_READ] = "OWORD block read",
326	[GEN6_DATAPORT_READ_MESSAGE_RENDER_UNORM_READ] = "RT UNORM read",
327	[GEN6_DATAPORT_READ_MESSAGE_OWORD_DUAL_BLOCK_READ] = "OWORD dual block read",
328	[GEN6_DATAPORT_READ_MESSAGE_MEDIA_BLOCK_READ] = "media block read",
329	[GEN6_DATAPORT_READ_MESSAGE_OWORD_UNALIGN_BLOCK_READ] = "OWORD unaligned block read",
330	[GEN6_DATAPORT_READ_MESSAGE_DWORD_SCATTERED_READ] = "DWORD scattered read",
331	[GEN6_DATAPORT_WRITE_MESSAGE_DWORD_ATOMIC_WRITE] = "DWORD atomic write",
332	[GEN6_DATAPORT_WRITE_MESSAGE_OWORD_BLOCK_WRITE] = "OWORD block write",
333	[GEN6_DATAPORT_WRITE_MESSAGE_OWORD_DUAL_BLOCK_WRITE] = "OWORD dual block write",
334	[GEN6_DATAPORT_WRITE_MESSAGE_MEDIA_BLOCK_WRITE] = "media block write",
335	[GEN6_DATAPORT_WRITE_MESSAGE_DWORD_SCATTERED_WRITE] = "DWORD scattered write",
336	[GEN6_DATAPORT_WRITE_MESSAGE_RENDER_TARGET_WRITE] = "RT write",
337	[GEN6_DATAPORT_WRITE_MESSAGE_STREAMED_VB_WRITE] = "streamed VB write",
338	[GEN6_DATAPORT_WRITE_MESSAGE_RENDER_TARGET_UNORM_WRITE] = "RT UNORMc write",
339};
340
341static const char *math_function[16] = {
342	[BRW_MATH_FUNCTION_INV] = "inv",
343	[BRW_MATH_FUNCTION_LOG] = "log",
344	[BRW_MATH_FUNCTION_EXP] = "exp",
345	[BRW_MATH_FUNCTION_SQRT] = "sqrt",
346	[BRW_MATH_FUNCTION_RSQ] = "rsq",
347	[BRW_MATH_FUNCTION_SIN] = "sin",
348	[BRW_MATH_FUNCTION_COS] = "cos",
349	[BRW_MATH_FUNCTION_SINCOS] = "sincos",
350	[BRW_MATH_FUNCTION_TAN] = "tan",
351	[BRW_MATH_FUNCTION_POW] = "pow",
352	[BRW_MATH_FUNCTION_INT_DIV_QUOTIENT_AND_REMAINDER] = "intdivmod",
353	[BRW_MATH_FUNCTION_INT_DIV_QUOTIENT] = "intdiv",
354	[BRW_MATH_FUNCTION_INT_DIV_REMAINDER] = "intmod",
355};
356
357static const char *math_saturate[2] = {
358	[0] = "",
359	[1] = "sat"
360};
361
362static const char *math_signed[2] = {
363	[0] = "",
364	[1] = "signed"
365};
366
367static const char *math_scalar[2] = {
368	[0] = "",
369	[1] = "scalar"
370};
371
372static const char *math_precision[2] = {
373	[0] = "",
374	[1] = "partial_precision"
375};
376
377static const char *urb_opcode[2] = {
378	[0] = "urb_write",
379	[1] = "ff_sync",
380};
381
382static const char *urb_swizzle[4] = {
383	[BRW_URB_SWIZZLE_NONE] = "",
384	[BRW_URB_SWIZZLE_INTERLEAVE] = "interleave",
385	[BRW_URB_SWIZZLE_TRANSPOSE] = "transpose",
386};
387
388static const char *urb_allocate[2] = {
389	[0] = "",
390	[1] = "allocate"
391};
392
393static const char *urb_used[2] = {
394	[0] = "",
395	[1] = "used"
396};
397
398static const char *urb_complete[2] = {
399	[0] = "",
400	[1] = "complete"
401};
402
403static const char *sampler_target_format[4] = {
404	[0] = "F",
405	[2] = "UD",
406	[3] = "D"
407};
408
409static int column;
410
411static int string(FILE *file, const char *str)
412{
413	fputs(str, file);
414	column += strlen(str);
415	return 0;
416}
417
418#if defined(__GNUC__) && (__GNUC__ > 2)
419__attribute__((format(printf, 2, 3)))
420#endif
421static int format(FILE *f, const char *fmt, ...)
422{
423	char buf[1024];
424	va_list	args;
425
426	va_start(args, fmt);
427	vsnprintf(buf, sizeof(buf) - 1, fmt, args);
428	va_end(args);
429
430	string(f, buf);
431	return 0;
432}
433
434static void newline(FILE *f)
435{
436	putc('\n', f);
437	column = 0;
438}
439
440static void pad(FILE *f, int c)
441{
442	do
443		string(f, " ");
444	while (column < c);
445}
446
447static void control(FILE *file, const char *name, const char *ctrl[], unsigned id, int *space)
448{
449	if (!ctrl[id]) {
450		fprintf(file, "*** invalid %s value %d ",
451			name, id);
452		assert(0);
453	}
454	if (ctrl[id][0]) {
455		if (space && *space)
456			string(file, " ");
457		string(file, ctrl[id]);
458		if (space)
459			*space = 1;
460	}
461}
462
463static void print_opcode(FILE *file, int id)
464{
465	if (!opcode[id].name) {
466		format(file, "*** invalid opcode value %d ", id);
467		assert(0);
468	}
469	string(file, opcode[id].name);
470}
471
472static int reg(FILE *file, unsigned _reg_file, unsigned _reg_nr)
473{
474	/* Clear the Compr4 instruction compression bit. */
475	if (_reg_file == BRW_MESSAGE_REGISTER_FILE)
476		_reg_nr &= ~(1 << 7);
477
478	if (_reg_file == BRW_ARCHITECTURE_REGISTER_FILE) {
479		switch (_reg_nr & 0xf0) {
480		case BRW_ARF_NULL:
481			string(file, "null");
482			return -1;
483		case BRW_ARF_ADDRESS:
484			format(file, "a%d", _reg_nr & 0x0f);
485			break;
486		case BRW_ARF_ACCUMULATOR:
487			format(file, "acc%d", _reg_nr & 0x0f);
488			break;
489		case BRW_ARF_FLAG:
490			format(file, "f%d", _reg_nr & 0x0f);
491			break;
492		case BRW_ARF_MASK:
493			format(file, "mask%d", _reg_nr & 0x0f);
494			break;
495		case BRW_ARF_MASK_STACK:
496			format(file, "msd%d", _reg_nr & 0x0f);
497			break;
498		case BRW_ARF_STATE:
499			format(file, "sr%d", _reg_nr & 0x0f);
500			break;
501		case BRW_ARF_CONTROL:
502			format(file, "cr%d", _reg_nr & 0x0f);
503			break;
504		case BRW_ARF_NOTIFICATION_COUNT:
505			format(file, "n%d", _reg_nr & 0x0f);
506			break;
507		case BRW_ARF_IP:
508			string(file, "ip");
509			return -1;
510		default:
511			format(file, "ARF%d", _reg_nr);
512			break;
513		}
514	} else {
515		control(file, "src reg file", reg_file, _reg_file, NULL);
516		format(file, "%d", _reg_nr);
517	}
518	return 0;
519}
520
521static void dest(FILE *file, const struct brw_instruction *inst)
522{
523	if (inst->header.access_mode == BRW_ALIGN_1) {
524		if (inst->bits1.da1.dest_address_mode == BRW_ADDRESS_DIRECT) {
525			if (reg(file, inst->bits1.da1.dest_reg_file, inst->bits1.da1.dest_reg_nr))
526				return;
527
528			if (inst->bits1.da1.dest_subreg_nr)
529				format(file, ".%d", inst->bits1.da1.dest_subreg_nr /
530				       reg_type_size[inst->bits1.da1.dest_reg_type]);
531			format(file, "<%d>", inst->bits1.da1.dest_horiz_stride);
532			control(file, "dest reg encoding", reg_encoding, inst->bits1.da1.dest_reg_type, NULL);
533		} else {
534			string(file, "g[a0");
535			if (inst->bits1.ia1.dest_subreg_nr)
536				format(file, ".%d", inst->bits1.ia1.dest_subreg_nr /
537				       reg_type_size[inst->bits1.ia1.dest_reg_type]);
538			if (inst->bits1.ia1.dest_indirect_offset)
539				format(file, " %d", inst->bits1.ia1.dest_indirect_offset);
540			string(file, "]");
541			format(file, "<%d>", inst->bits1.ia1.dest_horiz_stride);
542			control(file, "dest reg encoding", reg_encoding, inst->bits1.ia1.dest_reg_type, NULL);
543		}
544	} else {
545		if (inst->bits1.da16.dest_address_mode == BRW_ADDRESS_DIRECT) {
546			if (reg(file, inst->bits1.da16.dest_reg_file, inst->bits1.da16.dest_reg_nr))
547				return;
548
549			if (inst->bits1.da16.dest_subreg_nr)
550				format(file, ".%d", inst->bits1.da16.dest_subreg_nr /
551				       reg_type_size[inst->bits1.da16.dest_reg_type]);
552			string(file, "<1>");
553			control(file, "writemask", writemask, inst->bits1.da16.dest_writemask, NULL);
554			control(file, "dest reg encoding", reg_encoding, inst->bits1.da16.dest_reg_type, NULL);
555		} else {
556			string(file, "Indirect align16 address mode not supported");
557		}
558	}
559}
560
561static void src_align1_region(FILE *file,
562			      unsigned _vert_stride, unsigned _width, unsigned _horiz_stride)
563{
564	string(file, "<");
565	control(file, "vert stride", vert_stride, _vert_stride, NULL);
566	string(file, ",");
567	control(file, "width", width, _width, NULL);
568	string(file, ",");
569	control(file, "horiz_stride", horiz_stride, _horiz_stride, NULL);
570	string(file, ">");
571}
572
573static void src_da1(FILE *file, unsigned type, unsigned _reg_file,
574		    unsigned _vert_stride, unsigned _width, unsigned _horiz_stride,
575		    unsigned reg_num, unsigned sub_reg_num, unsigned __abs, unsigned _negate)
576{
577	control(file, "negate", negate, _negate, NULL);
578	control(file, "abs", _abs, __abs, NULL);
579
580	if (reg(file, _reg_file, reg_num))
581		return;
582
583	if (sub_reg_num)
584		format(file, ".%d", sub_reg_num / reg_type_size[type]); /* use formal style like spec */
585	src_align1_region(file, _vert_stride, _width, _horiz_stride);
586	control(file, "src reg encoding", reg_encoding, type, NULL);
587}
588
589static void src_ia1(FILE *file,
590		    unsigned type,
591		    unsigned _reg_file,
592		    int _addr_imm,
593		    unsigned _addr_subreg_nr,
594		    unsigned _negate,
595		    unsigned __abs,
596		    unsigned _addr_mode,
597		    unsigned _horiz_stride,
598		    unsigned _width,
599		    unsigned _vert_stride)
600{
601	control(file, "negate", negate, _negate, NULL);
602	control(file, "abs", _abs, __abs, NULL);
603
604	string(file, "g[a0");
605	if (_addr_subreg_nr)
606		format(file, ".%d", _addr_subreg_nr);
607	if (_addr_imm)
608		format(file, " %d", _addr_imm);
609	string(file, "]");
610	src_align1_region(file, _vert_stride, _width, _horiz_stride);
611	control(file, "src reg encoding", reg_encoding, type, NULL);
612}
613
614static void src_da16(FILE *file,
615		     unsigned _reg_type,
616		     unsigned _reg_file,
617		     unsigned _vert_stride,
618		     unsigned _reg_nr,
619		     unsigned _subreg_nr,
620		     unsigned __abs,
621		     unsigned _negate,
622		     unsigned swz_x,
623		     unsigned swz_y,
624		     unsigned swz_z,
625		     unsigned swz_w)
626{
627	control(file, "negate", negate, _negate, NULL);
628	control(file, "abs", _abs, __abs, NULL);
629
630	if (reg(file, _reg_file, _reg_nr))
631		return;
632
633	if (_subreg_nr)
634		/* bit4 for subreg number byte addressing. Make this same meaning as
635		   in da1 case, so output looks consistent. */
636		format(file, ".%d", 16 / reg_type_size[_reg_type]);
637	string(file, "<");
638	control(file, "vert stride", vert_stride, _vert_stride, NULL);
639	string(file, ",4,1>");
640	/*
641	 * Three kinds of swizzle display:
642	 *  identity - nothing printed
643	 *  1->all	 - print the single channel
644	 *  1->1     - print the mapping
645	 */
646	if (swz_x == BRW_CHANNEL_X &&
647	    swz_y == BRW_CHANNEL_Y &&
648	    swz_z == BRW_CHANNEL_Z &&
649	    swz_w == BRW_CHANNEL_W)
650	{
651		;
652	}
653	else if (swz_x == swz_y && swz_x == swz_z && swz_x == swz_w)
654	{
655		string(file, ".");
656		control(file, "channel select", chan_sel, swz_x, NULL);
657	}
658	else
659	{
660		string(file, ".");
661		control(file, "channel select", chan_sel, swz_x, NULL);
662		control(file, "channel select", chan_sel, swz_y, NULL);
663		control(file, "channel select", chan_sel, swz_z, NULL);
664		control(file, "channel select", chan_sel, swz_w, NULL);
665	}
666	control(file, "src da16 reg type", reg_encoding, _reg_type, NULL);
667}
668
669static void imm(FILE *file, unsigned type, const struct brw_instruction *inst)
670{
671	switch (type) {
672	case BRW_REGISTER_TYPE_UD:
673		format(file, "0x%08xUD", inst->bits3.ud);
674		break;
675	case BRW_REGISTER_TYPE_D:
676		format(file, "%dD", inst->bits3.d);
677		break;
678	case BRW_REGISTER_TYPE_UW:
679		format(file, "0x%04xUW", (uint16_t) inst->bits3.ud);
680		break;
681	case BRW_REGISTER_TYPE_W:
682		format(file, "%dW", (int16_t) inst->bits3.d);
683		break;
684	case BRW_REGISTER_TYPE_UB:
685		format(file, "0x%02xUB", (int8_t) inst->bits3.ud);
686		break;
687	case BRW_REGISTER_TYPE_VF:
688		format(file, "Vector Float");
689		break;
690	case BRW_REGISTER_TYPE_V:
691		format(file, "0x%08xV", inst->bits3.ud);
692		break;
693	case BRW_REGISTER_TYPE_F:
694		format(file, "%-gF", inst->bits3.f);
695	}
696}
697
698static void src0(FILE *file, const struct brw_instruction *inst)
699{
700	if (inst->bits1.da1.src0_reg_file == BRW_IMMEDIATE_VALUE)
701		imm(file, inst->bits1.da1.src0_reg_type, inst);
702	else if (inst->header.access_mode == BRW_ALIGN_1) {
703		if (inst->bits2.da1.src0_address_mode == BRW_ADDRESS_DIRECT) {
704			src_da1(file,
705				inst->bits1.da1.src0_reg_type,
706				inst->bits1.da1.src0_reg_file,
707				inst->bits2.da1.src0_vert_stride,
708				inst->bits2.da1.src0_width,
709				inst->bits2.da1.src0_horiz_stride,
710				inst->bits2.da1.src0_reg_nr,
711				inst->bits2.da1.src0_subreg_nr,
712				inst->bits2.da1.src0_abs,
713				inst->bits2.da1.src0_negate);
714		} else {
715			src_ia1(file,
716				inst->bits1.ia1.src0_reg_type,
717				inst->bits1.ia1.src0_reg_file,
718				inst->bits2.ia1.src0_indirect_offset,
719				inst->bits2.ia1.src0_subreg_nr,
720				inst->bits2.ia1.src0_negate,
721				inst->bits2.ia1.src0_abs,
722				inst->bits2.ia1.src0_address_mode,
723				inst->bits2.ia1.src0_horiz_stride,
724				inst->bits2.ia1.src0_width,
725				inst->bits2.ia1.src0_vert_stride);
726		}
727	} else {
728		if (inst->bits2.da16.src0_address_mode == BRW_ADDRESS_DIRECT) {
729			src_da16(file,
730				 inst->bits1.da16.src0_reg_type,
731				 inst->bits1.da16.src0_reg_file,
732				 inst->bits2.da16.src0_vert_stride,
733				 inst->bits2.da16.src0_reg_nr,
734				 inst->bits2.da16.src0_subreg_nr,
735				 inst->bits2.da16.src0_abs,
736				 inst->bits2.da16.src0_negate,
737				 inst->bits2.da16.src0_swz_x,
738				 inst->bits2.da16.src0_swz_y,
739				 inst->bits2.da16.src0_swz_z,
740				 inst->bits2.da16.src0_swz_w);
741		} else {
742			string(file, "Indirect align16 address mode not supported");
743		}
744	}
745}
746
747static void src1(FILE *file, const struct brw_instruction *inst)
748{
749	if (inst->bits1.da1.src1_reg_file == BRW_IMMEDIATE_VALUE)
750		imm(file, inst->bits1.da1.src1_reg_type, inst);
751	else if (inst->header.access_mode == BRW_ALIGN_1) {
752		if (inst->bits3.da1.src1_address_mode == BRW_ADDRESS_DIRECT) {
753			src_da1(file,
754				inst->bits1.da1.src1_reg_type,
755				inst->bits1.da1.src1_reg_file,
756				inst->bits3.da1.src1_vert_stride,
757				inst->bits3.da1.src1_width,
758				inst->bits3.da1.src1_horiz_stride,
759				inst->bits3.da1.src1_reg_nr,
760				inst->bits3.da1.src1_subreg_nr,
761				inst->bits3.da1.src1_abs,
762				inst->bits3.da1.src1_negate);
763		} else {
764			src_ia1(file,
765				inst->bits1.ia1.src1_reg_type,
766				inst->bits1.ia1.src1_reg_file,
767				inst->bits3.ia1.src1_indirect_offset,
768				inst->bits3.ia1.src1_subreg_nr,
769				inst->bits3.ia1.src1_negate,
770				inst->bits3.ia1.src1_abs,
771				inst->bits3.ia1.src1_address_mode,
772				inst->bits3.ia1.src1_horiz_stride,
773				inst->bits3.ia1.src1_width,
774				inst->bits3.ia1.src1_vert_stride);
775		}
776	} else {
777		if (inst->bits3.da16.src1_address_mode == BRW_ADDRESS_DIRECT) {
778			src_da16(file,
779				 inst->bits1.da16.src1_reg_type,
780				 inst->bits1.da16.src1_reg_file,
781				 inst->bits3.da16.src1_vert_stride,
782				 inst->bits3.da16.src1_reg_nr,
783				 inst->bits3.da16.src1_subreg_nr,
784				 inst->bits3.da16.src1_abs,
785				 inst->bits3.da16.src1_negate,
786				 inst->bits3.da16.src1_swz_x,
787				 inst->bits3.da16.src1_swz_y,
788				 inst->bits3.da16.src1_swz_z,
789				 inst->bits3.da16.src1_swz_w);
790		} else {
791			string(file, "Indirect align16 address mode not supported");
792		}
793	}
794}
795
796static const int esize[6] = {
797	[0] = 1,
798	[1] = 2,
799	[2] = 4,
800	[3] = 8,
801	[4] = 16,
802	[5] = 32,
803};
804
805static int qtr_ctrl(FILE *file, const struct brw_instruction *inst)
806{
807	int qtr_ctl = inst->header.compression_control;
808	int size = esize[inst->header.execution_size];
809
810	if (size == 8) {
811		switch (qtr_ctl) {
812		case 0:
813			string(file, " 1Q");
814			break;
815		case 1:
816			string(file, " 2Q");
817			break;
818		case 2:
819			string(file, " 3Q");
820			break;
821		case 3:
822			string(file, " 4Q");
823			break;
824		}
825	} else if (size == 16){
826		if (qtr_ctl < 2)
827			string(file, " 1H");
828		else
829			string(file, " 2H");
830	}
831	return 0;
832}
833
834void brw_disasm(FILE *file, const struct brw_instruction *inst, int gen)
835{
836	int space = 0;
837
838	format(file, "%08x %08x %08x %08x\n",
839	       ((const uint32_t*)inst)[0],
840	       ((const uint32_t*)inst)[1],
841	       ((const uint32_t*)inst)[2],
842	       ((const uint32_t*)inst)[3]);
843
844	if (inst->header.predicate_control) {
845		string(file, "(");
846		control(file, "predicate inverse", pred_inv, inst->header.predicate_inverse, NULL);
847		string(file, "f0");
848		if (inst->bits2.da1.flag_subreg_nr)
849			format(file, ".%d", inst->bits2.da1.flag_subreg_nr);
850		if (inst->header.access_mode == BRW_ALIGN_1)
851			control(file, "predicate control align1", pred_ctrl_align1,
852				inst->header.predicate_control, NULL);
853		else
854			control(file, "predicate control align16", pred_ctrl_align16,
855				inst->header.predicate_control, NULL);
856		string(file, ") ");
857	}
858
859	print_opcode(file, inst->header.opcode);
860	control(file, "saturate", saturate, inst->header.saturate, NULL);
861	control(file, "debug control", debug_ctrl, inst->header.debug_control, NULL);
862
863	if (inst->header.opcode == BRW_OPCODE_MATH) {
864		string(file, " ");
865		control(file, "function", math_function,
866			inst->header.destreg__conditionalmod, NULL);
867	} else if (inst->header.opcode != BRW_OPCODE_SEND &&
868		   inst->header.opcode != BRW_OPCODE_SENDC)
869		control(file, "conditional modifier", conditional_modifier,
870			inst->header.destreg__conditionalmod, NULL);
871
872	if (inst->header.opcode != BRW_OPCODE_NOP) {
873		string(file, "(");
874		control(file, "execution size", exec_size, inst->header.execution_size, NULL);
875		string(file, ")");
876	}
877
878	if (inst->header.opcode == BRW_OPCODE_SEND && gen < 060)
879		format(file, " %d", inst->header.destreg__conditionalmod);
880
881	if (opcode[inst->header.opcode].ndst > 0) {
882		pad(file, 16);
883		dest(file, inst);
884	} else if (gen >= 060 &&
885		   (inst->header.opcode == BRW_OPCODE_IF ||
886		    inst->header.opcode == BRW_OPCODE_ELSE ||
887		    inst->header.opcode == BRW_OPCODE_ENDIF ||
888		    inst->header.opcode == BRW_OPCODE_WHILE)) {
889		format(file, " %d", inst->bits1.branch_gen6.jump_count);
890	}
891
892	if (opcode[inst->header.opcode].nsrc > 0) {
893		pad(file, 32);
894		src0(file, inst);
895	}
896	if (opcode[inst->header.opcode].nsrc > 1) {
897		pad(file, 48);
898		src1(file, inst);
899	}
900
901	if (inst->header.opcode == BRW_OPCODE_SEND ||
902	    inst->header.opcode == BRW_OPCODE_SENDC) {
903		enum brw_message_target target;
904
905		if (gen >= 060)
906			target = inst->header.destreg__conditionalmod;
907		else if (gen >= 050)
908			target = inst->bits2.send_gen5.sfid;
909		else
910			target = inst->bits3.generic.msg_target;
911
912		newline (file);
913		pad (file, 16);
914		space = 0;
915
916		if (gen >= 060) {
917			control (file, "target function", target_function_gen6,
918				 target, &space);
919		} else {
920			control (file, "target function", target_function,
921				 target, &space);
922		}
923
924		switch (target) {
925		case BRW_SFID_MATH:
926			control (file, "math function", math_function,
927				 inst->bits3.math.function, &space);
928			control (file, "math saturate", math_saturate,
929				 inst->bits3.math.saturate, &space);
930			control (file, "math signed", math_signed,
931				 inst->bits3.math.int_type, &space);
932			control (file, "math scalar", math_scalar,
933				 inst->bits3.math.data_type, &space);
934			control (file, "math precision", math_precision,
935				 inst->bits3.math.precision, &space);
936			break;
937		case BRW_SFID_SAMPLER:
938			if (gen >= 070) {
939				format (file, " (%d, %d, %d, %d)",
940					inst->bits3.sampler_gen7.binding_table_index,
941					inst->bits3.sampler_gen7.sampler,
942					inst->bits3.sampler_gen7.msg_type,
943					inst->bits3.sampler_gen7.simd_mode);
944			} else if (gen >= 050) {
945				format (file, " (%d, %d, %d, %d)",
946					inst->bits3.sampler_gen5.binding_table_index,
947					inst->bits3.sampler_gen5.sampler,
948					inst->bits3.sampler_gen5.msg_type,
949					inst->bits3.sampler_gen5.simd_mode);
950			} else if (gen >= 045) {
951				format (file, " (%d, %d)",
952					inst->bits3.sampler_g4x.binding_table_index,
953					inst->bits3.sampler_g4x.sampler);
954			} else {
955				format (file, " (%d, %d, ",
956					inst->bits3.sampler.binding_table_index,
957					inst->bits3.sampler.sampler);
958				control (file, "sampler target format",
959					 sampler_target_format,
960					 inst->bits3.sampler.return_format, NULL);
961				string (file, ")");
962			}
963			break;
964		case BRW_SFID_DATAPORT_READ:
965			if (gen >= 060) {
966				format (file, " (%d, %d, %d, %d)",
967					inst->bits3.gen6_dp.binding_table_index,
968					inst->bits3.gen6_dp.msg_control,
969					inst->bits3.gen6_dp.msg_type,
970					inst->bits3.gen6_dp.send_commit_msg);
971			} else if (gen >= 045) {
972				format (file, " (%d, %d, %d)",
973					inst->bits3.dp_read_gen5.binding_table_index,
974					inst->bits3.dp_read_gen5.msg_control,
975					inst->bits3.dp_read_gen5.msg_type);
976			} else {
977				format (file, " (%d, %d, %d)",
978					inst->bits3.dp_read.binding_table_index,
979					inst->bits3.dp_read.msg_control,
980					inst->bits3.dp_read.msg_type);
981			}
982			break;
983
984		case BRW_SFID_DATAPORT_WRITE:
985			if (gen >= 070) {
986				format (file, " (");
987
988				control (file, "DP rc message type",
989					 dp_rc_msg_type_gen6,
990					 inst->bits3.gen7_dp.msg_type, &space);
991
992				format (file, ", %d, %d, %d)",
993					inst->bits3.gen7_dp.binding_table_index,
994					inst->bits3.gen7_dp.msg_control,
995					inst->bits3.gen7_dp.msg_type);
996			} else if (gen >= 060) {
997				format (file, " (");
998
999				control (file, "DP rc message type",
1000					 dp_rc_msg_type_gen6,
1001					 inst->bits3.gen6_dp.msg_type, &space);
1002
1003				format (file, ", %d, %d, %d, %d)",
1004					inst->bits3.gen6_dp.binding_table_index,
1005					inst->bits3.gen6_dp.msg_control,
1006					inst->bits3.gen6_dp.msg_type,
1007					inst->bits3.gen6_dp.send_commit_msg);
1008			} else {
1009				format (file, " (%d, %d, %d, %d)",
1010					inst->bits3.dp_write.binding_table_index,
1011					(inst->bits3.dp_write.last_render_target << 3) |
1012					inst->bits3.dp_write.msg_control,
1013					inst->bits3.dp_write.msg_type,
1014					inst->bits3.dp_write.send_commit_msg);
1015			}
1016			break;
1017
1018		case BRW_SFID_URB:
1019			if (gen >= 050) {
1020				format (file, " %d", inst->bits3.urb_gen5.offset);
1021			} else {
1022				format (file, " %d", inst->bits3.urb.offset);
1023			}
1024
1025			space = 1;
1026			if (gen >= 050) {
1027				control (file, "urb opcode", urb_opcode,
1028					 inst->bits3.urb_gen5.opcode, &space);
1029			}
1030			control (file, "urb swizzle", urb_swizzle,
1031				 inst->bits3.urb.swizzle_control, &space);
1032			control (file, "urb allocate", urb_allocate,
1033				 inst->bits3.urb.allocate, &space);
1034			control (file, "urb used", urb_used,
1035				 inst->bits3.urb.used, &space);
1036			control (file, "urb complete", urb_complete,
1037				 inst->bits3.urb.complete, &space);
1038			break;
1039		case BRW_SFID_THREAD_SPAWNER:
1040			break;
1041		case GEN7_SFID_DATAPORT_DATA_CACHE:
1042			format (file, " (%d, %d, %d)",
1043				inst->bits3.gen7_dp.binding_table_index,
1044				inst->bits3.gen7_dp.msg_control,
1045				inst->bits3.gen7_dp.msg_type);
1046			break;
1047
1048
1049		default:
1050			format (file, "unsupported target %d", target);
1051			break;
1052		}
1053		if (space)
1054			string (file, " ");
1055		if (gen >= 050) {
1056			format (file, "mlen %d",
1057				inst->bits3.generic_gen5.msg_length);
1058			format (file, " rlen %d",
1059				inst->bits3.generic_gen5.response_length);
1060		} else {
1061			format (file, "mlen %d",
1062				inst->bits3.generic.msg_length);
1063			format (file, " rlen %d",
1064				inst->bits3.generic.response_length);
1065		}
1066	}
1067	pad(file, 64);
1068	if (inst->header.opcode != BRW_OPCODE_NOP) {
1069		string(file, "{");
1070		space = 1;
1071		control(file, "access mode", access_mode, inst->header.access_mode, &space);
1072		if (gen >= 060)
1073			control(file, "write enable control", wectrl, inst->header.mask_control, &space);
1074		else
1075			control(file, "mask control", mask_ctrl, inst->header.mask_control, &space);
1076		control(file, "dependency control", dep_ctrl, inst->header.dependency_control, &space);
1077
1078		if (gen >= 060)
1079			qtr_ctrl(file, inst);
1080		else {
1081			if (inst->header.compression_control == BRW_COMPRESSION_COMPRESSED &&
1082			    opcode[inst->header.opcode].ndst > 0 &&
1083			    inst->bits1.da1.dest_reg_file == BRW_MESSAGE_REGISTER_FILE &&
1084			    inst->bits1.da1.dest_reg_nr & (1 << 7)) {
1085				format(file, " compr4");
1086			} else {
1087				control(file, "compression control", compr_ctrl,
1088					inst->header.compression_control, &space);
1089			}
1090		}
1091
1092		control(file, "thread control", thread_ctrl, inst->header.thread_control, &space);
1093		if (gen >= 060)
1094			control(file, "acc write control", accwr, inst->header.acc_wr_control, &space);
1095		if (inst->header.opcode == BRW_OPCODE_SEND ||
1096		    inst->header.opcode == BRW_OPCODE_SENDC)
1097			control(file, "end of thread", end_of_thread,
1098				inst->bits3.generic.end_of_thread, &space);
1099		if (space)
1100			string(file, " ");
1101		string(file, "}");
1102	}
1103	string(file, ";");
1104	newline(file);
1105}
1106