xref: /aosp_15_r20/external/mesa3d/src/freedreno/afuc/disasm.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker  * Copyright © 2017 Rob Clark <[email protected]>
3*61046927SAndroid Build Coastguard Worker  * SPDX-License-Identifier: MIT
4*61046927SAndroid Build Coastguard Worker  */
5*61046927SAndroid Build Coastguard Worker 
6*61046927SAndroid Build Coastguard Worker #include <assert.h>
7*61046927SAndroid Build Coastguard Worker #include <err.h>
8*61046927SAndroid Build Coastguard Worker #include <fcntl.h>
9*61046927SAndroid Build Coastguard Worker #include <getopt.h>
10*61046927SAndroid Build Coastguard Worker #include <stdarg.h>
11*61046927SAndroid Build Coastguard Worker #include <stdbool.h>
12*61046927SAndroid Build Coastguard Worker #include <stdint.h>
13*61046927SAndroid Build Coastguard Worker #include <stdio.h>
14*61046927SAndroid Build Coastguard Worker #include <stdlib.h>
15*61046927SAndroid Build Coastguard Worker #include <string.h>
16*61046927SAndroid Build Coastguard Worker #include <unistd.h>
17*61046927SAndroid Build Coastguard Worker 
18*61046927SAndroid Build Coastguard Worker #include "util/os_file.h"
19*61046927SAndroid Build Coastguard Worker 
20*61046927SAndroid Build Coastguard Worker #include "compiler/isaspec/isaspec.h"
21*61046927SAndroid Build Coastguard Worker 
22*61046927SAndroid Build Coastguard Worker #include "freedreno_pm4.h"
23*61046927SAndroid Build Coastguard Worker 
24*61046927SAndroid Build Coastguard Worker #include "afuc.h"
25*61046927SAndroid Build Coastguard Worker #include "afuc-isa.h"
26*61046927SAndroid Build Coastguard Worker #include "util.h"
27*61046927SAndroid Build Coastguard Worker #include "emu.h"
28*61046927SAndroid Build Coastguard Worker 
29*61046927SAndroid Build Coastguard Worker int gpuver;
30*61046927SAndroid Build Coastguard Worker 
31*61046927SAndroid Build Coastguard Worker /* non-verbose mode should output something suitable to feed back into
32*61046927SAndroid Build Coastguard Worker  * assembler.. verbose mode has additional output useful for debugging
33*61046927SAndroid Build Coastguard Worker  * (like unexpected bits that are set)
34*61046927SAndroid Build Coastguard Worker  */
35*61046927SAndroid Build Coastguard Worker static bool verbose = false;
36*61046927SAndroid Build Coastguard Worker 
37*61046927SAndroid Build Coastguard Worker /* emulator mode: */
38*61046927SAndroid Build Coastguard Worker static bool emulator = false;
39*61046927SAndroid Build Coastguard Worker 
40*61046927SAndroid Build Coastguard Worker #define printerr(fmt, ...) afuc_printc(AFUC_ERR, fmt, ##__VA_ARGS__)
41*61046927SAndroid Build Coastguard Worker #define printlbl(fmt, ...) afuc_printc(AFUC_LBL, fmt, ##__VA_ARGS__)
42*61046927SAndroid Build Coastguard Worker 
43*61046927SAndroid Build Coastguard Worker static const char *
getpm4(uint32_t id)44*61046927SAndroid Build Coastguard Worker getpm4(uint32_t id)
45*61046927SAndroid Build Coastguard Worker {
46*61046927SAndroid Build Coastguard Worker    return afuc_pm_id_name(id);
47*61046927SAndroid Build Coastguard Worker }
48*61046927SAndroid Build Coastguard Worker 
49*61046927SAndroid Build Coastguard Worker static void
print_gpu_reg(FILE * out,uint32_t regbase)50*61046927SAndroid Build Coastguard Worker print_gpu_reg(FILE *out, uint32_t regbase)
51*61046927SAndroid Build Coastguard Worker {
52*61046927SAndroid Build Coastguard Worker    if (regbase < 0x100)
53*61046927SAndroid Build Coastguard Worker       return;
54*61046927SAndroid Build Coastguard Worker 
55*61046927SAndroid Build Coastguard Worker    char *name = afuc_gpu_reg_name(regbase);
56*61046927SAndroid Build Coastguard Worker    if (name) {
57*61046927SAndroid Build Coastguard Worker       fprintf(out, "\t; %s", name);
58*61046927SAndroid Build Coastguard Worker       free(name);
59*61046927SAndroid Build Coastguard Worker    }
60*61046927SAndroid Build Coastguard Worker }
61*61046927SAndroid Build Coastguard Worker 
62*61046927SAndroid Build Coastguard Worker void
print_control_reg(uint32_t id)63*61046927SAndroid Build Coastguard Worker print_control_reg(uint32_t id)
64*61046927SAndroid Build Coastguard Worker {
65*61046927SAndroid Build Coastguard Worker    char *name = afuc_control_reg_name(id);
66*61046927SAndroid Build Coastguard Worker    if (name) {
67*61046927SAndroid Build Coastguard Worker       printf("@%s", name);
68*61046927SAndroid Build Coastguard Worker       free(name);
69*61046927SAndroid Build Coastguard Worker    } else {
70*61046927SAndroid Build Coastguard Worker       printf("0x%03x", id);
71*61046927SAndroid Build Coastguard Worker    }
72*61046927SAndroid Build Coastguard Worker }
73*61046927SAndroid Build Coastguard Worker 
74*61046927SAndroid Build Coastguard Worker void
print_sqe_reg(uint32_t id)75*61046927SAndroid Build Coastguard Worker print_sqe_reg(uint32_t id)
76*61046927SAndroid Build Coastguard Worker {
77*61046927SAndroid Build Coastguard Worker    char *name = afuc_sqe_reg_name(id);
78*61046927SAndroid Build Coastguard Worker    if (name) {
79*61046927SAndroid Build Coastguard Worker       printf("@%s", name);
80*61046927SAndroid Build Coastguard Worker       free(name);
81*61046927SAndroid Build Coastguard Worker    } else {
82*61046927SAndroid Build Coastguard Worker       printf("0x%03x", id);
83*61046927SAndroid Build Coastguard Worker    }
84*61046927SAndroid Build Coastguard Worker }
85*61046927SAndroid Build Coastguard Worker 
86*61046927SAndroid Build Coastguard Worker void
print_pipe_reg(uint32_t id)87*61046927SAndroid Build Coastguard Worker print_pipe_reg(uint32_t id)
88*61046927SAndroid Build Coastguard Worker {
89*61046927SAndroid Build Coastguard Worker    char *name = afuc_pipe_reg_name(id);
90*61046927SAndroid Build Coastguard Worker    if (name) {
91*61046927SAndroid Build Coastguard Worker       printf("|%s", name);
92*61046927SAndroid Build Coastguard Worker       free(name);
93*61046927SAndroid Build Coastguard Worker    } else {
94*61046927SAndroid Build Coastguard Worker       printf("0x%03x", id);
95*61046927SAndroid Build Coastguard Worker    }
96*61046927SAndroid Build Coastguard Worker }
97*61046927SAndroid Build Coastguard Worker 
98*61046927SAndroid Build Coastguard Worker struct decode_state {
99*61046927SAndroid Build Coastguard Worker    uint32_t immed;
100*61046927SAndroid Build Coastguard Worker    uint8_t shift;
101*61046927SAndroid Build Coastguard Worker    bool has_immed;
102*61046927SAndroid Build Coastguard Worker    bool dst_is_addr;
103*61046927SAndroid Build Coastguard Worker };
104*61046927SAndroid Build Coastguard Worker 
105*61046927SAndroid Build Coastguard Worker static void
field_print_cb(struct isa_print_state * state,const char * field_name,uint64_t val)106*61046927SAndroid Build Coastguard Worker field_print_cb(struct isa_print_state *state, const char *field_name, uint64_t val)
107*61046927SAndroid Build Coastguard Worker {
108*61046927SAndroid Build Coastguard Worker    if (!strcmp(field_name, "CONTROLREG")) {
109*61046927SAndroid Build Coastguard Worker       char *name = afuc_control_reg_name(val);
110*61046927SAndroid Build Coastguard Worker       if (name) {
111*61046927SAndroid Build Coastguard Worker          isa_print(state, "@%s", name);
112*61046927SAndroid Build Coastguard Worker          free(name);
113*61046927SAndroid Build Coastguard Worker       } else {
114*61046927SAndroid Build Coastguard Worker          isa_print(state, "0x%03x", (unsigned)val);
115*61046927SAndroid Build Coastguard Worker       }
116*61046927SAndroid Build Coastguard Worker    } else if (!strcmp(field_name, "SQEREG")) {
117*61046927SAndroid Build Coastguard Worker       char *name = afuc_sqe_reg_name(val);
118*61046927SAndroid Build Coastguard Worker       if (name) {
119*61046927SAndroid Build Coastguard Worker          isa_print(state, "%%%s", name);
120*61046927SAndroid Build Coastguard Worker          free(name);
121*61046927SAndroid Build Coastguard Worker       } else {
122*61046927SAndroid Build Coastguard Worker          isa_print(state, "0x%03x", (unsigned)val);
123*61046927SAndroid Build Coastguard Worker       }
124*61046927SAndroid Build Coastguard Worker    }
125*61046927SAndroid Build Coastguard Worker }
126*61046927SAndroid Build Coastguard Worker 
127*61046927SAndroid Build Coastguard Worker static void
pre_instr_cb(void * data,unsigned n,void * instr)128*61046927SAndroid Build Coastguard Worker pre_instr_cb(void *data, unsigned n, void *instr)
129*61046927SAndroid Build Coastguard Worker {
130*61046927SAndroid Build Coastguard Worker    struct decode_state *state = data;
131*61046927SAndroid Build Coastguard Worker    state->has_immed = state->dst_is_addr = false;
132*61046927SAndroid Build Coastguard Worker    state->shift = 0;
133*61046927SAndroid Build Coastguard Worker 
134*61046927SAndroid Build Coastguard Worker    if (verbose)
135*61046927SAndroid Build Coastguard Worker       printf("\t%04x: %08x  ", n, *(uint32_t *)instr);
136*61046927SAndroid Build Coastguard Worker }
137*61046927SAndroid Build Coastguard Worker 
138*61046927SAndroid Build Coastguard Worker static void
field_cb(void * data,const char * field_name,struct isa_decode_value * val)139*61046927SAndroid Build Coastguard Worker field_cb(void *data, const char *field_name, struct isa_decode_value *val)
140*61046927SAndroid Build Coastguard Worker {
141*61046927SAndroid Build Coastguard Worker    struct decode_state *state = data;
142*61046927SAndroid Build Coastguard Worker 
143*61046927SAndroid Build Coastguard Worker    if (!strcmp(field_name, "RIMMED")) {
144*61046927SAndroid Build Coastguard Worker       state->immed = val->num;
145*61046927SAndroid Build Coastguard Worker       state->has_immed = true;
146*61046927SAndroid Build Coastguard Worker    }
147*61046927SAndroid Build Coastguard Worker 
148*61046927SAndroid Build Coastguard Worker    if (!strcmp(field_name, "SHIFT")) {
149*61046927SAndroid Build Coastguard Worker       state->shift = val->num;
150*61046927SAndroid Build Coastguard Worker    }
151*61046927SAndroid Build Coastguard Worker 
152*61046927SAndroid Build Coastguard Worker    if (!strcmp(field_name, "DST")) {
153*61046927SAndroid Build Coastguard Worker       if (val->num == REG_ADDR)
154*61046927SAndroid Build Coastguard Worker          state->dst_is_addr = true;
155*61046927SAndroid Build Coastguard Worker    }
156*61046927SAndroid Build Coastguard Worker }
157*61046927SAndroid Build Coastguard Worker 
158*61046927SAndroid Build Coastguard Worker static void
post_instr_cb(void * data,unsigned n,void * instr)159*61046927SAndroid Build Coastguard Worker post_instr_cb(void *data, unsigned n, void *instr)
160*61046927SAndroid Build Coastguard Worker {
161*61046927SAndroid Build Coastguard Worker    struct decode_state *state = data;
162*61046927SAndroid Build Coastguard Worker 
163*61046927SAndroid Build Coastguard Worker    if (state->has_immed) {
164*61046927SAndroid Build Coastguard Worker       uint32_t immed = state->immed << state->shift;
165*61046927SAndroid Build Coastguard Worker       if (state->dst_is_addr && state->shift >= 16) {
166*61046927SAndroid Build Coastguard Worker          immed &= ~0x40000; /* b18 disables auto-increment of address */
167*61046927SAndroid Build Coastguard Worker          if ((immed & 0x00ffffff) == 0) {
168*61046927SAndroid Build Coastguard Worker             printf("\t; ");
169*61046927SAndroid Build Coastguard Worker             print_pipe_reg(immed >> 24);
170*61046927SAndroid Build Coastguard Worker          }
171*61046927SAndroid Build Coastguard Worker       } else {
172*61046927SAndroid Build Coastguard Worker          print_gpu_reg(stdout, immed);
173*61046927SAndroid Build Coastguard Worker       }
174*61046927SAndroid Build Coastguard Worker    }
175*61046927SAndroid Build Coastguard Worker }
176*61046927SAndroid Build Coastguard Worker 
177*61046927SAndroid Build Coastguard Worker uint32_t jumptbl_offset = ~0;
178*61046927SAndroid Build Coastguard Worker 
179*61046927SAndroid Build Coastguard Worker /* Assume that instructions that don't match are raw data */
180*61046927SAndroid Build Coastguard Worker static void
no_match(FILE * out,const BITSET_WORD * bitset,size_t size)181*61046927SAndroid Build Coastguard Worker no_match(FILE *out, const BITSET_WORD *bitset, size_t size)
182*61046927SAndroid Build Coastguard Worker {
183*61046927SAndroid Build Coastguard Worker    if (jumptbl_offset != ~0 && bitset[0] == afuc_nop_literal(jumptbl_offset, gpuver)) {
184*61046927SAndroid Build Coastguard Worker       fprintf(out, "[#jumptbl]\n");
185*61046927SAndroid Build Coastguard Worker    } else {
186*61046927SAndroid Build Coastguard Worker       fprintf(out, "[%08x]", bitset[0]);
187*61046927SAndroid Build Coastguard Worker       print_gpu_reg(out, bitset[0]);
188*61046927SAndroid Build Coastguard Worker       fprintf(out, "\n");
189*61046927SAndroid Build Coastguard Worker    }
190*61046927SAndroid Build Coastguard Worker }
191*61046927SAndroid Build Coastguard Worker 
192*61046927SAndroid Build Coastguard Worker static void
get_decode_options(struct isa_decode_options * options)193*61046927SAndroid Build Coastguard Worker get_decode_options(struct isa_decode_options *options)
194*61046927SAndroid Build Coastguard Worker {
195*61046927SAndroid Build Coastguard Worker    *options = (struct isa_decode_options) {
196*61046927SAndroid Build Coastguard Worker       .gpu_id = gpuver,
197*61046927SAndroid Build Coastguard Worker       .branch_labels = true,
198*61046927SAndroid Build Coastguard Worker       .field_cb = field_cb,
199*61046927SAndroid Build Coastguard Worker       .field_print_cb = field_print_cb,
200*61046927SAndroid Build Coastguard Worker       .pre_instr_cb = pre_instr_cb,
201*61046927SAndroid Build Coastguard Worker       .post_instr_cb = post_instr_cb,
202*61046927SAndroid Build Coastguard Worker       .no_match_cb = no_match,
203*61046927SAndroid Build Coastguard Worker    };
204*61046927SAndroid Build Coastguard Worker }
205*61046927SAndroid Build Coastguard Worker 
206*61046927SAndroid Build Coastguard Worker static void
disasm_instr(struct isa_decode_options * options,uint32_t * instrs,unsigned pc)207*61046927SAndroid Build Coastguard Worker disasm_instr(struct isa_decode_options *options, uint32_t *instrs, unsigned pc)
208*61046927SAndroid Build Coastguard Worker {
209*61046927SAndroid Build Coastguard Worker    afuc_isa_disasm(&instrs[pc], 4, stdout, options);
210*61046927SAndroid Build Coastguard Worker }
211*61046927SAndroid Build Coastguard Worker 
212*61046927SAndroid Build Coastguard Worker static void
setup_packet_table(struct isa_decode_options * options,uint32_t * jmptbl,uint32_t sizedwords)213*61046927SAndroid Build Coastguard Worker setup_packet_table(struct isa_decode_options *options,
214*61046927SAndroid Build Coastguard Worker                    uint32_t *jmptbl, uint32_t sizedwords)
215*61046927SAndroid Build Coastguard Worker {
216*61046927SAndroid Build Coastguard Worker    struct isa_entrypoint *entrypoints = malloc(sizedwords * sizeof(struct isa_entrypoint));
217*61046927SAndroid Build Coastguard Worker 
218*61046927SAndroid Build Coastguard Worker    for (unsigned i = 0; i < sizedwords; i++) {
219*61046927SAndroid Build Coastguard Worker       entrypoints[i].offset = jmptbl[i];
220*61046927SAndroid Build Coastguard Worker       unsigned n = i; // + CP_NOP;
221*61046927SAndroid Build Coastguard Worker       entrypoints[i].name = afuc_pm_id_name(n);
222*61046927SAndroid Build Coastguard Worker       if (!entrypoints[i].name) {
223*61046927SAndroid Build Coastguard Worker          char *name;
224*61046927SAndroid Build Coastguard Worker          asprintf(&name, "UNKN%d", n);
225*61046927SAndroid Build Coastguard Worker          entrypoints[i].name = name;
226*61046927SAndroid Build Coastguard Worker       }
227*61046927SAndroid Build Coastguard Worker    }
228*61046927SAndroid Build Coastguard Worker 
229*61046927SAndroid Build Coastguard Worker    options->entrypoints = entrypoints;
230*61046927SAndroid Build Coastguard Worker    options->entrypoint_count = sizedwords;
231*61046927SAndroid Build Coastguard Worker }
232*61046927SAndroid Build Coastguard Worker 
233*61046927SAndroid Build Coastguard Worker static uint32_t
find_jump_table(uint32_t * instrs,uint32_t sizedwords,uint32_t * jmptbl,uint32_t jmptbl_size)234*61046927SAndroid Build Coastguard Worker find_jump_table(uint32_t *instrs, uint32_t sizedwords,
235*61046927SAndroid Build Coastguard Worker                 uint32_t *jmptbl, uint32_t jmptbl_size)
236*61046927SAndroid Build Coastguard Worker {
237*61046927SAndroid Build Coastguard Worker    for (unsigned i = 0; i <= sizedwords - jmptbl_size; i++) {
238*61046927SAndroid Build Coastguard Worker       bool found = true;
239*61046927SAndroid Build Coastguard Worker       for (unsigned j = 0; j < jmptbl_size; j++) {
240*61046927SAndroid Build Coastguard Worker          if (instrs[i + j] != jmptbl[j]) {
241*61046927SAndroid Build Coastguard Worker             found = false;
242*61046927SAndroid Build Coastguard Worker             break;
243*61046927SAndroid Build Coastguard Worker          }
244*61046927SAndroid Build Coastguard Worker       }
245*61046927SAndroid Build Coastguard Worker       if (found)
246*61046927SAndroid Build Coastguard Worker          return i;
247*61046927SAndroid Build Coastguard Worker    }
248*61046927SAndroid Build Coastguard Worker 
249*61046927SAndroid Build Coastguard Worker    return ~0;
250*61046927SAndroid Build Coastguard Worker }
251*61046927SAndroid Build Coastguard Worker 
252*61046927SAndroid Build Coastguard Worker static void
disasm(struct emu * emu)253*61046927SAndroid Build Coastguard Worker disasm(struct emu *emu)
254*61046927SAndroid Build Coastguard Worker {
255*61046927SAndroid Build Coastguard Worker    uint32_t sizedwords = emu->sizedwords;
256*61046927SAndroid Build Coastguard Worker    uint32_t lpac_offset = 0, bv_offset = 0;
257*61046927SAndroid Build Coastguard Worker 
258*61046927SAndroid Build Coastguard Worker    EMU_GPU_REG(CP_SQE_INSTR_BASE);
259*61046927SAndroid Build Coastguard Worker    EMU_GPU_REG(CP_LPAC_SQE_INSTR_BASE);
260*61046927SAndroid Build Coastguard Worker    EMU_CONTROL_REG(BV_INSTR_BASE);
261*61046927SAndroid Build Coastguard Worker    EMU_CONTROL_REG(LPAC_INSTR_BASE);
262*61046927SAndroid Build Coastguard Worker 
263*61046927SAndroid Build Coastguard Worker    emu_init(emu);
264*61046927SAndroid Build Coastguard Worker    emu->processor = EMU_PROC_SQE;
265*61046927SAndroid Build Coastguard Worker 
266*61046927SAndroid Build Coastguard Worker    struct isa_decode_options options;
267*61046927SAndroid Build Coastguard Worker    struct decode_state state;
268*61046927SAndroid Build Coastguard Worker    get_decode_options(&options);
269*61046927SAndroid Build Coastguard Worker    options.cbdata = &state;
270*61046927SAndroid Build Coastguard Worker 
271*61046927SAndroid Build Coastguard Worker #ifdef BOOTSTRAP_DEBUG
272*61046927SAndroid Build Coastguard Worker    while (true) {
273*61046927SAndroid Build Coastguard Worker       disasm_instr(&options, emu->instrs, emu->gpr_regs.pc);
274*61046927SAndroid Build Coastguard Worker       emu_step(emu);
275*61046927SAndroid Build Coastguard Worker    }
276*61046927SAndroid Build Coastguard Worker #endif
277*61046927SAndroid Build Coastguard Worker 
278*61046927SAndroid Build Coastguard Worker    emu_run_bootstrap(emu);
279*61046927SAndroid Build Coastguard Worker 
280*61046927SAndroid Build Coastguard Worker    /* Figure out if we have BV/LPAC SQE appended: */
281*61046927SAndroid Build Coastguard Worker    if (gpuver >= 7) {
282*61046927SAndroid Build Coastguard Worker       bv_offset = emu_get_reg64(emu, &BV_INSTR_BASE) -
283*61046927SAndroid Build Coastguard Worker          emu_get_reg64(emu, &CP_SQE_INSTR_BASE);
284*61046927SAndroid Build Coastguard Worker       bv_offset /= 4;
285*61046927SAndroid Build Coastguard Worker       lpac_offset = emu_get_reg64(emu, &LPAC_INSTR_BASE) -
286*61046927SAndroid Build Coastguard Worker          emu_get_reg64(emu, &CP_SQE_INSTR_BASE);
287*61046927SAndroid Build Coastguard Worker       lpac_offset /= 4;
288*61046927SAndroid Build Coastguard Worker       sizedwords = MIN2(bv_offset, lpac_offset);
289*61046927SAndroid Build Coastguard Worker    } else {
290*61046927SAndroid Build Coastguard Worker       if (emu_get_reg64(emu, &CP_LPAC_SQE_INSTR_BASE)) {
291*61046927SAndroid Build Coastguard Worker          lpac_offset = emu_get_reg64(emu, &CP_LPAC_SQE_INSTR_BASE) -
292*61046927SAndroid Build Coastguard Worker                emu_get_reg64(emu, &CP_SQE_INSTR_BASE);
293*61046927SAndroid Build Coastguard Worker          lpac_offset /= 4;
294*61046927SAndroid Build Coastguard Worker          sizedwords = lpac_offset;
295*61046927SAndroid Build Coastguard Worker       }
296*61046927SAndroid Build Coastguard Worker    }
297*61046927SAndroid Build Coastguard Worker 
298*61046927SAndroid Build Coastguard Worker    setup_packet_table(&options, emu->jmptbl, ARRAY_SIZE(emu->jmptbl));
299*61046927SAndroid Build Coastguard Worker 
300*61046927SAndroid Build Coastguard Worker    jumptbl_offset = find_jump_table(emu->instrs, sizedwords, emu->jmptbl,
301*61046927SAndroid Build Coastguard Worker                                     ARRAY_SIZE(emu->jmptbl));
302*61046927SAndroid Build Coastguard Worker 
303*61046927SAndroid Build Coastguard Worker    /* TODO add option to emulate LPAC SQE instead: */
304*61046927SAndroid Build Coastguard Worker    if (emulator) {
305*61046927SAndroid Build Coastguard Worker       /* Start from clean slate: */
306*61046927SAndroid Build Coastguard Worker       emu_fini(emu);
307*61046927SAndroid Build Coastguard Worker       emu_init(emu);
308*61046927SAndroid Build Coastguard Worker 
309*61046927SAndroid Build Coastguard Worker       while (true) {
310*61046927SAndroid Build Coastguard Worker          disasm_instr(&options, emu->instrs, emu->gpr_regs.pc);
311*61046927SAndroid Build Coastguard Worker          emu_step(emu);
312*61046927SAndroid Build Coastguard Worker       }
313*61046927SAndroid Build Coastguard Worker    }
314*61046927SAndroid Build Coastguard Worker 
315*61046927SAndroid Build Coastguard Worker    /* print instructions: */
316*61046927SAndroid Build Coastguard Worker    afuc_isa_disasm(emu->instrs, MIN2(sizedwords, jumptbl_offset) * 4, stdout, &options);
317*61046927SAndroid Build Coastguard Worker 
318*61046927SAndroid Build Coastguard Worker    /* print jump table */
319*61046927SAndroid Build Coastguard Worker    if (jumptbl_offset != ~0) {
320*61046927SAndroid Build Coastguard Worker       if (gpuver >= 7) {
321*61046927SAndroid Build Coastguard Worker          /* The BV/LPAC microcode must be aligned to 32 bytes. On a7xx, by
322*61046927SAndroid Build Coastguard Worker           * convention the firmware aligns the jumptable preceding it instead
323*61046927SAndroid Build Coastguard Worker           * of the microcode itself, with nop instructions. Insert this
324*61046927SAndroid Build Coastguard Worker           * directive to make sure that it stays aligned when reassembling
325*61046927SAndroid Build Coastguard Worker           * even if the user modifies the BR microcode.
326*61046927SAndroid Build Coastguard Worker           */
327*61046927SAndroid Build Coastguard Worker          printf(".align 32\n");
328*61046927SAndroid Build Coastguard Worker       }
329*61046927SAndroid Build Coastguard Worker       printf("jumptbl:\n");
330*61046927SAndroid Build Coastguard Worker       printf(".jumptbl\n");
331*61046927SAndroid Build Coastguard Worker 
332*61046927SAndroid Build Coastguard Worker       if (jumptbl_offset + ARRAY_SIZE(emu->jmptbl) != sizedwords) {
333*61046927SAndroid Build Coastguard Worker          for (unsigned i = jumptbl_offset + ARRAY_SIZE(emu->jmptbl); i < sizedwords; i++)
334*61046927SAndroid Build Coastguard Worker             printf("[%08x]\n", emu->instrs[i]);
335*61046927SAndroid Build Coastguard Worker       }
336*61046927SAndroid Build Coastguard Worker    }
337*61046927SAndroid Build Coastguard Worker 
338*61046927SAndroid Build Coastguard Worker    if (bv_offset) {
339*61046927SAndroid Build Coastguard Worker       printf("\n.section BV\n");
340*61046927SAndroid Build Coastguard Worker       printf(";\n");
341*61046927SAndroid Build Coastguard Worker       printf("; BV microcode:\n");
342*61046927SAndroid Build Coastguard Worker       printf(";\n");
343*61046927SAndroid Build Coastguard Worker 
344*61046927SAndroid Build Coastguard Worker       emu_fini(emu);
345*61046927SAndroid Build Coastguard Worker 
346*61046927SAndroid Build Coastguard Worker       emu->processor = EMU_PROC_BV;
347*61046927SAndroid Build Coastguard Worker       emu->instrs += bv_offset;
348*61046927SAndroid Build Coastguard Worker       emu->sizedwords -= bv_offset;
349*61046927SAndroid Build Coastguard Worker 
350*61046927SAndroid Build Coastguard Worker       emu_init(emu);
351*61046927SAndroid Build Coastguard Worker       emu_run_bootstrap(emu);
352*61046927SAndroid Build Coastguard Worker 
353*61046927SAndroid Build Coastguard Worker       setup_packet_table(&options, emu->jmptbl, ARRAY_SIZE(emu->jmptbl));
354*61046927SAndroid Build Coastguard Worker 
355*61046927SAndroid Build Coastguard Worker       uint32_t sizedwords = lpac_offset - bv_offset;
356*61046927SAndroid Build Coastguard Worker 
357*61046927SAndroid Build Coastguard Worker       jumptbl_offset = find_jump_table(emu->instrs, sizedwords, emu->jmptbl,
358*61046927SAndroid Build Coastguard Worker                                        ARRAY_SIZE(emu->jmptbl));
359*61046927SAndroid Build Coastguard Worker 
360*61046927SAndroid Build Coastguard Worker       afuc_isa_disasm(emu->instrs, MIN2(sizedwords, jumptbl_offset) * 4, stdout, &options);
361*61046927SAndroid Build Coastguard Worker 
362*61046927SAndroid Build Coastguard Worker       if (jumptbl_offset != ~0) {
363*61046927SAndroid Build Coastguard Worker          printf(".align 32\n");
364*61046927SAndroid Build Coastguard Worker          printf("jumptbl:\n");
365*61046927SAndroid Build Coastguard Worker          printf(".jumptbl\n");
366*61046927SAndroid Build Coastguard Worker          if (jumptbl_offset + ARRAY_SIZE(emu->jmptbl) != sizedwords) {
367*61046927SAndroid Build Coastguard Worker             for (unsigned i = jumptbl_offset + ARRAY_SIZE(emu->jmptbl); i < sizedwords; i++)
368*61046927SAndroid Build Coastguard Worker                printf("[%08x]\n", emu->instrs[i]);
369*61046927SAndroid Build Coastguard Worker          }
370*61046927SAndroid Build Coastguard Worker       }
371*61046927SAndroid Build Coastguard Worker 
372*61046927SAndroid Build Coastguard Worker       emu->instrs -= bv_offset;
373*61046927SAndroid Build Coastguard Worker       emu->sizedwords += bv_offset;
374*61046927SAndroid Build Coastguard Worker    }
375*61046927SAndroid Build Coastguard Worker 
376*61046927SAndroid Build Coastguard Worker    if (lpac_offset) {
377*61046927SAndroid Build Coastguard Worker       printf("\n.section LPAC\n");
378*61046927SAndroid Build Coastguard Worker       printf(";\n");
379*61046927SAndroid Build Coastguard Worker       printf("; LPAC microcode:\n");
380*61046927SAndroid Build Coastguard Worker       printf(";\n");
381*61046927SAndroid Build Coastguard Worker 
382*61046927SAndroid Build Coastguard Worker       emu_fini(emu);
383*61046927SAndroid Build Coastguard Worker 
384*61046927SAndroid Build Coastguard Worker       emu->processor = EMU_PROC_LPAC;
385*61046927SAndroid Build Coastguard Worker       emu->instrs += lpac_offset;
386*61046927SAndroid Build Coastguard Worker       emu->sizedwords -= lpac_offset;
387*61046927SAndroid Build Coastguard Worker 
388*61046927SAndroid Build Coastguard Worker       emu_init(emu);
389*61046927SAndroid Build Coastguard Worker       emu_run_bootstrap(emu);
390*61046927SAndroid Build Coastguard Worker 
391*61046927SAndroid Build Coastguard Worker       setup_packet_table(&options, emu->jmptbl, ARRAY_SIZE(emu->jmptbl));
392*61046927SAndroid Build Coastguard Worker 
393*61046927SAndroid Build Coastguard Worker       jumptbl_offset = find_jump_table(emu->instrs, emu->sizedwords, emu->jmptbl,
394*61046927SAndroid Build Coastguard Worker                                        ARRAY_SIZE(emu->jmptbl));
395*61046927SAndroid Build Coastguard Worker 
396*61046927SAndroid Build Coastguard Worker       afuc_isa_disasm(emu->instrs, MIN2(emu->sizedwords, jumptbl_offset) * 4, stdout, &options);
397*61046927SAndroid Build Coastguard Worker 
398*61046927SAndroid Build Coastguard Worker       if (jumptbl_offset != ~0) {
399*61046927SAndroid Build Coastguard Worker          printf("jumptbl:\n");
400*61046927SAndroid Build Coastguard Worker          printf(".jumptbl\n");
401*61046927SAndroid Build Coastguard Worker          if (jumptbl_offset + ARRAY_SIZE(emu->jmptbl) != emu->sizedwords) {
402*61046927SAndroid Build Coastguard Worker             for (unsigned i = jumptbl_offset + ARRAY_SIZE(emu->jmptbl); i < emu->sizedwords; i++)
403*61046927SAndroid Build Coastguard Worker                printf("[%08x]\n", emu->instrs[i]);
404*61046927SAndroid Build Coastguard Worker          }
405*61046927SAndroid Build Coastguard Worker       }
406*61046927SAndroid Build Coastguard Worker 
407*61046927SAndroid Build Coastguard Worker       emu->instrs -= lpac_offset;
408*61046927SAndroid Build Coastguard Worker       emu->sizedwords += lpac_offset;
409*61046927SAndroid Build Coastguard Worker    }
410*61046927SAndroid Build Coastguard Worker }
411*61046927SAndroid Build Coastguard Worker 
412*61046927SAndroid Build Coastguard Worker static void
disasm_raw(uint32_t * instrs,int sizedwords)413*61046927SAndroid Build Coastguard Worker disasm_raw(uint32_t *instrs, int sizedwords)
414*61046927SAndroid Build Coastguard Worker {
415*61046927SAndroid Build Coastguard Worker    struct isa_decode_options options;
416*61046927SAndroid Build Coastguard Worker    struct decode_state state;
417*61046927SAndroid Build Coastguard Worker    get_decode_options(&options);
418*61046927SAndroid Build Coastguard Worker    options.cbdata = &state;
419*61046927SAndroid Build Coastguard Worker 
420*61046927SAndroid Build Coastguard Worker    afuc_isa_disasm(instrs, sizedwords * 4, stdout, &options);
421*61046927SAndroid Build Coastguard Worker }
422*61046927SAndroid Build Coastguard Worker 
423*61046927SAndroid Build Coastguard Worker static void
disasm_legacy(uint32_t * buf,int sizedwords)424*61046927SAndroid Build Coastguard Worker disasm_legacy(uint32_t *buf, int sizedwords)
425*61046927SAndroid Build Coastguard Worker {
426*61046927SAndroid Build Coastguard Worker    uint32_t *instrs = buf;
427*61046927SAndroid Build Coastguard Worker    const int jmptbl_start = instrs[1] & 0xffff;
428*61046927SAndroid Build Coastguard Worker    uint32_t *jmptbl = &buf[jmptbl_start];
429*61046927SAndroid Build Coastguard Worker    int i;
430*61046927SAndroid Build Coastguard Worker 
431*61046927SAndroid Build Coastguard Worker    struct isa_decode_options options;
432*61046927SAndroid Build Coastguard Worker    struct decode_state state;
433*61046927SAndroid Build Coastguard Worker    get_decode_options(&options);
434*61046927SAndroid Build Coastguard Worker    options.cbdata = &state;
435*61046927SAndroid Build Coastguard Worker 
436*61046927SAndroid Build Coastguard Worker    /* parse jumptable: */
437*61046927SAndroid Build Coastguard Worker    setup_packet_table(&options, jmptbl, 0x80);
438*61046927SAndroid Build Coastguard Worker 
439*61046927SAndroid Build Coastguard Worker    /* print instructions: */
440*61046927SAndroid Build Coastguard Worker    afuc_isa_disasm(instrs, sizedwords * 4, stdout, &options);
441*61046927SAndroid Build Coastguard Worker 
442*61046927SAndroid Build Coastguard Worker    /* print jumptable: */
443*61046927SAndroid Build Coastguard Worker    if (verbose) {
444*61046927SAndroid Build Coastguard Worker       printf(";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n");
445*61046927SAndroid Build Coastguard Worker       printf("; JUMP TABLE\n");
446*61046927SAndroid Build Coastguard Worker       for (i = 0; i < 0x7f; i++) {
447*61046927SAndroid Build Coastguard Worker          int n = i; // + CP_NOP;
448*61046927SAndroid Build Coastguard Worker          uint32_t offset = jmptbl[i];
449*61046927SAndroid Build Coastguard Worker          const char *name = getpm4(n);
450*61046927SAndroid Build Coastguard Worker          printf("%3d %02x: ", n, n);
451*61046927SAndroid Build Coastguard Worker          printf("%04x", offset);
452*61046927SAndroid Build Coastguard Worker          if (name) {
453*61046927SAndroid Build Coastguard Worker             printf("   ; %s", name);
454*61046927SAndroid Build Coastguard Worker          } else {
455*61046927SAndroid Build Coastguard Worker             printf("   ; UNKN%d", n);
456*61046927SAndroid Build Coastguard Worker          }
457*61046927SAndroid Build Coastguard Worker          printf("\n");
458*61046927SAndroid Build Coastguard Worker       }
459*61046927SAndroid Build Coastguard Worker    }
460*61046927SAndroid Build Coastguard Worker }
461*61046927SAndroid Build Coastguard Worker 
462*61046927SAndroid Build Coastguard Worker static void
usage(void)463*61046927SAndroid Build Coastguard Worker usage(void)
464*61046927SAndroid Build Coastguard Worker {
465*61046927SAndroid Build Coastguard Worker    fprintf(stderr, "Usage:\n"
466*61046927SAndroid Build Coastguard Worker                    "\tdisasm [-g GPUVER] [-v] [-c] [-r] filename.asm\n"
467*61046927SAndroid Build Coastguard Worker                    "\t\t-c - use colors\n"
468*61046927SAndroid Build Coastguard Worker                    "\t\t-e - emulator mode\n"
469*61046927SAndroid Build Coastguard Worker                    "\t\t-g - override GPU firmware id\n"
470*61046927SAndroid Build Coastguard Worker                    "\t\t-r - raw disasm, don't try to find jumptable\n"
471*61046927SAndroid Build Coastguard Worker                    "\t\t-v - verbose output\n"
472*61046927SAndroid Build Coastguard Worker            );
473*61046927SAndroid Build Coastguard Worker    exit(2);
474*61046927SAndroid Build Coastguard Worker }
475*61046927SAndroid Build Coastguard Worker 
476*61046927SAndroid Build Coastguard Worker int
main(int argc,char ** argv)477*61046927SAndroid Build Coastguard Worker main(int argc, char **argv)
478*61046927SAndroid Build Coastguard Worker {
479*61046927SAndroid Build Coastguard Worker    uint32_t *buf;
480*61046927SAndroid Build Coastguard Worker    char *file;
481*61046927SAndroid Build Coastguard Worker    bool colors = false;
482*61046927SAndroid Build Coastguard Worker    size_t sz;
483*61046927SAndroid Build Coastguard Worker    int c, ret;
484*61046927SAndroid Build Coastguard Worker    bool unit_test = false;
485*61046927SAndroid Build Coastguard Worker    bool raw = false;
486*61046927SAndroid Build Coastguard Worker    enum afuc_fwid fw_id = 0;
487*61046927SAndroid Build Coastguard Worker 
488*61046927SAndroid Build Coastguard Worker    /* Argument parsing: */
489*61046927SAndroid Build Coastguard Worker    while ((c = getopt(argc, argv, "ceg:rvu")) != -1) {
490*61046927SAndroid Build Coastguard Worker       switch (c) {
491*61046927SAndroid Build Coastguard Worker       case 'c':
492*61046927SAndroid Build Coastguard Worker          colors = true;
493*61046927SAndroid Build Coastguard Worker          break;
494*61046927SAndroid Build Coastguard Worker       case 'e':
495*61046927SAndroid Build Coastguard Worker          emulator = true;
496*61046927SAndroid Build Coastguard Worker          verbose  = true;
497*61046927SAndroid Build Coastguard Worker          break;
498*61046927SAndroid Build Coastguard Worker       case 'g':
499*61046927SAndroid Build Coastguard Worker          fw_id = strtol(optarg, NULL, 16);
500*61046927SAndroid Build Coastguard Worker          break;
501*61046927SAndroid Build Coastguard Worker       case 'r':
502*61046927SAndroid Build Coastguard Worker          raw = true;
503*61046927SAndroid Build Coastguard Worker          break;
504*61046927SAndroid Build Coastguard Worker       case 'v':
505*61046927SAndroid Build Coastguard Worker          verbose = true;
506*61046927SAndroid Build Coastguard Worker          break;
507*61046927SAndroid Build Coastguard Worker       case 'u':
508*61046927SAndroid Build Coastguard Worker          /* special "hidden" flag for unit tests, to avoid file paths (which
509*61046927SAndroid Build Coastguard Worker           * can differ from reference output)
510*61046927SAndroid Build Coastguard Worker           */
511*61046927SAndroid Build Coastguard Worker          unit_test = true;
512*61046927SAndroid Build Coastguard Worker          break;
513*61046927SAndroid Build Coastguard Worker       default:
514*61046927SAndroid Build Coastguard Worker          usage();
515*61046927SAndroid Build Coastguard Worker       }
516*61046927SAndroid Build Coastguard Worker    }
517*61046927SAndroid Build Coastguard Worker 
518*61046927SAndroid Build Coastguard Worker    if (optind >= argc) {
519*61046927SAndroid Build Coastguard Worker       fprintf(stderr, "no file specified!\n");
520*61046927SAndroid Build Coastguard Worker       usage();
521*61046927SAndroid Build Coastguard Worker    }
522*61046927SAndroid Build Coastguard Worker 
523*61046927SAndroid Build Coastguard Worker    file = argv[optind];
524*61046927SAndroid Build Coastguard Worker 
525*61046927SAndroid Build Coastguard Worker    buf = (uint32_t *)os_read_file(file, &sz);
526*61046927SAndroid Build Coastguard Worker 
527*61046927SAndroid Build Coastguard Worker    if (!fw_id)
528*61046927SAndroid Build Coastguard Worker       fw_id = afuc_get_fwid(buf[1]);
529*61046927SAndroid Build Coastguard Worker 
530*61046927SAndroid Build Coastguard Worker    ret = afuc_util_init(fw_id, &gpuver, colors);
531*61046927SAndroid Build Coastguard Worker    if (ret < 0) {
532*61046927SAndroid Build Coastguard Worker       usage();
533*61046927SAndroid Build Coastguard Worker    }
534*61046927SAndroid Build Coastguard Worker 
535*61046927SAndroid Build Coastguard Worker    /* a6xx is *mostly* a superset of a5xx, but some opcodes shuffle
536*61046927SAndroid Build Coastguard Worker     * around, and behavior of special regs is a bit different.  Right
537*61046927SAndroid Build Coastguard Worker     * now we only bother to support the a6xx variant.
538*61046927SAndroid Build Coastguard Worker     */
539*61046927SAndroid Build Coastguard Worker    if (emulator && (gpuver < 6 || gpuver > 7)) {
540*61046927SAndroid Build Coastguard Worker       fprintf(stderr, "Emulator only supported on a6xx-a7xx!\n");
541*61046927SAndroid Build Coastguard Worker       return 1;
542*61046927SAndroid Build Coastguard Worker    }
543*61046927SAndroid Build Coastguard Worker 
544*61046927SAndroid Build Coastguard Worker    printf("; a%dxx microcode\n", gpuver);
545*61046927SAndroid Build Coastguard Worker 
546*61046927SAndroid Build Coastguard Worker    if (!unit_test)
547*61046927SAndroid Build Coastguard Worker       printf("; Disassembling microcode: %s\n", file);
548*61046927SAndroid Build Coastguard Worker    printf("; Version: %08x\n\n", buf[1]);
549*61046927SAndroid Build Coastguard Worker 
550*61046927SAndroid Build Coastguard Worker    if (raw) {
551*61046927SAndroid Build Coastguard Worker       disasm_raw(buf, sz / 4);
552*61046927SAndroid Build Coastguard Worker    } else if (gpuver < 6) {
553*61046927SAndroid Build Coastguard Worker       disasm_legacy(&buf[1], sz / 4 - 1);
554*61046927SAndroid Build Coastguard Worker    } else {
555*61046927SAndroid Build Coastguard Worker       struct emu emu = {
556*61046927SAndroid Build Coastguard Worker             .instrs = &buf[1],
557*61046927SAndroid Build Coastguard Worker             .sizedwords = sz / 4 - 1,
558*61046927SAndroid Build Coastguard Worker             .fw_id = fw_id,
559*61046927SAndroid Build Coastguard Worker       };
560*61046927SAndroid Build Coastguard Worker 
561*61046927SAndroid Build Coastguard Worker       disasm(&emu);
562*61046927SAndroid Build Coastguard Worker    }
563*61046927SAndroid Build Coastguard Worker 
564*61046927SAndroid Build Coastguard Worker    return 0;
565*61046927SAndroid Build Coastguard Worker }
566