hw/arm/virt: parameter passing cleanups
[qemu.git] / disas / lm32.c
1 /*
2 * Simple LatticeMico32 disassembler.
3 *
4 * Copyright (c) 2012 Michael Walle <michael@walle.cc>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21 #include "qemu/osdep.h"
22 #include "disas/bfd.h"
23
24 typedef enum {
25 LM32_OP_SRUI = 0, LM32_OP_NORI, LM32_OP_MULI, LM32_OP_SH, LM32_OP_LB,
26 LM32_OP_SRI, LM32_OP_XORI, LM32_OP_LH, LM32_OP_ANDI, LM32_OP_XNORI,
27 LM32_OP_LW, LM32_OP_LHU, LM32_OP_SB, LM32_OP_ADDI, LM32_OP_ORI,
28 LM32_OP_SLI, LM32_OP_LBU, LM32_OP_BE, LM32_OP_BG, LM32_OP_BGE,
29 LM32_OP_BGEU, LM32_OP_BGU, LM32_OP_SW, LM32_OP_BNE, LM32_OP_ANDHI,
30 LM32_OP_CMPEI, LM32_OP_CMPGI, LM32_OP_CMPGEI, LM32_OP_CMPGEUI,
31 LM32_OP_CMPGUI, LM32_OP_ORHI, LM32_OP_CMPNEI, LM32_OP_SRU, LM32_OP_NOR,
32 LM32_OP_MUL, LM32_OP_DIVU, LM32_OP_RCSR, LM32_OP_SR, LM32_OP_XOR,
33 LM32_OP_ILL0, LM32_OP_AND, LM32_OP_XNOR, LM32_OP_ILL1, LM32_OP_SCALL,
34 LM32_OP_SEXTB, LM32_OP_ADD, LM32_OP_OR, LM32_OP_SL, LM32_OP_B,
35 LM32_OP_MODU, LM32_OP_SUB, LM32_OP_ILL2, LM32_OP_WCSR, LM32_OP_ILL3,
36 LM32_OP_CALL, LM32_OP_SEXTH, LM32_OP_BI, LM32_OP_CMPE, LM32_OP_CMPG,
37 LM32_OP_CMPGE, LM32_OP_CMPGEU, LM32_OP_CMPGU, LM32_OP_CALLI, LM32_OP_CMPNE,
38 } Lm32Opcode;
39
40 typedef enum {
41 FMT_INVALID = 0, FMT_RRI5, FMT_RRI16, FMT_IMM26, FMT_LOAD, FMT_STORE,
42 FMT_RRR, FMT_R, FMT_RNR, FMT_CRN, FMT_CNR, FMT_BREAK,
43 } Lm32OpcodeFmt;
44
45 typedef enum {
46 LM32_CSR_IE = 0, LM32_CSR_IM, LM32_CSR_IP, LM32_CSR_ICC, LM32_CSR_DCC,
47 LM32_CSR_CC, LM32_CSR_CFG, LM32_CSR_EBA, LM32_CSR_DC, LM32_CSR_DEBA,
48 LM32_CSR_CFG2, LM32_CSR_JTX = 0xe, LM32_CSR_JRX, LM32_CSR_BP0,
49 LM32_CSR_BP1, LM32_CSR_BP2, LM32_CSR_BP3, LM32_CSR_WP0 = 0x18,
50 LM32_CSR_WP1, LM32_CSR_WP2, LM32_CSR_WP3,
51 } Lm32CsrNum;
52
53 typedef struct {
54 int csr;
55 const char *name;
56 } Lm32CsrInfo;
57
58 static const Lm32CsrInfo lm32_csr_info[] = {
59 {LM32_CSR_IE, "ie", },
60 {LM32_CSR_IM, "im", },
61 {LM32_CSR_IP, "ip", },
62 {LM32_CSR_ICC, "icc", },
63 {LM32_CSR_DCC, "dcc", },
64 {LM32_CSR_CC, "cc", },
65 {LM32_CSR_CFG, "cfg", },
66 {LM32_CSR_EBA, "eba", },
67 {LM32_CSR_DC, "dc", },
68 {LM32_CSR_DEBA, "deba", },
69 {LM32_CSR_CFG2, "cfg2", },
70 {LM32_CSR_JTX, "jtx", },
71 {LM32_CSR_JRX, "jrx", },
72 {LM32_CSR_BP0, "bp0", },
73 {LM32_CSR_BP1, "bp1", },
74 {LM32_CSR_BP2, "bp2", },
75 {LM32_CSR_BP3, "bp3", },
76 {LM32_CSR_WP0, "wp0", },
77 {LM32_CSR_WP1, "wp1", },
78 {LM32_CSR_WP2, "wp2", },
79 {LM32_CSR_WP3, "wp3", },
80 };
81
82 static const Lm32CsrInfo *find_csr_info(int csr)
83 {
84 const Lm32CsrInfo *info;
85 int i;
86
87 for (i = 0; i < ARRAY_SIZE(lm32_csr_info); i++) {
88 info = &lm32_csr_info[i];
89 if (csr == info->csr) {
90 return info;
91 }
92 }
93
94 return NULL;
95 }
96
97 typedef struct {
98 int reg;
99 const char *name;
100 } Lm32RegInfo;
101
102 typedef enum {
103 LM32_REG_R0 = 0, LM32_REG_R1, LM32_REG_R2, LM32_REG_R3, LM32_REG_R4,
104 LM32_REG_R5, LM32_REG_R6, LM32_REG_R7, LM32_REG_R8, LM32_REG_R9,
105 LM32_REG_R10, LM32_REG_R11, LM32_REG_R12, LM32_REG_R13, LM32_REG_R14,
106 LM32_REG_R15, LM32_REG_R16, LM32_REG_R17, LM32_REG_R18, LM32_REG_R19,
107 LM32_REG_R20, LM32_REG_R21, LM32_REG_R22, LM32_REG_R23, LM32_REG_R24,
108 LM32_REG_R25, LM32_REG_GP, LM32_REG_FP, LM32_REG_SP, LM32_REG_RA,
109 LM32_REG_EA, LM32_REG_BA,
110 } Lm32RegNum;
111
112 static const Lm32RegInfo lm32_reg_info[] = {
113 {LM32_REG_R0, "r0", },
114 {LM32_REG_R1, "r1", },
115 {LM32_REG_R2, "r2", },
116 {LM32_REG_R3, "r3", },
117 {LM32_REG_R4, "r4", },
118 {LM32_REG_R5, "r5", },
119 {LM32_REG_R6, "r6", },
120 {LM32_REG_R7, "r7", },
121 {LM32_REG_R8, "r8", },
122 {LM32_REG_R9, "r9", },
123 {LM32_REG_R10, "r10", },
124 {LM32_REG_R11, "r11", },
125 {LM32_REG_R12, "r12", },
126 {LM32_REG_R13, "r13", },
127 {LM32_REG_R14, "r14", },
128 {LM32_REG_R15, "r15", },
129 {LM32_REG_R16, "r16", },
130 {LM32_REG_R17, "r17", },
131 {LM32_REG_R18, "r18", },
132 {LM32_REG_R19, "r19", },
133 {LM32_REG_R20, "r20", },
134 {LM32_REG_R21, "r21", },
135 {LM32_REG_R22, "r22", },
136 {LM32_REG_R23, "r23", },
137 {LM32_REG_R24, "r24", },
138 {LM32_REG_R25, "r25", },
139 {LM32_REG_GP, "gp", },
140 {LM32_REG_FP, "fp", },
141 {LM32_REG_SP, "sp", },
142 {LM32_REG_RA, "ra", },
143 {LM32_REG_EA, "ea", },
144 {LM32_REG_BA, "ba", },
145 };
146
147 static const Lm32RegInfo *find_reg_info(int reg)
148 {
149 assert(ARRAY_SIZE(lm32_reg_info) == 32);
150 return &lm32_reg_info[reg & 0x1f];
151 }
152
153 typedef struct {
154 struct {
155 uint32_t code;
156 uint32_t mask;
157 } op;
158 const char *name;
159 const char *args_fmt;
160 } Lm32OpcodeInfo;
161
162 static const Lm32OpcodeInfo lm32_opcode_info[] = {
163 /* pseudo instructions */
164 {{0x34000000, 0xffffffff}, "nop", NULL},
165 {{0xac000002, 0xffffffff}, "break", NULL},
166 {{0xac000003, 0xffffffff}, "scall", NULL},
167 {{0xc3e00000, 0xffffffff}, "bret", NULL},
168 {{0xc3c00000, 0xffffffff}, "eret", NULL},
169 {{0xc3a00000, 0xffffffff}, "ret", NULL},
170 {{0xa4000000, 0xfc1f07ff}, "not", "%2, %0"},
171 {{0xb8000000, 0xfc1f07ff}, "mv", "%2, %0"},
172 {{0x71e00000, 0xffe00000}, "mvhi", "%1, %u"},
173 {{0x34000000, 0xffe00000}, "mvi", "%1, %s"},
174
175 #define _O(op) {op << 26, 0x3f << 26}
176 /* regular opcodes */
177 {_O(LM32_OP_ADD), "add", "%2, %0, %1" },
178 {_O(LM32_OP_ADDI), "addi", "%1, %0, %s" },
179 {_O(LM32_OP_AND), "and", "%2, %0, %1" },
180 {_O(LM32_OP_ANDHI), "andhi", "%1, %0, %u" },
181 {_O(LM32_OP_ANDI), "andi", "%1, %0, %u" },
182 {_O(LM32_OP_B), "b", "%0", },
183 {_O(LM32_OP_BE), "be", "%1, %0, %r" },
184 {_O(LM32_OP_BG), "bg", "%1, %0, %r" },
185 {_O(LM32_OP_BGE), "bge", "%1, %0, %r" },
186 {_O(LM32_OP_BGEU), "bgeu", "%1, %0, %r" },
187 {_O(LM32_OP_BGU), "bgu", "%1, %0, %r" },
188 {_O(LM32_OP_BI), "bi", "%R", },
189 {_O(LM32_OP_BNE), "bne", "%1, %0, %r" },
190 {_O(LM32_OP_CALL), "call", "%0", },
191 {_O(LM32_OP_CALLI), "calli", "%R", },
192 {_O(LM32_OP_CMPE), "cmpe", "%2, %0, %1" },
193 {_O(LM32_OP_CMPEI), "cmpei", "%1, %0, %s" },
194 {_O(LM32_OP_CMPG), "cmpg", "%2, %0, %1" },
195 {_O(LM32_OP_CMPGE), "cmpge", "%2, %0, %1" },
196 {_O(LM32_OP_CMPGEI), "cmpgei", "%1, %0, %s" },
197 {_O(LM32_OP_CMPGEU), "cmpgeu", "%2, %0, %1" },
198 {_O(LM32_OP_CMPGEUI), "cmpgeui", "%1, %0, %s" },
199 {_O(LM32_OP_CMPGI), "cmpgi", "%1, %0, %s" },
200 {_O(LM32_OP_CMPGU), "cmpgu", "%2, %0, %1" },
201 {_O(LM32_OP_CMPGUI), "cmpgui", "%1, %0, %s" },
202 {_O(LM32_OP_CMPNE), "cmpne", "%2, %0, %1" },
203 {_O(LM32_OP_CMPNEI), "cmpnei", "%1, %0, %s" },
204 {_O(LM32_OP_DIVU), "divu", "%2, %0, %1" },
205 {_O(LM32_OP_LB), "lb", "%1, (%0+%s)" },
206 {_O(LM32_OP_LBU), "lbu", "%1, (%0+%s)" },
207 {_O(LM32_OP_LH), "lh", "%1, (%0+%s)" },
208 {_O(LM32_OP_LHU), "lhu", "%1, (%0+%s)" },
209 {_O(LM32_OP_LW), "lw", "%1, (%0+%s)" },
210 {_O(LM32_OP_MODU), "modu", "%2, %0, %1" },
211 {_O(LM32_OP_MULI), "muli", "%1, %0, %s" },
212 {_O(LM32_OP_MUL), "mul", "%2, %0, %1" },
213 {_O(LM32_OP_NORI), "nori", "%1, %0, %u" },
214 {_O(LM32_OP_NOR), "nor", "%2, %0, %1" },
215 {_O(LM32_OP_ORHI), "orhi", "%1, %0, %u" },
216 {_O(LM32_OP_ORI), "ori", "%1, %0, %u" },
217 {_O(LM32_OP_OR), "or", "%2, %0, %1" },
218 {_O(LM32_OP_RCSR), "rcsr", "%2, %c", },
219 {_O(LM32_OP_SB), "sb", "(%0+%s), %1" },
220 {_O(LM32_OP_SEXTB), "sextb", "%2, %0", },
221 {_O(LM32_OP_SEXTH), "sexth", "%2, %0", },
222 {_O(LM32_OP_SH), "sh", "(%0+%s), %1" },
223 {_O(LM32_OP_SLI), "sli", "%1, %0, %h" },
224 {_O(LM32_OP_SL), "sl", "%2, %0, %1" },
225 {_O(LM32_OP_SRI), "sri", "%1, %0, %h" },
226 {_O(LM32_OP_SR), "sr", "%2, %0, %1" },
227 {_O(LM32_OP_SRUI), "srui", "%1, %0, %d" },
228 {_O(LM32_OP_SRU), "sru", "%2, %0, %s" },
229 {_O(LM32_OP_SUB), "sub", "%2, %0, %s" },
230 {_O(LM32_OP_SW), "sw", "(%0+%s), %1" },
231 {_O(LM32_OP_WCSR), "wcsr", "%c, %1", },
232 {_O(LM32_OP_XNORI), "xnori", "%1, %0, %u" },
233 {_O(LM32_OP_XNOR), "xnor", "%2, %0, %1" },
234 {_O(LM32_OP_XORI), "xori", "%1, %0, %u" },
235 {_O(LM32_OP_XOR), "xor", "%2, %0, %1" },
236 #undef _O
237 };
238
239 static const Lm32OpcodeInfo *find_opcode_info(uint32_t opcode)
240 {
241 const Lm32OpcodeInfo *info;
242 int i;
243 for (i = 0; i < ARRAY_SIZE(lm32_opcode_info); i++) {
244 info = &lm32_opcode_info[i];
245 if ((opcode & info->op.mask) == info->op.code) {
246 return info;
247 }
248 }
249
250 return NULL;
251 }
252
253 int print_insn_lm32(bfd_vma memaddr, struct disassemble_info *info)
254 {
255 fprintf_function fprintf_fn = info->fprintf_func;
256 void *stream = info->stream;
257 int rc;
258 uint8_t insn[4];
259 const Lm32OpcodeInfo *opc_info;
260 uint32_t op;
261 const char *args_fmt;
262
263 rc = info->read_memory_func(memaddr, insn, 4, info);
264 if (rc != 0) {
265 info->memory_error_func(rc, memaddr, info);
266 return -1;
267 }
268
269 fprintf_fn(stream, "%02x %02x %02x %02x ",
270 insn[0], insn[1], insn[2], insn[3]);
271
272 op = bfd_getb32(insn);
273 opc_info = find_opcode_info(op);
274 if (opc_info) {
275 fprintf_fn(stream, "%-8s ", opc_info->name);
276 args_fmt = opc_info->args_fmt;
277 while (args_fmt && *args_fmt) {
278 if (*args_fmt == '%') {
279 switch (*(++args_fmt)) {
280 case '0': {
281 uint8_t r0;
282 const char *r0_name;
283 r0 = (op >> 21) & 0x1f;
284 r0_name = find_reg_info(r0)->name;
285 fprintf_fn(stream, "%s", r0_name);
286 break;
287 }
288 case '1': {
289 uint8_t r1;
290 const char *r1_name;
291 r1 = (op >> 16) & 0x1f;
292 r1_name = find_reg_info(r1)->name;
293 fprintf_fn(stream, "%s", r1_name);
294 break;
295 }
296 case '2': {
297 uint8_t r2;
298 const char *r2_name;
299 r2 = (op >> 11) & 0x1f;
300 r2_name = find_reg_info(r2)->name;
301 fprintf_fn(stream, "%s", r2_name);
302 break;
303 }
304 case 'c': {
305 uint8_t csr;
306 const Lm32CsrInfo *info;
307 csr = (op >> 21) & 0x1f;
308 info = find_csr_info(csr);
309 if (info) {
310 fprintf_fn(stream, "%s", info->name);
311 } else {
312 fprintf_fn(stream, "0x%x", csr);
313 }
314 break;
315 }
316 case 'u': {
317 uint16_t u16;
318 u16 = op & 0xffff;
319 fprintf_fn(stream, "0x%x", u16);
320 break;
321 }
322 case 's': {
323 int16_t s16;
324 s16 = (int16_t)(op & 0xffff);
325 fprintf_fn(stream, "%d", s16);
326 break;
327 }
328 case 'r': {
329 uint32_t rela;
330 rela = memaddr + (((int16_t)(op & 0xffff)) << 2);
331 fprintf_fn(stream, "%x", rela);
332 break;
333 }
334 case 'R': {
335 uint32_t rela;
336 int32_t imm26;
337 imm26 = (int32_t)((op & 0x3ffffff) << 6) >> 4;
338 rela = memaddr + imm26;
339 fprintf_fn(stream, "%x", rela);
340 break;
341 }
342 case 'h': {
343 uint8_t u5;
344 u5 = (op & 0x1f);
345 fprintf_fn(stream, "%d", u5);
346 break;
347 }
348 default:
349 break;
350 }
351 } else {
352 fprintf_fn(stream, "%c", *args_fmt);
353 }
354 args_fmt++;
355 }
356 } else {
357 fprintf_fn(stream, ".word 0x%x", op);
358 }
359
360 return 4;
361 }