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 append(disasm
, "rf%d", instr
->raddr_b
);
67 append(disasm
, "r%d", mux
);
72 v3d_qpu_disasm_waddr(struct disasm_state
*disasm
, uint32_t waddr
, bool magic
)
75 append(disasm
, "rf%d", waddr
);
79 const char *name
= v3d_qpu_magic_waddr_name(waddr
);
81 append(disasm
, "%s", name
);
83 append(disasm
, "waddr UNKNOWN %d", waddr
);
87 v3d_qpu_disasm_add(struct disasm_state
*disasm
,
88 const struct v3d_qpu_instr
*instr
)
90 bool has_dst
= v3d_qpu_add_op_has_dst(instr
->alu
.add
.op
);
91 int num_src
= v3d_qpu_add_op_num_src(instr
->alu
.add
.op
);
93 append(disasm
, "%s", v3d_qpu_add_op_name(instr
->alu
.add
.op
));
94 append(disasm
, "%s", v3d_qpu_cond_name(instr
->flags
.ac
));
95 append(disasm
, "%s", v3d_qpu_pf_name(instr
->flags
.apf
));
96 append(disasm
, "%s", v3d_qpu_uf_name(instr
->flags
.auf
));
101 v3d_qpu_disasm_waddr(disasm
, instr
->alu
.add
.waddr
,
102 instr
->alu
.add
.magic_write
);
103 append(disasm
, v3d_qpu_pack_name(instr
->alu
.add
.output_pack
));
108 append(disasm
, ", ");
109 v3d_qpu_disasm_raddr(disasm
, instr
, instr
->alu
.add
.a
);
111 v3d_qpu_unpack_name(instr
->alu
.add
.a_unpack
));
115 append(disasm
, ", ");
116 v3d_qpu_disasm_raddr(disasm
, instr
, instr
->alu
.add
.b
);
118 v3d_qpu_unpack_name(instr
->alu
.add
.b_unpack
));
123 v3d_qpu_disasm_mul(struct disasm_state
*disasm
,
124 const struct v3d_qpu_instr
*instr
)
126 bool has_dst
= v3d_qpu_mul_op_has_dst(instr
->alu
.mul
.op
);
127 int num_src
= v3d_qpu_mul_op_num_src(instr
->alu
.mul
.op
);
130 append(disasm
, "; ");
132 append(disasm
, "%s", v3d_qpu_mul_op_name(instr
->alu
.mul
.op
));
133 append(disasm
, "%s", v3d_qpu_cond_name(instr
->flags
.mc
));
134 append(disasm
, "%s", v3d_qpu_pf_name(instr
->flags
.mpf
));
135 append(disasm
, "%s", v3d_qpu_uf_name(instr
->flags
.muf
));
137 if (instr
->alu
.mul
.op
== V3D_QPU_M_NOP
)
143 v3d_qpu_disasm_waddr(disasm
, instr
->alu
.mul
.waddr
,
144 instr
->alu
.mul
.magic_write
);
145 append(disasm
, v3d_qpu_pack_name(instr
->alu
.mul
.output_pack
));
150 append(disasm
, ", ");
151 v3d_qpu_disasm_raddr(disasm
, instr
, instr
->alu
.mul
.a
);
153 v3d_qpu_unpack_name(instr
->alu
.mul
.a_unpack
));
157 append(disasm
, ", ");
158 v3d_qpu_disasm_raddr(disasm
, instr
, instr
->alu
.mul
.b
);
160 v3d_qpu_unpack_name(instr
->alu
.mul
.b_unpack
));
165 v3d_qpu_disasm_sig(struct disasm_state
*disasm
,
166 const struct v3d_qpu_instr
*instr
)
168 const struct v3d_qpu_sig
*sig
= &instr
->sig
;
182 append(disasm
, "; thrsw");
184 append(disasm
, "; ldvary");
186 append(disasm
, "; ldvpm");
188 append(disasm
, "; ldtmu");
190 append(disasm
, "; ldunif");
192 append(disasm
, "; wrtmuc");
196 v3d_qpu_disasm_alu(struct disasm_state
*disasm
,
197 const struct v3d_qpu_instr
*instr
)
199 v3d_qpu_disasm_add(disasm
, instr
);
200 v3d_qpu_disasm_mul(disasm
, instr
);
201 v3d_qpu_disasm_sig(disasm
, instr
);
205 v3d_qpu_disasm_branch(struct disasm_state
*disasm
,
206 const struct v3d_qpu_instr
*instr
)
209 if (instr
->branch
.ub
)
211 append(disasm
, "%s", v3d_qpu_branch_cond_name(instr
->branch
.cond
));
212 append(disasm
, "%s", v3d_qpu_msfign_name(instr
->branch
.msfign
));
214 switch (instr
->branch
.bdi
) {
215 case V3D_QPU_BRANCH_DEST_ABS
:
216 append(disasm
, " zero_addr+0x%08x", instr
->branch
.offset
);
219 case V3D_QPU_BRANCH_DEST_REL
:
220 append(disasm
, " %d", instr
->branch
.offset
);
223 case V3D_QPU_BRANCH_DEST_LINK_REG
:
224 append(disasm
, " lri");
227 case V3D_QPU_BRANCH_DEST_REGFILE
:
228 append(disasm
, " rf%d", instr
->branch
.raddr_a
);
232 if (instr
->branch
.ub
) {
233 switch (instr
->branch
.bdu
) {
234 case V3D_QPU_BRANCH_DEST_ABS
:
235 append(disasm
, ", a:unif");
238 case V3D_QPU_BRANCH_DEST_REL
:
239 append(disasm
, ", r:unif");
242 case V3D_QPU_BRANCH_DEST_LINK_REG
:
243 append(disasm
, ", lri");
246 case V3D_QPU_BRANCH_DEST_REGFILE
:
247 append(disasm
, ", rf%d", instr
->branch
.raddr_a
);
254 v3d_qpu_decode(const struct v3d_device_info
*devinfo
,
255 const struct v3d_qpu_instr
*instr
)
257 struct disasm_state disasm
= {
258 .string
= rzalloc_size(NULL
, 1),
263 switch (instr
->type
) {
264 case V3D_QPU_INSTR_TYPE_ALU
:
265 v3d_qpu_disasm_alu(&disasm
, instr
);
268 case V3D_QPU_INSTR_TYPE_BRANCH
:
269 v3d_qpu_disasm_branch(&disasm
, instr
);
273 return disasm
.string
;
277 * Returns a string containing the disassembled representation of the QPU
278 * instruction. It is the caller's responsibility to free the return value
279 * with ralloc_free().
282 v3d_qpu_disasm(const struct v3d_device_info
*devinfo
, uint64_t inst
)
284 struct v3d_qpu_instr instr
;
285 bool ok
= v3d_qpu_instr_unpack(devinfo
, inst
, &instr
);
286 assert(ok
); (void)ok
;
288 return v3d_qpu_decode(devinfo
, &instr
);
292 v3d_qpu_dump(const struct v3d_device_info
*devinfo
,
293 const struct v3d_qpu_instr
*instr
)
295 const char *decoded
= v3d_qpu_decode(devinfo
, instr
);
296 fprintf(stderr
, "%s", decoded
);
297 ralloc_free((char *)decoded
);