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