ilo: add a new disassembler
[mesa.git] / src / gallium / drivers / ilo / shader / toy_compiler_disasm.c
1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 2014 LunarG, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 * Chia-I Wu <olv@lunarg.com>
26 */
27
28 #include <stdio.h>
29 #include "genhw/genhw.h"
30 #include "toy_compiler.h"
31
32 #define DISASM_PRINTER_BUFFER_SIZE 256
33 #define DISASM_PRINTER_COLUMN_WIDTH 16
34
35 #define READ(dw, field) (((dw) & field ## __MASK) >> field ## __SHIFT)
36
37 struct disasm_printer {
38 char buf[DISASM_PRINTER_BUFFER_SIZE];
39 int len;
40 };
41
42 struct disasm_operand {
43 unsigned file:2;
44 unsigned type:3;
45
46 unsigned addr_mode:1;
47 unsigned reg:8;
48 unsigned subreg:5;
49 unsigned addr_subreg:3;
50 unsigned addr_imm:10;
51 };
52
53 struct disasm_dst_operand {
54 struct disasm_operand base;
55
56 unsigned horz_stride:2;
57 unsigned writemask:4;
58 };
59
60 struct disasm_src_operand {
61 struct disasm_operand base;
62
63 unsigned vert_stride:4;
64 unsigned width:3;
65 unsigned horz_stride:2;
66 unsigned swizzle_x:2;
67 unsigned swizzle_y:2;
68 unsigned swizzle_z:2;
69 unsigned swizzle_w:2;
70 unsigned negate:1;
71 unsigned absolute:1;
72 };
73
74 struct disasm_inst {
75 const struct ilo_dev_info *dev;
76
77 unsigned has_jip:1;
78 unsigned has_uip:1;
79
80 unsigned opcode:7;
81 unsigned access_mode:1;
82 unsigned mask_ctrl:1;
83 unsigned dep_ctrl:2;
84 unsigned qtr_ctrl:2;
85 unsigned thread_ctrl:2;
86 unsigned pred_ctrl:4;
87 unsigned pred_inv:1;
88 unsigned exec_size:3;
89
90 unsigned cond_modifier:4;
91 unsigned sfid:4;
92 unsigned fc:4;
93
94 unsigned acc_wr_ctrl:1;
95 unsigned cmpt_ctrl:1;
96 unsigned debug_ctrl:1;
97 unsigned saturate:1;
98
99 unsigned nib_ctrl:1;
100
101 unsigned flag_reg:1;
102 unsigned flag_subreg:1;
103
104 struct disasm_dst_operand dst;
105 struct disasm_src_operand src0;
106 struct disasm_src_operand src1;
107 union {
108 struct disasm_src_operand src2;
109 uint32_t imm32;
110 } u;
111 };
112
113 static const struct {
114 const char *name;
115 int src_count;
116 } disasm_opcode_table[128] = {
117 [GEN6_OPCODE_ILLEGAL] = { "illegal", 0 },
118 [GEN6_OPCODE_MOV] = { "mov", 1 },
119 [GEN6_OPCODE_SEL] = { "sel", 2 },
120 [GEN6_OPCODE_MOVI] = { "movi", 1 },
121 [GEN6_OPCODE_NOT] = { "not", 1 },
122 [GEN6_OPCODE_AND] = { "and", 2 },
123 [GEN6_OPCODE_OR] = { "or", 2 },
124 [GEN6_OPCODE_XOR] = { "xor", 2 },
125 [GEN6_OPCODE_SHR] = { "shr", 2 },
126 [GEN6_OPCODE_SHL] = { "shl", 2 },
127 [GEN6_OPCODE_DIM] = { "dim", 1 },
128 [GEN6_OPCODE_ASR] = { "asr", 2 },
129 [GEN6_OPCODE_CMP] = { "cmp", 2 },
130 [GEN6_OPCODE_CMPN] = { "cmpn", 2 },
131 [GEN7_OPCODE_CSEL] = { "csel", 3 },
132 [GEN7_OPCODE_F32TO16] = { "f32to16", 1 },
133 [GEN7_OPCODE_F16TO32] = { "f16to32", 1 },
134 [GEN7_OPCODE_BFREV] = { "bfrev", 1 },
135 [GEN7_OPCODE_BFE] = { "bfe", 3 },
136 [GEN7_OPCODE_BFI1] = { "bfi1", 2 },
137 [GEN7_OPCODE_BFI2] = { "bfi2", 3 },
138 [GEN6_OPCODE_JMPI] = { "jmpi", 1 },
139 [GEN7_OPCODE_BRD] = { "brd", 1 },
140 [GEN6_OPCODE_IF] = { "if", 2 },
141 [GEN7_OPCODE_BRC] = { "brc", 1 },
142 [GEN6_OPCODE_ELSE] = { "else", 1 },
143 [GEN6_OPCODE_ENDIF] = { "endif", 0 },
144 [GEN6_OPCODE_CASE] = { "case", 2 },
145 [GEN6_OPCODE_WHILE] = { "while", 1 },
146 [GEN6_OPCODE_BREAK] = { "break", 1 },
147 [GEN6_OPCODE_CONT] = { "cont", 1 },
148 [GEN6_OPCODE_HALT] = { "halt", 1 },
149 [GEN75_OPCODE_CALLA] = { "calla", 1 },
150 [GEN6_OPCODE_CALL] = { "call", 1 },
151 [GEN6_OPCODE_RETURN] = { "return", 1 },
152 [GEN6_OPCODE_WAIT] = { "wait", 1 },
153 [GEN6_OPCODE_SEND] = { "send", 1 },
154 [GEN6_OPCODE_SENDC] = { "sendc", 1 },
155 [GEN6_OPCODE_MATH] = { "math", 2 },
156 [GEN6_OPCODE_ADD] = { "add", 2 },
157 [GEN6_OPCODE_MUL] = { "mul", 2 },
158 [GEN6_OPCODE_AVG] = { "avg", 2 },
159 [GEN6_OPCODE_FRC] = { "frc", 1 },
160 [GEN6_OPCODE_RNDU] = { "rndu", 1 },
161 [GEN6_OPCODE_RNDD] = { "rndd", 1 },
162 [GEN6_OPCODE_RNDE] = { "rnde", 1 },
163 [GEN6_OPCODE_RNDZ] = { "rndz", 1 },
164 [GEN6_OPCODE_MAC] = { "mac", 2 },
165 [GEN6_OPCODE_MACH] = { "mach", 2 },
166 [GEN6_OPCODE_LZD] = { "lzd", 1 },
167 [GEN7_OPCODE_FBH] = { "fbh", 1 },
168 [GEN7_OPCODE_FBL] = { "fbl", 1 },
169 [GEN7_OPCODE_CBIT] = { "cbit", 1 },
170 [GEN7_OPCODE_ADDC] = { "addc", 2 },
171 [GEN7_OPCODE_SUBB] = { "subb", 2 },
172 [GEN6_OPCODE_SAD2] = { "sad2", 2 },
173 [GEN6_OPCODE_SADA2] = { "sada2", 2 },
174 [GEN6_OPCODE_DP4] = { "dp4", 2 },
175 [GEN6_OPCODE_DPH] = { "dph", 2 },
176 [GEN6_OPCODE_DP3] = { "dp3", 2 },
177 [GEN6_OPCODE_DP2] = { "dp2", 2 },
178 [GEN6_OPCODE_LINE] = { "line", 2 },
179 [GEN6_OPCODE_PLN] = { "pln", 2 },
180 [GEN6_OPCODE_MAD] = { "mad", 3 },
181 [GEN6_OPCODE_LRP] = { "lrp", 3 },
182 [GEN6_OPCODE_NOP] = { "nop", 0 },
183 };
184
185 static void
186 disasm_inst_decode_dw0_gen6(struct disasm_inst *inst, uint32_t dw0)
187 {
188 inst->opcode = READ(dw0, GEN6_INST_OPCODE);
189
190 switch (inst->opcode) {
191 case GEN6_OPCODE_IF:
192 inst->has_jip = true;
193 inst->has_uip = (inst->dev->gen >= ILO_GEN(7));
194 break;
195 case GEN6_OPCODE_BREAK:
196 case GEN6_OPCODE_CONT:
197 case GEN6_OPCODE_HALT:
198 inst->has_uip = true;
199 /* fall through */
200 case GEN6_OPCODE_JMPI:
201 case GEN7_OPCODE_BRD:
202 case GEN7_OPCODE_BRC:
203 case GEN6_OPCODE_ELSE:
204 case GEN6_OPCODE_ENDIF:
205 case GEN6_OPCODE_CASE:
206 case GEN6_OPCODE_WHILE:
207 case GEN75_OPCODE_CALLA:
208 case GEN6_OPCODE_CALL:
209 case GEN6_OPCODE_RETURN:
210 inst->has_jip = true;
211 break;
212 default:
213 break;
214 }
215
216 inst->access_mode = READ(dw0, GEN6_INST_ACCESSMODE);
217 inst->mask_ctrl = READ(dw0, GEN6_INST_MASKCTRL);
218 inst->dep_ctrl = READ(dw0, GEN6_INST_DEPCTRL);
219 inst->qtr_ctrl = READ(dw0, GEN6_INST_QTRCTRL);
220 inst->thread_ctrl = READ(dw0, GEN6_INST_THREADCTRL);
221 inst->pred_ctrl = READ(dw0, GEN6_INST_PREDCTRL);
222
223 inst->pred_inv = (bool) (dw0 & GEN6_INST_PREDINV);
224
225 inst->exec_size = READ(dw0, GEN6_INST_EXECSIZE);
226
227 switch (inst->opcode) {
228 case GEN6_OPCODE_SEND:
229 case GEN6_OPCODE_SENDC:
230 inst->sfid = READ(dw0, GEN6_INST_SFID);
231 break;
232 case GEN6_OPCODE_MATH:
233 inst->fc = READ(dw0, GEN6_INST_FC);
234 break;
235 default:
236 inst->cond_modifier = READ(dw0, GEN6_INST_CONDMODIFIER);
237 break;
238 }
239
240 inst->acc_wr_ctrl = (bool) (dw0 & GEN6_INST_ACCWRCTRL);
241 inst->cmpt_ctrl = (bool) (dw0 & GEN6_INST_CMPTCTRL);
242 inst->debug_ctrl = (bool) (dw0 & GEN6_INST_DEBUGCTRL);
243 inst->saturate = (bool) (dw0 & GEN6_INST_SATURATE);
244 }
245
246 static bool
247 disasm_inst_jip_in_dw1_high_gen6(const struct disasm_inst *inst)
248 {
249 return (inst->dev->gen == ILO_GEN(6) && inst->has_jip && !inst->has_uip);
250 }
251
252 static void
253 disasm_inst_decode_dw1_gen6(struct disasm_inst *inst, uint32_t dw1)
254 {
255 inst->dst.base.file = READ(dw1, GEN6_INST_DST_FILE);
256 inst->dst.base.type = READ(dw1, GEN6_INST_DST_TYPE);
257 inst->src0.base.file = READ(dw1, GEN6_INST_SRC0_FILE);
258 inst->src0.base.type = READ(dw1, GEN6_INST_SRC0_TYPE);
259 inst->src1.base.file = READ(dw1, GEN6_INST_SRC1_FILE);
260 inst->src1.base.type = READ(dw1, GEN6_INST_SRC1_TYPE);
261
262 if (inst->dev->gen >= ILO_GEN(7))
263 inst->nib_ctrl = (bool) (dw1 & GEN7_INST_NIBCTRL);
264
265 if (disasm_inst_jip_in_dw1_high_gen6(inst)) {
266 inst->u.imm32 = dw1 >> 16;
267 return;
268 }
269
270 inst->dst.base.addr_mode = READ(dw1, GEN6_INST_DST_ADDRMODE);
271
272 if (inst->dst.base.addr_mode == GEN6_ADDRMODE_DIRECT) {
273 inst->dst.base.reg = READ(dw1, GEN6_INST_DST_REG);
274
275 if (inst->access_mode == GEN6_ALIGN_1) {
276 inst->dst.base.subreg = READ(dw1, GEN6_INST_DST_SUBREG);
277 } else {
278 inst->dst.base.subreg = READ(dw1, GEN6_INST_DST_SUBREG_ALIGN16) <<
279 GEN6_INST_DST_SUBREG_ALIGN16__SHR;
280 }
281 } else {
282 inst->dst.base.addr_subreg = READ(dw1, GEN6_INST_DST_ADDR_SUBREG);
283
284 if (inst->access_mode == GEN6_ALIGN_1) {
285 inst->dst.base.addr_imm = READ(dw1, GEN6_INST_DST_ADDR_IMM);
286 } else {
287 inst->dst.base.addr_imm = READ(dw1, GEN6_INST_DST_ADDR_IMM_ALIGN16) <<
288 GEN6_INST_DST_ADDR_IMM_ALIGN16__SHR;
289 }
290 }
291
292 inst->dst.horz_stride = READ(dw1, GEN6_INST_DST_HORZSTRIDE);
293
294 if (inst->access_mode == GEN6_ALIGN_1)
295 inst->dst.writemask = 0xf;
296 else
297 inst->dst.writemask = READ(dw1, GEN6_INST_DST_WRITEMASK);
298 }
299
300 static void
301 disasm_inst_decode_dw2_dw3_gen6(struct disasm_inst *inst,
302 uint32_t dw2, uint32_t dw3)
303 {
304 int count, i;
305
306 if (inst->dev->gen >= ILO_GEN(7))
307 inst->flag_reg = READ(dw2, GEN7_INST_FLAG_REG);
308
309 inst->flag_subreg = READ(dw2, GEN6_INST_FLAG_SUBREG);
310
311 if (inst->src0.base.file == GEN6_FILE_IMM ||
312 inst->src1.base.file == GEN6_FILE_IMM) {
313 count = 1;
314 if (!disasm_inst_jip_in_dw1_high_gen6(inst))
315 inst->u.imm32 = dw3;
316 } else {
317 count = 2;
318 }
319
320 for (i = 0; i < count; i++) {
321 struct disasm_src_operand *src = (i == 0) ? &inst->src0 : &inst->src1;
322 const uint32_t dw = (i == 0) ? dw2 : dw3;
323
324 src->base.addr_mode = READ(dw, GEN6_INST_SRC_ADDRMODE);
325
326 if (src->base.addr_mode == GEN6_ADDRMODE_DIRECT) {
327 src->base.reg = READ(dw, GEN6_INST_SRC_REG);
328
329 if (inst->access_mode == GEN6_ALIGN_1) {
330 src->base.subreg = READ(dw, GEN6_INST_SRC_SUBREG);
331 } else {
332 src->base.subreg = READ(dw, GEN6_INST_SRC_SUBREG_ALIGN16) <<
333 GEN6_INST_SRC_SUBREG_ALIGN16__SHR;
334 }
335 } else {
336 src->base.addr_subreg = READ(dw, GEN6_INST_SRC_ADDR_SUBREG);
337
338 if (inst->access_mode == GEN6_ALIGN_1) {
339 src->base.addr_imm = READ(dw, GEN6_INST_SRC_ADDR_IMM);
340 } else {
341 src->base.addr_imm = READ(dw, GEN6_INST_SRC_ADDR_IMM_ALIGN16) <<
342 GEN6_INST_SRC_ADDR_IMM_ALIGN16__SHR;
343 }
344 }
345
346 src->vert_stride = READ(dw, GEN6_INST_SRC_VERTSTRIDE);
347
348 if (inst->access_mode == GEN6_ALIGN_1) {
349 src->width = READ(dw, GEN6_INST_SRC_WIDTH);
350 src->horz_stride = READ(dw, GEN6_INST_SRC_HORZSTRIDE);
351
352 src->swizzle_x = GEN6_SWIZZLE_X;
353 src->swizzle_y = GEN6_SWIZZLE_Y;
354 src->swizzle_z = GEN6_SWIZZLE_Z;
355 src->swizzle_w = GEN6_SWIZZLE_W;
356 } else {
357 src->width = GEN6_WIDTH_4;
358 src->horz_stride = GEN6_HORZSTRIDE_1;
359
360 src->swizzle_x = READ(dw, GEN6_INST_SRC_SWIZZLE_X);
361 src->swizzle_y = READ(dw, GEN6_INST_SRC_SWIZZLE_Y);
362 src->swizzle_z = READ(dw, GEN6_INST_SRC_SWIZZLE_Z);
363 src->swizzle_w = READ(dw, GEN6_INST_SRC_SWIZZLE_W);
364 }
365
366 src->negate = (bool) (dw & GEN6_INST_SRC_NEGATE);
367 src->absolute = (bool) (dw & GEN6_INST_SRC_ABSOLUTE);
368 }
369 }
370
371 static void
372 disasm_inst_decode_3src_dw1_gen6(struct disasm_inst *inst, uint32_t dw1)
373 {
374 static unsigned type_mapping[4] = {
375 [GEN7_TYPE_F_3SRC] = GEN6_TYPE_F,
376 [GEN7_TYPE_D_3SRC] = GEN6_TYPE_D,
377 [GEN7_TYPE_UD_3SRC] = GEN6_TYPE_UD,
378 [GEN7_TYPE_DF_3SRC] = GEN7_TYPE_DF,
379 };
380
381 inst->flag_subreg = READ(dw1, GEN6_3SRC_FLAG_SUBREG);
382
383 if (inst->dev->gen >= ILO_GEN(7)) {
384 inst->nib_ctrl = (bool) (dw1 & GEN7_3SRC_NIBCTRL);
385 inst->flag_reg = READ(dw1, GEN7_3SRC_FLAG_REG);
386
387 inst->dst.base.file = GEN6_FILE_GRF;
388 inst->dst.base.type = READ(dw1, GEN7_3SRC_DST_TYPE);
389 inst->dst.base.type = type_mapping[inst->dst.base.type];
390
391 inst->src0.base.type = READ(dw1, GEN7_3SRC_SRC_TYPE);
392 inst->src0.base.type = type_mapping[inst->src0.base.type];
393
394 inst->src1.base.type = inst->src0.base.type;
395 inst->u.src2.base.type = inst->src0.base.type;
396 } else {
397 inst->dst.base.file = (dw1 & GEN6_3SRC_DST_FILE_MRF) ?
398 GEN6_FILE_MRF: GEN6_FILE_GRF;
399 inst->dst.base.type = GEN6_TYPE_F;
400
401 inst->src0.base.type = GEN6_TYPE_F;
402 inst->src1.base.type = GEN6_TYPE_F;
403 inst->u.src2.base.type = GEN6_TYPE_F;
404 }
405
406 inst->dst.base.addr_mode = GEN6_ADDRMODE_DIRECT;
407 inst->dst.base.reg = READ(dw1, GEN6_3SRC_DST_REG);
408 inst->dst.base.subreg = READ(dw1, GEN6_3SRC_DST_SUBREG) <<
409 GEN6_3SRC_DST_SUBREG__SHR;
410
411 inst->dst.horz_stride = GEN6_HORZSTRIDE_1;
412 inst->dst.writemask = READ(dw1, GEN6_3SRC_DST_WRITEMASK);
413
414 inst->src0.base.file = GEN6_FILE_GRF;
415 inst->src0.negate = (bool) (dw1 & GEN6_3SRC_SRC0_NEGATE);
416 inst->src0.absolute = (bool) (dw1 & GEN6_3SRC_SRC0_ABSOLUTE);
417 inst->src1.base.file = GEN6_FILE_GRF;
418 inst->src1.negate = (bool) (dw1 & GEN6_3SRC_SRC1_NEGATE);
419 inst->src1.absolute = (bool) (dw1 & GEN6_3SRC_SRC1_ABSOLUTE);
420 inst->u.src2.base.file = GEN6_FILE_GRF;
421 inst->u.src2.negate = (bool) (dw1 & GEN6_3SRC_SRC2_NEGATE);
422 inst->u.src2.absolute = (bool) (dw1 & GEN6_3SRC_SRC2_ABSOLUTE);
423 }
424
425 static void
426 disasm_inst_decode_3src_dw2_dw3_gen6(struct disasm_inst *inst,
427 uint32_t dw2, uint32_t dw3)
428 {
429 const uint64_t qw = (uint64_t) dw3 << 32 | dw2;
430 int i;
431
432 for (i = 0; i < 3; i++) {
433 struct disasm_src_operand *src = (i == 0) ? &inst->src0 :
434 (i == 1) ? &inst->src1 :
435 &inst->u.src2;
436 const uint32_t dw = (i == 0) ? READ(qw, GEN6_3SRC_SRC_0) :
437 (i == 1) ? READ(qw, GEN6_3SRC_SRC_1) :
438 READ(qw, GEN6_3SRC_SRC_2);
439
440 src->base.addr_mode = GEN6_ADDRMODE_DIRECT;
441 src->base.reg = READ(dw, GEN6_3SRC_SRC_REG);
442 src->base.subreg = READ(dw, GEN6_3SRC_SRC_SUBREG) <<
443 GEN6_3SRC_SRC_SUBREG__SHR;
444
445 if (dw & GEN6_3SRC_SRC_REPCTRL) {
446 src->vert_stride = GEN6_VERTSTRIDE_0;
447 src->width = GEN6_WIDTH_1;
448 src->horz_stride = GEN6_HORZSTRIDE_0;
449 } else {
450 src->vert_stride = GEN6_VERTSTRIDE_4;
451 src->width = GEN6_WIDTH_4;
452 src->horz_stride = GEN6_HORZSTRIDE_1;
453 }
454
455 src->swizzle_x = READ(dw, GEN6_3SRC_SRC_SWIZZLE_X);
456 src->swizzle_y = READ(dw, GEN6_3SRC_SRC_SWIZZLE_Y);
457 src->swizzle_z = READ(dw, GEN6_3SRC_SRC_SWIZZLE_Z);
458 src->swizzle_w = READ(dw, GEN6_3SRC_SRC_SWIZZLE_W);
459 }
460 }
461
462 /*
463 * When GEN6_INST_CMPTCTRL of DW0 is set, the instruction has 64 bits and is
464 * in EU_INSTRUCTION_COMPACT_TWO_SRC form. We should have expanded it to its
465 * original form.
466 *
467 * Depending on the opcode, the 128-bits instruction is in one of the
468 * following forms
469 *
470 * - EU_INSTRUCTION_BASIC_ONE_SRC
471 * - EU_INSTRUCTION_BASIC_TWO_SRC
472 * - EU_INSTRUCTION_BASIC_THREE_SRC
473 * - EU_INSTRUCTION_BRANCH_CONDITIONAL
474 * - EU_INSTRUCTION_BRANCH_ONE_SRC
475 * - EU_INSTRUCTION_BRANCH_TWO_SRC
476 * - EU_INSTRUCTION_ILLEGAL
477 * - EU_INSTRUCTION_MATH
478 * - EU_INSTRUCTION_NOP
479 * - EU_INSTRUCTION_SEND
480 *
481 * In EU_INSTRUCTION_BASIC_ONE_SRC form,
482 *
483 * - DW0 is EU_INSTRUCTION_HEADER
484 * - DW1 is EU_INSTRUCTION_OPERAND_CONTROLS
485 * - DW2 is Source 0 and EU_INSTRUCTION_FLAGS
486 * - DW3 is reserved unless Source 0 is an immediate
487 *
488 * All other forms except EU_INSTRUCTION_BASIC_THREE_SRC are quite compatible
489 * with EU_INSTRUCTION_BASIC_ONE_SRC.
490 */
491 static void
492 disasm_inst_decode(struct disasm_inst *inst,
493 const uint32_t *dw)
494 {
495 assert(!(dw[0] & GEN6_INST_CMPTCTRL));
496
497 disasm_inst_decode_dw0_gen6(inst, dw[0]);
498
499 switch (inst->opcode) {
500 case GEN7_OPCODE_CSEL:
501 case GEN7_OPCODE_BFE:
502 case GEN7_OPCODE_BFI2:
503 case GEN6_OPCODE_MAD:
504 case GEN6_OPCODE_LRP:
505 disasm_inst_decode_3src_dw1_gen6(inst, dw[1]);
506 disasm_inst_decode_3src_dw2_dw3_gen6(inst, dw[2], dw[3]);
507 break;
508 default:
509 disasm_inst_decode_dw1_gen6(inst, dw[1]);
510 disasm_inst_decode_dw2_dw3_gen6(inst, dw[2], dw[3]);
511 break;
512 }
513 }
514
515 static const char *
516 disasm_inst_opcode(const struct disasm_inst *inst)
517 {
518 return (disasm_opcode_table[inst->opcode].name) ?
519 disasm_opcode_table[inst->opcode].name : "BAD";
520 }
521
522 static const char *
523 disasm_inst_pred_ctrl(const struct disasm_inst *inst)
524 {
525 if (inst->access_mode == GEN6_ALIGN_1) {
526 switch (inst->pred_ctrl) {
527 case GEN6_PREDCTRL_NORMAL: return "";
528 case GEN6_PREDCTRL_ANYV: return ".anyv";
529 case GEN6_PREDCTRL_ALLV: return ".allv";
530 case GEN6_PREDCTRL_ANY2H: return ".any2h";
531 case GEN6_PREDCTRL_ALL2H: return ".all2h";
532 case GEN6_PREDCTRL_ANY4H: return ".any4h";
533 case GEN6_PREDCTRL_ALL4H: return ".all4h";
534 case GEN6_PREDCTRL_ANY8H: return ".any8h";
535 case GEN6_PREDCTRL_ALL8H: return ".all8h";
536 case GEN6_PREDCTRL_ANY16H: return ".any16h";
537 case GEN6_PREDCTRL_ALL16H: return ".all16h";
538 case GEN7_PREDCTRL_ANY32H: return ".any32h";
539 case GEN7_PREDCTRL_ALL32H: return ".all32h";
540 default: return ".BAD";
541 }
542 } else {
543 switch (inst->pred_ctrl) {
544 case GEN6_PREDCTRL_NORMAL: return "";
545 case GEN6_PREDCTRL_X: return ".x";
546 case GEN6_PREDCTRL_Y: return ".y";
547 case GEN6_PREDCTRL_Z: return ".z";
548 case GEN6_PREDCTRL_W: return ".w";
549 default: return ".BAD";
550 }
551 }
552 }
553
554 static char
555 disasm_inst_pred_inv(const struct disasm_inst *inst)
556 {
557 return (inst->pred_inv) ? '-' : '+';
558 }
559
560 static const char *
561 disasm_inst_exec_size(const struct disasm_inst *inst)
562 {
563 switch (inst->exec_size) {
564 case GEN6_EXECSIZE_1: return "1";
565 case GEN6_EXECSIZE_2: return "2";
566 case GEN6_EXECSIZE_4: return "4";
567 case GEN6_EXECSIZE_8: return "8";
568 case GEN6_EXECSIZE_16: return "16";
569 case GEN6_EXECSIZE_32: return "32";
570 default: return "BAD";
571 }
572 }
573
574 static const char *
575 disasm_inst_fc(const struct disasm_inst *inst)
576 {
577 assert(inst->opcode == GEN6_OPCODE_MATH);
578
579 switch (inst->fc) {
580 case GEN6_MATH_INV: return "inv";
581 case GEN6_MATH_LOG: return "log";
582 case GEN6_MATH_EXP: return "exp";
583 case GEN6_MATH_SQRT: return "sqrt";
584 case GEN6_MATH_RSQ: return "rsq";
585 case GEN6_MATH_SIN: return "sin";
586 case GEN6_MATH_COS: return "cos";
587 case GEN6_MATH_FDIV: return "fdiv";
588 case GEN6_MATH_POW: return "pow";
589 case GEN6_MATH_INT_DIV: return "int_div";
590 case GEN6_MATH_INT_DIV_QUOTIENT: return "int_div_quotient";
591 case GEN6_MATH_INT_DIV_REMAINDER: return "int_div_remainder";
592 default: return "BAD";
593 }
594 }
595
596 static const char *
597 disasm_inst_sfid(const struct disasm_inst *inst)
598 {
599 assert(inst->opcode == GEN6_OPCODE_SEND ||
600 inst->opcode == GEN6_OPCODE_SENDC);
601
602 switch (inst->sfid) {
603 case GEN6_SFID_NULL: return "null";
604 case GEN6_SFID_SAMPLER: return "sampler";
605 case GEN6_SFID_GATEWAY: return "gateway";
606 case GEN6_SFID_DP_SAMPLER: return "dp sampler";
607 case GEN6_SFID_DP_RC: return "dp render";
608 case GEN6_SFID_URB: return "urb";
609 case GEN6_SFID_SPAWNER: return "spawner";
610 case GEN6_SFID_VME: return "vme";
611 case GEN6_SFID_DP_CC: return "dp const";
612 case GEN7_SFID_DP_DC0: return "dp data 0";
613 case GEN7_SFID_PI: return "pixel interp";
614 case GEN75_SFID_DP_DC1: return "dp data 1";
615 default: return "BAD";
616 }
617 }
618
619 static const char *
620 disasm_inst_cond_modifier(const struct disasm_inst *inst)
621 {
622 switch (inst->cond_modifier) {
623 case GEN6_COND_NONE: return "";
624 case GEN6_COND_Z: return ".z";
625 case GEN6_COND_NZ: return ".nz";
626 case GEN6_COND_G: return ".g";
627 case GEN6_COND_GE: return ".ge";
628 case GEN6_COND_L: return ".l";
629 case GEN6_COND_LE: return ".le";
630 case GEN6_COND_O: return ".o";
631 case GEN6_COND_U: return ".u";
632 default: return ".BAD";
633 }
634 }
635
636 static const char *
637 disasm_inst_debug_ctrl(const struct disasm_inst *inst)
638 {
639 return (inst->debug_ctrl) ? ".breakpoint" : "";
640 }
641
642 static const char *
643 disasm_inst_saturate(const struct disasm_inst *inst)
644 {
645 return (inst->saturate) ? ".sat" : "";
646 }
647
648 static const char *
649 disasm_inst_flag_reg(const struct disasm_inst *inst)
650 {
651 static const char *flag_names[2][2] = {
652 { "f0", "f0.1" },
653 { "f1.0", "f1.1" },
654 };
655
656 return (inst->flag_reg <= 1 && inst->flag_subreg <= 1) ?
657 flag_names[inst->flag_reg][inst->flag_subreg] : "fBAD";
658 }
659
660 static const char *
661 disasm_inst_access_mode(const struct disasm_inst *inst)
662 {
663 switch (inst->access_mode) {
664 case GEN6_ALIGN_1: return " align1";
665 case GEN6_ALIGN_16: return " align16";
666 default: return " alignBAD";
667 }
668 }
669
670 static const char *
671 disasm_inst_mask_ctrl(const struct disasm_inst *inst)
672 {
673 switch (inst->mask_ctrl) {
674 case GEN6_MASKCTRL_NORMAL: return "";
675 case GEN6_MASKCTRL_NOMASK: return " WE_all";
676 default: return " WE_BAD";
677 }
678 }
679
680 static const char *
681 disasm_inst_dep_ctrl(const struct disasm_inst *inst)
682 {
683 switch (inst->dep_ctrl) {
684 case GEN6_DEPCTRL_NORMAL: return "";
685 case GEN6_DEPCTRL_NODDCLR: return " NoDDClr";
686 case GEN6_DEPCTRL_NODDCHK: return " NoDDChk";
687 case GEN6_DEPCTRL_NEITHER: return " NoDDClr,NoDDChk";
688 default: return " NoDDBAD";
689 }
690 }
691
692 static const char *
693 disasm_inst_qtr_ctrl(const struct disasm_inst *inst)
694 {
695 switch (inst->exec_size) {
696 case GEN6_EXECSIZE_8:
697 switch (inst->qtr_ctrl) {
698 case GEN6_QTRCTRL_1Q: return " 1Q";
699 case GEN6_QTRCTRL_2Q: return " 2Q";
700 case GEN6_QTRCTRL_3Q: return " 3Q";
701 case GEN6_QTRCTRL_4Q: return " 4Q";
702 default: return " BADQ";
703 }
704 break;
705 case GEN6_EXECSIZE_16:
706 switch (inst->qtr_ctrl) {
707 case GEN6_QTRCTRL_1H: return " 1H";
708 case GEN6_QTRCTRL_2H: return " 2H";
709 default: return " BADH";
710 }
711 break;
712 default:
713 return "";
714 }
715
716 }
717
718 static const char *
719 disasm_inst_thread_ctrl(const struct disasm_inst *inst)
720 {
721 switch (inst->thread_ctrl) {
722 case GEN6_THREADCTRL_NORMAL: return "";
723 case GEN6_THREADCTRL_ATOMIC: return " atomic";
724 case GEN6_THREADCTRL_SWITCH: return " switch";
725 default: return " BAD";
726 }
727 }
728
729 static const char *
730 disasm_inst_acc_wr_ctrl(const struct disasm_inst *inst)
731 {
732 return (inst->acc_wr_ctrl) ? " AccWrEnable" : "";
733 }
734
735 static const char *
736 disasm_inst_cmpt_ctrl(const struct disasm_inst *inst)
737 {
738 return (inst->cmpt_ctrl) ? " compacted" : "";
739 }
740
741 static const char *
742 disasm_inst_eot(const struct disasm_inst *inst)
743 {
744 if (inst->opcode == GEN6_OPCODE_SEND ||
745 inst->opcode == GEN6_OPCODE_SENDC)
746 return (inst->u.imm32 & GEN6_MSG_EOT) ? " EOT" : "";
747 else
748 return "";
749 }
750
751 static const char *
752 disasm_inst_file(const struct disasm_inst *inst,
753 const struct disasm_operand *operand,
754 bool *multi_regs)
755 {
756 switch (operand->file) {
757 case GEN6_FILE_ARF:
758 switch (operand->reg & 0xf0) {
759 case GEN6_ARF_NULL: *multi_regs = false; return "null";
760 case GEN6_ARF_A0: *multi_regs = true; return "a";
761 case GEN6_ARF_ACC0: *multi_regs = true; return "acc";
762 case GEN6_ARF_F0: *multi_regs = true; return "f";
763 case GEN6_ARF_SR0: *multi_regs = true; return "sr";
764 case GEN6_ARF_CR0: *multi_regs = true; return "cr";
765 case GEN6_ARF_N0: *multi_regs = true; return "n";
766 case GEN6_ARF_IP: *multi_regs = false; return "ip";
767 case GEN6_ARF_TDR: *multi_regs = false; return "tdr";
768 case GEN7_ARF_TM0: *multi_regs = true; return "tm";
769 default: *multi_regs = false; return "BAD";
770 }
771 break;
772 case GEN6_FILE_GRF: *multi_regs = true; return "g";
773 case GEN6_FILE_MRF: *multi_regs = true; return "m";
774 case GEN6_FILE_IMM: *multi_regs = true; return "";
775 default: *multi_regs = false; return "BAD";
776 }
777 }
778
779 static const char *
780 disasm_inst_type(const struct disasm_inst *inst,
781 const struct disasm_operand *operand)
782 {
783 if (operand->file == GEN6_FILE_IMM) {
784 switch (operand->type) {
785 case GEN6_TYPE_UD: return "UD";
786 case GEN6_TYPE_D: return "D";
787 case GEN6_TYPE_UW: return "UW";
788 case GEN6_TYPE_W: return "W";
789 case GEN6_TYPE_UV_IMM: return "UV";
790 case GEN6_TYPE_VF_IMM: return "VF";
791 case GEN6_TYPE_V_IMM: return "V";
792 case GEN6_TYPE_F: return "F";
793 default: return "BAD";
794 }
795 } else {
796 switch (operand->type) {
797 case GEN6_TYPE_UD: return "UD";
798 case GEN6_TYPE_D: return "D";
799 case GEN6_TYPE_UW: return "UW";
800 case GEN6_TYPE_W: return "W";
801 case GEN6_TYPE_UB: return "UB";
802 case GEN6_TYPE_B: return "B";
803 case GEN7_TYPE_DF: return "DF";
804 case GEN6_TYPE_F: return "F";
805 default: return "BAD";
806 }
807 }
808 }
809
810 static const char *
811 disasm_inst_vert_stride(const struct disasm_inst *inst, unsigned vert_stride)
812 {
813 switch (vert_stride) {
814 case GEN6_VERTSTRIDE_0: return "0";
815 case GEN6_VERTSTRIDE_1: return "1";
816 case GEN6_VERTSTRIDE_2: return "2";
817 case GEN6_VERTSTRIDE_4: return "4";
818 case GEN6_VERTSTRIDE_8: return "8";
819 case GEN6_VERTSTRIDE_16: return "16";
820 case GEN6_VERTSTRIDE_32: return "32";
821 case GEN6_VERTSTRIDE_VXH: return "VxH";
822 default: return "BAD";
823 }
824 }
825
826 static const char *
827 disasm_inst_width(const struct disasm_inst *inst, unsigned width)
828 {
829 switch (width) {
830 case GEN6_WIDTH_1: return "1";
831 case GEN6_WIDTH_2: return "2";
832 case GEN6_WIDTH_4: return "4";
833 case GEN6_WIDTH_8: return "8";
834 case GEN6_WIDTH_16: return "16";
835 default: return "BAD";
836 }
837 }
838
839 static const char *
840 disasm_inst_horz_stride(const struct disasm_inst *inst, unsigned horz_stride)
841 {
842 switch (horz_stride) {
843 case GEN6_HORZSTRIDE_0: return "0";
844 case GEN6_HORZSTRIDE_1: return "1";
845 case GEN6_HORZSTRIDE_2: return "2";
846 case GEN6_HORZSTRIDE_4: return "4";
847 default: return "BAD";
848 }
849 }
850
851 static const char *
852 disasm_inst_writemask(const struct disasm_inst *inst, unsigned writemask)
853 {
854 switch (writemask) {
855 case 0x0: return ".";
856 case 0x1: return ".x";
857 case 0x2: return ".y";
858 case 0x3: return ".xy";
859 case 0x4: return ".z";
860 case 0x5: return ".xz";
861 case 0x6: return ".yz";
862 case 0x7: return ".xyz";
863 case 0x8: return ".w";
864 case 0x9: return ".xw";
865 case 0xa: return ".yw";
866 case 0xb: return ".xyw";
867 case 0xc: return ".zw";
868 case 0xd: return ".xzw";
869 case 0xe: return ".yzw";
870 case 0xf: return "";
871 default: return ".BAD";
872 }
873 }
874
875 static const char *
876 disasm_inst_negate(const struct disasm_inst *inst, bool negate)
877 {
878 return (negate) ? "-" : "";
879 }
880
881 static const char *
882 disasm_inst_absolute(const struct disasm_inst *inst, bool absolute)
883 {
884 return (absolute) ? "(abs)" : "";
885 }
886
887 static bool
888 disasm_inst_is_null(const struct disasm_inst *inst,
889 const struct disasm_operand *operand)
890 {
891 return (operand->file == GEN6_FILE_ARF && operand->reg == GEN6_ARF_NULL);
892 }
893
894 static int
895 disasm_inst_type_size(const struct disasm_inst *inst,
896 const struct disasm_operand *operand)
897 {
898 assert(operand->file != GEN6_FILE_IMM);
899
900 switch (operand->type) {
901 case GEN6_TYPE_UD: return 4;
902 case GEN6_TYPE_D: return 4;
903 case GEN6_TYPE_UW: return 2;
904 case GEN6_TYPE_W: return 2;
905 case GEN6_TYPE_UB: return 1;
906 case GEN6_TYPE_B: return 1;
907 case GEN7_TYPE_DF: return 8;
908 case GEN6_TYPE_F: return 4;
909 default: return 1;
910 }
911 }
912
913 static void
914 disasm_printer_reset(struct disasm_printer *printer)
915 {
916 printer->buf[0] = '\0';
917 printer->len = 0;
918 }
919
920 static const char *
921 disasm_printer_get_string(struct disasm_printer *printer)
922 {
923 return printer->buf;
924 }
925
926 static void _util_printf_format(2, 3)
927 disasm_printer_add(struct disasm_printer *printer, const char *format, ...)
928 {
929 const size_t avail = sizeof(printer->buf) - printer->len;
930 va_list ap;
931 int written;
932
933 va_start(ap, format);
934 written = vsnprintf(printer->buf + printer->len, avail, format, ap);
935 va_end(ap);
936
937 /* truncated */
938 if (written < 0 || written >= avail) {
939 memcpy(printer->buf + sizeof(printer->buf) - 4, "...", 4);
940 printer->len = sizeof(printer->buf) - 1;
941 } else {
942 printer->len += written;
943 }
944 }
945
946 /**
947 * Pad to the specified column.
948 */
949 static void
950 disasm_printer_column(struct disasm_printer *printer, int col)
951 {
952 int len = DISASM_PRINTER_COLUMN_WIDTH * col;
953
954 if (len <= printer->len) {
955 if (!printer->len)
956 return;
957
958 /* at least one space */
959 len = printer->len + 1;
960 }
961
962 if (len >= sizeof(printer->buf)) {
963 len = sizeof(printer->buf) - 1;
964
965 if (len <= printer->len)
966 return;
967 }
968
969 memset(printer->buf + printer->len, ' ', len - printer->len);
970 printer->len = len;
971 printer->buf[printer->len] = '\0';
972 }
973
974 static void
975 disasm_printer_add_op(struct disasm_printer *printer,
976 const struct disasm_inst *inst)
977 {
978 if (inst->pred_ctrl != GEN6_PREDCTRL_NONE) {
979 disasm_printer_add(printer, "(%c%s%s) ",
980 disasm_inst_pred_inv(inst),
981 disasm_inst_flag_reg(inst),
982 disasm_inst_pred_ctrl(inst));
983 }
984
985 disasm_printer_add(printer, "%s%s%s%s",
986 disasm_inst_opcode(inst),
987 disasm_inst_saturate(inst),
988 disasm_inst_debug_ctrl(inst),
989 disasm_inst_cond_modifier(inst));
990
991 if (inst->cond_modifier != GEN6_COND_NONE) {
992 switch (inst->opcode) {
993 case GEN6_OPCODE_SEL:
994 case GEN6_OPCODE_IF:
995 case GEN6_OPCODE_WHILE:
996 /* these do not update flag registers */
997 break;
998 default:
999 disasm_printer_add(printer, ".%s", disasm_inst_flag_reg(inst));
1000 break;
1001 }
1002 }
1003
1004 if (inst->opcode == GEN6_OPCODE_MATH)
1005 disasm_printer_add(printer, " %s", disasm_inst_fc(inst));
1006 if (inst->opcode != GEN6_OPCODE_NOP)
1007 disasm_printer_add(printer, "(%s)", disasm_inst_exec_size(inst));
1008 }
1009
1010 static void
1011 disasm_printer_add_operand(struct disasm_printer *printer,
1012 const struct disasm_inst *inst,
1013 const struct disasm_operand *operand)
1014 {
1015 const char *name;
1016 bool multi_regs;
1017
1018 name = disasm_inst_file(inst, operand, &multi_regs);
1019 if (!multi_regs) {
1020 disasm_printer_add(printer, name);
1021 return;
1022 }
1023
1024 if (operand->file == GEN6_FILE_IMM) {
1025 switch (operand->type) {
1026 case GEN6_TYPE_UD:
1027 disasm_printer_add(printer, "0x%08xUD", inst->u.imm32);
1028 break;
1029 case GEN6_TYPE_D:
1030 disasm_printer_add(printer, "%dD", inst->u.imm32);
1031 break;
1032 case GEN6_TYPE_UW:
1033 disasm_printer_add(printer, "0x%04xUW", (uint16_t) inst->u.imm32);
1034 break;
1035 case GEN6_TYPE_W:
1036 disasm_printer_add(printer, "%dW", (int16_t) inst->u.imm32);
1037 break;
1038 case GEN6_TYPE_UV_IMM:
1039 disasm_printer_add(printer, "0x%08xUV", inst->u.imm32);
1040 break;
1041 case GEN6_TYPE_VF_IMM:
1042 disasm_printer_add(printer, "Vector Float");
1043 break;
1044 case GEN6_TYPE_V_IMM:
1045 disasm_printer_add(printer, "0x%08xV", inst->u.imm32);
1046 break;
1047 case GEN6_TYPE_F:
1048 disasm_printer_add(printer, "%-gF", uif(inst->u.imm32));
1049 break;
1050 default:
1051 disasm_printer_add(printer, "BAD");
1052 break;
1053 }
1054
1055 return;
1056 }
1057
1058 if (operand->addr_mode == GEN6_ADDRMODE_DIRECT) {
1059 unsigned reg, subreg;
1060
1061 reg = operand->reg;
1062 if (operand->file == GEN6_FILE_ARF)
1063 reg &= 0xf;
1064
1065 subreg = operand->subreg / disasm_inst_type_size(inst, operand);
1066
1067 if (subreg)
1068 disasm_printer_add(printer, "%s%d.%d", name, reg, subreg);
1069 else
1070 disasm_printer_add(printer, "%s%d", name, reg);
1071 } else {
1072 disasm_printer_add(printer, "%s[a0.%d %d]",
1073 name, operand->addr_subreg, operand->addr_imm);
1074 }
1075 }
1076
1077 static void
1078 disasm_printer_add_dst(struct disasm_printer *printer,
1079 const struct disasm_inst *inst,
1080 const struct disasm_dst_operand *dst)
1081 {
1082 disasm_printer_add_operand(printer, inst, &dst->base);
1083
1084 /* dst is an immediate when in EU_INSTRUCTION_BRANCH_CONDITIONAL form */
1085 if (disasm_inst_is_null(inst, &dst->base) ||
1086 dst->base.file == GEN6_FILE_IMM)
1087 return;
1088
1089 disasm_printer_add(printer, "<%s>%s%s",
1090 disasm_inst_horz_stride(inst, dst->horz_stride),
1091 disasm_inst_writemask(inst, dst->writemask),
1092 disasm_inst_type(inst, &dst->base));
1093 }
1094
1095 static void
1096 disasm_printer_add_src(struct disasm_printer *printer,
1097 const struct disasm_inst *inst,
1098 const struct disasm_src_operand *src)
1099 {
1100 static const char swizzle_chars[4] = { 'x', 'y', 'z', 'w' };
1101 char swizzle[5];
1102
1103 disasm_printer_add(printer, "%s%s",
1104 disasm_inst_negate(inst, src->negate),
1105 disasm_inst_absolute(inst, src->absolute));
1106
1107 disasm_printer_add_operand(printer, inst, &src->base);
1108
1109 if (disasm_inst_is_null(inst, &src->base) ||
1110 src->base.file == GEN6_FILE_IMM)
1111 return;
1112
1113 if (src->swizzle_x == 0 && src->swizzle_y == 1 &&
1114 src->swizzle_z == 2 && src->swizzle_w == 3) {
1115 swizzle[0] = '\0';
1116 } else if (src->swizzle_x == src->swizzle_y &&
1117 src->swizzle_x == src->swizzle_z &&
1118 src->swizzle_x == src->swizzle_w) {
1119 swizzle[0] = swizzle_chars[src->swizzle_x];
1120 swizzle[1] = '\0';
1121 } else {
1122 swizzle[0] = swizzle_chars[src->swizzle_x];
1123 swizzle[1] = swizzle_chars[src->swizzle_y];
1124 swizzle[2] = swizzle_chars[src->swizzle_z];
1125 swizzle[3] = swizzle_chars[src->swizzle_w];
1126 swizzle[4] = '\0';
1127 }
1128
1129 disasm_printer_add(printer, "<%s,%s,%s>%s%s",
1130 disasm_inst_vert_stride(inst, src->vert_stride),
1131 disasm_inst_width(inst, src->width),
1132 disasm_inst_horz_stride(inst, src->horz_stride),
1133 swizzle,
1134 disasm_inst_type(inst, &src->base));
1135 }
1136
1137 static void
1138 disasm_printer_add_ctrl(struct disasm_printer *printer,
1139 const struct disasm_inst *inst)
1140 {
1141 if (inst->opcode == GEN6_OPCODE_NOP) {
1142 disasm_printer_add(printer, ";");
1143 return;
1144 }
1145
1146 disasm_printer_add(printer, "{%s%s%s%s%s%s%s%s };",
1147 disasm_inst_access_mode(inst),
1148 disasm_inst_mask_ctrl(inst),
1149 disasm_inst_dep_ctrl(inst),
1150 disasm_inst_qtr_ctrl(inst),
1151 disasm_inst_cmpt_ctrl(inst),
1152 disasm_inst_thread_ctrl(inst),
1153 disasm_inst_acc_wr_ctrl(inst),
1154 disasm_inst_eot(inst));
1155 }
1156
1157 static void
1158 disasm_printer_add_mdesc_sampler(struct disasm_printer *printer,
1159 const struct disasm_inst *inst,
1160 uint32_t mdesc)
1161 {
1162 int op, simd;
1163
1164 if (inst->dev->gen >= ILO_GEN(7)) {
1165 op = READ(mdesc, GEN7_MSG_SAMPLER_OP);
1166 simd = READ(mdesc, GEN7_MSG_SAMPLER_SIMD);
1167 } {
1168 op = READ(mdesc, GEN6_MSG_SAMPLER_OP);
1169 simd = READ(mdesc, GEN6_MSG_SAMPLER_SIMD);
1170 }
1171
1172 disasm_printer_add(printer, " (%d, %d, %d, %d)",
1173 READ(mdesc, GEN6_MSG_SAMPLER_SURFACE),
1174 READ(mdesc, GEN6_MSG_SAMPLER_INDEX),
1175 op, simd);
1176 }
1177
1178 static void
1179 disasm_printer_add_mdesc_urb(struct disasm_printer *printer,
1180 const struct disasm_inst *inst,
1181 uint32_t mdesc)
1182 {
1183 const char *op;
1184 int offset;
1185 bool interleaved, complete, allocate, used;
1186
1187 if (inst->dev->gen >= ILO_GEN(7)) {
1188 switch (READ(mdesc, GEN7_MSG_URB_OP)) {
1189 case GEN7_MSG_URB_WRITE_HWORD: op = "write HWord"; break;
1190 case GEN7_MSG_URB_WRITE_OWORD: op = "write OWord"; break;
1191 case GEN7_MSG_URB_READ_HWORD: op = "read HWord"; break;
1192 case GEN7_MSG_URB_READ_OWORD: op = "read OWord"; break;
1193 case GEN7_MSG_URB_ATOMIC_MOV: op = "atomic mov"; break;
1194 case GEN7_MSG_URB_ATOMIC_INC: op = "atomic inc"; break;
1195 default: op = "BAD"; break;
1196 }
1197
1198 offset = READ(mdesc, GEN7_MSG_URB_GLOBAL_OFFSET);
1199 interleaved = mdesc & GEN7_MSG_URB_INTERLEAVED;
1200 complete = mdesc & GEN7_MSG_URB_COMPLETE;
1201
1202 allocate = false;
1203 used = false;
1204 } else {
1205 switch (READ(mdesc, GEN6_MSG_URB_OP)) {
1206 case GEN6_MSG_URB_WRITE: op = "urb_write"; break;
1207 case GEN6_MSG_URB_FF_SYNC: op = "ff_sync"; break;
1208 default: op = "BAD"; break;
1209 }
1210
1211 offset = READ(mdesc, GEN6_MSG_URB_OFFSET);
1212 interleaved = mdesc & GEN6_MSG_URB_INTERLEAVED;
1213 complete = mdesc & GEN6_MSG_URB_COMPLETE;
1214
1215 allocate = mdesc & GEN6_MSG_URB_ALLOCATE;
1216 used = mdesc & GEN6_MSG_URB_USED;
1217 }
1218
1219 disasm_printer_add(printer, " %d %s%s%s%s%s", offset, op,
1220 (interleaved) ? " interleave" : "",
1221 (allocate) ? " allocate" : "",
1222 (used) ? " used" : "",
1223 (complete) ? " complete" : "");
1224 }
1225
1226 static void
1227 disasm_printer_add_mdesc_dp_sampler(struct disasm_printer *printer,
1228 const struct disasm_inst *inst,
1229 uint32_t mdesc)
1230 {
1231 const int op = (inst->dev->gen >= ILO_GEN(7)) ?
1232 READ(mdesc, GEN7_MSG_DP_OP) : READ(mdesc, GEN6_MSG_DP_OP);
1233 const bool write_commit = (inst->dev->gen == ILO_GEN(6)) ?
1234 (mdesc & GEN6_MSG_DP_SEND_WRITE_COMMIT) : 0;
1235
1236 disasm_printer_add(printer, " (%d, %d, %d, %d)",
1237 READ(mdesc, GEN6_MSG_DP_SURFACE),
1238 READ(mdesc, GEN6_MSG_DP_OWORD_BLOCK_SIZE),
1239 op, write_commit);
1240 }
1241
1242 static void
1243 disasm_printer_add_mdesc_dp_rc(struct disasm_printer *printer,
1244 const struct disasm_inst *inst,
1245 uint32_t mdesc)
1246 {
1247 const int op = (inst->dev->gen >= ILO_GEN(7)) ?
1248 READ(mdesc, GEN7_MSG_DP_OP) : READ(mdesc, GEN6_MSG_DP_OP);
1249 const char *str;
1250 bool is_rt_write;
1251
1252 if (inst->dev->gen >= ILO_GEN(7.5)) {
1253 switch (op) {
1254 case GEN75_MSG_DP_RC_MEDIA_BLOCK_READ: str = "media block read"; break;
1255 case GEN75_MSG_DP_RC_MEMORY_FENCE: str = "memory fence"; break;
1256 case GEN75_MSG_DP_RC_MEDIA_BLOCK_WRITE: str = "media block write"; break;
1257 case GEN75_MSG_DP_RC_RT_WRITE: str = "RT write"; break;
1258 default: str = "BAD"; break;
1259 }
1260
1261 is_rt_write = (op == GEN75_MSG_DP_RC_RT_WRITE);
1262 } else if (inst->dev->gen >= ILO_GEN(7)) {
1263 switch (op) {
1264 case GEN7_MSG_DP_RC_MEDIA_BLOCK_READ: str = "media block read"; break;
1265 case GEN7_MSG_DP_RC_TYPED_SURFACE_READ: str = "typed surface read"; break;
1266 case GEN7_MSG_DP_RC_TYPED_ATOMIC_OP: str = "typed atomic op"; break;
1267 case GEN7_MSG_DP_RC_MEMORY_FENCE: str = "memory fence"; break;
1268 case GEN7_MSG_DP_RC_MEDIA_BLOCK_WRITE: str = "media block write"; break;
1269 case GEN7_MSG_DP_RC_RT_WRITE: str = "RT write"; break;
1270 case GEN7_MSG_DP_RC_TYPED_SURFACE_WRITE: str = "typed surface write"; break;
1271 default: str = "BAD"; break;
1272 }
1273
1274 is_rt_write = (op == GEN7_MSG_DP_RC_RT_WRITE);
1275 } else {
1276 switch (op) {
1277 case GEN6_MSG_DP_OWORD_BLOCK_READ: str = "OWORD block read"; break;
1278 case GEN6_MSG_DP_RT_UNORM_READ: str = "RT UNORM read"; break;
1279 case GEN6_MSG_DP_OWORD_DUAL_BLOCK_READ: str = "OWORD dual block read"; break;
1280 case GEN6_MSG_DP_MEDIA_BLOCK_READ: str = "media block read"; break;
1281 case GEN6_MSG_DP_UNALIGNED_OWORD_BLOCK_READ: str = "unaligned OWORD block read"; break;
1282 case GEN6_MSG_DP_DWORD_SCATTERED_READ: str = "DWORD scattered read"; break;
1283 case GEN6_MSG_DP_DWORD_ATOMIC_WRITE: str = "DWORD atomic write"; break;
1284 case GEN6_MSG_DP_OWORD_BLOCK_WRITE: str = "OWORD block write"; break;
1285 case GEN6_MSG_DP_OWORD_DUAL_BLOCK_WRITE: str = "OWORD dual block_write"; break;
1286 case GEN6_MSG_DP_MEDIA_BLOCK_WRITE: str = "media block write"; break;
1287 case GEN6_MSG_DP_DWORD_SCATTERED_WRITE: str = "DWORD scattered write"; break;
1288 case GEN6_MSG_DP_RT_WRITE: str = "RT write"; break;
1289 case GEN6_MSG_DP_SVB_WRITE: str = "SVB write"; break;
1290 case GEN6_MSG_DP_RT_UNORM_WRITE: str = "RT UNORM write"; break;
1291 default: str = "BAD"; break;
1292 }
1293
1294 is_rt_write = (op == GEN6_MSG_DP_RT_WRITE);
1295 }
1296
1297 disasm_printer_add(printer, " %s", str);
1298
1299 if (is_rt_write) {
1300 switch (mdesc & GEN6_MSG_DP_RT_MODE__MASK) {
1301 case GEN6_MSG_DP_RT_MODE_SIMD16: str = "SIMD16"; break;
1302 case GEN6_MSG_DP_RT_MODE_SIMD16_REPDATA: str = "SIMD16/RepData"; break;
1303 case GEN6_MSG_DP_RT_MODE_SIMD8_DUALSRC_LO: str = "SIMD8/DualSrcLow"; break;
1304 case GEN6_MSG_DP_RT_MODE_SIMD8_DUALSRC_HI: str = "SIMD8/DualSrcHigh"; break;
1305 case GEN6_MSG_DP_RT_MODE_SIMD8_LO: str = "SIMD8"; break;
1306 case GEN6_MSG_DP_RT_MODE_SIMD8_IMAGE_WR: str = "SIMD8/ImageWrite"; break;
1307 default: str = "BAD"; break;
1308 }
1309
1310 disasm_printer_add(printer, " %s%s%s%s", str,
1311 (mdesc & GEN6_MSG_DP_SLOTGRP_HI) ? " Hi" : "",
1312 (mdesc & GEN6_MSG_DP_RT_LAST) ? " LastRT" : "",
1313 (inst->dev->gen == ILO_GEN(6) &&
1314 (mdesc & GEN6_MSG_DP_SEND_WRITE_COMMIT)) ? " WriteCommit" : "");
1315 }
1316
1317 disasm_printer_add(printer, " Surface = %d",
1318 READ(mdesc, GEN6_MSG_DP_SURFACE));
1319 }
1320
1321 static void
1322 disasm_printer_add_mdesc(struct disasm_printer *printer,
1323 const struct disasm_inst *inst)
1324 {
1325 const uint32_t mdesc = inst->u.imm32;
1326
1327 assert(inst->opcode == GEN6_OPCODE_SEND ||
1328 inst->opcode == GEN6_OPCODE_SENDC);
1329 assert(inst->src1.base.file == GEN6_FILE_IMM);
1330
1331 disasm_printer_add(printer, " %s", disasm_inst_sfid(inst));
1332
1333 switch (inst->sfid) {
1334 case GEN6_SFID_SAMPLER:
1335 disasm_printer_add_mdesc_sampler(printer, inst, mdesc);
1336 break;
1337 case GEN6_SFID_DP_SAMPLER:
1338 disasm_printer_add_mdesc_dp_sampler(printer, inst, mdesc);
1339 break;
1340 case GEN6_SFID_DP_RC:
1341 disasm_printer_add_mdesc_dp_rc(printer, inst, mdesc);
1342 break;
1343 case GEN6_SFID_URB:
1344 disasm_printer_add_mdesc_urb(printer, inst, mdesc);
1345 break;
1346 case GEN6_SFID_DP_CC:
1347 case GEN7_SFID_DP_DC0:
1348 case GEN7_SFID_PI:
1349 case GEN75_SFID_DP_DC1:
1350 default:
1351 break;
1352 }
1353
1354 disasm_printer_add(printer, " mlen %d rlen %d",
1355 READ(mdesc, GEN6_MSG_MLEN),
1356 READ(mdesc, GEN6_MSG_RLEN));
1357 }
1358
1359 static void
1360 disasm_printer_print_inst(struct disasm_printer *printer,
1361 const struct disasm_inst *inst)
1362 {
1363 int col = 0;
1364
1365 disasm_printer_reset(printer);
1366
1367 disasm_printer_column(printer, col++);
1368 disasm_printer_add_op(printer, inst);
1369
1370 if (inst->has_jip || inst->has_uip) {
1371 if (inst->has_jip) {
1372 disasm_printer_column(printer, col++);
1373 disasm_printer_add(printer, "JIP: %d", (int16_t) inst->u.imm32);
1374 }
1375
1376 if (inst->has_uip) {
1377 disasm_printer_column(printer, col++);
1378 disasm_printer_add(printer, "UIP: %d",
1379 (int16_t) (inst->u.imm32 >> 16));
1380 }
1381 } else {
1382 const int src_count = disasm_opcode_table[inst->opcode].src_count;
1383 const struct disasm_src_operand *src[3];
1384 int i;
1385
1386 /* get src operands */
1387 switch (src_count) {
1388 case 3:
1389 src[2] = &inst->u.src2;
1390 case 2:
1391 src[1] = &inst->src1;
1392 case 1:
1393 src[0] = &inst->src0;
1394 case 0:
1395 default:
1396 break;
1397 }
1398
1399 if (src_count) {
1400 disasm_printer_column(printer, col++);
1401 disasm_printer_add_dst(printer, inst, &inst->dst);
1402
1403 for (i = 0; i < src_count; i++) {
1404 disasm_printer_column(printer, col++);
1405 disasm_printer_add_src(printer, inst, src[i]);
1406 }
1407 }
1408 }
1409
1410 if (inst->opcode == GEN6_OPCODE_SEND ||
1411 inst->opcode == GEN6_OPCODE_SENDC) {
1412 /* start a new line */
1413 ilo_printf("%s\n", disasm_printer_get_string(printer));
1414 disasm_printer_reset(printer);
1415 col = 0;
1416
1417 disasm_printer_column(printer, col++);
1418
1419 disasm_printer_column(printer, col++);
1420 disasm_printer_add_mdesc(printer, inst);
1421 }
1422
1423 if (col < 4)
1424 col = 4;
1425
1426 disasm_printer_column(printer, col++);
1427 disasm_printer_add_ctrl(printer, inst);
1428
1429 ilo_printf("%s\n", disasm_printer_get_string(printer));
1430 }
1431
1432 void
1433 toy_compiler_disassemble(const struct ilo_dev_info *dev,
1434 const void *kernel, int size,
1435 bool dump_hex)
1436 {
1437 const uint32_t *cur = (const uint32_t *) kernel;
1438 const uint32_t *end = cur + size / sizeof(*cur);
1439 struct disasm_printer printer;
1440
1441 disasm_printer_reset(&printer);
1442
1443 while (cur < end) {
1444 struct disasm_inst inst;
1445 const bool compacted = (cur[0] & GEN6_INST_CMPTCTRL);
1446 const uint32_t *dw = cur;
1447 uint32_t temp[4];
1448
1449 cur += (compacted) ? 2 : 4;
1450 /* incomplete instruction */
1451 if (cur > end)
1452 break;
1453
1454 if (compacted) {
1455 /* no compaction support yet */
1456 memset(temp, 0, sizeof(temp));
1457 dw = temp;
1458 }
1459
1460 if (dump_hex) {
1461 ilo_printf("0x%08x 0x%08x 0x%08x 0x%08x ",
1462 dw[0], dw[1], dw[2], dw[3]);
1463 }
1464
1465 memset(&inst, 0, sizeof(inst));
1466 inst.dev = dev;
1467 disasm_inst_decode(&inst, dw);
1468 inst.cmpt_ctrl = compacted;
1469
1470 disasm_printer_print_inst(&printer, &inst);
1471 }
1472 }