2d5ae62a64a3563bf7705667087c72e6f586ad1a
[mesa.git] / src / gallium / drivers / freedreno / a3xx / disasm-a3xx.c
1 /*
2 * Copyright (c) 2013 Rob Clark <robdclark@gmail.com>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <stdint.h>
27 #include <string.h>
28 #include <assert.h>
29
30 #include <util/u_debug.h>
31
32 #include "disasm.h"
33 #include "instr-a3xx.h"
34
35 static enum debug_t debug;
36
37 #define printf debug_printf
38
39 static const char *levels[] = {
40 "",
41 "\t",
42 "\t\t",
43 "\t\t\t",
44 "\t\t\t\t",
45 "\t\t\t\t\t",
46 "\t\t\t\t\t\t",
47 "\t\t\t\t\t\t\t",
48 "\t\t\t\t\t\t\t\t",
49 "\t\t\t\t\t\t\t\t\t",
50 "x",
51 "x",
52 "x",
53 "x",
54 "x",
55 "x",
56 };
57
58 static const char *component = "xyzw";
59
60 static const char *type[] = {
61 [TYPE_F16] = "f16",
62 [TYPE_F32] = "f32",
63 [TYPE_U16] = "u16",
64 [TYPE_U32] = "u32",
65 [TYPE_S16] = "s16",
66 [TYPE_S32] = "s32",
67 [TYPE_U8] = "u8",
68 [TYPE_S8] = "s8",
69 };
70
71 static void print_reg(reg_t reg, bool full, bool r, bool c, bool im,
72 bool neg, bool abs, bool addr_rel)
73 {
74 const char type = c ? 'c' : 'r';
75
76 // XXX I prefer - and || for neg/abs, but preserving format used
77 // by libllvm-a3xx for easy diffing..
78
79 if (abs && neg)
80 printf("(absneg)");
81 else if (neg)
82 printf("(neg)");
83 else if (abs)
84 printf("(abs)");
85
86 if (r)
87 printf("(r)");
88
89 if (im) {
90 printf("%d", reg.iim_val);
91 } else if (addr_rel) {
92 /* I would just use %+d but trying to make it diff'able with
93 * libllvm-a3xx...
94 */
95 if (reg.iim_val < 0)
96 printf("%s%c<a0.x - %d>", full ? "" : "h", type, -reg.iim_val);
97 else if (reg.iim_val > 0)
98 printf("%s%c<a0.x + %d>", full ? "" : "h", type, reg.iim_val);
99 else
100 printf("%s%c<a0.x>", full ? "" : "h", type);
101 } else if ((reg.num == REG_A0) && !c) {
102 printf("a0.%c", component[reg.comp]);
103 } else if ((reg.num == REG_P0) && !c) {
104 printf("p0.%c", component[reg.comp]);
105 } else {
106 printf("%s%c%d.%c", full ? "" : "h", type, reg.num, component[reg.comp]);
107 }
108 }
109
110
111 /* current instruction repeat flag: */
112 static unsigned repeat;
113
114 static void print_reg_dst(reg_t reg, bool full, bool addr_rel)
115 {
116 print_reg(reg, full, false, false, false, false, false, addr_rel);
117 }
118
119 static void print_reg_src(reg_t reg, bool full, bool r, bool c, bool im,
120 bool neg, bool abs, bool addr_rel)
121 {
122 print_reg(reg, full, r, c, im, neg, abs, addr_rel);
123 }
124
125 static void print_instr_cat0(instr_t *instr)
126 {
127 instr_cat0_t *cat0 = &instr->cat0;
128
129 switch (cat0->opc) {
130 case OPC_KILL:
131 printf(" %sp0.%c", cat0->inv ? "!" : "",
132 component[cat0->comp]);
133 break;
134 case OPC_BR:
135 printf(" %sp0.%c, #%d", cat0->inv ? "!" : "",
136 component[cat0->comp], cat0->immed);
137 break;
138 case OPC_JUMP:
139 case OPC_CALL:
140 printf(" #%d", cat0->immed);
141 break;
142 }
143
144 if ((debug & PRINT_VERBOSE) && (cat0->dummy1|cat0->dummy2|cat0->dummy3|cat0->dummy4))
145 printf("\t{0: %x,%x,%x,%x}", cat0->dummy1, cat0->dummy2, cat0->dummy3, cat0->dummy4);
146 }
147
148 static void print_instr_cat1(instr_t *instr)
149 {
150 instr_cat1_t *cat1 = &instr->cat1;
151
152 if (cat1->ul)
153 printf("(ul)");
154
155 if (cat1->src_type == cat1->dst_type) {
156 if ((cat1->src_type == TYPE_S16) && (((reg_t)cat1->dst).num == REG_A0)) {
157 /* special case (nmemonic?): */
158 printf("mova");
159 } else {
160 printf("mov.%s%s", type[cat1->src_type], type[cat1->dst_type]);
161 }
162 } else {
163 printf("cov.%s%s", type[cat1->src_type], type[cat1->dst_type]);
164 }
165
166 printf(" ");
167
168 if (cat1->even)
169 printf("(even)");
170
171 if (cat1->pos_inf)
172 printf("(pos_infinity)");
173
174 print_reg_dst((reg_t)(cat1->dst), type_size(cat1->dst_type) == 32,
175 cat1->dst_rel);
176
177 printf(", ");
178
179 /* ugg, have to special case this.. vs print_reg().. */
180 if (cat1->src_im) {
181 if (type_float(cat1->src_type))
182 printf("(%f)", cat1->fim_val);
183 else
184 printf("%d", cat1->iim_val);
185 } else if (cat1->src_rel && !cat1->src_c) {
186 /* I would just use %+d but trying to make it diff'able with
187 * libllvm-a3xx...
188 */
189 char type = cat1->src_rel_c ? 'c' : 'r';
190 if (cat1->off < 0)
191 printf("%c<a0.x - %d>", type, -cat1->off);
192 else if (cat1->off > 0)
193 printf("%c<a0.x + %d>", type, cat1->off);
194 else
195 printf("c<a0.x>");
196 } else {
197 print_reg_src((reg_t)(cat1->src), type_size(cat1->src_type) == 32,
198 cat1->src_r, cat1->src_c, cat1->src_im, false, false, false);
199 }
200
201 if ((debug & PRINT_VERBOSE) && (cat1->must_be_0))
202 printf("\t{1: %x}", cat1->must_be_0);
203 }
204
205 static void print_instr_cat2(instr_t *instr)
206 {
207 instr_cat2_t *cat2 = &instr->cat2;
208 static const char *cond[] = {
209 "lt",
210 "le",
211 "gt",
212 "ge",
213 "eq",
214 "ne",
215 "?6?",
216 };
217
218 switch (cat2->opc) {
219 case OPC_CMPS_F:
220 case OPC_CMPS_U:
221 case OPC_CMPS_S:
222 case OPC_CMPV_F:
223 case OPC_CMPV_U:
224 case OPC_CMPV_S:
225 printf(".%s", cond[cat2->cond]);
226 break;
227 }
228
229 printf(" ");
230 if (cat2->ei)
231 printf("(ei)");
232 print_reg_dst((reg_t)(cat2->dst), cat2->full ^ cat2->dst_half, false);
233 printf(", ");
234
235 if (cat2->c1.src1_c) {
236 print_reg_src((reg_t)(cat2->c1.src1), cat2->full, cat2->src1_r,
237 cat2->c1.src1_c, cat2->src1_im, cat2->src1_neg,
238 cat2->src1_abs, false);
239 } else if (cat2->rel1.src1_rel) {
240 print_reg_src((reg_t)(cat2->rel1.src1), cat2->full, cat2->src1_r,
241 cat2->rel1.src1_c, cat2->src1_im, cat2->src1_neg,
242 cat2->src1_abs, cat2->rel1.src1_rel);
243 } else {
244 print_reg_src((reg_t)(cat2->src1), cat2->full, cat2->src1_r,
245 false, cat2->src1_im, cat2->src1_neg,
246 cat2->src1_abs, false);
247 }
248
249 switch (cat2->opc) {
250 case OPC_ABSNEG_F:
251 case OPC_ABSNEG_S:
252 case OPC_CLZ_B:
253 case OPC_CLZ_S:
254 case OPC_SIGN_F:
255 case OPC_FLOOR_F:
256 case OPC_CEIL_F:
257 case OPC_RNDNE_F:
258 case OPC_RNDAZ_F:
259 case OPC_TRUNC_F:
260 case OPC_NOT_B:
261 case OPC_BFREV_B:
262 case OPC_SETRM:
263 case OPC_CBITS_B:
264 /* these only have one src reg */
265 break;
266 default:
267 printf(", ");
268 if (cat2->c2.src2_c) {
269 print_reg_src((reg_t)(cat2->c2.src2), cat2->full, cat2->src2_r,
270 cat2->c2.src2_c, cat2->src2_im, cat2->src2_neg,
271 cat2->src2_abs, false);
272 } else if (cat2->rel2.src2_rel) {
273 print_reg_src((reg_t)(cat2->rel2.src2), cat2->full, cat2->src2_r,
274 cat2->rel2.src2_c, cat2->src2_im, cat2->src2_neg,
275 cat2->src2_abs, cat2->rel2.src2_rel);
276 } else {
277 print_reg_src((reg_t)(cat2->src2), cat2->full, cat2->src2_r,
278 false, cat2->src2_im, cat2->src2_neg,
279 cat2->src2_abs, false);
280 }
281 break;
282 }
283 }
284
285 static void print_instr_cat3(instr_t *instr)
286 {
287 instr_cat3_t *cat3 = &instr->cat3;
288 bool full = true;
289
290 // XXX is this based on opc or some other bit?
291 switch (cat3->opc) {
292 case OPC_MAD_F16:
293 case OPC_MAD_U16:
294 case OPC_MAD_S16:
295 case OPC_SEL_B16:
296 case OPC_SEL_S16:
297 case OPC_SEL_F16:
298 case OPC_SAD_S16:
299 case OPC_SAD_S32: // really??
300 full = false;
301 break;
302 }
303
304 printf(" ");
305 print_reg_dst((reg_t)(cat3->dst), full ^ cat3->dst_half, false);
306 printf(", ");
307 if (cat3->c1.src1_c) {
308 print_reg_src((reg_t)(cat3->c1.src1), full,
309 cat3->src1_r, cat3->c1.src1_c, false, cat3->src1_neg,
310 false, false);
311 } else if (cat3->rel1.src1_rel) {
312 print_reg_src((reg_t)(cat3->rel1.src1), full,
313 cat3->src1_r, cat3->rel1.src1_c, false, cat3->src1_neg,
314 false, cat3->rel1.src1_rel);
315 } else {
316 print_reg_src((reg_t)(cat3->src1), full,
317 cat3->src1_r, false, false, cat3->src1_neg,
318 false, false);
319 }
320 printf(", ");
321 print_reg_src((reg_t)cat3->src2, full,
322 cat3->src2_r, cat3->src2_c, false, cat3->src2_neg,
323 false, false);
324 printf(", ");
325 if (cat3->c2.src3_c) {
326 print_reg_src((reg_t)(cat3->c2.src3), full,
327 cat3->src3_r, cat3->c2.src3_c, false, cat3->src3_neg,
328 false, false);
329 } else if (cat3->rel2.src3_rel) {
330 print_reg_src((reg_t)(cat3->rel2.src3), full,
331 cat3->src3_r, cat3->rel2.src3_c, false, cat3->src3_neg,
332 false, cat3->rel2.src3_rel);
333 } else {
334 print_reg_src((reg_t)(cat3->src3), full,
335 cat3->src3_r, false, false, cat3->src3_neg,
336 false, false);
337 }
338 }
339
340 static void print_instr_cat4(instr_t *instr)
341 {
342 instr_cat4_t *cat4 = &instr->cat4;
343
344 printf(" ");
345 print_reg_dst((reg_t)(cat4->dst), cat4->full ^ cat4->dst_half, false);
346 printf(", ");
347
348 if (cat4->c.src_c) {
349 print_reg_src((reg_t)(cat4->c.src), cat4->full,
350 cat4->src_r, cat4->c.src_c, cat4->src_im,
351 cat4->src_neg, cat4->src_abs, false);
352 } else if (cat4->rel.src_rel) {
353 print_reg_src((reg_t)(cat4->rel.src), cat4->full,
354 cat4->src_r, cat4->rel.src_c, cat4->src_im,
355 cat4->src_neg, cat4->src_abs, cat4->rel.src_rel);
356 } else {
357 print_reg_src((reg_t)(cat4->src), cat4->full,
358 cat4->src_r, false, cat4->src_im,
359 cat4->src_neg, cat4->src_abs, false);
360 }
361
362 if ((debug & PRINT_VERBOSE) && (cat4->dummy1|cat4->dummy2))
363 printf("\t{4: %x,%x}", cat4->dummy1, cat4->dummy2);
364 }
365
366 static void print_instr_cat5(instr_t *instr)
367 {
368 static const struct {
369 bool src1, src2, samp, tex;
370 } info[0x1f] = {
371 [OPC_ISAM] = { true, false, true, true, },
372 [OPC_ISAML] = { true, true, true, true, },
373 [OPC_ISAMM] = { true, false, true, true, },
374 [OPC_SAM] = { true, false, true, true, },
375 [OPC_SAMB] = { true, true, true, true, },
376 [OPC_SAML] = { true, true, true, true, },
377 [OPC_SAMGQ] = { true, false, true, true, },
378 [OPC_GETLOD] = { true, false, true, true, },
379 [OPC_CONV] = { true, true, true, true, },
380 [OPC_CONVM] = { true, true, true, true, },
381 [OPC_GETSIZE] = { true, false, false, true, },
382 [OPC_GETBUF] = { false, false, false, true, },
383 [OPC_GETPOS] = { true, false, false, true, },
384 [OPC_GETINFO] = { false, false, false, true, },
385 [OPC_DSX] = { true, false, false, false, },
386 [OPC_DSY] = { true, false, false, false, },
387 [OPC_GATHER4R] = { true, false, true, true, },
388 [OPC_GATHER4G] = { true, false, true, true, },
389 [OPC_GATHER4B] = { true, false, true, true, },
390 [OPC_GATHER4A] = { true, false, true, true, },
391 [OPC_SAMGP0] = { true, false, true, true, },
392 [OPC_SAMGP1] = { true, false, true, true, },
393 [OPC_SAMGP2] = { true, false, true, true, },
394 [OPC_SAMGP3] = { true, false, true, true, },
395 [OPC_DSXPP_1] = { true, false, false, false, },
396 [OPC_DSYPP_1] = { true, false, false, false, },
397 [OPC_RGETPOS] = { false, false, false, false, },
398 [OPC_RGETINFO] = { false, false, false, false, },
399 };
400 instr_cat5_t *cat5 = &instr->cat5;
401 int i;
402
403 if (cat5->is_3d) printf(".3d");
404 if (cat5->is_a) printf(".a");
405 if (cat5->is_o) printf(".o");
406 if (cat5->is_p) printf(".p");
407 if (cat5->is_s) printf(".s");
408 if (cat5->is_s2en) printf(".s2en");
409
410 printf(" ");
411
412 switch (cat5->opc) {
413 case OPC_DSXPP_1:
414 case OPC_DSYPP_1:
415 break;
416 default:
417 printf("(%s)", type[cat5->type]);
418 break;
419 }
420
421 printf("(");
422 for (i = 0; i < 4; i++)
423 if (cat5->wrmask & (1 << i))
424 printf("%c", "xyzw"[i]);
425 printf(")");
426
427 print_reg_dst((reg_t)(cat5->dst), type_size(cat5->type) == 32, false);
428
429 if (info[cat5->opc].src1) {
430 printf(", ");
431 print_reg_src((reg_t)(cat5->src1), cat5->full, false, false, false,
432 false, false, false);
433 }
434
435 if (cat5->is_s2en) {
436 printf(", ");
437 print_reg_src((reg_t)(cat5->s2en.src2), cat5->full, false, false, false,
438 false, false, false);
439 printf(", ");
440 print_reg_src((reg_t)(cat5->s2en.src3), false, false, false, false,
441 false, false, false);
442 } else {
443 if (cat5->is_o || info[cat5->opc].src2) {
444 printf(", ");
445 print_reg_src((reg_t)(cat5->norm.src2), cat5->full,
446 false, false, false, false, false, false);
447 }
448 if (info[cat5->opc].samp)
449 printf(", s#%d", cat5->norm.samp);
450 if (info[cat5->opc].tex)
451 printf(", t#%d", cat5->norm.tex);
452 }
453
454 if (debug & PRINT_VERBOSE) {
455 if (cat5->is_s2en) {
456 if ((debug & PRINT_VERBOSE) && (cat5->s2en.dummy1|cat5->s2en.dummy2|cat5->dummy2))
457 printf("\t{5: %x,%x,%x}", cat5->s2en.dummy1, cat5->s2en.dummy2, cat5->dummy2);
458 } else {
459 if ((debug & PRINT_VERBOSE) && (cat5->norm.dummy1|cat5->dummy2))
460 printf("\t{5: %x,%x}", cat5->norm.dummy1, cat5->dummy2);
461 }
462 }
463 }
464
465 static int32_t u2i(uint32_t val, int nbits)
466 {
467 return ((val >> (nbits-1)) * ~((1 << nbits) - 1)) | val;
468 }
469
470 static void print_instr_cat6(instr_t *instr)
471 {
472 instr_cat6_t *cat6 = &instr->cat6;
473
474 printf(".%s ", type[cat6->type]);
475
476 switch (cat6->opc) {
477 case OPC_LDG:
478 case OPC_LDP:
479 case OPC_LDL:
480 case OPC_LDLW:
481 case OPC_LDLV:
482 /* load instructions: */
483 print_reg_dst((reg_t)(cat6->a.dst), type_size(cat6->type) == 32, false);
484 printf(",");
485 switch (cat6->opc) {
486 case OPC_LDG:
487 printf("g");
488 break;
489 case OPC_LDP:
490 printf("p");
491 break;
492 case OPC_LDL:
493 case OPC_LDLW:
494 case OPC_LDLV:
495 printf("l");
496 break;
497 }
498 printf("[");
499 print_reg_src((reg_t)(cat6->a.src), true,
500 false, false, false, false, false, false);
501 if (cat6->a.off)
502 printf("%+d", cat6->a.off);
503 printf("]");
504 break;
505 case OPC_PREFETCH:
506 /* similar to load instructions: */
507 printf("g[");
508 print_reg_src((reg_t)(cat6->a.src), true,
509 false, false, false, false, false, false);
510 if (cat6->a.off)
511 printf("%+d", cat6->a.off);
512 printf("]");
513 break;
514 case OPC_STG:
515 case OPC_STP:
516 case OPC_STL:
517 case OPC_STLW:
518 /* store instructions: */
519 switch (cat6->opc) {
520 case OPC_STG:
521 printf("g");
522 break;
523 case OPC_STP:
524 printf("p");
525 break;
526 case OPC_STL:
527 case OPC_STLW:
528 printf("l");
529 break;
530 }
531 printf("[");
532 print_reg_dst((reg_t)(cat6->b.dst), true, false);
533 if (cat6->b.off || cat6->b.off_hi)
534 printf("%+d", u2i((cat6->b.off_hi << 8) | cat6->b.off, 13));
535 printf("]");
536 printf(",");
537 print_reg_src((reg_t)(cat6->b.src), type_size(cat6->type) == 32,
538 false, false, false, false, false, false);
539
540 break;
541 case OPC_STI:
542 /* sti has same encoding as other store instructions, but
543 * slightly different syntax:
544 */
545 print_reg_dst((reg_t)(cat6->b.dst), false /* XXX is it always half? */, false);
546 if (cat6->b.off || cat6->b.off_hi)
547 printf("%+d", u2i((cat6->b.off_hi << 8) | cat6->b.off, 13));
548 printf(",");
549 print_reg_src((reg_t)(cat6->b.src), type_size(cat6->type) == 32,
550 false, false, false, false, false, false);
551 break;
552 }
553
554 printf(", %d", cat6->iim_val);
555
556 if (debug & PRINT_VERBOSE) {
557 switch (cat6->opc) {
558 case OPC_LDG:
559 case OPC_LDP:
560 /* load instructions: */
561 if (cat6->a.dummy1|cat6->a.dummy2|cat6->a.dummy3)
562 printf("\t{6: %x,%x,%x}", cat6->a.dummy1, cat6->a.dummy2, cat6->a.dummy3);
563 if ((cat6->a.must_be_one1 != 1) || (cat6->a.must_be_one2 != 1))
564 printf("{?? %d,%d ??}", cat6->a.must_be_one1, cat6->a.must_be_one2);
565 break;
566 case OPC_STG:
567 case OPC_STP:
568 case OPC_STI:
569 /* store instructions: */
570 if (cat6->b.dummy1|cat6->b.dummy2)
571 printf("\t{6: %x,%x}", cat6->b.dummy1, cat6->b.dummy2);
572 if ((cat6->b.must_be_one1 != 1) || (cat6->b.must_be_one2 != 1) ||
573 (cat6->b.must_be_zero1 != 0))
574 printf("{?? %d,%d,%d ??}", cat6->b.must_be_one1, cat6->b.must_be_one2,
575 cat6->b.must_be_zero1);
576 break;
577 }
578 }
579 }
580
581 /* size of largest OPC field of all the instruction categories: */
582 #define NOPC_BITS 6
583
584 struct opc_info {
585 uint16_t cat;
586 uint16_t opc;
587 const char *name;
588 void (*print)(instr_t *instr);
589 } opcs[1 << (3+NOPC_BITS)] = {
590 #define OPC(cat, opc, name) [((cat) << NOPC_BITS) | (opc)] = { (cat), (opc), #name, print_instr_cat##cat }
591 /* category 0: */
592 OPC(0, OPC_NOP, nop),
593 OPC(0, OPC_BR, br),
594 OPC(0, OPC_JUMP, jump),
595 OPC(0, OPC_CALL, call),
596 OPC(0, OPC_RET, ret),
597 OPC(0, OPC_KILL, kill),
598 OPC(0, OPC_END, end),
599 OPC(0, OPC_EMIT, emit),
600 OPC(0, OPC_CUT, cut),
601 OPC(0, OPC_CHMASK, chmask),
602 OPC(0, OPC_CHSH, chsh),
603 OPC(0, OPC_FLOW_REV, flow_rev),
604
605 /* category 1: */
606 OPC(1, 0, ),
607
608 /* category 2: */
609 OPC(2, OPC_ADD_F, add.f),
610 OPC(2, OPC_MIN_F, min.f),
611 OPC(2, OPC_MAX_F, max.f),
612 OPC(2, OPC_MUL_F, mul.f),
613 OPC(2, OPC_SIGN_F, sign.f),
614 OPC(2, OPC_CMPS_F, cmps.f),
615 OPC(2, OPC_ABSNEG_F, absneg.f),
616 OPC(2, OPC_CMPV_F, cmpv.f),
617 OPC(2, OPC_FLOOR_F, floor.f),
618 OPC(2, OPC_CEIL_F, ceil.f),
619 OPC(2, OPC_RNDNE_F, rndne.f),
620 OPC(2, OPC_RNDAZ_F, rndaz.f),
621 OPC(2, OPC_TRUNC_F, trunc.f),
622 OPC(2, OPC_ADD_U, add.u),
623 OPC(2, OPC_ADD_S, add.s),
624 OPC(2, OPC_SUB_U, sub.u),
625 OPC(2, OPC_SUB_S, sub.s),
626 OPC(2, OPC_CMPS_U, cmps.u),
627 OPC(2, OPC_CMPS_S, cmps.s),
628 OPC(2, OPC_MIN_U, min.u),
629 OPC(2, OPC_MIN_S, min.s),
630 OPC(2, OPC_MAX_U, max.u),
631 OPC(2, OPC_MAX_S, max.s),
632 OPC(2, OPC_ABSNEG_S, absneg.s),
633 OPC(2, OPC_AND_B, and.b),
634 OPC(2, OPC_OR_B, or.b),
635 OPC(2, OPC_NOT_B, not.b),
636 OPC(2, OPC_XOR_B, xor.b),
637 OPC(2, OPC_CMPV_U, cmpv.u),
638 OPC(2, OPC_CMPV_S, cmpv.s),
639 OPC(2, OPC_MUL_U, mul.u),
640 OPC(2, OPC_MUL_S, mul.s),
641 OPC(2, OPC_MULL_U, mull.u),
642 OPC(2, OPC_BFREV_B, bfrev.b),
643 OPC(2, OPC_CLZ_S, clz.s),
644 OPC(2, OPC_CLZ_B, clz.b),
645 OPC(2, OPC_SHL_B, shl.b),
646 OPC(2, OPC_SHR_B, shr.b),
647 OPC(2, OPC_ASHR_B, ashr.b),
648 OPC(2, OPC_BARY_F, bary.f),
649 OPC(2, OPC_MGEN_B, mgen.b),
650 OPC(2, OPC_GETBIT_B, getbit.b),
651 OPC(2, OPC_SETRM, setrm),
652 OPC(2, OPC_CBITS_B, cbits.b),
653 OPC(2, OPC_SHB, shb),
654 OPC(2, OPC_MSAD, msad),
655
656 /* category 3: */
657 OPC(3, OPC_MAD_U16, mad.u16),
658 OPC(3, OPC_MADSH_U16, madsh.u16),
659 OPC(3, OPC_MAD_S16, mad.s16),
660 OPC(3, OPC_MADSH_M16, madsh.m16),
661 OPC(3, OPC_MAD_U24, mad.u24),
662 OPC(3, OPC_MAD_S24, mad.s24),
663 OPC(3, OPC_MAD_F16, mad.f16),
664 OPC(3, OPC_MAD_F32, mad.f32),
665 OPC(3, OPC_SEL_B16, sel.b16),
666 OPC(3, OPC_SEL_B32, sel.b32),
667 OPC(3, OPC_SEL_S16, sel.s16),
668 OPC(3, OPC_SEL_S32, sel.s32),
669 OPC(3, OPC_SEL_F16, sel.f16),
670 OPC(3, OPC_SEL_F32, sel.f32),
671 OPC(3, OPC_SAD_S16, sad.s16),
672 OPC(3, OPC_SAD_S32, sad.s32),
673
674 /* category 4: */
675 OPC(4, OPC_RCP, rcp),
676 OPC(4, OPC_RSQ, rsq),
677 OPC(4, OPC_LOG2, log2),
678 OPC(4, OPC_EXP2, exp2),
679 OPC(4, OPC_SIN, sin),
680 OPC(4, OPC_COS, cos),
681 OPC(4, OPC_SQRT, sqrt),
682
683 /* category 5: */
684 OPC(5, OPC_ISAM, isam),
685 OPC(5, OPC_ISAML, isaml),
686 OPC(5, OPC_ISAMM, isamm),
687 OPC(5, OPC_SAM, sam),
688 OPC(5, OPC_SAMB, samb),
689 OPC(5, OPC_SAML, saml),
690 OPC(5, OPC_SAMGQ, samgq),
691 OPC(5, OPC_GETLOD, getlod),
692 OPC(5, OPC_CONV, conv),
693 OPC(5, OPC_CONVM, convm),
694 OPC(5, OPC_GETSIZE, getsize),
695 OPC(5, OPC_GETBUF, getbuf),
696 OPC(5, OPC_GETPOS, getpos),
697 OPC(5, OPC_GETINFO, getinfo),
698 OPC(5, OPC_DSX, dsx),
699 OPC(5, OPC_DSY, dsy),
700 OPC(5, OPC_GATHER4R, gather4r),
701 OPC(5, OPC_GATHER4G, gather4g),
702 OPC(5, OPC_GATHER4B, gather4b),
703 OPC(5, OPC_GATHER4A, gather4a),
704 OPC(5, OPC_SAMGP0, samgp0),
705 OPC(5, OPC_SAMGP1, samgp1),
706 OPC(5, OPC_SAMGP2, samgp2),
707 OPC(5, OPC_SAMGP3, samgp3),
708 OPC(5, OPC_DSXPP_1, dsxpp.1),
709 OPC(5, OPC_DSYPP_1, dsypp.1),
710 OPC(5, OPC_RGETPOS, rgetpos),
711 OPC(5, OPC_RGETINFO, rgetinfo),
712
713
714 /* category 6: */
715 OPC(6, OPC_LDG, ldg),
716 OPC(6, OPC_LDL, ldl),
717 OPC(6, OPC_LDP, ldp),
718 OPC(6, OPC_STG, stg),
719 OPC(6, OPC_STL, stl),
720 OPC(6, OPC_STP, stp),
721 OPC(6, OPC_STI, sti),
722 OPC(6, OPC_G2L, g2l),
723 OPC(6, OPC_L2G, l2g),
724 OPC(6, OPC_PREFETCH, prefetch),
725 OPC(6, OPC_LDLW, ldlw),
726 OPC(6, OPC_STLW, stlw),
727 OPC(6, OPC_RESFMT, resfmt),
728 OPC(6, OPC_RESINFO, resinf),
729 OPC(6, OPC_ATOMIC_ADD_L, atomic.add.l),
730 OPC(6, OPC_ATOMIC_SUB_L, atomic.sub.l),
731 OPC(6, OPC_ATOMIC_XCHG_L, atomic.xchg.l),
732 OPC(6, OPC_ATOMIC_INC_L, atomic.inc.l),
733 OPC(6, OPC_ATOMIC_DEC_L, atomic.dec.l),
734 OPC(6, OPC_ATOMIC_CMPXCHG_L, atomic.cmpxchg.l),
735 OPC(6, OPC_ATOMIC_MIN_L, atomic.min.l),
736 OPC(6, OPC_ATOMIC_MAX_L, atomic.max.l),
737 OPC(6, OPC_ATOMIC_AND_L, atomic.and.l),
738 OPC(6, OPC_ATOMIC_OR_L, atomic.or.l),
739 OPC(6, OPC_ATOMIC_XOR_L, atomic.xor.l),
740 OPC(6, OPC_LDGB_TYPED_4D, ldgb.typed.4d),
741 OPC(6, OPC_STGB_4D_4, stgb.4d.4),
742 OPC(6, OPC_STIB, stib),
743 OPC(6, OPC_LDC_4, ldc.4),
744 OPC(6, OPC_LDLV, ldlv),
745
746
747 #undef OPC
748 };
749
750 #define GETINFO(instr) (&(opcs[((instr)->opc_cat << NOPC_BITS) | getopc(instr)]))
751
752 static uint32_t getopc(instr_t *instr)
753 {
754 switch (instr->opc_cat) {
755 case 0: return instr->cat0.opc;
756 case 1: return 0;
757 case 2: return instr->cat2.opc;
758 case 3: return instr->cat3.opc;
759 case 4: return instr->cat4.opc;
760 case 5: return instr->cat5.opc;
761 case 6: return instr->cat6.opc;
762 default: return 0;
763 }
764 }
765
766 static void print_instr(uint32_t *dwords, int level, int n)
767 {
768 instr_t *instr = (instr_t *)dwords;
769 uint32_t opc = getopc(instr);
770 const char *name;
771
772 printf("%s%04d[%08xx_%08xx] ", levels[level], n, dwords[1], dwords[0]);
773
774 #if 0
775 /* print unknown bits: */
776 if (debug & PRINT_RAW)
777 printf("[%08xx_%08xx] ", dwords[1] & 0x001ff800, dwords[0] & 0x00000000);
778
779 if (debug & PRINT_VERBOSE)
780 printf("%d,%02d ", instr->opc_cat, opc);
781 #endif
782
783 /* NOTE: order flags are printed is a bit fugly.. but for now I
784 * try to match the order in llvm-a3xx disassembler for easy
785 * diff'ing..
786 */
787
788 if (instr->sync)
789 printf("(sy)");
790 if (instr->ss && (instr->opc_cat <= 4))
791 printf("(ss)");
792 if (instr->jmp_tgt)
793 printf("(jp)");
794 if (instr->repeat && (instr->opc_cat <= 4)) {
795 printf("(rpt%d)", instr->repeat);
796 repeat = instr->repeat;
797 } else {
798 repeat = 0;
799 }
800 if (instr->ul && ((2 <= instr->opc_cat) && (instr->opc_cat <= 4)))
801 printf("(ul)");
802
803 name = GETINFO(instr)->name;
804
805 if (name) {
806 printf("%s", name);
807 GETINFO(instr)->print(instr);
808 } else {
809 printf("unknown(%d,%d)", instr->opc_cat, opc);
810 }
811
812 printf("\n");
813 }
814
815 int disasm_a3xx(uint32_t *dwords, int sizedwords, int level, enum shader_t type)
816 {
817 int i;
818
819 assert((sizedwords % 2) == 0);
820
821 for (i = 0; i < sizedwords; i += 2)
822 print_instr(&dwords[i], level, i/2);
823
824 return 0;
825 }