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/dis-asm.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 | } |
362 | |