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
) {
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
;
221 append(disasm
, "; thrsw");
223 append(disasm
, "; ldvary");
224 v3d_qpu_disasm_sig_addr(disasm
, instr
);
227 append(disasm
, "; ldvpm");
229 append(disasm
, "; ldtmu");
230 v3d_qpu_disasm_sig_addr(disasm
, instr
);
233 append(disasm
, "; ldtlb");
234 v3d_qpu_disasm_sig_addr(disasm
, instr
);
237 append(disasm
, "; ldtlbu");
238 v3d_qpu_disasm_sig_addr(disasm
, instr
);
241 append(disasm
, "; ldunif");
243 append(disasm
, "; ldunifrf");
244 v3d_qpu_disasm_sig_addr(disasm
, instr
);
247 append(disasm
, "; ldunifa");
248 if (sig
->ldunifarf
) {
249 append(disasm
, "; ldunifarf");
250 v3d_qpu_disasm_sig_addr(disasm
, instr
);
253 append(disasm
, "; wrtmuc");
257 v3d_qpu_disasm_alu(struct disasm_state
*disasm
,
258 const struct v3d_qpu_instr
*instr
)
260 v3d_qpu_disasm_add(disasm
, instr
);
261 v3d_qpu_disasm_mul(disasm
, instr
);
262 v3d_qpu_disasm_sig(disasm
, instr
);
266 v3d_qpu_disasm_branch(struct disasm_state
*disasm
,
267 const struct v3d_qpu_instr
*instr
)
270 if (instr
->branch
.ub
)
272 append(disasm
, "%s", v3d_qpu_branch_cond_name(instr
->branch
.cond
));
273 append(disasm
, "%s", v3d_qpu_msfign_name(instr
->branch
.msfign
));
275 switch (instr
->branch
.bdi
) {
276 case V3D_QPU_BRANCH_DEST_ABS
:
277 append(disasm
, " zero_addr+0x%08x", instr
->branch
.offset
);
280 case V3D_QPU_BRANCH_DEST_REL
:
281 append(disasm
, " %d", instr
->branch
.offset
);
284 case V3D_QPU_BRANCH_DEST_LINK_REG
:
285 append(disasm
, " lri");
288 case V3D_QPU_BRANCH_DEST_REGFILE
:
289 append(disasm
, " rf%d", instr
->branch
.raddr_a
);
293 if (instr
->branch
.ub
) {
294 switch (instr
->branch
.bdu
) {
295 case V3D_QPU_BRANCH_DEST_ABS
:
296 append(disasm
, ", a:unif");
299 case V3D_QPU_BRANCH_DEST_REL
:
300 append(disasm
, ", r:unif");
303 case V3D_QPU_BRANCH_DEST_LINK_REG
:
304 append(disasm
, ", lri");
307 case V3D_QPU_BRANCH_DEST_REGFILE
:
308 append(disasm
, ", rf%d", instr
->branch
.raddr_a
);
315 v3d_qpu_decode(const struct v3d_device_info
*devinfo
,
316 const struct v3d_qpu_instr
*instr
)
318 struct disasm_state disasm
= {
319 .string
= rzalloc_size(NULL
, 1),
324 switch (instr
->type
) {
325 case V3D_QPU_INSTR_TYPE_ALU
:
326 v3d_qpu_disasm_alu(&disasm
, instr
);
329 case V3D_QPU_INSTR_TYPE_BRANCH
:
330 v3d_qpu_disasm_branch(&disasm
, instr
);
334 return disasm
.string
;
338 * Returns a string containing the disassembled representation of the QPU
339 * instruction. It is the caller's responsibility to free the return value
340 * with ralloc_free().
343 v3d_qpu_disasm(const struct v3d_device_info
*devinfo
, uint64_t inst
)
345 struct v3d_qpu_instr instr
;
346 bool ok
= v3d_qpu_instr_unpack(devinfo
, inst
, &instr
);
347 assert(ok
); (void)ok
;
349 return v3d_qpu_decode(devinfo
, &instr
);
353 v3d_qpu_dump(const struct v3d_device_info
*devinfo
,
354 const struct v3d_qpu_instr
*instr
)
356 const char *decoded
= v3d_qpu_decode(devinfo
, instr
);
357 fprintf(stderr
, "%s", decoded
);
358 ralloc_free((char *)decoded
);