2 * Copyright © 2016 Broadcom
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
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
26 #include "util/ralloc.h"
28 #include "broadcom/common/v3d_device_info.h"
29 #include "qpu_instr.h"
30 #include "qpu_disasm.h"
33 const struct v3d_device_info
*devinfo
;
39 append(struct disasm_state
*disasm
, const char *fmt
, ...)
43 ralloc_vasprintf_rewrite_tail(&disasm
->string
,
50 pad_to(struct disasm_state
*disasm
, int n
)
52 /* FIXME: Do a single append somehow. */
53 while (disasm
->offset
< n
)
59 v3d_qpu_disasm_raddr(struct disasm_state
*disasm
,
60 const struct v3d_qpu_instr
*instr
, uint8_t mux
)
62 if (mux
== V3D_QPU_MUX_A
) {
63 append(disasm
, "rf%d", instr
->raddr_a
);
64 } else if (mux
== V3D_QPU_MUX_B
) {
65 if (instr
->sig
.small_imm
) {
67 MAYBE_UNUSED
bool ok
=
68 v3d_qpu_small_imm_unpack(disasm
->devinfo
,
72 if ((int)val
>= -16 && (int)val
<= 15)
73 append(disasm
, "%d", val
);
75 append(disasm
, "0x%08x", val
);
78 append(disasm
, "rf%d", instr
->raddr_b
);
81 append(disasm
, "r%d", mux
);
86 v3d_qpu_disasm_waddr(struct disasm_state
*disasm
, uint32_t waddr
, bool magic
)
89 append(disasm
, "rf%d", waddr
);
93 const char *name
= v3d_qpu_magic_waddr_name(waddr
);
95 append(disasm
, "%s", name
);
97 append(disasm
, "waddr UNKNOWN %d", waddr
);
101 v3d_qpu_disasm_add(struct disasm_state
*disasm
,
102 const struct v3d_qpu_instr
*instr
)
104 bool has_dst
= v3d_qpu_add_op_has_dst(instr
->alu
.add
.op
);
105 int num_src
= v3d_qpu_add_op_num_src(instr
->alu
.add
.op
);
107 append(disasm
, "%s", v3d_qpu_add_op_name(instr
->alu
.add
.op
));
108 if (!v3d_qpu_sig_writes_address(disasm
->devinfo
, &instr
->sig
))
109 append(disasm
, "%s", v3d_qpu_cond_name(instr
->flags
.ac
));
110 append(disasm
, "%s", v3d_qpu_pf_name(instr
->flags
.apf
));
111 append(disasm
, "%s", v3d_qpu_uf_name(instr
->flags
.auf
));
116 v3d_qpu_disasm_waddr(disasm
, instr
->alu
.add
.waddr
,
117 instr
->alu
.add
.magic_write
);
118 append(disasm
, v3d_qpu_pack_name(instr
->alu
.add
.output_pack
));
123 append(disasm
, ", ");
124 v3d_qpu_disasm_raddr(disasm
, instr
, instr
->alu
.add
.a
);
126 v3d_qpu_unpack_name(instr
->alu
.add
.a_unpack
));
130 append(disasm
, ", ");
131 v3d_qpu_disasm_raddr(disasm
, instr
, instr
->alu
.add
.b
);
133 v3d_qpu_unpack_name(instr
->alu
.add
.b_unpack
));
138 v3d_qpu_disasm_mul(struct disasm_state
*disasm
,
139 const struct v3d_qpu_instr
*instr
)
141 bool has_dst
= v3d_qpu_mul_op_has_dst(instr
->alu
.mul
.op
);
142 int num_src
= v3d_qpu_mul_op_num_src(instr
->alu
.mul
.op
);
145 append(disasm
, "; ");
147 append(disasm
, "%s", v3d_qpu_mul_op_name(instr
->alu
.mul
.op
));
148 if (!v3d_qpu_sig_writes_address(disasm
->devinfo
, &instr
->sig
))
149 append(disasm
, "%s", v3d_qpu_cond_name(instr
->flags
.mc
));
150 append(disasm
, "%s", v3d_qpu_pf_name(instr
->flags
.mpf
));
151 append(disasm
, "%s", v3d_qpu_uf_name(instr
->flags
.muf
));
153 if (instr
->alu
.mul
.op
== V3D_QPU_M_NOP
)
159 v3d_qpu_disasm_waddr(disasm
, instr
->alu
.mul
.waddr
,
160 instr
->alu
.mul
.magic_write
);
161 append(disasm
, v3d_qpu_pack_name(instr
->alu
.mul
.output_pack
));
166 append(disasm
, ", ");
167 v3d_qpu_disasm_raddr(disasm
, instr
, instr
->alu
.mul
.a
);
169 v3d_qpu_unpack_name(instr
->alu
.mul
.a_unpack
));
173 append(disasm
, ", ");
174 v3d_qpu_disasm_raddr(disasm
, instr
, instr
->alu
.mul
.b
);
176 v3d_qpu_unpack_name(instr
->alu
.mul
.b_unpack
));
181 v3d_qpu_disasm_sig_addr(struct disasm_state
*disasm
,
182 const struct v3d_qpu_instr
*instr
)
184 if (disasm
->devinfo
->ver
< 41)
187 if (!instr
->sig_magic
)
188 append(disasm
, ".rf%d", instr
->sig_addr
);
190 const char *name
= v3d_qpu_magic_waddr_name(instr
->sig_addr
);
192 append(disasm
, ".%s", name
);
194 append(disasm
, ".UNKNOWN%d", instr
->sig_addr
);
199 v3d_qpu_disasm_sig(struct disasm_state
*disasm
,
200 const struct v3d_qpu_instr
*instr
)
202 const struct v3d_qpu_sig
*sig
= &instr
->sig
;
219 append(disasm
, "; thrsw");
221 append(disasm
, "; ldvary");
222 v3d_qpu_disasm_sig_addr(disasm
, instr
);
225 append(disasm
, "; ldvpm");
227 append(disasm
, "; ldtmu");
228 v3d_qpu_disasm_sig_addr(disasm
, instr
);
231 append(disasm
, "; ldtlb");
232 v3d_qpu_disasm_sig_addr(disasm
, instr
);
235 append(disasm
, "; ldtlbu");
236 v3d_qpu_disasm_sig_addr(disasm
, instr
);
239 append(disasm
, "; ldunif");
241 append(disasm
, "; ldunifrf");
242 v3d_qpu_disasm_sig_addr(disasm
, instr
);
245 append(disasm
, "; ldunifa");
246 if (sig
->ldunifarf
) {
247 append(disasm
, "; ldunifarf");
248 v3d_qpu_disasm_sig_addr(disasm
, instr
);
251 append(disasm
, "; wrtmuc");
255 v3d_qpu_disasm_alu(struct disasm_state
*disasm
,
256 const struct v3d_qpu_instr
*instr
)
258 v3d_qpu_disasm_add(disasm
, instr
);
259 v3d_qpu_disasm_mul(disasm
, instr
);
260 v3d_qpu_disasm_sig(disasm
, instr
);
264 v3d_qpu_disasm_branch(struct disasm_state
*disasm
,
265 const struct v3d_qpu_instr
*instr
)
268 if (instr
->branch
.ub
)
270 append(disasm
, "%s", v3d_qpu_branch_cond_name(instr
->branch
.cond
));
271 append(disasm
, "%s", v3d_qpu_msfign_name(instr
->branch
.msfign
));
273 switch (instr
->branch
.bdi
) {
274 case V3D_QPU_BRANCH_DEST_ABS
:
275 append(disasm
, " zero_addr+0x%08x", instr
->branch
.offset
);
278 case V3D_QPU_BRANCH_DEST_REL
:
279 append(disasm
, " %d", instr
->branch
.offset
);
282 case V3D_QPU_BRANCH_DEST_LINK_REG
:
283 append(disasm
, " lri");
286 case V3D_QPU_BRANCH_DEST_REGFILE
:
287 append(disasm
, " rf%d", instr
->branch
.raddr_a
);
291 if (instr
->branch
.ub
) {
292 switch (instr
->branch
.bdu
) {
293 case V3D_QPU_BRANCH_DEST_ABS
:
294 append(disasm
, ", a:unif");
297 case V3D_QPU_BRANCH_DEST_REL
:
298 append(disasm
, ", r:unif");
301 case V3D_QPU_BRANCH_DEST_LINK_REG
:
302 append(disasm
, ", lri");
305 case V3D_QPU_BRANCH_DEST_REGFILE
:
306 append(disasm
, ", rf%d", instr
->branch
.raddr_a
);
313 v3d_qpu_decode(const struct v3d_device_info
*devinfo
,
314 const struct v3d_qpu_instr
*instr
)
316 struct disasm_state disasm
= {
317 .string
= rzalloc_size(NULL
, 1),
322 switch (instr
->type
) {
323 case V3D_QPU_INSTR_TYPE_ALU
:
324 v3d_qpu_disasm_alu(&disasm
, instr
);
327 case V3D_QPU_INSTR_TYPE_BRANCH
:
328 v3d_qpu_disasm_branch(&disasm
, instr
);
332 return disasm
.string
;
336 * Returns a string containing the disassembled representation of the QPU
337 * instruction. It is the caller's responsibility to free the return value
338 * with ralloc_free().
341 v3d_qpu_disasm(const struct v3d_device_info
*devinfo
, uint64_t inst
)
343 struct v3d_qpu_instr instr
;
344 bool ok
= v3d_qpu_instr_unpack(devinfo
, inst
, &instr
);
345 assert(ok
); (void)ok
;
347 return v3d_qpu_decode(devinfo
, &instr
);
351 v3d_qpu_dump(const struct v3d_device_info
*devinfo
,
352 const struct v3d_qpu_instr
*instr
)
354 const char *decoded
= v3d_qpu_decode(devinfo
, instr
);
355 fprintf(stderr
, "%s", decoded
);
356 ralloc_free((char *)decoded
);