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