2 * Copyright (c) 2013 Rob Clark <robdclark@gmail.com>
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:
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
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
31 #include <util/u_debug.h>
33 #include "instr-a3xx.h"
35 /* bitmask of debug flags */
37 PRINT_RAW
= 0x1, /* dump raw hexdump */
42 static enum debug_t debug
;
44 #define printf debug_printf
46 static const char *levels
[] = {
65 static const char *component
= "xyzw";
67 static const char *type
[] = {
83 /* current instruction repeat flag: */
85 /* current instruction repeat indx/offset (for --expand): */
88 unsigned instructions
;
91 static const char *float_imms
[] = {
106 static void print_reg(struct disasm_ctx
*ctx
, reg_t reg
, bool full
,
107 bool is_float
, bool r
,
108 bool c
, bool im
, bool neg
, bool abs
, bool addr_rel
)
110 const char type
= c
? 'c' : 'r';
112 // XXX I prefer - and || for neg/abs, but preserving format used
113 // by libllvm-a3xx for easy diffing..
116 fprintf(ctx
->out
, "(absneg)");
118 fprintf(ctx
->out
, "(neg)");
120 fprintf(ctx
->out
, "(abs)");
123 fprintf(ctx
->out
, "(r)");
126 if (is_float
&& full
&& reg
.iim_val
< ARRAY_SIZE(float_imms
)) {
127 fprintf(ctx
->out
, "(%s)", float_imms
[reg
.iim_val
]);
129 fprintf(ctx
->out
, "%d", reg
.iim_val
);
131 } else if (addr_rel
) {
132 /* I would just use %+d but trying to make it diff'able with
136 fprintf(ctx
->out
, "%s%c<a0.x - %d>", full
? "" : "h", type
, -reg
.iim_val
);
137 else if (reg
.iim_val
> 0)
138 fprintf(ctx
->out
, "%s%c<a0.x + %d>", full
? "" : "h", type
, reg
.iim_val
);
140 fprintf(ctx
->out
, "%s%c<a0.x>", full
? "" : "h", type
);
141 } else if ((reg
.num
== REG_A0
) && !c
) {
142 /* This matches libllvm output, the second (scalar) address register
143 * seems to be called a1.x instead of a0.y.
145 fprintf(ctx
->out
, "a%d.x", reg
.comp
);
146 } else if ((reg
.num
== REG_P0
) && !c
) {
147 fprintf(ctx
->out
, "p0.%c", component
[reg
.comp
]);
149 fprintf(ctx
->out
, "%s%c%d.%c", full
? "" : "h", type
, reg
.num
, component
[reg
.comp
]);
150 if (0 && full
&& !c
) {
155 fprintf(ctx
->out
, " (hr%d.%c,hr%d.%c)", hr0
.num
, component
[hr0
.comp
], hr1
.num
, component
[hr1
.comp
]);
160 static unsigned regidx(reg_t reg
)
162 return (4 * reg
.num
) + reg
.comp
;
165 static reg_t
idxreg(unsigned idx
)
173 static void print_reg_dst(struct disasm_ctx
*ctx
, reg_t reg
, bool full
, bool addr_rel
)
175 reg
= idxreg(regidx(reg
) + ctx
->repeatidx
);
176 print_reg(ctx
, reg
, full
, false, false, false, false, false, false, addr_rel
);
179 /* TODO switch to using reginfo struct everywhere, since more readable
180 * than passing a bunch of bools to print_reg_src
188 bool f
; /* src reg is interpreted as float, used for printing immediates */
195 static void print_src(struct disasm_ctx
*ctx
, struct reginfo
*info
)
197 reg_t reg
= info
->reg
;
200 reg
= idxreg(regidx(info
->reg
) + ctx
->repeatidx
);
202 print_reg(ctx
, reg
, info
->full
, info
->f
, info
->r
, info
->c
, info
->im
,
203 info
->neg
, info
->abs
, info
->addr_rel
);
206 //static void print_dst(struct disasm_ctx *ctx, struct reginfo *info)
208 // print_reg_dst(ctx, info->reg, info->full, info->addr_rel);
211 static void print_instr_cat0(struct disasm_ctx
*ctx
, instr_t
*instr
)
213 static const struct {
218 [BRANCH_PLAIN
] = { "r", 1, false },
219 [BRANCH_OR
] = { "rao", 2, false },
220 [BRANCH_AND
] = { "raa", 2, false },
221 [BRANCH_CONST
] = { "rac", 0, true },
222 [BRANCH_ANY
] = { "any", 1, false },
223 [BRANCH_ALL
] = { "all", 1, false },
224 [BRANCH_X
] = { "rax", 0, false },
226 instr_cat0_t
*cat0
= &instr
->cat0
;
228 switch (instr_opc(instr
, ctx
->gpu_id
)) {
232 fprintf(ctx
->out
, " %sp0.%c", cat0
->inv0
? "!" : "",
233 component
[cat0
->comp0
]);
236 fprintf(ctx
->out
, "%s", brinfo
[cat0
->brtype
].suffix
);
237 if (brinfo
[cat0
->brtype
].idx
) {
238 fprintf(ctx
->out
, ".%u", cat0
->idx
);
240 if (brinfo
[cat0
->brtype
].nsrc
>= 1) {
241 fprintf(ctx
->out
, " %sp0.%c,", cat0
->inv0
? "!" : "",
242 component
[cat0
->comp0
]);
244 if (brinfo
[cat0
->brtype
].nsrc
>= 2) {
245 fprintf(ctx
->out
, " %sp0.%c,", cat0
->inv1
? "!" : "",
246 component
[cat0
->comp1
]);
248 fprintf(ctx
->out
, " #%d", cat0
->a3xx
.immed
);
255 fprintf(ctx
->out
, " #%d", cat0
->a3xx
.immed
);
259 if ((debug
& PRINT_VERBOSE
) && (cat0
->dummy3
|cat0
->dummy4
))
260 fprintf(ctx
->out
, "\t{0: %x,%x}", cat0
->dummy3
, cat0
->dummy4
);
263 static void print_instr_cat1(struct disasm_ctx
*ctx
, instr_t
*instr
)
265 instr_cat1_t
*cat1
= &instr
->cat1
;
268 fprintf(ctx
->out
, "(ul)");
270 if (cat1
->src_type
== cat1
->dst_type
) {
271 if ((cat1
->src_type
== TYPE_S16
) && (((reg_t
)cat1
->dst
).num
== REG_A0
)) {
272 /* special case (nmemonic?): */
273 fprintf(ctx
->out
, "mova");
275 fprintf(ctx
->out
, "mov.%s%s", type
[cat1
->src_type
], type
[cat1
->dst_type
]);
278 fprintf(ctx
->out
, "cov.%s%s", type
[cat1
->src_type
], type
[cat1
->dst_type
]);
281 fprintf(ctx
->out
, " ");
284 fprintf(ctx
->out
, "(even)");
287 fprintf(ctx
->out
, "(pos_infinity)");
289 print_reg_dst(ctx
, (reg_t
)(cat1
->dst
), type_size(cat1
->dst_type
) == 32,
292 fprintf(ctx
->out
, ", ");
294 /* ugg, have to special case this.. vs print_reg().. */
296 if (type_float(cat1
->src_type
))
297 fprintf(ctx
->out
, "(%f)", cat1
->fim_val
);
298 else if (type_uint(cat1
->src_type
))
299 fprintf(ctx
->out
, "0x%08x", cat1
->uim_val
);
301 fprintf(ctx
->out
, "%d", cat1
->iim_val
);
302 } else if (cat1
->src_rel
&& !cat1
->src_c
) {
303 /* I would just use %+d but trying to make it diff'able with
306 char type
= cat1
->src_rel_c
? 'c' : 'r';
307 const char *full
= (type_size(cat1
->src_type
) == 32) ? "" : "h";
309 fprintf(ctx
->out
, "%s%c<a0.x - %d>", full
, type
, -cat1
->off
);
310 else if (cat1
->off
> 0)
311 fprintf(ctx
->out
, "%s%c<a0.x + %d>", full
, type
, cat1
->off
);
313 fprintf(ctx
->out
, "%s%c<a0.x>", full
, type
);
315 struct reginfo src
= {
316 .reg
= (reg_t
)cat1
->src
,
317 .full
= type_size(cat1
->src_type
) == 32,
322 print_src(ctx
, &src
);
325 if ((debug
& PRINT_VERBOSE
) && (cat1
->must_be_0
))
326 fprintf(ctx
->out
, "\t{1: %x}", cat1
->must_be_0
);
329 static void print_instr_cat2(struct disasm_ctx
*ctx
, instr_t
*instr
)
331 instr_cat2_t
*cat2
= &instr
->cat2
;
332 int opc
= _OPC(2, cat2
->opc
);
333 static const char *cond
[] = {
350 fprintf(ctx
->out
, ".%s", cond
[cat2
->cond
]);
354 fprintf(ctx
->out
, " ");
356 fprintf(ctx
->out
, "(ei)");
357 print_reg_dst(ctx
, (reg_t
)(cat2
->dst
), cat2
->full
^ cat2
->dst_half
, false);
358 fprintf(ctx
->out
, ", ");
360 struct reginfo src1
= {
362 .r
= cat2
->repeat
? cat2
->src1_r
: 0,
363 .f
= is_cat2_float(opc
),
365 .abs
= cat2
->src1_abs
,
366 .neg
= cat2
->src1_neg
,
369 if (cat2
->c1
.src1_c
) {
370 src1
.reg
= (reg_t
)(cat2
->c1
.src1
);
372 } else if (cat2
->rel1
.src1_rel
) {
373 src1
.reg
= (reg_t
)(cat2
->rel1
.src1
);
374 src1
.c
= cat2
->rel1
.src1_c
;
375 src1
.addr_rel
= true;
377 src1
.reg
= (reg_t
)(cat2
->src1
);
379 print_src(ctx
, &src1
);
381 struct reginfo src2
= {
382 .r
= cat2
->repeat
? cat2
->src2_r
: 0,
384 .f
= is_cat2_float(opc
),
385 .abs
= cat2
->src2_abs
,
386 .neg
= cat2
->src2_neg
,
404 /* these only have one src reg */
407 fprintf(ctx
->out
, ", ");
408 if (cat2
->c2
.src2_c
) {
409 src2
.reg
= (reg_t
)(cat2
->c2
.src2
);
411 } else if (cat2
->rel2
.src2_rel
) {
412 src2
.reg
= (reg_t
)(cat2
->rel2
.src2
);
413 src2
.c
= cat2
->rel2
.src2_c
;
414 src2
.addr_rel
= true;
416 src2
.reg
= (reg_t
)(cat2
->src2
);
418 print_src(ctx
, &src2
);
423 static void print_instr_cat3(struct disasm_ctx
*ctx
, instr_t
*instr
)
425 instr_cat3_t
*cat3
= &instr
->cat3
;
426 bool full
= instr_cat3_full(cat3
);
428 fprintf(ctx
->out
, " ");
429 print_reg_dst(ctx
, (reg_t
)(cat3
->dst
), full
^ cat3
->dst_half
, false);
430 fprintf(ctx
->out
, ", ");
432 struct reginfo src1
= {
433 .r
= cat3
->repeat
? cat3
->src1_r
: 0,
435 .neg
= cat3
->src1_neg
,
437 if (cat3
->c1
.src1_c
) {
438 src1
.reg
= (reg_t
)(cat3
->c1
.src1
);
440 } else if (cat3
->rel1
.src1_rel
) {
441 src1
.reg
= (reg_t
)(cat3
->rel1
.src1
);
442 src1
.c
= cat3
->rel1
.src1_c
;
443 src1
.addr_rel
= true;
445 src1
.reg
= (reg_t
)(cat3
->src1
);
447 print_src(ctx
, &src1
);
449 fprintf(ctx
->out
, ", ");
450 struct reginfo src2
= {
451 .reg
= (reg_t
)cat3
->src2
,
453 .r
= cat3
->repeat
? cat3
->src2_r
: 0,
455 .neg
= cat3
->src2_neg
,
457 print_src(ctx
, &src2
);
459 fprintf(ctx
->out
, ", ");
460 struct reginfo src3
= {
463 .neg
= cat3
->src3_neg
,
465 if (cat3
->c2
.src3_c
) {
466 src3
.reg
= (reg_t
)(cat3
->c2
.src3
);
468 } else if (cat3
->rel2
.src3_rel
) {
469 src3
.reg
= (reg_t
)(cat3
->rel2
.src3
);
470 src3
.c
= cat3
->rel2
.src3_c
;
471 src3
.addr_rel
= true;
473 src3
.reg
= (reg_t
)(cat3
->src3
);
475 print_src(ctx
, &src3
);
478 static void print_instr_cat4(struct disasm_ctx
*ctx
, instr_t
*instr
)
480 instr_cat4_t
*cat4
= &instr
->cat4
;
482 fprintf(ctx
->out
, " ");
483 print_reg_dst(ctx
, (reg_t
)(cat4
->dst
), cat4
->full
^ cat4
->dst_half
, false);
484 fprintf(ctx
->out
, ", ");
486 struct reginfo src
= {
490 .neg
= cat4
->src_neg
,
491 .abs
= cat4
->src_abs
,
494 src
.reg
= (reg_t
)(cat4
->c
.src
);
496 } else if (cat4
->rel
.src_rel
) {
497 src
.reg
= (reg_t
)(cat4
->rel
.src
);
498 src
.c
= cat4
->rel
.src_c
;
501 src
.reg
= (reg_t
)(cat4
->src
);
503 print_src(ctx
, &src
);
505 if ((debug
& PRINT_VERBOSE
) && (cat4
->dummy1
|cat4
->dummy2
))
506 fprintf(ctx
->out
, "\t{4: %x,%x}", cat4
->dummy1
, cat4
->dummy2
);
509 static void print_instr_cat5(struct disasm_ctx
*ctx
, instr_t
*instr
)
511 static const struct {
512 bool src1
, src2
, samp
, tex
;
514 [opc_op(OPC_ISAM
)] = { true, false, true, true, },
515 [opc_op(OPC_ISAML
)] = { true, true, true, true, },
516 [opc_op(OPC_ISAMM
)] = { true, false, true, true, },
517 [opc_op(OPC_SAM
)] = { true, false, true, true, },
518 [opc_op(OPC_SAMB
)] = { true, true, true, true, },
519 [opc_op(OPC_SAML
)] = { true, true, true, true, },
520 [opc_op(OPC_SAMGQ
)] = { true, false, true, true, },
521 [opc_op(OPC_GETLOD
)] = { true, false, true, true, },
522 [opc_op(OPC_CONV
)] = { true, true, true, true, },
523 [opc_op(OPC_CONVM
)] = { true, true, true, true, },
524 [opc_op(OPC_GETSIZE
)] = { true, false, false, true, },
525 [opc_op(OPC_GETBUF
)] = { false, false, false, true, },
526 [opc_op(OPC_GETPOS
)] = { true, false, false, true, },
527 [opc_op(OPC_GETINFO
)] = { false, false, false, true, },
528 [opc_op(OPC_DSX
)] = { true, false, false, false, },
529 [opc_op(OPC_DSY
)] = { true, false, false, false, },
530 [opc_op(OPC_GATHER4R
)] = { true, false, true, true, },
531 [opc_op(OPC_GATHER4G
)] = { true, false, true, true, },
532 [opc_op(OPC_GATHER4B
)] = { true, false, true, true, },
533 [opc_op(OPC_GATHER4A
)] = { true, false, true, true, },
534 [opc_op(OPC_SAMGP0
)] = { true, false, true, true, },
535 [opc_op(OPC_SAMGP1
)] = { true, false, true, true, },
536 [opc_op(OPC_SAMGP2
)] = { true, false, true, true, },
537 [opc_op(OPC_SAMGP3
)] = { true, false, true, true, },
538 [opc_op(OPC_DSXPP_1
)] = { true, false, false, false, },
539 [opc_op(OPC_DSYPP_1
)] = { true, false, false, false, },
540 [opc_op(OPC_RGETPOS
)] = { true, false, false, false, },
541 [opc_op(OPC_RGETINFO
)] = { false, false, false, false, },
544 static const struct {
549 } desc_features
[8] = {
550 [CAT5_NONUNIFORM
] = { .indirect
= true, },
551 [CAT5_UNIFORM
] = { .indirect
= true, .uniform
= true, },
552 [CAT5_BINDLESS_IMM
] = { .bindless
= true, },
553 [CAT5_BINDLESS_UNIFORM
] = {
558 [CAT5_BINDLESS_NONUNIFORM
] = {
562 [CAT5_BINDLESS_A1_IMM
] = {
566 [CAT5_BINDLESS_A1_UNIFORM
] = {
572 [CAT5_BINDLESS_A1_NONUNIFORM
] = {
579 instr_cat5_t
*cat5
= &instr
->cat5
;
583 cat5
->is_s2en_bindless
&&
584 desc_features
[cat5
->s2en_bindless
.desc_mode
].indirect
;
586 cat5
->is_s2en_bindless
&&
587 desc_features
[cat5
->s2en_bindless
.desc_mode
].bindless
;
589 cat5
->is_s2en_bindless
&&
590 desc_features
[cat5
->s2en_bindless
.desc_mode
].use_a1
;
592 cat5
->is_s2en_bindless
&&
593 desc_features
[cat5
->s2en_bindless
.desc_mode
].uniform
;
595 if (cat5
->is_3d
) fprintf(ctx
->out
, ".3d");
596 if (cat5
->is_a
) fprintf(ctx
->out
, ".a");
597 if (cat5
->is_o
) fprintf(ctx
->out
, ".o");
598 if (cat5
->is_p
) fprintf(ctx
->out
, ".p");
599 if (cat5
->is_s
) fprintf(ctx
->out
, ".s");
600 if (desc_indirect
) fprintf(ctx
->out
, ".s2en");
601 if (uniform
) fprintf(ctx
->out
, ".uniform");
604 unsigned base
= (cat5
->s2en_bindless
.base_hi
<< 1) | cat5
->base_lo
;
605 fprintf(ctx
->out
, ".base%d", base
);
608 fprintf(ctx
->out
, " ");
610 switch (_OPC(5, cat5
->opc
)) {
615 fprintf(ctx
->out
, "(%s)", type
[cat5
->type
]);
619 fprintf(ctx
->out
, "(");
620 for (i
= 0; i
< 4; i
++)
621 if (cat5
->wrmask
& (1 << i
))
622 fprintf(ctx
->out
, "%c", "xyzw"[i
]);
623 fprintf(ctx
->out
, ")");
625 print_reg_dst(ctx
, (reg_t
)(cat5
->dst
), type_size(cat5
->type
) == 32, false);
627 if (info
[cat5
->opc
].src1
) {
628 fprintf(ctx
->out
, ", ");
629 struct reginfo src
= { .reg
= (reg_t
)(cat5
->src1
), .full
= cat5
->full
};
630 print_src(ctx
, &src
);
633 if (cat5
->is_o
|| info
[cat5
->opc
].src2
) {
634 fprintf(ctx
->out
, ", ");
635 struct reginfo src
= { .reg
= (reg_t
)(cat5
->src2
), .full
= cat5
->full
};
636 print_src(ctx
, &src
);
638 if (cat5
->is_s2en_bindless
) {
639 if (!desc_indirect
) {
640 if (info
[cat5
->opc
].samp
) {
642 fprintf(ctx
->out
, ", s#%d", cat5
->s2en_bindless
.src3
);
644 fprintf(ctx
->out
, ", s#%d", cat5
->s2en_bindless
.src3
& 0xf);
647 if (info
[cat5
->opc
].tex
&& !use_a1
) {
648 fprintf(ctx
->out
, ", t#%d", cat5
->s2en_bindless
.src3
>> 4);
652 if (info
[cat5
->opc
].samp
)
653 fprintf(ctx
->out
, ", s#%d", cat5
->norm
.samp
);
654 if (info
[cat5
->opc
].tex
)
655 fprintf(ctx
->out
, ", t#%d", cat5
->norm
.tex
);
659 fprintf(ctx
->out
, ", ");
660 struct reginfo src
= { .reg
= (reg_t
)(cat5
->s2en_bindless
.src3
), .full
= bindless
};
661 print_src(ctx
, &src
);
665 fprintf(ctx
->out
, ", a1.x");
667 if (debug
& PRINT_VERBOSE
) {
668 if (cat5
->is_s2en_bindless
) {
669 if ((debug
& PRINT_VERBOSE
) && cat5
->s2en_bindless
.dummy1
)
670 fprintf(ctx
->out
, "\t{5: %x}", cat5
->s2en_bindless
.dummy1
);
672 if ((debug
& PRINT_VERBOSE
) && cat5
->norm
.dummy1
)
673 fprintf(ctx
->out
, "\t{5: %x}", cat5
->norm
.dummy1
);
678 static void print_instr_cat6_a3xx(struct disasm_ctx
*ctx
, instr_t
*instr
)
680 instr_cat6_t
*cat6
= &instr
->cat6
;
681 char sd
= 0, ss
= 0; /* dst/src address space */
683 struct reginfo dst
, src1
, src2
, ssbo
;
684 int src1off
= 0, dstoff
= 0;
686 memset(&dst
, 0, sizeof(dst
));
687 memset(&src1
, 0, sizeof(src1
));
688 memset(&src2
, 0, sizeof(src2
));
689 memset(&ssbo
, 0, sizeof(ssbo
));
691 switch (_OPC(6, cat6
->opc
)) {
694 dst
.full
= type_size(cat6
->type
) == 32;
695 src1
.full
= type_size(cat6
->type
) == 32;
696 src2
.full
= type_size(cat6
->type
) == 32;
709 dst
.full
= type_size(cat6
->type
) == 32;
710 src1
.full
= type_size(cat6
->type
) == 32;
711 src2
.full
= type_size(cat6
->type
) == 32;
714 dst
.full
= type_size(cat6
->type
) == 32;
720 switch (_OPC(6, cat6
->opc
)) {
724 fprintf(ctx
->out
, ".%dd", cat6
->ldgb
.d
+ 1);
727 fprintf(ctx
->out
, ".%s", cat6
->ldgb
.typed
? "typed" : "untyped");
728 fprintf(ctx
->out
, ".%dd", cat6
->ldgb
.d
+ 1);
729 fprintf(ctx
->out
, ".%s", type
[cat6
->type
]);
730 fprintf(ctx
->out
, ".%d", cat6
->ldgb
.type_size
+ 1);
734 fprintf(ctx
->out
, ".%s", cat6
->stgb
.typed
? "typed" : "untyped");
735 fprintf(ctx
->out
, ".%dd", cat6
->stgb
.d
+ 1);
736 fprintf(ctx
->out
, ".%s", type
[cat6
->type
]);
737 fprintf(ctx
->out
, ".%d", cat6
->stgb
.type_size
+ 1);
741 case OPC_ATOMIC_XCHG
:
744 case OPC_ATOMIC_CMPXCHG
:
750 ss
= cat6
->g
? 'g' : 'l';
751 fprintf(ctx
->out
, ".%s", cat6
->ldgb
.typed
? "typed" : "untyped");
752 fprintf(ctx
->out
, ".%dd", cat6
->ldgb
.d
+ 1);
753 fprintf(ctx
->out
, ".%s", type
[cat6
->type
]);
754 fprintf(ctx
->out
, ".%d", cat6
->ldgb
.type_size
+ 1);
755 fprintf(ctx
->out
, ".%c", ss
);
758 dst
.im
= cat6
->g
&& !cat6
->dst_off
;
759 fprintf(ctx
->out
, ".%s", type
[cat6
->type
]);
762 fprintf(ctx
->out
, " ");
764 switch (_OPC(6, cat6
->opc
)) {
805 if ((_OPC(6, cat6
->opc
) == OPC_STGB
) || (_OPC(6, cat6
->opc
) == OPC_STIB
)) {
808 memset(&src3
, 0, sizeof(src3
));
810 src1
.reg
= (reg_t
)(cat6
->stgb
.src1
);
811 src2
.reg
= (reg_t
)(cat6
->stgb
.src2
);
812 src2
.im
= cat6
->stgb
.src2_im
;
813 src3
.reg
= (reg_t
)(cat6
->stgb
.src3
);
814 src3
.im
= cat6
->stgb
.src3_im
;
817 fprintf(ctx
->out
, "g[%u], ", cat6
->stgb
.dst_ssbo
);
818 print_src(ctx
, &src1
);
819 fprintf(ctx
->out
, ", ");
820 print_src(ctx
, &src2
);
821 fprintf(ctx
->out
, ", ");
822 print_src(ctx
, &src3
);
824 if (debug
& PRINT_VERBOSE
)
825 fprintf(ctx
->out
, " (pad0=%x, pad3=%x)", cat6
->stgb
.pad0
, cat6
->stgb
.pad3
);
830 if (is_atomic(_OPC(6, cat6
->opc
))) {
832 src1
.reg
= (reg_t
)(cat6
->ldgb
.src1
);
833 src1
.im
= cat6
->ldgb
.src1_im
;
834 src2
.reg
= (reg_t
)(cat6
->ldgb
.src2
);
835 src2
.im
= cat6
->ldgb
.src2_im
;
836 dst
.reg
= (reg_t
)(cat6
->ldgb
.dst
);
838 print_src(ctx
, &dst
);
839 fprintf(ctx
->out
, ", ");
842 memset(&src3
, 0, sizeof(src3
));
844 src3
.reg
= (reg_t
)(cat6
->ldgb
.src3
);
847 /* For images, the ".typed" variant is used and src2 is
848 * the ivecN coordinates, ie ivec2 for 2d.
850 * For SSBOs, the ".untyped" variant is used and src2 is
851 * a simple dword offset.. src3 appears to be
852 * uvec2(offset * 4, 0). Not sure the point of that.
855 fprintf(ctx
->out
, "g[%u], ", cat6
->ldgb
.src_ssbo
);
856 print_src(ctx
, &src1
); /* value */
857 fprintf(ctx
->out
, ", ");
858 print_src(ctx
, &src2
); /* offset/coords */
859 fprintf(ctx
->out
, ", ");
860 print_src(ctx
, &src3
); /* 64b byte offset.. */
862 if (debug
& PRINT_VERBOSE
) {
863 fprintf(ctx
->out
, " (pad0=%x, mustbe0=%x)", cat6
->ldgb
.pad0
,
866 } else { /* ss == 'l' */
867 fprintf(ctx
->out
, "l[");
868 print_src(ctx
, &src1
); /* simple byte offset */
869 fprintf(ctx
->out
, "], ");
870 print_src(ctx
, &src2
); /* value */
872 if (debug
& PRINT_VERBOSE
) {
873 fprintf(ctx
->out
, " (src3=%x, pad0=%x, src_ssbo_im=%x, mustbe0=%x)",
874 cat6
->ldgb
.src3
, cat6
->ldgb
.pad0
,
875 cat6
->ldgb
.src_ssbo_im
, cat6
->ldgb
.mustbe0
);
880 } else if (_OPC(6, cat6
->opc
) == OPC_RESINFO
) {
881 dst
.reg
= (reg_t
)(cat6
->ldgb
.dst
);
882 ssbo
.reg
= (reg_t
)(cat6
->ldgb
.src_ssbo
);
883 ssbo
.im
= cat6
->ldgb
.src_ssbo_im
;
885 print_src(ctx
, &dst
);
886 fprintf(ctx
->out
, ", ");
888 fprintf(ctx
->out
, "g[");
889 print_src(ctx
, &ssbo
);
890 fprintf(ctx
->out
, "]");
893 } else if (_OPC(6, cat6
->opc
) == OPC_LDGB
) {
895 src1
.reg
= (reg_t
)(cat6
->ldgb
.src1
);
896 src1
.im
= cat6
->ldgb
.src1_im
;
897 src2
.reg
= (reg_t
)(cat6
->ldgb
.src2
);
898 src2
.im
= cat6
->ldgb
.src2_im
;
899 ssbo
.reg
= (reg_t
)(cat6
->ldgb
.src_ssbo
);
900 ssbo
.im
= cat6
->ldgb
.src_ssbo_im
;
901 dst
.reg
= (reg_t
)(cat6
->ldgb
.dst
);
903 print_src(ctx
, &dst
);
904 fprintf(ctx
->out
, ", ");
906 fprintf(ctx
->out
, "g[");
907 print_src(ctx
, &ssbo
);
908 fprintf(ctx
->out
, "], ");
910 print_src(ctx
, &src1
);
911 fprintf(ctx
->out
, ", ");
912 print_src(ctx
, &src2
);
914 if (debug
& PRINT_VERBOSE
)
915 fprintf(ctx
->out
, " (pad0=%x, ssbo_im=%x, mustbe0=%x)", cat6
->ldgb
.pad0
, cat6
->ldgb
.src_ssbo_im
, cat6
->ldgb
.mustbe0
);
918 } else if (_OPC(6, cat6
->opc
) == OPC_LDG
&& cat6
->a
.src1_im
&& cat6
->a
.src2_im
) {
921 memset(&src3
, 0, sizeof(src3
));
922 src1
.reg
= (reg_t
)(cat6
->a
.src1
);
923 src2
.reg
= (reg_t
)(cat6
->a
.src2
);
924 src2
.im
= cat6
->a
.src2_im
;
925 src3
.reg
= (reg_t
)(cat6
->a
.off
);
927 dst
.reg
= (reg_t
)(cat6
->d
.dst
);
929 print_src(ctx
, &dst
);
930 fprintf(ctx
->out
, ", g[");
931 print_src(ctx
, &src1
);
932 fprintf(ctx
->out
, "+");
933 print_src(ctx
, &src3
);
934 fprintf(ctx
->out
, "], ");
935 print_src(ctx
, &src2
);
940 dst
.reg
= (reg_t
)(cat6
->c
.dst
);
941 dstoff
= cat6
->c
.off
;
943 dst
.reg
= (reg_t
)(cat6
->d
.dst
);
947 src1
.reg
= (reg_t
)(cat6
->a
.src1
);
948 src1
.im
= cat6
->a
.src1_im
;
949 src2
.reg
= (reg_t
)(cat6
->a
.src2
);
950 src2
.im
= cat6
->a
.src2_im
;
951 src1off
= cat6
->a
.off
;
953 src1
.reg
= (reg_t
)(cat6
->b
.src1
);
954 src1
.im
= cat6
->b
.src1_im
;
955 src2
.reg
= (reg_t
)(cat6
->b
.src2
);
956 src2
.im
= cat6
->b
.src2_im
;
961 fprintf(ctx
->out
, "%c[", sd
);
962 /* note: dst might actually be a src (ie. address to store to) */
963 print_src(ctx
, &dst
);
964 if (cat6
->dst_off
&& cat6
->g
) {
965 struct reginfo dstoff_reg
= {
966 .reg
= (reg_t
) cat6
->c
.off
,
969 fprintf(ctx
->out
, "+");
970 print_src(ctx
, &dstoff_reg
);
972 fprintf(ctx
->out
, "%+d", dstoff
);
974 fprintf(ctx
->out
, "]");
975 fprintf(ctx
->out
, ", ");
979 fprintf(ctx
->out
, "%c[", ss
);
981 /* can have a larger than normal immed, so hack: */
983 fprintf(ctx
->out
, "%u", src1
.reg
.dummy13
);
985 print_src(ctx
, &src1
);
988 if (cat6
->src_off
&& cat6
->g
)
989 print_src(ctx
, &src2
);
991 fprintf(ctx
->out
, "%+d", src1off
);
993 fprintf(ctx
->out
, "]");
995 switch (_OPC(6, cat6
->opc
)) {
1000 fprintf(ctx
->out
, ", ");
1001 print_src(ctx
, &src2
);
1006 static void print_instr_cat6_a6xx(struct disasm_ctx
*ctx
, instr_t
*instr
)
1008 instr_cat6_a6xx_t
*cat6
= &instr
->cat6_a6xx
;
1009 struct reginfo src1
, src2
, ssbo
;
1010 uint32_t opc
= _OPC(6, cat6
->opc
);
1011 bool uses_type
= opc
!= OPC_LDC
;
1013 static const struct {
1017 } desc_features
[8] = {
1025 [CAT6_NONUNIFORM
] = {
1027 .name
= "nonuniform"
1029 [CAT6_BINDLESS_IMM
] = {
1033 [CAT6_BINDLESS_UNIFORM
] = {
1038 [CAT6_BINDLESS_NONUNIFORM
] = {
1041 .name
= "nonuniform"
1045 bool indirect_ssbo
= desc_features
[cat6
->desc_mode
].indirect
;
1046 bool bindless
= desc_features
[cat6
->desc_mode
].bindless
;
1047 bool type_full
= cat6
->type
!= TYPE_U16
;
1050 memset(&src1
, 0, sizeof(src1
));
1051 memset(&src2
, 0, sizeof(src2
));
1052 memset(&ssbo
, 0, sizeof(ssbo
));
1055 fprintf(ctx
->out
, ".%s", cat6
->typed
? "typed" : "untyped");
1056 fprintf(ctx
->out
, ".%dd", cat6
->d
+ 1);
1057 fprintf(ctx
->out
, ".%s", type
[cat6
->type
]);
1059 fprintf(ctx
->out
, ".offset%d", cat6
->d
);
1061 fprintf(ctx
->out
, ".%u", cat6
->type_size
+ 1);
1063 fprintf(ctx
->out
, ".%s", desc_features
[cat6
->desc_mode
].name
);
1065 fprintf(ctx
->out
, ".base%d", cat6
->base
);
1066 fprintf(ctx
->out
, " ");
1068 src2
.reg
= (reg_t
)(cat6
->src2
);
1069 src2
.full
= type_full
;
1070 print_src(ctx
, &src2
);
1071 fprintf(ctx
->out
, ", ");
1073 if (opc
!= OPC_RESINFO
) {
1074 src1
.reg
= (reg_t
)(cat6
->src1
);
1075 src1
.full
= true; // XXX
1076 print_src(ctx
, &src1
);
1077 fprintf(ctx
->out
, ", ");
1080 ssbo
.reg
= (reg_t
)(cat6
->ssbo
);
1081 ssbo
.im
= !indirect_ssbo
;
1083 print_src(ctx
, &ssbo
);
1085 if (debug
& PRINT_VERBOSE
) {
1086 fprintf(ctx
->out
, " (pad1=%x, pad2=%x, pad3=%x, pad4=%x, pad5=%x)",
1087 cat6
->pad1
, cat6
->pad2
, cat6
->pad3
, cat6
->pad4
, cat6
->pad5
);
1091 static void print_instr_cat6(struct disasm_ctx
*ctx
, instr_t
*instr
)
1093 if (!is_cat6_legacy(instr
, ctx
->gpu_id
)) {
1094 print_instr_cat6_a6xx(ctx
, instr
);
1095 if (debug
& PRINT_VERBOSE
)
1096 fprintf(ctx
->out
, " NEW");
1098 print_instr_cat6_a3xx(ctx
, instr
);
1099 if (debug
& PRINT_VERBOSE
)
1100 fprintf(ctx
->out
, " LEGACY");
1103 static void print_instr_cat7(struct disasm_ctx
*ctx
, instr_t
*instr
)
1105 instr_cat7_t
*cat7
= &instr
->cat7
;
1108 fprintf(ctx
->out
, ".g");
1110 fprintf(ctx
->out
, ".l");
1112 if (_OPC(7, cat7
->opc
) == OPC_FENCE
) {
1114 fprintf(ctx
->out
, ".r");
1116 fprintf(ctx
->out
, ".w");
1120 /* size of largest OPC field of all the instruction categories: */
1123 static const struct opc_info
{
1127 void (*print
)(struct disasm_ctx
*ctx
, instr_t
*instr
);
1128 } opcs
[1 << (3+NOPC_BITS
)] = {
1129 #define OPC(cat, opc, name) [(opc)] = { (cat), (opc), #name, print_instr_cat##cat }
1131 OPC(0, OPC_NOP
, nop
),
1133 OPC(0, OPC_JUMP
, jump
),
1134 OPC(0, OPC_CALL
, call
),
1135 OPC(0, OPC_RET
, ret
),
1136 OPC(0, OPC_KILL
, kill
),
1137 OPC(0, OPC_END
, end
),
1138 OPC(0, OPC_EMIT
, emit
),
1139 OPC(0, OPC_CUT
, cut
),
1140 OPC(0, OPC_CHMASK
, chmask
),
1141 OPC(0, OPC_CHSH
, chsh
),
1142 OPC(0, OPC_FLOW_REV
, flow_rev
),
1143 OPC(0, OPC_PREDT
, predt
),
1144 OPC(0, OPC_PREDF
, predf
),
1145 OPC(0, OPC_PREDE
, prede
),
1146 OPC(0, OPC_BKT
, bkt
),
1147 OPC(0, OPC_STKS
, stks
),
1148 OPC(0, OPC_STKR
, stkr
),
1149 OPC(0, OPC_XSET
, xset
),
1150 OPC(0, OPC_XCLR
, xclr
),
1151 OPC(0, OPC_GETONE
, getone
),
1152 OPC(0, OPC_DBG
, dbg
),
1153 OPC(0, OPC_SHPS
, shps
),
1154 OPC(0, OPC_SHPE
, shpe
),
1160 OPC(2, OPC_ADD_F
, add
.f
),
1161 OPC(2, OPC_MIN_F
, min
.f
),
1162 OPC(2, OPC_MAX_F
, max
.f
),
1163 OPC(2, OPC_MUL_F
, mul
.f
),
1164 OPC(2, OPC_SIGN_F
, sign
.f
),
1165 OPC(2, OPC_CMPS_F
, cmps
.f
),
1166 OPC(2, OPC_ABSNEG_F
, absneg
.f
),
1167 OPC(2, OPC_CMPV_F
, cmpv
.f
),
1168 OPC(2, OPC_FLOOR_F
, floor
.f
),
1169 OPC(2, OPC_CEIL_F
, ceil
.f
),
1170 OPC(2, OPC_RNDNE_F
, rndne
.f
),
1171 OPC(2, OPC_RNDAZ_F
, rndaz
.f
),
1172 OPC(2, OPC_TRUNC_F
, trunc
.f
),
1173 OPC(2, OPC_ADD_U
, add
.u
),
1174 OPC(2, OPC_ADD_S
, add
.s
),
1175 OPC(2, OPC_SUB_U
, sub
.u
),
1176 OPC(2, OPC_SUB_S
, sub
.s
),
1177 OPC(2, OPC_CMPS_U
, cmps
.u
),
1178 OPC(2, OPC_CMPS_S
, cmps
.s
),
1179 OPC(2, OPC_MIN_U
, min
.u
),
1180 OPC(2, OPC_MIN_S
, min
.s
),
1181 OPC(2, OPC_MAX_U
, max
.u
),
1182 OPC(2, OPC_MAX_S
, max
.s
),
1183 OPC(2, OPC_ABSNEG_S
, absneg
.s
),
1184 OPC(2, OPC_AND_B
, and.b
),
1185 OPC(2, OPC_OR_B
, or.b
),
1186 OPC(2, OPC_NOT_B
, not.b
),
1187 OPC(2, OPC_XOR_B
, xor.b
),
1188 OPC(2, OPC_CMPV_U
, cmpv
.u
),
1189 OPC(2, OPC_CMPV_S
, cmpv
.s
),
1190 OPC(2, OPC_MUL_U24
, mul
.u24
),
1191 OPC(2, OPC_MUL_S24
, mul
.s24
),
1192 OPC(2, OPC_MULL_U
, mull
.u
),
1193 OPC(2, OPC_BFREV_B
, bfrev
.b
),
1194 OPC(2, OPC_CLZ_S
, clz
.s
),
1195 OPC(2, OPC_CLZ_B
, clz
.b
),
1196 OPC(2, OPC_SHL_B
, shl
.b
),
1197 OPC(2, OPC_SHR_B
, shr
.b
),
1198 OPC(2, OPC_ASHR_B
, ashr
.b
),
1199 OPC(2, OPC_BARY_F
, bary
.f
),
1200 OPC(2, OPC_MGEN_B
, mgen
.b
),
1201 OPC(2, OPC_GETBIT_B
, getbit
.b
),
1202 OPC(2, OPC_SETRM
, setrm
),
1203 OPC(2, OPC_CBITS_B
, cbits
.b
),
1204 OPC(2, OPC_SHB
, shb
),
1205 OPC(2, OPC_MSAD
, msad
),
1208 OPC(3, OPC_MAD_U16
, mad
.u16
),
1209 OPC(3, OPC_MADSH_U16
, madsh
.u16
),
1210 OPC(3, OPC_MAD_S16
, mad
.s16
),
1211 OPC(3, OPC_MADSH_M16
, madsh
.m16
),
1212 OPC(3, OPC_MAD_U24
, mad
.u24
),
1213 OPC(3, OPC_MAD_S24
, mad
.s24
),
1214 OPC(3, OPC_MAD_F16
, mad
.f16
),
1215 OPC(3, OPC_MAD_F32
, mad
.f32
),
1216 OPC(3, OPC_SEL_B16
, sel
.b16
),
1217 OPC(3, OPC_SEL_B32
, sel
.b32
),
1218 OPC(3, OPC_SEL_S16
, sel
.s16
),
1219 OPC(3, OPC_SEL_S32
, sel
.s32
),
1220 OPC(3, OPC_SEL_F16
, sel
.f16
),
1221 OPC(3, OPC_SEL_F32
, sel
.f32
),
1222 OPC(3, OPC_SAD_S16
, sad
.s16
),
1223 OPC(3, OPC_SAD_S32
, sad
.s32
),
1226 OPC(4, OPC_RCP
, rcp
),
1227 OPC(4, OPC_RSQ
, rsq
),
1228 OPC(4, OPC_LOG2
, log2
),
1229 OPC(4, OPC_EXP2
, exp2
),
1230 OPC(4, OPC_SIN
, sin
),
1231 OPC(4, OPC_COS
, cos
),
1232 OPC(4, OPC_SQRT
, sqrt
),
1233 OPC(4, OPC_HRSQ
, hrsq
),
1234 OPC(4, OPC_HLOG2
, hlog2
),
1235 OPC(4, OPC_HEXP2
, hexp2
),
1238 OPC(5, OPC_ISAM
, isam
),
1239 OPC(5, OPC_ISAML
, isaml
),
1240 OPC(5, OPC_ISAMM
, isamm
),
1241 OPC(5, OPC_SAM
, sam
),
1242 OPC(5, OPC_SAMB
, samb
),
1243 OPC(5, OPC_SAML
, saml
),
1244 OPC(5, OPC_SAMGQ
, samgq
),
1245 OPC(5, OPC_GETLOD
, getlod
),
1246 OPC(5, OPC_CONV
, conv
),
1247 OPC(5, OPC_CONVM
, convm
),
1248 OPC(5, OPC_GETSIZE
, getsize
),
1249 OPC(5, OPC_GETBUF
, getbuf
),
1250 OPC(5, OPC_GETPOS
, getpos
),
1251 OPC(5, OPC_GETINFO
, getinfo
),
1252 OPC(5, OPC_DSX
, dsx
),
1253 OPC(5, OPC_DSY
, dsy
),
1254 OPC(5, OPC_GATHER4R
, gather4r
),
1255 OPC(5, OPC_GATHER4G
, gather4g
),
1256 OPC(5, OPC_GATHER4B
, gather4b
),
1257 OPC(5, OPC_GATHER4A
, gather4a
),
1258 OPC(5, OPC_SAMGP0
, samgp0
),
1259 OPC(5, OPC_SAMGP1
, samgp1
),
1260 OPC(5, OPC_SAMGP2
, samgp2
),
1261 OPC(5, OPC_SAMGP3
, samgp3
),
1262 OPC(5, OPC_DSXPP_1
, dsxpp
.1),
1263 OPC(5, OPC_DSYPP_1
, dsypp
.1),
1264 OPC(5, OPC_RGETPOS
, rgetpos
),
1265 OPC(5, OPC_RGETINFO
, rgetinfo
),
1269 OPC(6, OPC_LDG
, ldg
),
1270 OPC(6, OPC_LDL
, ldl
),
1271 OPC(6, OPC_LDP
, ldp
),
1272 OPC(6, OPC_STG
, stg
),
1273 OPC(6, OPC_STL
, stl
),
1274 OPC(6, OPC_STP
, stp
),
1275 OPC(6, OPC_LDIB
, ldib
),
1276 OPC(6, OPC_G2L
, g2l
),
1277 OPC(6, OPC_L2G
, l2g
),
1278 OPC(6, OPC_PREFETCH
, prefetch
),
1279 OPC(6, OPC_LDLW
, ldlw
),
1280 OPC(6, OPC_STLW
, stlw
),
1281 OPC(6, OPC_RESFMT
, resfmt
),
1282 OPC(6, OPC_RESINFO
, resinfo
),
1283 OPC(6, OPC_ATOMIC_ADD
, atomic
.add
),
1284 OPC(6, OPC_ATOMIC_SUB
, atomic
.sub
),
1285 OPC(6, OPC_ATOMIC_XCHG
, atomic
.xchg
),
1286 OPC(6, OPC_ATOMIC_INC
, atomic
.inc
),
1287 OPC(6, OPC_ATOMIC_DEC
, atomic
.dec
),
1288 OPC(6, OPC_ATOMIC_CMPXCHG
, atomic
.cmpxchg
),
1289 OPC(6, OPC_ATOMIC_MIN
, atomic
.min
),
1290 OPC(6, OPC_ATOMIC_MAX
, atomic
.max
),
1291 OPC(6, OPC_ATOMIC_AND
, atomic
.and),
1292 OPC(6, OPC_ATOMIC_OR
, atomic
.or),
1293 OPC(6, OPC_ATOMIC_XOR
, atomic
.xor),
1294 OPC(6, OPC_LDGB
, ldgb
),
1295 OPC(6, OPC_STGB
, stgb
),
1296 OPC(6, OPC_STIB
, stib
),
1297 OPC(6, OPC_LDC
, ldc
),
1298 OPC(6, OPC_LDLV
, ldlv
),
1300 OPC(7, OPC_BAR
, bar
),
1301 OPC(7, OPC_FENCE
, fence
),
1306 #define GETINFO(instr) (&(opcs[((instr)->opc_cat << NOPC_BITS) | instr_opc(instr, ctx->gpu_id)]))
1308 // XXX hack.. probably should move this table somewhere common:
1310 const char *ir3_instr_name(struct ir3_instruction
*instr
)
1312 if (opc_cat(instr
->opc
) == -1) return "??meta??";
1313 return opcs
[instr
->opc
].name
;
1316 static void print_single_instr(struct disasm_ctx
*ctx
, instr_t
*instr
)
1318 const char *name
= GETINFO(instr
)->name
;
1319 uint32_t opc
= instr_opc(instr
, ctx
->gpu_id
);
1322 fprintf(ctx
->out
, "%s", name
);
1323 GETINFO(instr
)->print(ctx
, instr
);
1325 fprintf(ctx
->out
, "unknown(%d,%d)", instr
->opc_cat
, opc
);
1327 switch (instr
->opc_cat
) {
1328 case 0: print_instr_cat0(ctx
, instr
); break;
1329 case 1: print_instr_cat1(ctx
, instr
); break;
1330 case 2: print_instr_cat2(ctx
, instr
); break;
1331 case 3: print_instr_cat3(ctx
, instr
); break;
1332 case 4: print_instr_cat4(ctx
, instr
); break;
1333 case 5: print_instr_cat5(ctx
, instr
); break;
1334 case 6: print_instr_cat6(ctx
, instr
); break;
1335 case 7: print_instr_cat7(ctx
, instr
); break;
1340 static bool print_instr(struct disasm_ctx
*ctx
, uint32_t *dwords
, int n
)
1342 instr_t
*instr
= (instr_t
*)dwords
;
1343 uint32_t opc
= instr_opc(instr
, ctx
->gpu_id
);
1345 unsigned cycles
= ctx
->instructions
;
1347 if (debug
& PRINT_VERBOSE
) {
1348 fprintf(ctx
->out
, "%s%04d:%04d[%08xx_%08xx] ", levels
[ctx
->level
],
1349 n
, cycles
++, dwords
[1], dwords
[0]);
1352 /* NOTE: order flags are printed is a bit fugly.. but for now I
1353 * try to match the order in llvm-a3xx disassembler for easy
1357 ctx
->repeat
= instr_repeat(instr
);
1358 ctx
->instructions
+= 1 + ctx
->repeat
;
1361 fprintf(ctx
->out
, "(sy)");
1363 if (instr
->ss
&& ((instr
->opc_cat
<= 4) || (instr
->opc_cat
== 7))) {
1364 fprintf(ctx
->out
, "(ss)");
1367 fprintf(ctx
->out
, "(jp)");
1368 if ((instr
->opc_cat
== 0) && instr
->cat0
.eq
)
1369 fprintf(ctx
->out
, "(eq)");
1370 if (instr_sat(instr
))
1371 fprintf(ctx
->out
, "(sat)");
1373 fprintf(ctx
->out
, "(rpt%d)", ctx
->repeat
);
1374 else if ((instr
->opc_cat
== 2) && (instr
->cat2
.src1_r
|| instr
->cat2
.src2_r
))
1375 nop
= (instr
->cat2
.src2_r
* 2) + instr
->cat2
.src1_r
;
1376 else if ((instr
->opc_cat
== 3) && (instr
->cat3
.src1_r
|| instr
->cat3
.src2_r
))
1377 nop
= (instr
->cat3
.src2_r
* 2) + instr
->cat3
.src1_r
;
1378 ctx
->instructions
+= nop
;
1380 fprintf(ctx
->out
, "(nop%d) ", nop
);
1382 if (instr
->ul
&& ((2 <= instr
->opc_cat
) && (instr
->opc_cat
<= 4)))
1383 fprintf(ctx
->out
, "(ul)");
1385 print_single_instr(ctx
, instr
);
1386 fprintf(ctx
->out
, "\n");
1388 if ((instr
->opc_cat
<= 4) && (debug
& EXPAND_REPEAT
)) {
1390 for (i
= 0; i
< nop
; i
++) {
1391 if (debug
& PRINT_VERBOSE
) {
1392 fprintf(ctx
->out
, "%s%04d:%04d[ ] ",
1393 levels
[ctx
->level
], n
, cycles
++);
1395 fprintf(ctx
->out
, "nop\n");
1397 for (i
= 0; i
< ctx
->repeat
; i
++) {
1398 ctx
->repeatidx
= i
+ 1;
1399 if (debug
& PRINT_VERBOSE
) {
1400 fprintf(ctx
->out
, "%s%04d:%04d[ ] ",
1401 levels
[ctx
->level
], n
, cycles
++);
1403 print_single_instr(ctx
, instr
);
1404 fprintf(ctx
->out
, "\n");
1409 return (instr
->opc_cat
== 0) && (opc
== OPC_END
);
1412 int disasm_a3xx(uint32_t *dwords
, int sizedwords
, int level
, FILE *out
, unsigned gpu_id
)
1414 struct disasm_ctx ctx
;
1418 assert((sizedwords
% 2) == 0);
1420 memset(&ctx
, 0, sizeof(ctx
));
1423 ctx
.gpu_id
= gpu_id
;
1425 for (i
= 0; i
< sizedwords
; i
+= 2) {
1426 print_instr(&ctx
, &dwords
[i
], i
/2);
1427 if (dwords
[i
] == 0 && dwords
[i
+ 1] == 0)