Commit | Line | Data |
---|---|---|
35c08157 | 1 | /* NDS32-specific support for 32-bit ELF. |
82704155 | 2 | Copyright (C) 2012-2019 Free Software Foundation, Inc. |
35c08157 KLC |
3 | Contributed by Andes Technology Corporation. |
4 | ||
5 | This file is part of BFD, the Binary File Descriptor library. | |
6 | ||
7 | This program is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 3 of the License, or | |
10 | (at your option) any later version. | |
11 | ||
12 | This program is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with this program; if not, write to the Free Software | |
19 | Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA | |
40c7a7cb | 20 | 02110-1301, USA. */ |
35c08157 KLC |
21 | |
22 | #include "sysdep.h" | |
23 | #include <stdio.h> | |
24 | #include "ansidecl.h" | |
88c1242d | 25 | #include "disassemble.h" |
35c08157 KLC |
26 | #include "bfd.h" |
27 | #include "symcat.h" | |
28 | #include "libiberty.h" | |
29 | #include "opintl.h" | |
30 | #include "bfd_stdint.h" | |
40c7a7cb KLC |
31 | #include "hashtab.h" |
32 | #include "nds32-asm.h" | |
33 | #include "opcode/nds32.h" | |
35c08157 | 34 | |
40c7a7cb KLC |
35 | /* Get fields macro define. */ |
36 | #define MASK_OP(insn, mask) ((insn) & (0x3f << 25 | (mask))) | |
35c08157 | 37 | |
fbaf61ad NC |
38 | /* For mapping symbol. */ |
39 | enum map_type | |
40 | { | |
41 | MAP_DATA0, | |
42 | MAP_DATA1, | |
43 | MAP_DATA2, | |
44 | MAP_DATA3, | |
45 | MAP_DATA4, | |
46 | MAP_CODE, | |
47 | }; | |
48 | ||
49 | struct nds32_private_data | |
50 | { | |
51 | /* Whether any mapping symbols are present in the provided symbol | |
52 | table. -1 if we do not know yet, otherwise 0 or 1. */ | |
53 | int has_mapping_symbols; | |
54 | ||
55 | /* Track the last type (although this doesn't seem to be useful). */ | |
56 | enum map_type last_mapping_type; | |
57 | ||
58 | /* Tracking symbol table information. */ | |
59 | int last_symbol_index; | |
60 | bfd_vma last_addr; | |
61 | }; | |
62 | ||
35c08157 KLC |
63 | /* Default text to print if an instruction isn't recognized. */ |
64 | #define UNKNOWN_INSN_MSG _("*unknown*") | |
40c7a7cb KLC |
65 | #define NDS32_PARSE_INSN16 0x01 |
66 | #define NDS32_PARSE_INSN32 0x02 | |
40c7a7cb | 67 | |
fbaf61ad NC |
68 | extern const field_t *nds32_field_table[NDS32_CORE_COUNT]; |
69 | extern opcode_t *nds32_opcode_table[NDS32_CORE_COUNT]; | |
70 | extern keyword_t **nds32_keyword_table[NDS32_CORE_COUNT]; | |
40c7a7cb KLC |
71 | extern struct nds32_opcode nds32_opcodes[]; |
72 | extern const field_t operand_fields[]; | |
fbaf61ad | 73 | extern keyword_t *keywords[]; |
40c7a7cb KLC |
74 | extern const keyword_t keyword_gpr[]; |
75 | static void print_insn16 (bfd_vma pc, disassemble_info *info, | |
76 | uint32_t insn, uint32_t parse_mode); | |
77 | static void print_insn32 (bfd_vma pc, disassemble_info *info, uint32_t insn, | |
78 | uint32_t parse_mode); | |
79 | static uint32_t nds32_mask_opcode (uint32_t); | |
80 | static void nds32_special_opcode (uint32_t, struct nds32_opcode **); | |
fbaf61ad NC |
81 | static int get_mapping_symbol_type (struct disassemble_info *, int, |
82 | enum map_type *); | |
83 | static int is_mapping_symbol (struct disassemble_info *, int, | |
84 | enum map_type *); | |
40c7a7cb KLC |
85 | |
86 | /* define in objdump.c. */ | |
87 | struct objdump_disasm_info | |
35c08157 | 88 | { |
40c7a7cb KLC |
89 | bfd * abfd; |
90 | asection * sec; | |
91 | bfd_boolean require_sec; | |
92 | arelent ** dynrelbuf; | |
93 | long dynrelcount; | |
94 | disassembler_ftype disassemble_fn; | |
95 | arelent * reloc; | |
35c08157 KLC |
96 | }; |
97 | ||
40c7a7cb | 98 | /* Hash function for disassemble. */ |
35c08157 | 99 | |
40c7a7cb | 100 | static htab_t opcode_htab; |
35c08157 | 101 | |
40c7a7cb | 102 | /* Find the value map register name. */ |
6b9d3259 | 103 | |
40c7a7cb KLC |
104 | static keyword_t * |
105 | nds32_find_reg_keyword (keyword_t *reg, int value) | |
35c08157 | 106 | { |
40c7a7cb KLC |
107 | if (!reg) |
108 | return NULL; | |
6b9d3259 | 109 | |
40c7a7cb KLC |
110 | while (reg->name != NULL && reg->value != value) |
111 | { | |
112 | reg++; | |
113 | } | |
114 | if (reg->name == NULL) | |
115 | return NULL; | |
116 | return reg; | |
117 | } | |
35c08157 KLC |
118 | |
119 | static void | |
40c7a7cb KLC |
120 | nds32_parse_audio_ext (const field_t *pfd, |
121 | disassemble_info *info, uint32_t insn) | |
35c08157 | 122 | { |
35c08157 KLC |
123 | fprintf_ftype func = info->fprintf_func; |
124 | void *stream = info->stream; | |
40c7a7cb KLC |
125 | keyword_t *psys_reg; |
126 | int int_value, new_value; | |
35c08157 | 127 | |
40c7a7cb | 128 | if (pfd->hw_res == HW_INT || pfd->hw_res == HW_UINT) |
35c08157 | 129 | { |
40c7a7cb KLC |
130 | if (pfd->hw_res == HW_INT) |
131 | int_value = | |
132 | N32_IMMS ((insn >> pfd->bitpos), pfd->bitsize) << pfd->shift; | |
133 | else | |
134 | int_value = __GF (insn, pfd->bitpos, pfd->bitsize) << pfd->shift; | |
35c08157 | 135 | |
3ee6e4fb | 136 | if (int_value < 10) |
40c7a7cb KLC |
137 | func (stream, "#%d", int_value); |
138 | else | |
139 | func (stream, "#0x%x", int_value); | |
35c08157 KLC |
140 | return; |
141 | } | |
40c7a7cb KLC |
142 | int_value = |
143 | __GF (insn, pfd->bitpos, pfd->bitsize) << pfd->shift; | |
144 | new_value = int_value; | |
145 | psys_reg = (keyword_t*) keywords[pfd->hw_res]; | |
35c08157 | 146 | |
40c7a7cb KLC |
147 | /* p = bit[4].bit[1:0], r = bit[4].bit[3:2]. */ |
148 | if (strcmp (pfd->name, "im5_i") == 0) | |
35c08157 | 149 | { |
40c7a7cb KLC |
150 | new_value = int_value & 0x03; |
151 | new_value |= ((int_value & 0x10) >> 2); | |
35c08157 | 152 | } |
40c7a7cb | 153 | else if (strcmp (pfd->name, "im5_m") == 0) |
35c08157 | 154 | { |
40c7a7cb | 155 | new_value = ((int_value & 0x1C) >> 2); |
35c08157 | 156 | } |
40c7a7cb KLC |
157 | /* p = 0.bit[1:0], r = 0.bit[3:2]. */ |
158 | /* q = 1.bit[1:0], s = 1.bit[5:4]. */ | |
159 | else if (strcmp (pfd->name, "im6_iq") == 0) | |
35c08157 | 160 | { |
40c7a7cb | 161 | new_value |= 0x04; |
35c08157 | 162 | } |
40c7a7cb | 163 | else if (strcmp (pfd->name, "im6_ms") == 0) |
35c08157 | 164 | { |
40c7a7cb KLC |
165 | new_value |= 0x04; |
166 | } | |
167 | /* Rt CONCAT(c, t21, t0). */ | |
168 | else if (strcmp (pfd->name, "a_rt21") == 0) | |
169 | { | |
170 | new_value = (insn & 0x00000020) >> 5; | |
171 | new_value |= (insn & 0x00000C00) >> 9; | |
172 | new_value |= (insn & 0x00008000) >> 12; | |
173 | } | |
174 | else if (strcmp (pfd->name, "a_rte") == 0) | |
175 | { | |
176 | new_value = (insn & 0x00000C00) >> 9; | |
177 | new_value |= (insn & 0x00008000) >> 12; | |
178 | } | |
179 | else if (strcmp (pfd->name, "a_rte1") == 0) | |
180 | { | |
181 | new_value = (insn & 0x00000C00) >> 9; | |
182 | new_value |= (insn & 0x00008000) >> 12; | |
183 | new_value |= 0x01; | |
35c08157 | 184 | } |
40c7a7cb KLC |
185 | else if (strcmp (pfd->name, "a_rte69") == 0) |
186 | { | |
187 | new_value = int_value << 1; | |
188 | } | |
189 | else if (strcmp (pfd->name, "a_rte69_1") == 0) | |
190 | { | |
191 | new_value = int_value << 1; | |
192 | new_value |= 0x01; | |
193 | } | |
194 | ||
195 | psys_reg = nds32_find_reg_keyword (psys_reg, new_value); | |
196 | if (!psys_reg) | |
197 | func (stream, "???"); | |
198 | else | |
199 | func (stream, "$%s", psys_reg->name); | |
35c08157 KLC |
200 | } |
201 | ||
fbaf61ad NC |
202 | /* Match instruction opcode with keyword table. */ |
203 | ||
204 | static field_t * | |
205 | match_field (char *name) | |
206 | { | |
207 | field_t *pfd; | |
208 | int k; | |
209 | ||
210 | for (k = 0; k < NDS32_CORE_COUNT; k++) | |
211 | { | |
212 | pfd = (field_t *) nds32_field_table[k]; | |
213 | while (1) | |
214 | { | |
215 | if (pfd->name == NULL) | |
216 | break; | |
217 | if (strcmp (name, pfd->name) == 0) | |
218 | return pfd; | |
219 | pfd++; | |
220 | } | |
221 | } | |
222 | ||
223 | return NULL; | |
224 | } | |
225 | ||
40c7a7cb | 226 | /* Dump instruction. If the opcode is unknown, return FALSE. */ |
35c08157 KLC |
227 | |
228 | static void | |
40c7a7cb KLC |
229 | nds32_parse_opcode (struct nds32_opcode *opc, bfd_vma pc ATTRIBUTE_UNUSED, |
230 | disassemble_info *info, uint32_t insn, | |
231 | uint32_t parse_mode) | |
35c08157 | 232 | { |
40c7a7cb | 233 | int op = 0; |
35c08157 KLC |
234 | fprintf_ftype func = info->fprintf_func; |
235 | void *stream = info->stream; | |
40c7a7cb KLC |
236 | const char *pstr_src; |
237 | char *pstr_tmp; | |
238 | char tmp_string[16]; | |
239 | unsigned int push25gpr = 0, lsmwRb, lsmwRe, lsmwEnb4, checkbit, i; | |
240 | int int_value, ifthe1st = 1; | |
241 | const field_t *pfd; | |
242 | keyword_t *psys_reg; | |
243 | ||
244 | if (opc == NULL) | |
35c08157 | 245 | { |
35c08157 KLC |
246 | func (stream, UNKNOWN_INSN_MSG); |
247 | return; | |
248 | } | |
35c08157 | 249 | |
40c7a7cb KLC |
250 | pstr_src = opc->instruction; |
251 | if (*pstr_src == 0) | |
35c08157 | 252 | { |
40c7a7cb | 253 | func (stream, "%s", opc->opcode); |
35c08157 KLC |
254 | return; |
255 | } | |
40c7a7cb KLC |
256 | /* NDS32_PARSE_INSN16. */ |
257 | if (parse_mode & NDS32_PARSE_INSN16) | |
258 | { | |
259 | func (stream, "%s ", opc->opcode); | |
260 | } | |
35c08157 | 261 | |
40c7a7cb KLC |
262 | /* NDS32_PARSE_INSN32. */ |
263 | else | |
35c08157 | 264 | { |
40c7a7cb KLC |
265 | op = N32_OP6 (insn); |
266 | if (op == N32_OP6_LSMW) | |
267 | func (stream, "%s.", opc->opcode); | |
268 | else if (strstr (opc->instruction, "tito")) | |
269 | func (stream, "%s", opc->opcode); | |
270 | else | |
3ee6e4fb | 271 | func (stream, "%s\t", opc->opcode); |
35c08157 KLC |
272 | } |
273 | ||
40c7a7cb | 274 | while (*pstr_src) |
35c08157 | 275 | { |
40c7a7cb KLC |
276 | switch (*pstr_src) |
277 | { | |
278 | case '%': | |
279 | case '=': | |
280 | case '&': | |
281 | pstr_src++; | |
3ee6e4fb | 282 | /* Compare with operand_fields[].name. */ |
40c7a7cb KLC |
283 | pstr_tmp = &tmp_string[0]; |
284 | while (*pstr_src) | |
285 | { | |
286 | if ((*pstr_src == ',') || (*pstr_src == ' ') | |
287 | || (*pstr_src == '{') || (*pstr_src == '}') | |
288 | || (*pstr_src == '[') || (*pstr_src == ']') | |
289 | || (*pstr_src == '(') || (*pstr_src == ')') | |
290 | || (*pstr_src == '+') || (*pstr_src == '<')) | |
291 | break; | |
292 | *pstr_tmp++ = *pstr_src++; | |
293 | } | |
294 | *pstr_tmp = 0; | |
35c08157 | 295 | |
fbaf61ad NC |
296 | if ((pfd = match_field (&tmp_string[0])) == NULL) |
297 | return; | |
35c08157 | 298 | |
3ee6e4fb | 299 | /* For insn-16. */ |
40c7a7cb KLC |
300 | if (parse_mode & NDS32_PARSE_INSN16) |
301 | { | |
302 | if (pfd->hw_res == HW_GPR) | |
303 | { | |
304 | int_value = | |
305 | __GF (insn, pfd->bitpos, pfd->bitsize) << pfd->shift; | |
306 | /* push25/pop25. */ | |
307 | if ((opc->value == 0xfc00) || (opc->value == 0xfc80)) | |
308 | { | |
309 | if (int_value == 0) | |
310 | int_value = 6; | |
311 | else | |
312 | int_value = (6 + (0x01 << int_value)); | |
313 | push25gpr = int_value; | |
314 | } | |
315 | else if (strcmp (pfd->name, "rt4") == 0) | |
316 | { | |
317 | int_value = nds32_r45map[int_value]; | |
318 | } | |
319 | func (stream, "$%s", keyword_gpr[int_value].name); | |
320 | } | |
321 | else if ((pfd->hw_res == HW_INT) || (pfd->hw_res == HW_UINT)) | |
322 | { | |
323 | if (pfd->hw_res == HW_INT) | |
324 | int_value = | |
325 | N32_IMMS ((insn >> pfd->bitpos), | |
326 | pfd->bitsize) << pfd->shift; | |
327 | else | |
328 | int_value = | |
329 | __GF (insn, pfd->bitpos, pfd->bitsize) << pfd->shift; | |
330 | ||
331 | /* movpi45. */ | |
332 | if (opc->value == 0xfa00) | |
333 | { | |
334 | int_value += 16; | |
335 | func (stream, "#0x%x", int_value); | |
336 | } | |
337 | /* lwi45.fe. */ | |
338 | else if (opc->value == 0xb200) | |
339 | { | |
340 | int_value = 0 - (128 - int_value); | |
341 | func (stream, "#%d", int_value); | |
342 | } | |
fbaf61ad | 343 | /* beqz38/bnez38/beqs38/bnes38/j8/beqzs8/bnezs8. */ |
40c7a7cb KLC |
344 | else if ((opc->value == 0xc000) || (opc->value == 0xc800) |
345 | || (opc->value == 0xd000) || (opc->value == 0xd800) | |
346 | || (opc->value == 0xd500) || (opc->value == 0xe800) | |
fbaf61ad | 347 | || (opc->value == 0xe900)) |
40c7a7cb KLC |
348 | { |
349 | info->print_address_func (int_value + pc, info); | |
350 | } | |
351 | /* push25/pop25. */ | |
352 | else if ((opc->value == 0xfc00) || (opc->value == 0xfc80)) | |
353 | { | |
354 | func (stream, "#%d ! {$r6", int_value); | |
355 | if (push25gpr != 6) | |
356 | func (stream, "~$%s", keyword_gpr[push25gpr].name); | |
357 | func (stream, ", $fp, $gp, $lp}"); | |
358 | } | |
40c7a7cb KLC |
359 | else if (pfd->hw_res == HW_INT) |
360 | { | |
3ee6e4fb | 361 | if (int_value < 10) |
40c7a7cb KLC |
362 | func (stream, "#%d", int_value); |
363 | else | |
364 | func (stream, "#0x%x", int_value); | |
365 | } | |
3ee6e4fb NC |
366 | else /* if (pfd->hw_res == HW_UINT). */ |
367 | { | |
368 | if (int_value < 10) | |
369 | func (stream, "#%u", int_value); | |
370 | else | |
371 | func (stream, "#0x%x", int_value); | |
372 | } | |
40c7a7cb | 373 | } |
35c08157 | 374 | |
40c7a7cb KLC |
375 | } |
376 | /* for audio-ext. */ | |
377 | else if (op == N32_OP6_AEXT) | |
378 | { | |
379 | nds32_parse_audio_ext (pfd, info, insn); | |
380 | } | |
381 | /* for insn-32. */ | |
fbaf61ad | 382 | else if (pfd->hw_res < HW_INT) |
40c7a7cb KLC |
383 | { |
384 | int_value = | |
385 | __GF (insn, pfd->bitpos, pfd->bitsize) << pfd->shift; | |
386 | ||
fbaf61ad NC |
387 | psys_reg = *(nds32_keyword_table[pfd->hw_res >> 8] |
388 | + (pfd->hw_res & 0xff)); | |
40c7a7cb KLC |
389 | |
390 | psys_reg = nds32_find_reg_keyword (psys_reg, int_value); | |
391 | /* For HW_SR, dump the index when it can't | |
392 | map the register name. */ | |
393 | if (!psys_reg && pfd->hw_res == HW_SR) | |
394 | func (stream, "%d", int_value); | |
395 | else if (!psys_reg) | |
396 | func (stream, "???"); | |
397 | else | |
398 | { | |
399 | if (pfd->hw_res == HW_GPR || pfd->hw_res == HW_CPR | |
400 | || pfd->hw_res == HW_FDR || pfd->hw_res == HW_FSR | |
401 | || pfd->hw_res == HW_DXR || pfd->hw_res == HW_SR | |
402 | || pfd->hw_res == HW_USR) | |
403 | func (stream, "$%s", psys_reg->name); | |
404 | else if (pfd->hw_res == HW_DTITON | |
405 | || pfd->hw_res == HW_DTITOFF) | |
406 | func (stream, ".%s", psys_reg->name); | |
407 | else | |
408 | func (stream, "%s", psys_reg->name); | |
409 | } | |
410 | } | |
411 | else if ((pfd->hw_res == HW_INT) || (pfd->hw_res == HW_UINT)) | |
412 | { | |
413 | if (pfd->hw_res == HW_INT) | |
414 | int_value = | |
415 | N32_IMMS ((insn >> pfd->bitpos), pfd->bitsize) << pfd->shift; | |
416 | else | |
417 | int_value = | |
418 | __GF (insn, pfd->bitpos, pfd->bitsize) << pfd->shift; | |
419 | ||
420 | if ((op == N32_OP6_BR1) || (op == N32_OP6_BR2)) | |
421 | { | |
422 | info->print_address_func (int_value + pc, info); | |
423 | } | |
424 | else if ((op == N32_OP6_BR3) && (pfd->bitpos == 0)) | |
425 | { | |
426 | info->print_address_func (int_value + pc, info); | |
427 | } | |
428 | else if (op == N32_OP6_JI) | |
429 | { | |
430 | /* FIXME: Handle relocation. */ | |
431 | if (info->flags & INSN_HAS_RELOC) | |
432 | pc = 0; | |
fbaf61ad | 433 | info->print_address_func (int_value + pc, info); |
40c7a7cb KLC |
434 | } |
435 | else if (op == N32_OP6_LSMW) | |
436 | { | |
437 | /* lmw.adm/smw.adm. */ | |
438 | func (stream, "#0x%x ! {", int_value); | |
439 | lsmwEnb4 = int_value; | |
440 | lsmwRb = ((insn >> 20) & 0x1F); | |
441 | lsmwRe = ((insn >> 10) & 0x1F); | |
442 | ||
443 | /* If [Rb, Re] specifies at least one register, | |
444 | Rb(4,0) <= Re(4,0) and 0 <= Rb(4,0), Re(4,0) < 28. | |
445 | Disassembling does not consider this currently because of | |
446 | the convience comparing with bsp320. */ | |
447 | if (lsmwRb != 31 || lsmwRe != 31) | |
448 | { | |
449 | func (stream, "$%s", keyword_gpr[lsmwRb].name); | |
450 | if (lsmwRb != lsmwRe) | |
451 | func (stream, "~$%s", keyword_gpr[lsmwRe].name); | |
452 | ifthe1st = 0; | |
453 | } | |
454 | if (lsmwEnb4 != 0) | |
455 | { | |
456 | /* $fp, $gp, $lp, $sp. */ | |
457 | checkbit = 0x08; | |
458 | for (i = 0; i < 4; i++) | |
459 | { | |
460 | if (lsmwEnb4 & checkbit) | |
461 | { | |
462 | if (ifthe1st == 1) | |
463 | { | |
464 | ifthe1st = 0; | |
465 | func (stream, "$%s", keyword_gpr[28 + i].name); | |
466 | } | |
467 | else | |
468 | func (stream, ", $%s", keyword_gpr[28 + i].name); | |
469 | } | |
470 | checkbit >>= 1; | |
471 | } | |
472 | } | |
473 | func (stream, "}"); | |
474 | } | |
475 | else if (pfd->hw_res == HW_INT) | |
476 | { | |
3ee6e4fb | 477 | if (int_value < 10) |
40c7a7cb KLC |
478 | func (stream, "#%d", int_value); |
479 | else | |
480 | func (stream, "#0x%x", int_value); | |
481 | } | |
3ee6e4fb | 482 | else /* if (pfd->hw_res == HW_UINT). */ |
40c7a7cb | 483 | { |
3ee6e4fb NC |
484 | if (int_value < 10) |
485 | func (stream, "#%u", int_value); | |
486 | else | |
487 | func (stream, "#0x%x", int_value); | |
40c7a7cb KLC |
488 | } |
489 | } | |
490 | break; | |
35c08157 | 491 | |
40c7a7cb KLC |
492 | case '{': |
493 | case '}': | |
494 | pstr_src++; | |
495 | break; | |
496 | ||
3ee6e4fb NC |
497 | case ',': |
498 | func (stream, ", "); | |
499 | pstr_src++; | |
500 | break; | |
501 | ||
502 | case '+': | |
503 | func (stream, " + "); | |
504 | pstr_src++; | |
505 | break; | |
506 | ||
507 | case '<': | |
508 | if (pstr_src[1] == '<') | |
509 | { | |
510 | func (stream, " << "); | |
511 | pstr_src += 2; | |
512 | } | |
513 | else | |
514 | { | |
515 | func (stream, " <"); | |
516 | pstr_src++; | |
517 | } | |
518 | break; | |
519 | ||
40c7a7cb KLC |
520 | default: |
521 | func (stream, "%c", *pstr_src++); | |
522 | break; | |
3ee6e4fb NC |
523 | } |
524 | } | |
35c08157 KLC |
525 | } |
526 | ||
40c7a7cb KLC |
527 | /* Filter instructions with some bits must be fixed. */ |
528 | ||
35c08157 | 529 | static void |
40c7a7cb | 530 | nds32_filter_unknown_insn (uint32_t insn, struct nds32_opcode **opc) |
35c08157 | 531 | { |
40c7a7cb KLC |
532 | if (!(*opc)) |
533 | return; | |
35c08157 | 534 | |
40c7a7cb | 535 | switch ((*opc)->value) |
35c08157 | 536 | { |
40c7a7cb KLC |
537 | case JREG (JR): |
538 | case JREG (JRNEZ): | |
539 | /* jr jr.xtoff */ | |
540 | if (__GF (insn, 6, 2) != 0 || __GF (insn, 15, 10) != 0) | |
541 | *opc = NULL; | |
35c08157 | 542 | break; |
40c7a7cb KLC |
543 | case MISC (STANDBY): |
544 | if (__GF (insn, 7, 18) != 0) | |
545 | *opc = NULL; | |
546 | break; | |
547 | case SIMD (PBSAD): | |
548 | case SIMD (PBSADA): | |
549 | if (__GF (insn, 5, 5) != 0) | |
550 | *opc = NULL; | |
551 | break; | |
fbaf61ad | 552 | case BR2 (SOP0): |
40c7a7cb KLC |
553 | if (__GF (insn, 20, 5) != 0) |
554 | *opc = NULL; | |
555 | break; | |
556 | case JREG (JRAL): | |
557 | if (__GF (insn, 5, 3) != 0 || __GF (insn, 15, 5) != 0) | |
558 | *opc = NULL; | |
559 | break; | |
560 | case ALU1 (NOR): | |
561 | case ALU1 (SLT): | |
562 | case ALU1 (SLTS): | |
563 | case ALU1 (SLLI): | |
564 | case ALU1 (SRLI): | |
565 | case ALU1 (SRAI): | |
566 | case ALU1 (ROTRI): | |
567 | case ALU1 (SLL): | |
568 | case ALU1 (SRL): | |
569 | case ALU1 (SRA): | |
570 | case ALU1 (ROTR): | |
571 | case ALU1 (SEB): | |
572 | case ALU1 (SEH): | |
573 | case ALU1 (ZEH): | |
574 | case ALU1 (WSBH): | |
575 | case ALU1 (SVA): | |
576 | case ALU1 (SVS): | |
577 | case ALU1 (CMOVZ): | |
578 | case ALU1 (CMOVN): | |
579 | if (__GF (insn, 5, 5) != 0) | |
580 | *opc = NULL; | |
581 | break; | |
582 | case MISC (IRET): | |
583 | case MISC (ISB): | |
584 | case MISC (DSB): | |
585 | if (__GF (insn, 5, 20) != 0) | |
586 | *opc = NULL; | |
35c08157 KLC |
587 | break; |
588 | } | |
589 | } | |
590 | ||
591 | static void | |
40c7a7cb KLC |
592 | print_insn32 (bfd_vma pc, disassemble_info *info, uint32_t insn, |
593 | uint32_t parse_mode) | |
35c08157 | 594 | { |
40c7a7cb KLC |
595 | /* Get the final correct opcode and parse. */ |
596 | struct nds32_opcode *opc; | |
597 | uint32_t opcode = nds32_mask_opcode (insn); | |
598 | opc = (struct nds32_opcode *) htab_find (opcode_htab, &opcode); | |
599 | ||
600 | nds32_special_opcode (insn, &opc); | |
601 | nds32_filter_unknown_insn (insn, &opc); | |
602 | nds32_parse_opcode (opc, pc, info, insn, parse_mode); | |
35c08157 KLC |
603 | } |
604 | ||
605 | static void | |
40c7a7cb KLC |
606 | print_insn16 (bfd_vma pc, disassemble_info *info, |
607 | uint32_t insn, uint32_t parse_mode) | |
35c08157 | 608 | { |
40c7a7cb KLC |
609 | struct nds32_opcode *opc; |
610 | uint32_t opcode; | |
611 | ||
612 | /* Get highest 7 bit in default. */ | |
613 | unsigned int mask = 0xfe00; | |
35c08157 | 614 | |
40c7a7cb KLC |
615 | /* Classify 16-bit instruction to 4 sets by bit 13 and 14. */ |
616 | switch (__GF (insn, 13, 2)) | |
35c08157 | 617 | { |
40c7a7cb KLC |
618 | case 0x0: |
619 | /* mov55 movi55 */ | |
620 | if (__GF (insn, 11, 2) == 0) | |
35c08157 | 621 | { |
40c7a7cb KLC |
622 | mask = 0xfc00; |
623 | /* ifret16 = mov55 $sp, $sp*/ | |
624 | if (__GF (insn, 0, 11) == 0x3ff) | |
625 | mask = 0xffff; | |
35c08157 | 626 | } |
40c7a7cb KLC |
627 | else if (__GF (insn, 9, 4) == 0xb) |
628 | mask = 0xfe07; | |
629 | break; | |
630 | case 0x1: | |
631 | /* lwi37 swi37 */ | |
632 | if (__GF (insn, 11, 2) == 0x3) | |
633 | mask = 0xf880; | |
634 | break; | |
635 | case 0x2: | |
636 | mask = 0xf800; | |
637 | /* Exclude beqz38, bnez38, beqs38, and bnes38. */ | |
638 | if (__GF (insn, 12, 1) == 0x1 | |
639 | && __GF (insn, 8, 3) == 0x5) | |
35c08157 | 640 | { |
40c7a7cb KLC |
641 | if (__GF (insn, 11, 1) == 0x0) |
642 | mask = 0xff00; | |
643 | else | |
644 | mask = 0xffe0; | |
35c08157 | 645 | } |
40c7a7cb KLC |
646 | break; |
647 | case 0x3: | |
648 | switch (__GF (insn, 11, 2)) | |
35c08157 | 649 | { |
35c08157 | 650 | case 0x1: |
40c7a7cb KLC |
651 | /* beqzs8 bnezs8 */ |
652 | if (__GF (insn, 9, 2) == 0x0) | |
653 | mask = 0xff00; | |
654 | /* addi10s */ | |
655 | else if (__GF(insn, 10, 1) == 0x1) | |
656 | mask = 0xfc00; | |
657 | break; | |
35c08157 | 658 | case 0x2: |
40c7a7cb KLC |
659 | /* lwi37.sp swi37.sp */ |
660 | mask = 0xf880; | |
661 | break; | |
35c08157 | 662 | case 0x3: |
40c7a7cb KLC |
663 | if (__GF (insn, 8, 3) == 0x5) |
664 | mask = 0xff00; | |
665 | else if (__GF (insn, 8, 3) == 0x4) | |
666 | mask = 0xff80; | |
667 | else if (__GF (insn, 9 , 2) == 0x3) | |
668 | mask = 0xfe07; | |
669 | break; | |
670 | } | |
671 | break; | |
672 | } | |
673 | opcode = insn & mask; | |
674 | opc = (struct nds32_opcode *) htab_find (opcode_htab, &opcode); | |
675 | ||
676 | nds32_special_opcode (insn, &opc); | |
677 | /* Get the final correct opcode and parse it. */ | |
678 | nds32_parse_opcode (opc, pc, info, insn, parse_mode); | |
679 | } | |
680 | ||
681 | static hashval_t | |
682 | htab_hash_hash (const void *p) | |
683 | { | |
684 | return (*(unsigned int *) p) % 49; | |
685 | } | |
686 | ||
687 | static int | |
688 | htab_hash_eq (const void *p, const void *q) | |
689 | { | |
690 | uint32_t pinsn = ((struct nds32_opcode *) p)->value; | |
691 | uint32_t qinsn = *((uint32_t *) q); | |
692 | ||
693 | return (pinsn == qinsn); | |
694 | } | |
695 | ||
696 | /* Get the format of instruction. */ | |
35c08157 | 697 | |
40c7a7cb KLC |
698 | static uint32_t |
699 | nds32_mask_opcode (uint32_t insn) | |
700 | { | |
701 | uint32_t opcode = N32_OP6 (insn); | |
702 | switch (opcode) | |
703 | { | |
704 | case N32_OP6_LBI: | |
705 | case N32_OP6_LHI: | |
706 | case N32_OP6_LWI: | |
707 | case N32_OP6_LDI: | |
708 | case N32_OP6_LBI_BI: | |
709 | case N32_OP6_LHI_BI: | |
710 | case N32_OP6_LWI_BI: | |
711 | case N32_OP6_LDI_BI: | |
712 | case N32_OP6_SBI: | |
713 | case N32_OP6_SHI: | |
714 | case N32_OP6_SWI: | |
715 | case N32_OP6_SDI: | |
716 | case N32_OP6_SBI_BI: | |
717 | case N32_OP6_SHI_BI: | |
718 | case N32_OP6_SWI_BI: | |
719 | case N32_OP6_SDI_BI: | |
720 | case N32_OP6_LBSI: | |
721 | case N32_OP6_LHSI: | |
722 | case N32_OP6_LWSI: | |
723 | case N32_OP6_LBSI_BI: | |
724 | case N32_OP6_LHSI_BI: | |
725 | case N32_OP6_LWSI_BI: | |
726 | case N32_OP6_MOVI: | |
727 | case N32_OP6_SETHI: | |
728 | case N32_OP6_ADDI: | |
729 | case N32_OP6_SUBRI: | |
730 | case N32_OP6_ANDI: | |
731 | case N32_OP6_XORI: | |
732 | case N32_OP6_ORI: | |
733 | case N32_OP6_SLTI: | |
734 | case N32_OP6_SLTSI: | |
735 | case N32_OP6_CEXT: | |
736 | case N32_OP6_BITCI: | |
737 | return MASK_OP (insn, 0); | |
738 | case N32_OP6_ALU2: | |
739 | /* FFBI */ | |
4ec521f2 | 740 | if (__GF (insn, 0, 7) == (N32_ALU2_FFBI | N32_BIT (6))) |
40c7a7cb | 741 | return MASK_OP (insn, 0x7f); |
4ec521f2 KLC |
742 | else if (__GF (insn, 0, 7) == (N32_ALU2_MFUSR | N32_BIT (6)) |
743 | || __GF (insn, 0, 7) == (N32_ALU2_MTUSR | N32_BIT (6))) | |
40c7a7cb KLC |
744 | /* RDOV CLROV */ |
745 | return MASK_OP (insn, 0xf81ff); | |
fbaf61ad NC |
746 | else if (__GF (insn, 0, 10) == (N32_ALU2_ONEOP | N32_BIT (7))) |
747 | { | |
748 | /* INSB */ | |
749 | if (__GF (insn, 12, 3) == 4) | |
750 | return MASK_OP (insn, 0x73ff); | |
751 | return MASK_OP (insn, 0x7fff); | |
752 | } | |
753 | return MASK_OP (insn, 0x3ff); | |
40c7a7cb KLC |
754 | case N32_OP6_ALU1: |
755 | case N32_OP6_SIMD: | |
756 | return MASK_OP (insn, 0x1f); | |
757 | case N32_OP6_MEM: | |
758 | return MASK_OP (insn, 0xff); | |
759 | case N32_OP6_JREG: | |
760 | return MASK_OP (insn, 0x7f); | |
761 | case N32_OP6_LSMW: | |
762 | return MASK_OP (insn, 0x23); | |
763 | case N32_OP6_SBGP: | |
764 | case N32_OP6_LBGP: | |
765 | return MASK_OP (insn, 0x1 << 19); | |
766 | case N32_OP6_HWGP: | |
767 | if (__GF (insn, 18, 2) == 0x3) | |
768 | return MASK_OP (insn, 0x7 << 17); | |
769 | return MASK_OP (insn, 0x3 << 18); | |
770 | case N32_OP6_DPREFI: | |
771 | return MASK_OP (insn, 0x1 << 24); | |
772 | case N32_OP6_LWC: | |
773 | case N32_OP6_SWC: | |
774 | case N32_OP6_LDC: | |
775 | case N32_OP6_SDC: | |
776 | return MASK_OP (insn, 0x1 << 12); | |
777 | case N32_OP6_JI: | |
778 | return MASK_OP (insn, 0x1 << 24); | |
779 | case N32_OP6_BR1: | |
780 | return MASK_OP (insn, 0x1 << 14); | |
781 | case N32_OP6_BR2: | |
fbaf61ad NC |
782 | if (__GF (insn, 16, 4) == 0) |
783 | return MASK_OP (insn, 0x1ff << 16); | |
784 | else | |
785 | return MASK_OP (insn, 0xf << 16); | |
40c7a7cb KLC |
786 | case N32_OP6_BR3: |
787 | return MASK_OP (insn, 0x1 << 19); | |
788 | case N32_OP6_MISC: | |
789 | switch (__GF (insn, 0, 5)) | |
790 | { | |
791 | case N32_MISC_MTSR: | |
792 | /* SETGIE and SETEND */ | |
793 | if (__GF (insn, 5, 5) == 0x1 || __GF (insn, 5, 5) == 0x2) | |
794 | return MASK_OP (insn, 0x1fffff); | |
795 | return MASK_OP (insn, 0x1f); | |
796 | case N32_MISC_TLBOP: | |
797 | if (__GF (insn, 5, 5) == 5 || __GF (insn, 5, 5) == 7) | |
798 | /* PB FLUA */ | |
799 | return MASK_OP (insn, 0x3ff); | |
800 | return MASK_OP (insn, 0x1f); | |
801 | default: | |
802 | return MASK_OP (insn, 0x1f); | |
803 | } | |
804 | case N32_OP6_COP: | |
805 | if (__GF (insn, 4, 2) == 0) | |
806 | { | |
807 | /* FPU */ | |
808 | switch (__GF (insn, 0, 4)) | |
35c08157 KLC |
809 | { |
810 | case 0x0: | |
35c08157 | 811 | case 0x8: |
40c7a7cb KLC |
812 | /* FS1/F2OP FD1/F2OP */ |
813 | if (__GF (insn, 6, 4) == 0xf) | |
814 | return MASK_OP (insn, 0x7fff); | |
815 | /* FS1 FD1 */ | |
816 | return MASK_OP (insn, 0x3ff); | |
817 | case 0x4: | |
35c08157 | 818 | case 0xc: |
40c7a7cb KLC |
819 | /* FS2 */ |
820 | return MASK_OP (insn, 0x3ff); | |
821 | case 0x1: | |
822 | case 0x9: | |
823 | /* XR */ | |
824 | if (__GF (insn, 6, 4) == 0xc) | |
825 | return MASK_OP (insn, 0x7fff); | |
826 | /* MFCP MTCP */ | |
827 | return MASK_OP (insn, 0x3ff); | |
828 | default: | |
829 | return MASK_OP (insn, 0xff); | |
35c08157 KLC |
830 | } |
831 | } | |
40c7a7cb KLC |
832 | else if (__GF (insn, 0, 2) == 0) |
833 | return MASK_OP (insn, 0xf); | |
834 | return MASK_OP (insn, 0xcf); | |
835 | case N32_OP6_AEXT: | |
836 | /* AUDIO */ | |
837 | switch (__GF (insn, 23, 2)) | |
35c08157 KLC |
838 | { |
839 | case 0x0: | |
40c7a7cb KLC |
840 | if (__GF (insn, 5, 4) == 0) |
841 | /* AMxxx AMAyyS AMyyS AMAWzS AMWzS */ | |
842 | return MASK_OP (insn, (0x1f << 20) | 0x1ff); | |
843 | else if (__GF (insn, 5, 4) == 1) | |
844 | /* ALR ASR ALA ASA AUPI */ | |
845 | return MASK_OP (insn, (0x1f << 20) | (0xf << 5)); | |
846 | else if (__GF (insn, 20, 3) == 0 && __GF (insn, 6, 3) == 1) | |
847 | /* ALR2 */ | |
848 | return MASK_OP (insn, (0x1f << 20) | (0x7 << 6)); | |
849 | else if (__GF (insn, 20 ,3) == 2 && __GF (insn, 6, 3) == 1) | |
850 | /* AWEXT ASATS48 */ | |
851 | return MASK_OP (insn, (0x1f << 20) | (0xf << 5)); | |
852 | else if (__GF (insn, 20 ,3) == 3 && __GF (insn, 6, 3) == 1) | |
853 | /* AMTAR AMTAR2 AMFAR AMFAR2 */ | |
854 | return MASK_OP (insn, (0x1f << 20) | (0x1f << 5)); | |
855 | else if (__GF (insn, 7, 2) == 3) | |
856 | /* AMxxxSA */ | |
857 | return MASK_OP (insn, (0x1f << 20) | (0x3 << 7)); | |
858 | else if (__GF (insn, 6, 3) == 2) | |
859 | /* AMxxxL.S */ | |
860 | return MASK_OP (insn, (0x1f << 20) | (0xf << 5)); | |
35c08157 | 861 | else |
40c7a7cb KLC |
862 | /* AmxxxL.l AmxxxL2.S AMxxxL2.L */ |
863 | return MASK_OP (insn, (0x1f << 20) | (0x7 << 6)); | |
35c08157 | 864 | case 0x1: |
40c7a7cb KLC |
865 | if (__GF (insn, 20, 3) == 0) |
866 | /* AADDL ASUBL */ | |
867 | return MASK_OP (insn, (0x1f << 20) | (0x1 << 5)); | |
868 | else if (__GF (insn, 20, 3) == 1) | |
869 | /* AMTARI Ix AMTARI Mx */ | |
870 | return MASK_OP (insn, (0x1f << 20)); | |
871 | else if (__GF (insn, 6, 3) == 2) | |
872 | /* AMAWzSl.S AMWzSl.S */ | |
873 | return MASK_OP (insn, (0x1f << 20) | (0xf << 5)); | |
874 | else if (__GF (insn, 7, 2) == 3) | |
875 | /* AMAWzSSA AMWzSSA */ | |
876 | return MASK_OP (insn, (0x1f << 20) | (0x3 << 7)); | |
877 | else | |
fbaf61ad NC |
878 | /* AMAWzSL.L AMAWzSL2.S AMAWzSL2.L |
879 | AMWzSL.L AMWzSL.L AMWzSL2.S */ | |
40c7a7cb KLC |
880 | return MASK_OP (insn, (0x1f << 20) | (0x7 << 6)); |
881 | case 0x2: | |
882 | if (__GF (insn, 6, 3) == 2) | |
883 | /* AMAyySl.S AMWyySl.S */ | |
884 | return MASK_OP (insn, (0x1f << 20) | (0xf << 5)); | |
885 | else if (__GF (insn, 7, 2) == 3) | |
886 | /* AMAWyySSA AMWyySSA */ | |
887 | return MASK_OP (insn, (0x1f << 20) | (0x3 << 7)); | |
888 | else | |
fbaf61ad NC |
889 | /* AMAWyySL.L AMAWyySL2.S AMAWyySL2.L |
890 | AMWyySL.L AMWyySL.L AMWyySL2.S */ | |
40c7a7cb | 891 | return MASK_OP (insn, (0x1f << 20) | (0x7 << 6)); |
35c08157 | 892 | } |
40c7a7cb KLC |
893 | return MASK_OP (insn, 0x1f << 20); |
894 | default: | |
895 | return (1 << 31); | |
35c08157 KLC |
896 | } |
897 | } | |
898 | ||
40c7a7cb KLC |
899 | /* Define cctl subtype. */ |
900 | static char *cctl_subtype [] = | |
35c08157 | 901 | { |
40c7a7cb KLC |
902 | /* 0x0 */ |
903 | "st0", "st0", "st0", "st2", "st2", "st3", "st3", "st4", | |
904 | "st1", "st1", "st1", "st0", "st0", NULL, NULL, "st5", | |
905 | /* 0x10 */ | |
906 | "st0", NULL, NULL, "st2", "st2", "st3", "st3", NULL, | |
907 | "st1", NULL, NULL, "st0", "st0", NULL, NULL, NULL | |
908 | }; | |
35c08157 | 909 | |
40c7a7cb | 910 | /* Check the subset of opcode. */ |
35c08157 | 911 | |
40c7a7cb KLC |
912 | static void |
913 | nds32_special_opcode (uint32_t insn, struct nds32_opcode **opc) | |
914 | { | |
915 | char *string = NULL; | |
916 | uint32_t op; | |
35c08157 | 917 | |
40c7a7cb KLC |
918 | if (!(*opc)) |
919 | return; | |
35c08157 | 920 | |
40c7a7cb KLC |
921 | /* Check if special case. */ |
922 | switch ((*opc)->value) | |
923 | { | |
924 | case OP6 (LWC): | |
925 | case OP6 (SWC): | |
926 | case OP6 (LDC): | |
927 | case OP6 (SDC): | |
928 | case FPU_RA_IMMBI (LWC): | |
929 | case FPU_RA_IMMBI (SWC): | |
930 | case FPU_RA_IMMBI (LDC): | |
931 | case FPU_RA_IMMBI (SDC): | |
932 | /* Check if cp0 => FPU. */ | |
35c08157 | 933 | if (__GF (insn, 13, 2) == 0) |
35c08157 | 934 | { |
40c7a7cb KLC |
935 | while (!((*opc)->attr & ATTR (FPU)) && (*opc)->next) |
936 | *opc = (*opc)->next; | |
35c08157 | 937 | } |
40c7a7cb KLC |
938 | break; |
939 | case ALU1 (ADD): | |
940 | case ALU1 (SUB): | |
941 | case ALU1 (AND): | |
942 | case ALU1 (XOR): | |
943 | case ALU1 (OR): | |
944 | /* Check if (add/add_slli) (sub/sub_slli) (and/and_slli). */ | |
945 | if (N32_SH5(insn) != 0) | |
946 | string = "sh"; | |
947 | break; | |
948 | case ALU1 (SRLI): | |
949 | /* Check if nop. */ | |
950 | if (__GF (insn, 10, 15) == 0) | |
951 | string = "nop"; | |
952 | break; | |
953 | case MISC (CCTL): | |
954 | string = cctl_subtype [__GF (insn, 5, 5)]; | |
955 | break; | |
956 | case JREG (JR): | |
957 | case JREG (JRAL): | |
958 | case JREG (JR) | JREG_RET: | |
959 | if (__GF (insn, 8, 2) != 0) | |
960 | string = "tit"; | |
fbaf61ad | 961 | break; |
40c7a7cb | 962 | case N32_OP6_COP: |
40c7a7cb KLC |
963 | break; |
964 | case 0x9200: | |
965 | /* nop16 */ | |
966 | if (__GF (insn, 0, 9) == 0) | |
967 | string = "nop16"; | |
968 | break; | |
969 | } | |
970 | ||
971 | if (string) | |
972 | { | |
973 | while (strstr ((*opc)->opcode, string) == NULL | |
974 | && strstr ((*opc)->instruction, string) == NULL && (*opc)->next) | |
975 | *opc = (*opc)->next; | |
35c08157 KLC |
976 | return; |
977 | } | |
40c7a7cb KLC |
978 | |
979 | /* Classify instruction is COP or FPU. */ | |
980 | op = N32_OP6 (insn); | |
981 | if (op == N32_OP6_COP && __GF (insn, 4, 2) != 0) | |
982 | { | |
983 | while (((*opc)->attr & ATTR (FPU)) != 0 && (*opc)->next) | |
984 | *opc = (*opc)->next; | |
985 | } | |
35c08157 KLC |
986 | } |
987 | ||
988 | int | |
989 | print_insn_nds32 (bfd_vma pc, disassemble_info *info) | |
990 | { | |
991 | int status; | |
992 | bfd_byte buf[4]; | |
fbaf61ad NC |
993 | bfd_byte buf_data[16]; |
994 | long long given; | |
995 | long long given1; | |
35c08157 | 996 | uint32_t insn; |
fbaf61ad NC |
997 | int n; |
998 | int last_symbol_index = -1; | |
999 | bfd_vma addr; | |
1000 | int is_data = FALSE; | |
1001 | bfd_boolean found = FALSE; | |
1002 | struct nds32_private_data *private_data; | |
1003 | unsigned int size = 16; | |
1004 | enum map_type mapping_type = MAP_CODE; | |
1005 | ||
1006 | if (info->private_data == NULL) | |
1007 | { | |
1008 | /* Note: remain lifecycle throughout whole execution. */ | |
1009 | static struct nds32_private_data private; | |
1010 | private.has_mapping_symbols = -1; /* unknown yet. */ | |
1011 | private.last_symbol_index = -1; | |
1012 | private.last_addr = 0; | |
1013 | info->private_data = &private; | |
1014 | } | |
1015 | private_data = info->private_data; | |
40c7a7cb | 1016 | |
fbaf61ad | 1017 | if (info->symtab_size != 0) |
40c7a7cb | 1018 | { |
fbaf61ad NC |
1019 | int start; |
1020 | if (pc == 0) | |
1021 | start = 0; | |
1022 | else | |
1023 | { | |
1024 | start = info->symtab_pos; | |
1025 | if (start < private_data->last_symbol_index) | |
1026 | start = private_data->last_symbol_index; | |
1027 | } | |
1028 | ||
1029 | if (0 > start) | |
1030 | start = 0; | |
35c08157 | 1031 | |
fbaf61ad NC |
1032 | if (private_data->has_mapping_symbols != 0 |
1033 | && ((strncmp (".text", info->section->name, 5) == 0))) | |
40c7a7cb | 1034 | { |
fbaf61ad | 1035 | for (n = start; n < info->symtab_size; n++) |
40c7a7cb | 1036 | { |
fbaf61ad NC |
1037 | addr = bfd_asymbol_value (info->symtab[n]); |
1038 | if (addr > pc) | |
1039 | break; | |
1040 | if (get_mapping_symbol_type (info, n, &mapping_type)) | |
1041 | { | |
1042 | last_symbol_index = n; | |
1043 | found = TRUE; | |
1044 | } | |
40c7a7cb | 1045 | } |
fbaf61ad NC |
1046 | |
1047 | if (found) | |
1048 | private_data->has_mapping_symbols = 1; | |
1049 | else if (!found && private_data->has_mapping_symbols == -1) | |
1050 | { | |
1051 | /* Make sure there are no any mapping symbol. */ | |
1052 | for (n = 0; n < info->symtab_size; n++) | |
1053 | { | |
1054 | if (is_mapping_symbol (info, n, &mapping_type)) | |
1055 | { | |
1056 | private_data->has_mapping_symbols = -1; | |
1057 | break; | |
1058 | } | |
1059 | } | |
1060 | if (private_data->has_mapping_symbols == -1) | |
1061 | private_data->has_mapping_symbols = 0; | |
1062 | } | |
1063 | ||
1064 | private_data->last_symbol_index = last_symbol_index; | |
1065 | private_data->last_mapping_type = mapping_type; | |
1066 | is_data = (private_data->last_mapping_type == MAP_DATA0 | |
1067 | || private_data->last_mapping_type == MAP_DATA1 | |
1068 | || private_data->last_mapping_type == MAP_DATA2 | |
1069 | || private_data->last_mapping_type == MAP_DATA3 | |
1070 | || private_data->last_mapping_type == MAP_DATA4); | |
1071 | } | |
1072 | } | |
1073 | ||
1074 | /* Wonder data or instruction. */ | |
1075 | if (is_data) | |
1076 | { | |
1077 | unsigned int i1; | |
1078 | ||
1079 | /* Fix corner case: there is no next mapping symbol, | |
1080 | let mapping type decides size */ | |
1081 | if (last_symbol_index + 1 >= info->symtab_size) | |
1082 | { | |
1083 | if (mapping_type == MAP_DATA0) | |
1084 | size = 1; | |
1085 | if (mapping_type == MAP_DATA1) | |
1086 | size = 2; | |
1087 | if (mapping_type == MAP_DATA2) | |
1088 | size = 4; | |
1089 | if (mapping_type == MAP_DATA3) | |
1090 | size = 8; | |
1091 | if (mapping_type == MAP_DATA4) | |
1092 | size = 16; | |
1093 | } | |
1094 | for (n = last_symbol_index + 1; n < info->symtab_size; n++) | |
1095 | { | |
1096 | addr = bfd_asymbol_value (info->symtab[n]); | |
1097 | ||
1098 | enum map_type fake_mapping_type; | |
1099 | if (get_mapping_symbol_type (info, n, &fake_mapping_type) | |
1100 | && (addr > pc | |
1101 | && ((info->section == NULL) | |
1102 | || (info->section == info->symtab[n]->section))) | |
1103 | && (addr - pc < size)) | |
1104 | { | |
1105 | size = addr - pc; | |
1106 | break; | |
1107 | } | |
1108 | } | |
1109 | ||
1110 | if (size == 3) | |
1111 | size = (pc & 1) ? 1 : 2; | |
1112 | ||
1113 | /* Read bytes from BFD. */ | |
1114 | info->read_memory_func (pc, (bfd_byte *) buf_data, size, info); | |
1115 | given = 0; | |
1116 | given1 = 0; | |
1117 | /* Start assembling data. */ | |
1118 | /* Little endian of data. */ | |
1119 | if (info->endian == BFD_ENDIAN_LITTLE) | |
1120 | { | |
1121 | for (i1 = size - 1;; i1--) | |
40c7a7cb | 1122 | { |
fbaf61ad NC |
1123 | if (i1 >= 8) |
1124 | given1 = buf_data[i1] | (given1 << 8); | |
1125 | else | |
1126 | given = buf_data[i1] | (given << 8); | |
1127 | ||
1128 | if (i1 == 0) | |
1129 | break; | |
40c7a7cb | 1130 | } |
40c7a7cb | 1131 | } |
fbaf61ad NC |
1132 | else |
1133 | { | |
1134 | /* Big endian of data. */ | |
1135 | for (i1 = 0; i1 < size; i1++) | |
1136 | { | |
1137 | if (i1 <= 7) | |
1138 | given = buf_data[i1] | (given << 8); | |
1139 | else | |
1140 | given1 = buf_data[i1] | (given1 << 8); | |
1141 | } | |
1142 | } | |
1143 | ||
1144 | info->bytes_per_line = 4; | |
1145 | ||
1146 | if (size == 16) | |
1147 | info->fprintf_func (info->stream, ".qword\t0x%016llx%016llx", | |
1148 | given, given1); | |
1149 | else if (size == 8) | |
1150 | info->fprintf_func (info->stream, ".dword\t0x%016llx", given); | |
1151 | else if (size == 4) | |
1152 | info->fprintf_func (info->stream, ".word\t0x%08llx", given); | |
1153 | else if (size == 2) | |
1154 | { | |
1155 | /* short */ | |
1156 | if (mapping_type == MAP_DATA0) | |
1157 | info->fprintf_func (info->stream, ".byte\t0x%02llx", given & 0xFF); | |
1158 | else | |
1159 | info->fprintf_func (info->stream, ".short\t0x%04llx", given); | |
1160 | } | |
1161 | else | |
1162 | { | |
1163 | /* byte */ | |
1164 | info->fprintf_func (info->stream, ".byte\t0x%02llx", given); | |
1165 | } | |
1166 | ||
1167 | return size; | |
40c7a7cb KLC |
1168 | } |
1169 | ||
1170 | status = info->read_memory_func (pc, (bfd_byte *) buf, 4, info); | |
35c08157 | 1171 | if (status) |
40c7a7cb | 1172 | { |
fbaf61ad | 1173 | /* For the last 16-bit instruction. */ |
40c7a7cb KLC |
1174 | status = info->read_memory_func (pc, (bfd_byte *) buf, 2, info); |
1175 | if (status) | |
1176 | { | |
1177 | (*info->memory_error_func)(status, pc, info); | |
1178 | return -1; | |
1179 | } | |
1180 | } | |
35c08157 | 1181 | |
40c7a7cb | 1182 | insn = bfd_getb32 (buf); |
35c08157 | 1183 | /* 16-bit instruction. */ |
40c7a7cb | 1184 | if (insn & 0x80000000) |
35c08157 | 1185 | { |
40c7a7cb | 1186 | print_insn16 (pc, info, (insn >> 16), NDS32_PARSE_INSN16); |
35c08157 KLC |
1187 | return 2; |
1188 | } | |
1189 | ||
1190 | /* 32-bit instructions. */ | |
40c7a7cb KLC |
1191 | else |
1192 | { | |
fbaf61ad | 1193 | print_insn32 (pc, info, insn, NDS32_PARSE_INSN32); |
40c7a7cb KLC |
1194 | return 4; |
1195 | } | |
35c08157 | 1196 | } |
fbaf61ad NC |
1197 | |
1198 | /* Ignore disassembling unnecessary name. */ | |
1199 | ||
1200 | static bfd_boolean | |
1201 | nds32_symbol_is_valid (asymbol *sym, | |
1202 | struct disassemble_info *info ATTRIBUTE_UNUSED) | |
1203 | { | |
1204 | const char *name; | |
1205 | ||
1206 | if (sym == NULL) | |
1207 | return FALSE; | |
1208 | ||
1209 | name = bfd_asymbol_name (sym); | |
1210 | ||
1211 | /* Mapping symbol is invalid. */ | |
1212 | if (name[0] == '$') | |
1213 | return FALSE; | |
1214 | return TRUE; | |
1215 | } | |
1216 | ||
1217 | static void | |
1218 | nds32_add_opcode_hash_table (unsigned indx) | |
1219 | { | |
1220 | opcode_t *opc; | |
1221 | ||
1222 | opc = nds32_opcode_table[indx]; | |
1223 | if (opc == NULL) | |
1224 | return; | |
1225 | ||
1226 | while (opc->opcode != NULL) | |
1227 | { | |
1228 | opcode_t **slot; | |
1229 | ||
1230 | slot = (opcode_t **) htab_find_slot | |
1231 | (opcode_htab, &opc->value, INSERT); | |
1232 | if (*slot == NULL) | |
1233 | { | |
1234 | /* This is the new one. */ | |
1235 | *slot = opc; | |
1236 | } | |
1237 | else | |
1238 | { | |
1239 | opcode_t *tmp; | |
1240 | ||
1241 | /* Already exists. Append to the list. */ | |
1242 | tmp = *slot; | |
1243 | while (tmp->next) | |
1244 | tmp = tmp->next; | |
1245 | tmp->next = opc; | |
1246 | opc->next = NULL; | |
1247 | } | |
1248 | opc++; | |
1249 | } | |
1250 | } | |
1251 | ||
1252 | void | |
1253 | disassemble_init_nds32 (struct disassemble_info *info) | |
1254 | { | |
1255 | static unsigned init_done = 0; | |
1256 | unsigned k; | |
1257 | ||
1258 | /* Set up symbol checking function. */ | |
1259 | info->symbol_is_valid = nds32_symbol_is_valid; | |
1260 | ||
1261 | /* Only need to initialize once: | |
1262 | High level will call this function for every object file. | |
1263 | For example, when disassemble all members of a library. */ | |
1264 | if (init_done) | |
1265 | return; | |
1266 | ||
1267 | /* Setup main core. */ | |
1268 | nds32_keyword_table[NDS32_MAIN_CORE] = &keywords[0]; | |
1269 | nds32_opcode_table[NDS32_MAIN_CORE] = &nds32_opcodes[0]; | |
1270 | nds32_field_table[NDS32_MAIN_CORE] = &operand_fields[0]; | |
1271 | ||
1272 | /* Build opcode table. */ | |
1273 | opcode_htab = htab_create_alloc (1024, htab_hash_hash, htab_hash_eq, | |
1274 | NULL, xcalloc, free); | |
1275 | ||
1276 | for (k = 0; k < NDS32_CORE_COUNT; k++) | |
1277 | { | |
1278 | /* Add op-codes. */ | |
1279 | nds32_add_opcode_hash_table (k); | |
1280 | } | |
1281 | ||
1282 | init_done = 1; | |
1283 | } | |
1284 | ||
1285 | static int | |
1286 | is_mapping_symbol (struct disassemble_info *info, int n, | |
1287 | enum map_type *map_type) | |
1288 | { | |
1289 | const char *name = NULL; | |
1290 | ||
1291 | /* Get symbol name. */ | |
1292 | name = bfd_asymbol_name (info->symtab[n]); | |
1293 | ||
1294 | if (name[1] == 'c') | |
1295 | { | |
1296 | *map_type = MAP_CODE; | |
1297 | return TRUE; | |
1298 | } | |
1299 | else if (name[1] == 'd' && name[2] == '0') | |
1300 | { | |
1301 | *map_type = MAP_DATA0; | |
1302 | return TRUE; | |
1303 | } | |
1304 | else if (name[1] == 'd' && name[2] == '1') | |
1305 | { | |
1306 | *map_type = MAP_DATA1; | |
1307 | return TRUE; | |
1308 | } | |
1309 | else if (name[1] == 'd' && name[2] == '2') | |
1310 | { | |
1311 | *map_type = MAP_DATA2; | |
1312 | return TRUE; | |
1313 | } | |
1314 | else if (name[1] == 'd' && name[2] == '3') | |
1315 | { | |
1316 | *map_type = MAP_DATA3; | |
1317 | return TRUE; | |
1318 | } | |
1319 | else if (name[1] == 'd' && name[2] == '4') | |
1320 | { | |
1321 | *map_type = MAP_DATA4; | |
1322 | return TRUE; | |
1323 | } | |
1324 | ||
1325 | return FALSE; | |
1326 | } | |
1327 | ||
1328 | static int | |
1329 | get_mapping_symbol_type (struct disassemble_info *info, int n, | |
1330 | enum map_type *map_type) | |
1331 | { | |
1332 | /* If the symbol is in a different section, ignore it. */ | |
1333 | if (info->section != NULL | |
1334 | && info->section != info->symtab[n]->section) | |
1335 | return FALSE; | |
1336 | ||
1337 | return is_mapping_symbol (info, n, map_type); | |
1338 | } |