Commit | Line | Data |
---|---|---|
98fa08a5 | 1 | // SPDX-License-Identifier: LGPL-2.1-or-later |
d16005f8 | 2 | /* |
98fa08a5 | 3 | * Copyright (C) 2014-2021 Paul Cercueil <paul@crapouillou.net> |
d16005f8 PC |
4 | */ |
5 | ||
d16005f8 | 6 | #include <stdbool.h> |
98fa08a5 | 7 | #include <stdio.h> |
d16005f8 PC |
8 | #include <stdlib.h> |
9 | #include <string.h> | |
10 | ||
d16005f8 | 11 | #include "lightrec-private.h" |
98fa08a5 | 12 | #include "regcache.h" |
d16005f8 | 13 | |
ba3814c1 | 14 | static const char * const std_opcodes[] = { |
98fa08a5 PC |
15 | [OP_J] = "j ", |
16 | [OP_JAL] = "jal ", | |
17 | [OP_BEQ] = "beq ", | |
18 | [OP_BNE] = "bne ", | |
19 | [OP_BLEZ] = "blez ", | |
20 | [OP_BGTZ] = "bgtz ", | |
21 | [OP_ADDI] = "addi ", | |
22 | [OP_ADDIU] = "addiu ", | |
23 | [OP_SLTI] = "slti ", | |
24 | [OP_SLTIU] = "sltiu ", | |
25 | [OP_ANDI] = "andi ", | |
26 | [OP_ORI] = "ori ", | |
27 | [OP_XORI] = "xori ", | |
28 | [OP_LUI] = "lui ", | |
29 | [OP_LB] = "lb ", | |
30 | [OP_LH] = "lh ", | |
31 | [OP_LWL] = "lwl ", | |
32 | [OP_LW] = "lw ", | |
33 | [OP_LBU] = "lbu ", | |
34 | [OP_LHU] = "lhu ", | |
35 | [OP_LWR] = "lwr ", | |
36 | [OP_SB] = "sb ", | |
37 | [OP_SH] = "sh ", | |
38 | [OP_SWL] = "swl ", | |
39 | [OP_SW] = "sw ", | |
40 | [OP_SWR] = "swr ", | |
41 | [OP_LWC2] = "lwc2 ", | |
42 | [OP_SWC2] = "swc2 ", | |
5459088b PC |
43 | [OP_META_MULT2] = "mult2 ", |
44 | [OP_META_MULTU2] = "multu2 ", | |
45 | [OP_META_LWU] = "lwu ", | |
46 | [OP_META_SWU] = "swu ", | |
98fa08a5 | 47 | }; |
d16005f8 | 48 | |
ba3814c1 | 49 | static const char * const special_opcodes[] = { |
98fa08a5 PC |
50 | [OP_SPECIAL_SLL] = "sll ", |
51 | [OP_SPECIAL_SRL] = "srl ", | |
52 | [OP_SPECIAL_SRA] = "sra ", | |
53 | [OP_SPECIAL_SLLV] = "sllv ", | |
54 | [OP_SPECIAL_SRLV] = "srlv ", | |
55 | [OP_SPECIAL_SRAV] = "srav ", | |
56 | [OP_SPECIAL_JR] = "jr ", | |
57 | [OP_SPECIAL_JALR] = "jalr ", | |
58 | [OP_SPECIAL_SYSCALL] = "syscall ", | |
59 | [OP_SPECIAL_BREAK] = "break ", | |
60 | [OP_SPECIAL_MFHI] = "mfhi ", | |
61 | [OP_SPECIAL_MTHI] = "mthi ", | |
62 | [OP_SPECIAL_MFLO] = "mflo ", | |
63 | [OP_SPECIAL_MTLO] = "mtlo ", | |
64 | [OP_SPECIAL_MULT] = "mult ", | |
65 | [OP_SPECIAL_MULTU] = "multu ", | |
66 | [OP_SPECIAL_DIV] = "div ", | |
67 | [OP_SPECIAL_DIVU] = "divu ", | |
68 | [OP_SPECIAL_ADD] = "add ", | |
69 | [OP_SPECIAL_ADDU] = "addu ", | |
70 | [OP_SPECIAL_SUB] = "sub ", | |
71 | [OP_SPECIAL_SUBU] = "subu ", | |
72 | [OP_SPECIAL_AND] = "and ", | |
73 | [OP_SPECIAL_OR] = "or ", | |
74 | [OP_SPECIAL_XOR] = "xor ", | |
75 | [OP_SPECIAL_NOR] = "nor ", | |
76 | [OP_SPECIAL_SLT] = "slt ", | |
77 | [OP_SPECIAL_SLTU] = "sltu ", | |
78 | }; | |
d16005f8 | 79 | |
ba3814c1 | 80 | static const char * const regimm_opcodes[] = { |
98fa08a5 PC |
81 | [OP_REGIMM_BLTZ] = "bltz ", |
82 | [OP_REGIMM_BGEZ] = "bgez ", | |
83 | [OP_REGIMM_BLTZAL] = "bltzal ", | |
84 | [OP_REGIMM_BGEZAL] = "bgezal ", | |
85 | }; | |
d16005f8 | 86 | |
ba3814c1 | 87 | static const char * const cp0_opcodes[] = { |
98fa08a5 PC |
88 | [OP_CP0_MFC0] = "mfc0 ", |
89 | [OP_CP0_CFC0] = "cfc0 ", | |
90 | [OP_CP0_MTC0] = "mtc0 ", | |
91 | [OP_CP0_CTC0] = "ctc0 ", | |
92 | [OP_CP0_RFE] = "rfe", | |
93 | }; | |
94 | ||
ba3814c1 | 95 | static const char * const cp2_basic_opcodes[] = { |
98fa08a5 PC |
96 | [OP_CP2_BASIC_MFC2] = "mfc2 ", |
97 | [OP_CP2_BASIC_CFC2] = "cfc2 ", | |
98 | [OP_CP2_BASIC_MTC2] = "mtc2 ", | |
99 | [OP_CP2_BASIC_CTC2] = "ctc2 ", | |
100 | }; | |
101 | ||
ba3814c1 PC |
102 | static const char * const cp2_opcodes[] = { |
103 | [OP_CP2_RTPS] = "rtps ", | |
104 | [OP_CP2_NCLIP] = "nclip ", | |
105 | [OP_CP2_OP] = "op ", | |
106 | [OP_CP2_DPCS] = "dpcs ", | |
107 | [OP_CP2_INTPL] = "intpl ", | |
108 | [OP_CP2_MVMVA] = "mvmva ", | |
109 | [OP_CP2_NCDS] = "ncds ", | |
110 | [OP_CP2_CDP] = "cdp ", | |
111 | [OP_CP2_NCDT] = "ncdt ", | |
112 | [OP_CP2_NCCS] = "nccs ", | |
113 | [OP_CP2_CC] = "cc ", | |
114 | [OP_CP2_NCS] = "ncs ", | |
115 | [OP_CP2_NCT] = "nct ", | |
116 | [OP_CP2_SQR] = "sqr ", | |
117 | [OP_CP2_DCPL] = "dcpl ", | |
118 | [OP_CP2_DPCT] = "dpct ", | |
119 | [OP_CP2_AVSZ3] = "avsz3 ", | |
120 | [OP_CP2_AVSZ4] = "avsz4 ", | |
121 | [OP_CP2_RTPT] = "rtpt ", | |
122 | [OP_CP2_GPF] = "gpf ", | |
123 | [OP_CP2_GPL] = "gpl ", | |
124 | [OP_CP2_NCCT] = "ncct ", | |
125 | }; | |
126 | ||
cb72ea13 PC |
127 | static const char * const meta_opcodes[] = { |
128 | [OP_META_MOV] = "move ", | |
129 | [OP_META_EXTC] = "extc ", | |
130 | [OP_META_EXTS] = "exts ", | |
131 | [OP_META_COM] = "com ", | |
132 | }; | |
133 | ||
ba3814c1 PC |
134 | static const char * const mult2_opcodes[] = { |
135 | "mult2 ", "multu2 ", | |
136 | }; | |
137 | ||
138 | static const char * const opcode_flags[] = { | |
98fa08a5 | 139 | "switched branch/DS", |
98fa08a5 PC |
140 | "sync point", |
141 | }; | |
142 | ||
ba3814c1 | 143 | static const char * const opcode_io_flags[] = { |
98fa08a5 PC |
144 | "self-modifying code", |
145 | "no invalidation", | |
22eee2ac | 146 | "no mask", |
cb72ea13 | 147 | "load delay", |
22eee2ac PC |
148 | }; |
149 | ||
ba3814c1 | 150 | static const char * const opcode_io_modes[] = { |
22eee2ac PC |
151 | "Memory access", |
152 | "I/O access", | |
153 | "RAM access", | |
154 | "BIOS access", | |
155 | "Scratchpad access", | |
ba3814c1 | 156 | "Mapped I/O access" |
98fa08a5 | 157 | }; |
d16005f8 | 158 | |
ba3814c1 | 159 | static const char * const opcode_branch_flags[] = { |
98fa08a5 PC |
160 | "emulate branch", |
161 | "local branch", | |
162 | }; | |
163 | ||
684432ad PC |
164 | static const char * const opcode_movi_flags[] = { |
165 | "movi", | |
166 | }; | |
167 | ||
ba3814c1 | 168 | static const char * const opcode_multdiv_flags[] = { |
98fa08a5 PC |
169 | "No LO", |
170 | "No HI", | |
171 | "No div check", | |
172 | }; | |
173 | ||
03535202 PC |
174 | static size_t do_snprintf(char *buf, size_t len, bool *first, |
175 | const char *arg1, const char *arg2) | |
176 | { | |
177 | size_t bytes; | |
178 | ||
179 | if (*first) | |
180 | bytes = snprintf(buf, len, "(%s%s", arg1, arg2); | |
181 | else | |
182 | bytes = snprintf(buf, len, ", %s%s", arg1, arg2); | |
183 | ||
184 | *first = false; | |
185 | ||
186 | return bytes; | |
187 | } | |
188 | ||
189 | static const char * const reg_op_token[3] = { | |
190 | "-", "*", "~", | |
191 | }; | |
192 | ||
193 | static int print_flags(char *buf, size_t len, const struct opcode *op, | |
ba3814c1 | 194 | const char * const *array, size_t array_size, |
22eee2ac | 195 | bool is_io) |
d16005f8 | 196 | { |
22eee2ac PC |
197 | const char *flag_name, *io_mode_name; |
198 | unsigned int i, io_mode; | |
98fa08a5 PC |
199 | size_t count = 0, bytes; |
200 | bool first = true; | |
03535202 PC |
201 | u32 flags = op->flags; |
202 | unsigned int reg_op; | |
d16005f8 | 203 | |
98fa08a5 PC |
204 | for (i = 0; i < array_size + ARRAY_SIZE(opcode_flags); i++) { |
205 | if (!(flags & BIT(i))) | |
206 | continue; | |
d16005f8 | 207 | |
98fa08a5 PC |
208 | if (i < ARRAY_SIZE(opcode_flags)) |
209 | flag_name = opcode_flags[i]; | |
d16005f8 | 210 | else |
98fa08a5 PC |
211 | flag_name = array[i - ARRAY_SIZE(opcode_flags)]; |
212 | ||
03535202 | 213 | bytes = do_snprintf(buf, len, &first, "", flag_name); |
98fa08a5 PC |
214 | buf += bytes; |
215 | len -= bytes; | |
216 | count += bytes; | |
d16005f8 PC |
217 | } |
218 | ||
22eee2ac PC |
219 | if (is_io) { |
220 | io_mode = LIGHTREC_FLAGS_GET_IO_MODE(flags); | |
221 | if (io_mode > 0) { | |
222 | io_mode_name = opcode_io_modes[io_mode - 1]; | |
223 | ||
03535202 PC |
224 | bytes = do_snprintf(buf, len, &first, "", io_mode_name); |
225 | buf += bytes; | |
226 | len -= bytes; | |
227 | count += bytes; | |
228 | } | |
229 | } | |
230 | ||
231 | if (OPT_EARLY_UNLOAD) { | |
232 | reg_op = LIGHTREC_FLAGS_GET_RS(flags); | |
233 | if (reg_op) { | |
234 | bytes = do_snprintf(buf, len, &first, | |
235 | reg_op_token[reg_op - 1], | |
236 | lightrec_reg_name(op->i.rs)); | |
237 | buf += bytes; | |
238 | len -= bytes; | |
239 | count += bytes; | |
240 | } | |
241 | ||
242 | reg_op = LIGHTREC_FLAGS_GET_RT(flags); | |
243 | if (reg_op) { | |
244 | bytes = do_snprintf(buf, len, &first, | |
245 | reg_op_token[reg_op - 1], | |
246 | lightrec_reg_name(op->i.rt)); | |
247 | buf += bytes; | |
248 | len -= bytes; | |
249 | count += bytes; | |
250 | } | |
22eee2ac | 251 | |
03535202 PC |
252 | reg_op = LIGHTREC_FLAGS_GET_RD(flags); |
253 | if (reg_op) { | |
254 | bytes = do_snprintf(buf, len, &first, | |
255 | reg_op_token[reg_op - 1], | |
256 | lightrec_reg_name(op->r.rd)); | |
22eee2ac PC |
257 | buf += bytes; |
258 | len -= bytes; | |
259 | count += bytes; | |
260 | } | |
261 | } | |
262 | ||
98fa08a5 PC |
263 | if (!first) |
264 | count += snprintf(buf, len, ")"); | |
265 | else | |
266 | *buf = '\0'; | |
d16005f8 | 267 | |
98fa08a5 | 268 | return count; |
d16005f8 PC |
269 | } |
270 | ||
98fa08a5 | 271 | static int print_op_special(union code c, char *buf, size_t len, |
ba3814c1 | 272 | const char * const **flags_ptr, size_t *nb_flags) |
d16005f8 | 273 | { |
98fa08a5 PC |
274 | switch (c.r.op) { |
275 | case OP_SPECIAL_SLL: | |
276 | case OP_SPECIAL_SRL: | |
277 | case OP_SPECIAL_SRA: | |
278 | return snprintf(buf, len, "%s%s,%s,%u", | |
279 | special_opcodes[c.r.op], | |
280 | lightrec_reg_name(c.r.rd), | |
281 | lightrec_reg_name(c.r.rt), | |
282 | c.r.imm); | |
283 | case OP_SPECIAL_SLLV: | |
284 | case OP_SPECIAL_SRLV: | |
285 | case OP_SPECIAL_SRAV: | |
286 | case OP_SPECIAL_ADD: | |
287 | case OP_SPECIAL_ADDU: | |
288 | case OP_SPECIAL_SUB: | |
289 | case OP_SPECIAL_SUBU: | |
290 | case OP_SPECIAL_AND: | |
291 | case OP_SPECIAL_OR: | |
292 | case OP_SPECIAL_XOR: | |
293 | case OP_SPECIAL_NOR: | |
294 | case OP_SPECIAL_SLT: | |
295 | case OP_SPECIAL_SLTU: | |
296 | return snprintf(buf, len, "%s%s,%s,%s", | |
297 | special_opcodes[c.r.op], | |
298 | lightrec_reg_name(c.r.rd), | |
299 | lightrec_reg_name(c.r.rt), | |
300 | lightrec_reg_name(c.r.rs)); | |
301 | case OP_SPECIAL_JR: | |
d8b04acd PC |
302 | *flags_ptr = opcode_branch_flags; |
303 | *nb_flags = ARRAY_SIZE(opcode_branch_flags); | |
304 | fallthrough; | |
98fa08a5 PC |
305 | case OP_SPECIAL_MTHI: |
306 | case OP_SPECIAL_MTLO: | |
307 | return snprintf(buf, len, "%s%s", | |
308 | special_opcodes[c.r.op], | |
309 | lightrec_reg_name(c.r.rs)); | |
310 | case OP_SPECIAL_JALR: | |
311 | return snprintf(buf, len, "%s%s,%s", | |
312 | special_opcodes[c.r.op], | |
313 | lightrec_reg_name(c.r.rd), | |
9259d748 | 314 | lightrec_reg_name(c.r.rs)); |
98fa08a5 PC |
315 | case OP_SPECIAL_SYSCALL: |
316 | case OP_SPECIAL_BREAK: | |
317 | return snprintf(buf, len, "%s", special_opcodes[c.r.op]); | |
318 | case OP_SPECIAL_MFHI: | |
319 | case OP_SPECIAL_MFLO: | |
320 | return snprintf(buf, len, "%s%s", | |
321 | special_opcodes[c.r.op], | |
322 | lightrec_reg_name(c.r.rd)); | |
323 | case OP_SPECIAL_MULT: | |
324 | case OP_SPECIAL_MULTU: | |
325 | case OP_SPECIAL_DIV: | |
326 | case OP_SPECIAL_DIVU: | |
327 | *flags_ptr = opcode_multdiv_flags; | |
328 | *nb_flags = ARRAY_SIZE(opcode_multdiv_flags); | |
329 | return snprintf(buf, len, "%s%s,%s,%s,%s", | |
330 | special_opcodes[c.r.op], | |
331 | lightrec_reg_name(get_mult_div_hi(c)), | |
332 | lightrec_reg_name(get_mult_div_lo(c)), | |
333 | lightrec_reg_name(c.r.rs), | |
334 | lightrec_reg_name(c.r.rt)); | |
d16005f8 | 335 | default: |
98fa08a5 | 336 | return snprintf(buf, len, "unknown (0x%08x)", c.opcode); |
d16005f8 PC |
337 | } |
338 | } | |
339 | ||
98fa08a5 | 340 | static int print_op_cp(union code c, char *buf, size_t len, unsigned int cp) |
d16005f8 | 341 | { |
98fa08a5 | 342 | if (cp == 2) { |
ba3814c1 PC |
343 | switch (c.r.op) { |
344 | case OP_CP2_BASIC: | |
98fa08a5 | 345 | return snprintf(buf, len, "%s%s,%u", |
ba3814c1 | 346 | cp2_basic_opcodes[c.i.rs], |
98fa08a5 PC |
347 | lightrec_reg_name(c.i.rt), |
348 | c.r.rd); | |
349 | default: | |
ba3814c1 | 350 | return snprintf(buf, len, "%s", cp2_opcodes[c.r.op]); |
98fa08a5 PC |
351 | } |
352 | } else { | |
353 | switch (c.i.rs) { | |
354 | case OP_CP0_MFC0: | |
355 | case OP_CP0_CFC0: | |
356 | case OP_CP0_MTC0: | |
357 | case OP_CP0_CTC0: | |
358 | return snprintf(buf, len, "%s%s,%u", | |
359 | cp0_opcodes[c.i.rs], | |
360 | lightrec_reg_name(c.i.rt), | |
361 | c.r.rd); | |
362 | case OP_CP0_RFE: | |
363 | return snprintf(buf, len, "rfe "); | |
364 | default: | |
365 | return snprintf(buf, len, "unknown (0x%08x)", c.opcode); | |
366 | } | |
367 | } | |
368 | } | |
369 | ||
370 | static int print_op(union code c, u32 pc, char *buf, size_t len, | |
ba3814c1 | 371 | const char * const **flags_ptr, size_t *nb_flags, |
22eee2ac | 372 | bool *is_io) |
98fa08a5 PC |
373 | { |
374 | if (c.opcode == 0) | |
375 | return snprintf(buf, len, "nop "); | |
376 | ||
377 | switch (c.i.op) { | |
378 | case OP_SPECIAL: | |
379 | return print_op_special(c, buf, len, flags_ptr, nb_flags); | |
380 | case OP_REGIMM: | |
381 | *flags_ptr = opcode_branch_flags; | |
382 | *nb_flags = ARRAY_SIZE(opcode_branch_flags); | |
383 | return snprintf(buf, len, "%s%s,0x%x", | |
384 | regimm_opcodes[c.i.rt], | |
385 | lightrec_reg_name(c.i.rs), | |
386 | pc + 4 + ((s16)c.i.imm << 2)); | |
387 | case OP_J: | |
388 | case OP_JAL: | |
d8b04acd PC |
389 | *flags_ptr = opcode_branch_flags; |
390 | *nb_flags = ARRAY_SIZE(opcode_branch_flags); | |
98fa08a5 PC |
391 | return snprintf(buf, len, "%s0x%x", |
392 | std_opcodes[c.i.op], | |
393 | (pc & 0xf0000000) | (c.j.imm << 2)); | |
394 | case OP_BEQ: | |
03535202 PC |
395 | if (c.i.rs == c.i.rt) { |
396 | *flags_ptr = opcode_branch_flags; | |
397 | *nb_flags = ARRAY_SIZE(opcode_branch_flags); | |
398 | return snprintf(buf, len, "b 0x%x", | |
399 | pc + 4 + ((s16)c.i.imm << 2)); | |
400 | } | |
401 | fallthrough; | |
98fa08a5 PC |
402 | case OP_BNE: |
403 | case OP_BLEZ: | |
404 | case OP_BGTZ: | |
405 | *flags_ptr = opcode_branch_flags; | |
406 | *nb_flags = ARRAY_SIZE(opcode_branch_flags); | |
407 | return snprintf(buf, len, "%s%s,%s,0x%x", | |
408 | std_opcodes[c.i.op], | |
409 | lightrec_reg_name(c.i.rs), | |
410 | lightrec_reg_name(c.i.rt), | |
411 | pc + 4 + ((s16)c.i.imm << 2)); | |
412 | case OP_ADDI: | |
413 | case OP_ADDIU: | |
684432ad PC |
414 | case OP_ORI: |
415 | *flags_ptr = opcode_movi_flags; | |
416 | *nb_flags = ARRAY_SIZE(opcode_movi_flags); | |
417 | fallthrough; | |
98fa08a5 PC |
418 | case OP_SLTI: |
419 | case OP_SLTIU: | |
420 | case OP_ANDI: | |
98fa08a5 PC |
421 | case OP_XORI: |
422 | return snprintf(buf, len, "%s%s,%s,0x%04hx", | |
423 | std_opcodes[c.i.op], | |
424 | lightrec_reg_name(c.i.rt), | |
425 | lightrec_reg_name(c.i.rs), | |
426 | (u16)c.i.imm); | |
427 | ||
428 | case OP_LUI: | |
684432ad PC |
429 | *flags_ptr = opcode_movi_flags; |
430 | *nb_flags = ARRAY_SIZE(opcode_movi_flags); | |
98fa08a5 PC |
431 | return snprintf(buf, len, "%s%s,0x%04hx", |
432 | std_opcodes[c.i.op], | |
433 | lightrec_reg_name(c.i.rt), | |
434 | (u16)c.i.imm); | |
435 | case OP_CP0: | |
436 | return print_op_cp(c, buf, len, 0); | |
437 | case OP_CP2: | |
438 | return print_op_cp(c, buf, len, 2); | |
439 | case OP_LB: | |
440 | case OP_LH: | |
441 | case OP_LWL: | |
442 | case OP_LW: | |
443 | case OP_LBU: | |
444 | case OP_LHU: | |
445 | case OP_LWR: | |
446 | case OP_SB: | |
447 | case OP_SH: | |
448 | case OP_SWL: | |
449 | case OP_SW: | |
450 | case OP_SWR: | |
5459088b PC |
451 | case OP_META_LWU: |
452 | case OP_META_SWU: | |
98fa08a5 PC |
453 | *flags_ptr = opcode_io_flags; |
454 | *nb_flags = ARRAY_SIZE(opcode_io_flags); | |
22eee2ac | 455 | *is_io = true; |
98fa08a5 PC |
456 | return snprintf(buf, len, "%s%s,%hd(%s)", |
457 | std_opcodes[c.i.op], | |
458 | lightrec_reg_name(c.i.rt), | |
459 | (s16)c.i.imm, | |
460 | lightrec_reg_name(c.i.rs)); | |
461 | case OP_LWC2: | |
462 | case OP_SWC2: | |
463 | *flags_ptr = opcode_io_flags; | |
464 | *nb_flags = ARRAY_SIZE(opcode_io_flags); | |
465 | return snprintf(buf, len, "%s%s,%hd(%s)", | |
466 | std_opcodes[c.i.op], | |
467 | lightrec_reg_name(c.i.rt), | |
468 | (s16)c.i.imm, | |
469 | lightrec_reg_name(c.i.rs)); | |
cb72ea13 PC |
470 | case OP_META: |
471 | return snprintf(buf, len, "%s%s,%s", | |
472 | meta_opcodes[c.m.op], | |
473 | lightrec_reg_name(c.m.rd), | |
474 | lightrec_reg_name(c.m.rs)); | |
ba3814c1 PC |
475 | case OP_META_MULT2: |
476 | case OP_META_MULTU2: | |
477 | *flags_ptr = opcode_multdiv_flags; | |
478 | *nb_flags = ARRAY_SIZE(opcode_multdiv_flags); | |
479 | return snprintf(buf, len, "%s%s,%s,%s,%u", | |
480 | mult2_opcodes[c.i.op == OP_META_MULTU2], | |
481 | lightrec_reg_name(get_mult_div_hi(c)), | |
482 | lightrec_reg_name(get_mult_div_lo(c)), | |
483 | lightrec_reg_name(c.r.rs), c.r.op); | |
98fa08a5 PC |
484 | default: |
485 | return snprintf(buf, len, "unknown (0x%08x)", c.opcode); | |
486 | } | |
487 | } | |
488 | ||
02487de7 | 489 | void lightrec_print_disassembly(const struct block *block, const u32 *code_ptr) |
98fa08a5 PC |
490 | { |
491 | const struct opcode *op; | |
ba3814c1 | 492 | const char * const *flags_ptr; |
98fa08a5 PC |
493 | size_t nb_flags, count, count2; |
494 | char buf[256], buf2[256], buf3[256]; | |
d16005f8 | 495 | unsigned int i; |
02487de7 | 496 | u32 pc, branch_pc, code; |
22eee2ac | 497 | bool is_io; |
98fa08a5 PC |
498 | |
499 | for (i = 0; i < block->nb_ops; i++) { | |
500 | op = &block->opcode_list[i]; | |
501 | branch_pc = get_branch_pc(block, i, 0); | |
502 | pc = block->pc + (i << 2); | |
02487de7 | 503 | code = LE32TOH(code_ptr[i]); |
98fa08a5 | 504 | |
02487de7 | 505 | count = print_op((union code)code, pc, buf, sizeof(buf), |
22eee2ac | 506 | &flags_ptr, &nb_flags, &is_io); |
98fa08a5 PC |
507 | |
508 | flags_ptr = NULL; | |
509 | nb_flags = 0; | |
22eee2ac | 510 | is_io = false; |
98fa08a5 | 511 | count2 = print_op(op->c, branch_pc, buf2, sizeof(buf2), |
22eee2ac | 512 | &flags_ptr, &nb_flags, &is_io); |
98fa08a5 | 513 | |
02487de7 | 514 | if (code == op->c.opcode) { |
98fa08a5 PC |
515 | *buf2 = '\0'; |
516 | count2 = 0; | |
517 | } | |
518 | ||
03535202 | 519 | print_flags(buf3, sizeof(buf3), op, flags_ptr, nb_flags, is_io); |
d16005f8 | 520 | |
98fa08a5 PC |
521 | printf("0x%08x (0x%x)\t%s%*c%s%*c%s\n", pc, i << 2, |
522 | buf, 30 - (int)count, ' ', buf2, 30 - (int)count2, ' ', buf3); | |
d16005f8 PC |
523 | } |
524 | } |