Commit | Line | Data |
---|---|---|
35c08157 | 1 | /* NDS32-specific support for 32-bit ELF. |
6f2750fe | 2 | Copyright (C) 2012-2016 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" | |
25 | #include "dis-asm.h" | |
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 KLC |
37 | |
38 | /* Default text to print if an instruction isn't recognized. */ | |
39 | #define UNKNOWN_INSN_MSG _("*unknown*") | |
40c7a7cb KLC |
40 | #define NDS32_PARSE_INSN16 0x01 |
41 | #define NDS32_PARSE_INSN32 0x02 | |
42 | #define NDS32_PARSE_EX9IT 0x04 | |
43 | #define NDS32_PARSE_EX9TAB 0x08 | |
44 | ||
45 | extern struct nds32_opcode nds32_opcodes[]; | |
46 | extern const field_t operand_fields[]; | |
47 | extern const keyword_t *keywords[]; | |
48 | extern const keyword_t keyword_gpr[]; | |
49 | static void print_insn16 (bfd_vma pc, disassemble_info *info, | |
50 | uint32_t insn, uint32_t parse_mode); | |
51 | static void print_insn32 (bfd_vma pc, disassemble_info *info, uint32_t insn, | |
52 | uint32_t parse_mode); | |
53 | static uint32_t nds32_mask_opcode (uint32_t); | |
54 | static void nds32_special_opcode (uint32_t, struct nds32_opcode **); | |
55 | ||
56 | /* define in objdump.c. */ | |
57 | struct objdump_disasm_info | |
35c08157 | 58 | { |
40c7a7cb KLC |
59 | bfd * abfd; |
60 | asection * sec; | |
61 | bfd_boolean require_sec; | |
62 | arelent ** dynrelbuf; | |
63 | long dynrelcount; | |
64 | disassembler_ftype disassemble_fn; | |
65 | arelent * reloc; | |
35c08157 KLC |
66 | }; |
67 | ||
40c7a7cb KLC |
68 | /* file_ptr ex9_filepos=NULL;. */ |
69 | bfd_byte *ex9_data = NULL; | |
70 | int ex9_ready = 0, ex9_base_offset = 0; | |
35c08157 | 71 | |
40c7a7cb | 72 | /* Hash function for disassemble. */ |
35c08157 | 73 | |
40c7a7cb | 74 | static htab_t opcode_htab; |
35c08157 | 75 | |
40c7a7cb KLC |
76 | static void |
77 | nds32_ex9_info (bfd_vma pc ATTRIBUTE_UNUSED, | |
78 | disassemble_info *info, uint32_t ex9_index) | |
35c08157 | 79 | { |
40c7a7cb KLC |
80 | uint32_t insn; |
81 | static asymbol *itb = NULL; | |
82 | bfd_byte buffer[4]; | |
83 | long unsigned int isec_vma; | |
35c08157 | 84 | |
40c7a7cb KLC |
85 | /* Lookup itb symbol. */ |
86 | if (!itb) | |
87 | { | |
88 | int i; | |
35c08157 | 89 | |
40c7a7cb KLC |
90 | for (i = 0; i < info->symtab_size; i++) |
91 | if (bfd_asymbol_name (info->symtab[i]) | |
92 | && (strcmp (bfd_asymbol_name (info->symtab[i]), "$_ITB_BASE_") == 0 | |
93 | || strcmp (bfd_asymbol_name (info->symtab[i]), | |
94 | "_ITB_BASE_") == 0)) | |
95 | { | |
96 | itb = info->symtab[i]; | |
97 | break; | |
98 | } | |
35c08157 | 99 | |
40c7a7cb KLC |
100 | /* Lookup it only once, in case _ITB_BASE_ doesn't exist at all. */ |
101 | if (itb == NULL) | |
102 | itb = (void *) -1; | |
103 | } | |
6b9d3259 | 104 | |
40c7a7cb KLC |
105 | if (itb == (void *) -1) |
106 | return; | |
107 | ||
108 | isec_vma = itb->section->vma; | |
109 | isec_vma = itb->section->vma - bfd_asymbol_value (itb); | |
110 | if (!itb->section || !itb->section->owner) | |
111 | return; | |
112 | bfd_get_section_contents (itb->section->owner, itb->section, buffer, | |
113 | ex9_index * 4 - isec_vma, 4); | |
114 | insn = bfd_getb32 (buffer); | |
115 | /* 16-bit instructions in ex9 table. */ | |
116 | if (insn & 0x80000000) | |
117 | print_insn16 (pc, info, (insn & 0x0000FFFF), | |
118 | NDS32_PARSE_INSN16 | NDS32_PARSE_EX9IT); | |
119 | /* 32-bit instructions in ex9 table. */ | |
120 | else | |
121 | print_insn32 (pc, info, insn, NDS32_PARSE_INSN32 | NDS32_PARSE_EX9IT); | |
122 | } | |
35c08157 | 123 | |
40c7a7cb | 124 | /* Find the value map register name. */ |
6b9d3259 | 125 | |
40c7a7cb KLC |
126 | static keyword_t * |
127 | nds32_find_reg_keyword (keyword_t *reg, int value) | |
35c08157 | 128 | { |
40c7a7cb KLC |
129 | if (!reg) |
130 | return NULL; | |
6b9d3259 | 131 | |
40c7a7cb KLC |
132 | while (reg->name != NULL && reg->value != value) |
133 | { | |
134 | reg++; | |
135 | } | |
136 | if (reg->name == NULL) | |
137 | return NULL; | |
138 | return reg; | |
139 | } | |
35c08157 KLC |
140 | |
141 | static void | |
40c7a7cb KLC |
142 | nds32_parse_audio_ext (const field_t *pfd, |
143 | disassemble_info *info, uint32_t insn) | |
35c08157 | 144 | { |
35c08157 KLC |
145 | fprintf_ftype func = info->fprintf_func; |
146 | void *stream = info->stream; | |
40c7a7cb KLC |
147 | keyword_t *psys_reg; |
148 | int int_value, new_value; | |
35c08157 | 149 | |
40c7a7cb | 150 | if (pfd->hw_res == HW_INT || pfd->hw_res == HW_UINT) |
35c08157 | 151 | { |
40c7a7cb KLC |
152 | if (pfd->hw_res == HW_INT) |
153 | int_value = | |
154 | N32_IMMS ((insn >> pfd->bitpos), pfd->bitsize) << pfd->shift; | |
155 | else | |
156 | int_value = __GF (insn, pfd->bitpos, pfd->bitsize) << pfd->shift; | |
35c08157 | 157 | |
3ee6e4fb | 158 | if (int_value < 10) |
40c7a7cb KLC |
159 | func (stream, "#%d", int_value); |
160 | else | |
161 | func (stream, "#0x%x", int_value); | |
35c08157 KLC |
162 | return; |
163 | } | |
40c7a7cb KLC |
164 | int_value = |
165 | __GF (insn, pfd->bitpos, pfd->bitsize) << pfd->shift; | |
166 | new_value = int_value; | |
167 | psys_reg = (keyword_t*) keywords[pfd->hw_res]; | |
35c08157 | 168 | |
40c7a7cb KLC |
169 | /* p = bit[4].bit[1:0], r = bit[4].bit[3:2]. */ |
170 | if (strcmp (pfd->name, "im5_i") == 0) | |
35c08157 | 171 | { |
40c7a7cb KLC |
172 | new_value = int_value & 0x03; |
173 | new_value |= ((int_value & 0x10) >> 2); | |
35c08157 | 174 | } |
40c7a7cb | 175 | else if (strcmp (pfd->name, "im5_m") == 0) |
35c08157 | 176 | { |
40c7a7cb | 177 | new_value = ((int_value & 0x1C) >> 2); |
35c08157 | 178 | } |
40c7a7cb KLC |
179 | /* p = 0.bit[1:0], r = 0.bit[3:2]. */ |
180 | /* q = 1.bit[1:0], s = 1.bit[5:4]. */ | |
181 | else if (strcmp (pfd->name, "im6_iq") == 0) | |
35c08157 | 182 | { |
40c7a7cb | 183 | new_value |= 0x04; |
35c08157 | 184 | } |
40c7a7cb | 185 | else if (strcmp (pfd->name, "im6_ms") == 0) |
35c08157 | 186 | { |
40c7a7cb KLC |
187 | new_value |= 0x04; |
188 | } | |
189 | /* Rt CONCAT(c, t21, t0). */ | |
190 | else if (strcmp (pfd->name, "a_rt21") == 0) | |
191 | { | |
192 | new_value = (insn & 0x00000020) >> 5; | |
193 | new_value |= (insn & 0x00000C00) >> 9; | |
194 | new_value |= (insn & 0x00008000) >> 12; | |
195 | } | |
196 | else if (strcmp (pfd->name, "a_rte") == 0) | |
197 | { | |
198 | new_value = (insn & 0x00000C00) >> 9; | |
199 | new_value |= (insn & 0x00008000) >> 12; | |
200 | } | |
201 | else if (strcmp (pfd->name, "a_rte1") == 0) | |
202 | { | |
203 | new_value = (insn & 0x00000C00) >> 9; | |
204 | new_value |= (insn & 0x00008000) >> 12; | |
205 | new_value |= 0x01; | |
35c08157 | 206 | } |
40c7a7cb KLC |
207 | else if (strcmp (pfd->name, "a_rte69") == 0) |
208 | { | |
209 | new_value = int_value << 1; | |
210 | } | |
211 | else if (strcmp (pfd->name, "a_rte69_1") == 0) | |
212 | { | |
213 | new_value = int_value << 1; | |
214 | new_value |= 0x01; | |
215 | } | |
216 | ||
217 | psys_reg = nds32_find_reg_keyword (psys_reg, new_value); | |
218 | if (!psys_reg) | |
219 | func (stream, "???"); | |
220 | else | |
221 | func (stream, "$%s", psys_reg->name); | |
35c08157 KLC |
222 | } |
223 | ||
40c7a7cb | 224 | /* Dump instruction. If the opcode is unknown, return FALSE. */ |
35c08157 KLC |
225 | |
226 | static void | |
40c7a7cb KLC |
227 | nds32_parse_opcode (struct nds32_opcode *opc, bfd_vma pc ATTRIBUTE_UNUSED, |
228 | disassemble_info *info, uint32_t insn, | |
229 | uint32_t parse_mode) | |
35c08157 | 230 | { |
40c7a7cb | 231 | int op = 0; |
35c08157 KLC |
232 | fprintf_ftype func = info->fprintf_func; |
233 | void *stream = info->stream; | |
40c7a7cb KLC |
234 | const char *pstr_src; |
235 | char *pstr_tmp; | |
236 | char tmp_string[16]; | |
237 | unsigned int push25gpr = 0, lsmwRb, lsmwRe, lsmwEnb4, checkbit, i; | |
238 | int int_value, ifthe1st = 1; | |
239 | const field_t *pfd; | |
240 | keyword_t *psys_reg; | |
241 | ||
242 | if (opc == NULL) | |
35c08157 | 243 | { |
35c08157 KLC |
244 | func (stream, UNKNOWN_INSN_MSG); |
245 | return; | |
246 | } | |
35c08157 | 247 | |
40c7a7cb KLC |
248 | if (parse_mode & NDS32_PARSE_EX9IT) |
249 | func (stream, " !"); | |
35c08157 | 250 | |
40c7a7cb KLC |
251 | pstr_src = opc->instruction; |
252 | if (*pstr_src == 0) | |
35c08157 | 253 | { |
40c7a7cb | 254 | func (stream, "%s", opc->opcode); |
35c08157 KLC |
255 | return; |
256 | } | |
40c7a7cb KLC |
257 | /* NDS32_PARSE_INSN16. */ |
258 | if (parse_mode & NDS32_PARSE_INSN16) | |
259 | { | |
260 | func (stream, "%s ", opc->opcode); | |
261 | } | |
35c08157 | 262 | |
40c7a7cb KLC |
263 | /* NDS32_PARSE_INSN32. */ |
264 | else | |
35c08157 | 265 | { |
40c7a7cb KLC |
266 | op = N32_OP6 (insn); |
267 | if (op == N32_OP6_LSMW) | |
268 | func (stream, "%s.", opc->opcode); | |
269 | else if (strstr (opc->instruction, "tito")) | |
270 | func (stream, "%s", opc->opcode); | |
271 | else | |
3ee6e4fb | 272 | func (stream, "%s\t", opc->opcode); |
35c08157 KLC |
273 | } |
274 | ||
40c7a7cb | 275 | while (*pstr_src) |
35c08157 | 276 | { |
40c7a7cb KLC |
277 | switch (*pstr_src) |
278 | { | |
279 | case '%': | |
280 | case '=': | |
281 | case '&': | |
282 | pstr_src++; | |
3ee6e4fb | 283 | /* Compare with operand_fields[].name. */ |
40c7a7cb KLC |
284 | pstr_tmp = &tmp_string[0]; |
285 | while (*pstr_src) | |
286 | { | |
287 | if ((*pstr_src == ',') || (*pstr_src == ' ') | |
288 | || (*pstr_src == '{') || (*pstr_src == '}') | |
289 | || (*pstr_src == '[') || (*pstr_src == ']') | |
290 | || (*pstr_src == '(') || (*pstr_src == ')') | |
291 | || (*pstr_src == '+') || (*pstr_src == '<')) | |
292 | break; | |
293 | *pstr_tmp++ = *pstr_src++; | |
294 | } | |
295 | *pstr_tmp = 0; | |
35c08157 | 296 | |
40c7a7cb KLC |
297 | pfd = (const field_t *) &operand_fields[0]; |
298 | while (1) | |
299 | { | |
300 | if (pfd->name == NULL) | |
301 | return; | |
302 | else if (strcmp (&tmp_string[0], pfd->name) == 0) | |
303 | break; | |
304 | pfd++; | |
305 | } | |
35c08157 | 306 | |
3ee6e4fb | 307 | /* For insn-16. */ |
40c7a7cb KLC |
308 | if (parse_mode & NDS32_PARSE_INSN16) |
309 | { | |
310 | if (pfd->hw_res == HW_GPR) | |
311 | { | |
312 | int_value = | |
313 | __GF (insn, pfd->bitpos, pfd->bitsize) << pfd->shift; | |
314 | /* push25/pop25. */ | |
315 | if ((opc->value == 0xfc00) || (opc->value == 0xfc80)) | |
316 | { | |
317 | if (int_value == 0) | |
318 | int_value = 6; | |
319 | else | |
320 | int_value = (6 + (0x01 << int_value)); | |
321 | push25gpr = int_value; | |
322 | } | |
323 | else if (strcmp (pfd->name, "rt4") == 0) | |
324 | { | |
325 | int_value = nds32_r45map[int_value]; | |
326 | } | |
327 | func (stream, "$%s", keyword_gpr[int_value].name); | |
328 | } | |
329 | else if ((pfd->hw_res == HW_INT) || (pfd->hw_res == HW_UINT)) | |
330 | { | |
331 | if (pfd->hw_res == HW_INT) | |
332 | int_value = | |
333 | N32_IMMS ((insn >> pfd->bitpos), | |
334 | pfd->bitsize) << pfd->shift; | |
335 | else | |
336 | int_value = | |
337 | __GF (insn, pfd->bitpos, pfd->bitsize) << pfd->shift; | |
338 | ||
339 | /* movpi45. */ | |
340 | if (opc->value == 0xfa00) | |
341 | { | |
342 | int_value += 16; | |
343 | func (stream, "#0x%x", int_value); | |
344 | } | |
345 | /* lwi45.fe. */ | |
346 | else if (opc->value == 0xb200) | |
347 | { | |
348 | int_value = 0 - (128 - int_value); | |
349 | func (stream, "#%d", int_value); | |
350 | } | |
351 | /* beqz38/bnez38/beqs38/bnes38/j8/beqzs8/bnezs8/ifcall9. */ | |
352 | else if ((opc->value == 0xc000) || (opc->value == 0xc800) | |
353 | || (opc->value == 0xd000) || (opc->value == 0xd800) | |
354 | || (opc->value == 0xd500) || (opc->value == 0xe800) | |
355 | || (opc->value == 0xe900) | |
356 | || (opc->value == 0xf800)) | |
357 | { | |
358 | info->print_address_func (int_value + pc, info); | |
359 | } | |
360 | /* push25/pop25. */ | |
361 | else if ((opc->value == 0xfc00) || (opc->value == 0xfc80)) | |
362 | { | |
363 | func (stream, "#%d ! {$r6", int_value); | |
364 | if (push25gpr != 6) | |
365 | func (stream, "~$%s", keyword_gpr[push25gpr].name); | |
366 | func (stream, ", $fp, $gp, $lp}"); | |
367 | } | |
368 | /* ex9.it. */ | |
369 | else if ((opc->value == 0xdd40) || (opc->value == 0xea00)) | |
370 | { | |
371 | func (stream, "#%d", int_value); | |
372 | nds32_ex9_info (pc, info, int_value); | |
373 | } | |
374 | else if (pfd->hw_res == HW_INT) | |
375 | { | |
3ee6e4fb | 376 | if (int_value < 10) |
40c7a7cb KLC |
377 | func (stream, "#%d", int_value); |
378 | else | |
379 | func (stream, "#0x%x", int_value); | |
380 | } | |
3ee6e4fb NC |
381 | else /* if (pfd->hw_res == HW_UINT). */ |
382 | { | |
383 | if (int_value < 10) | |
384 | func (stream, "#%u", int_value); | |
385 | else | |
386 | func (stream, "#0x%x", int_value); | |
387 | } | |
40c7a7cb | 388 | } |
35c08157 | 389 | |
40c7a7cb KLC |
390 | } |
391 | /* for audio-ext. */ | |
392 | else if (op == N32_OP6_AEXT) | |
393 | { | |
394 | nds32_parse_audio_ext (pfd, info, insn); | |
395 | } | |
396 | /* for insn-32. */ | |
397 | else if (pfd->hw_res < _HW_LAST) | |
398 | { | |
399 | int_value = | |
400 | __GF (insn, pfd->bitpos, pfd->bitsize) << pfd->shift; | |
401 | ||
402 | psys_reg = (keyword_t*) keywords[pfd->hw_res]; | |
403 | ||
404 | psys_reg = nds32_find_reg_keyword (psys_reg, int_value); | |
405 | /* For HW_SR, dump the index when it can't | |
406 | map the register name. */ | |
407 | if (!psys_reg && pfd->hw_res == HW_SR) | |
408 | func (stream, "%d", int_value); | |
409 | else if (!psys_reg) | |
410 | func (stream, "???"); | |
411 | else | |
412 | { | |
413 | if (pfd->hw_res == HW_GPR || pfd->hw_res == HW_CPR | |
414 | || pfd->hw_res == HW_FDR || pfd->hw_res == HW_FSR | |
415 | || pfd->hw_res == HW_DXR || pfd->hw_res == HW_SR | |
416 | || pfd->hw_res == HW_USR) | |
417 | func (stream, "$%s", psys_reg->name); | |
418 | else if (pfd->hw_res == HW_DTITON | |
419 | || pfd->hw_res == HW_DTITOFF) | |
420 | func (stream, ".%s", psys_reg->name); | |
421 | else | |
422 | func (stream, "%s", psys_reg->name); | |
423 | } | |
424 | } | |
425 | else if ((pfd->hw_res == HW_INT) || (pfd->hw_res == HW_UINT)) | |
426 | { | |
427 | if (pfd->hw_res == HW_INT) | |
428 | int_value = | |
429 | N32_IMMS ((insn >> pfd->bitpos), pfd->bitsize) << pfd->shift; | |
430 | else | |
431 | int_value = | |
432 | __GF (insn, pfd->bitpos, pfd->bitsize) << pfd->shift; | |
433 | ||
434 | if ((op == N32_OP6_BR1) || (op == N32_OP6_BR2)) | |
435 | { | |
436 | info->print_address_func (int_value + pc, info); | |
437 | } | |
438 | else if ((op == N32_OP6_BR3) && (pfd->bitpos == 0)) | |
439 | { | |
440 | info->print_address_func (int_value + pc, info); | |
441 | } | |
442 | else if (op == N32_OP6_JI) | |
443 | { | |
444 | /* FIXME: Handle relocation. */ | |
445 | if (info->flags & INSN_HAS_RELOC) | |
446 | pc = 0; | |
447 | /* Check if insn32 in ex9 table. */ | |
448 | if (parse_mode & NDS32_PARSE_EX9IT) | |
449 | info->print_address_func ((pc & 0xFE000000) | int_value, | |
450 | info); | |
451 | /* Check if decode ex9 table, PC(31,25)|Inst(23,0)<<1. */ | |
452 | else if (parse_mode & NDS32_PARSE_EX9TAB) | |
453 | func (stream, "PC(31,25)|#0x%x", int_value); | |
454 | else | |
455 | info->print_address_func (int_value + pc, info); | |
456 | } | |
457 | else if (op == N32_OP6_LSMW) | |
458 | { | |
459 | /* lmw.adm/smw.adm. */ | |
460 | func (stream, "#0x%x ! {", int_value); | |
461 | lsmwEnb4 = int_value; | |
462 | lsmwRb = ((insn >> 20) & 0x1F); | |
463 | lsmwRe = ((insn >> 10) & 0x1F); | |
464 | ||
465 | /* If [Rb, Re] specifies at least one register, | |
466 | Rb(4,0) <= Re(4,0) and 0 <= Rb(4,0), Re(4,0) < 28. | |
467 | Disassembling does not consider this currently because of | |
468 | the convience comparing with bsp320. */ | |
469 | if (lsmwRb != 31 || lsmwRe != 31) | |
470 | { | |
471 | func (stream, "$%s", keyword_gpr[lsmwRb].name); | |
472 | if (lsmwRb != lsmwRe) | |
473 | func (stream, "~$%s", keyword_gpr[lsmwRe].name); | |
474 | ifthe1st = 0; | |
475 | } | |
476 | if (lsmwEnb4 != 0) | |
477 | { | |
478 | /* $fp, $gp, $lp, $sp. */ | |
479 | checkbit = 0x08; | |
480 | for (i = 0; i < 4; i++) | |
481 | { | |
482 | if (lsmwEnb4 & checkbit) | |
483 | { | |
484 | if (ifthe1st == 1) | |
485 | { | |
486 | ifthe1st = 0; | |
487 | func (stream, "$%s", keyword_gpr[28 + i].name); | |
488 | } | |
489 | else | |
490 | func (stream, ", $%s", keyword_gpr[28 + i].name); | |
491 | } | |
492 | checkbit >>= 1; | |
493 | } | |
494 | } | |
495 | func (stream, "}"); | |
496 | } | |
497 | else if (pfd->hw_res == HW_INT) | |
498 | { | |
3ee6e4fb | 499 | if (int_value < 10) |
40c7a7cb KLC |
500 | func (stream, "#%d", int_value); |
501 | else | |
502 | func (stream, "#0x%x", int_value); | |
503 | } | |
3ee6e4fb | 504 | else /* if (pfd->hw_res == HW_UINT). */ |
40c7a7cb | 505 | { |
3ee6e4fb NC |
506 | if (int_value < 10) |
507 | func (stream, "#%u", int_value); | |
508 | else | |
509 | func (stream, "#0x%x", int_value); | |
40c7a7cb KLC |
510 | } |
511 | } | |
512 | break; | |
35c08157 | 513 | |
40c7a7cb KLC |
514 | case '{': |
515 | case '}': | |
516 | pstr_src++; | |
517 | break; | |
518 | ||
3ee6e4fb NC |
519 | case ',': |
520 | func (stream, ", "); | |
521 | pstr_src++; | |
522 | break; | |
523 | ||
524 | case '+': | |
525 | func (stream, " + "); | |
526 | pstr_src++; | |
527 | break; | |
528 | ||
529 | case '<': | |
530 | if (pstr_src[1] == '<') | |
531 | { | |
532 | func (stream, " << "); | |
533 | pstr_src += 2; | |
534 | } | |
535 | else | |
536 | { | |
537 | func (stream, " <"); | |
538 | pstr_src++; | |
539 | } | |
540 | break; | |
541 | ||
40c7a7cb KLC |
542 | default: |
543 | func (stream, "%c", *pstr_src++); | |
544 | break; | |
3ee6e4fb NC |
545 | } |
546 | } | |
35c08157 KLC |
547 | } |
548 | ||
40c7a7cb KLC |
549 | /* Filter instructions with some bits must be fixed. */ |
550 | ||
35c08157 | 551 | static void |
40c7a7cb | 552 | nds32_filter_unknown_insn (uint32_t insn, struct nds32_opcode **opc) |
35c08157 | 553 | { |
40c7a7cb KLC |
554 | if (!(*opc)) |
555 | return; | |
35c08157 | 556 | |
40c7a7cb | 557 | switch ((*opc)->value) |
35c08157 | 558 | { |
40c7a7cb KLC |
559 | case JREG (JR): |
560 | case JREG (JRNEZ): | |
561 | /* jr jr.xtoff */ | |
562 | if (__GF (insn, 6, 2) != 0 || __GF (insn, 15, 10) != 0) | |
563 | *opc = NULL; | |
35c08157 | 564 | break; |
40c7a7cb KLC |
565 | case MISC (STANDBY): |
566 | if (__GF (insn, 7, 18) != 0) | |
567 | *opc = NULL; | |
568 | break; | |
569 | case SIMD (PBSAD): | |
570 | case SIMD (PBSADA): | |
571 | if (__GF (insn, 5, 5) != 0) | |
572 | *opc = NULL; | |
573 | break; | |
574 | case BR2 (IFCALL): | |
575 | if (__GF (insn, 20, 5) != 0) | |
576 | *opc = NULL; | |
577 | break; | |
578 | case JREG (JRAL): | |
579 | if (__GF (insn, 5, 3) != 0 || __GF (insn, 15, 5) != 0) | |
580 | *opc = NULL; | |
581 | break; | |
582 | case ALU1 (NOR): | |
583 | case ALU1 (SLT): | |
584 | case ALU1 (SLTS): | |
585 | case ALU1 (SLLI): | |
586 | case ALU1 (SRLI): | |
587 | case ALU1 (SRAI): | |
588 | case ALU1 (ROTRI): | |
589 | case ALU1 (SLL): | |
590 | case ALU1 (SRL): | |
591 | case ALU1 (SRA): | |
592 | case ALU1 (ROTR): | |
593 | case ALU1 (SEB): | |
594 | case ALU1 (SEH): | |
595 | case ALU1 (ZEH): | |
596 | case ALU1 (WSBH): | |
597 | case ALU1 (SVA): | |
598 | case ALU1 (SVS): | |
599 | case ALU1 (CMOVZ): | |
600 | case ALU1 (CMOVN): | |
601 | if (__GF (insn, 5, 5) != 0) | |
602 | *opc = NULL; | |
603 | break; | |
604 | case MISC (IRET): | |
605 | case MISC (ISB): | |
606 | case MISC (DSB): | |
607 | if (__GF (insn, 5, 20) != 0) | |
608 | *opc = NULL; | |
35c08157 KLC |
609 | break; |
610 | } | |
611 | } | |
612 | ||
613 | static void | |
40c7a7cb KLC |
614 | print_insn32 (bfd_vma pc, disassemble_info *info, uint32_t insn, |
615 | uint32_t parse_mode) | |
35c08157 | 616 | { |
40c7a7cb KLC |
617 | /* Get the final correct opcode and parse. */ |
618 | struct nds32_opcode *opc; | |
619 | uint32_t opcode = nds32_mask_opcode (insn); | |
620 | opc = (struct nds32_opcode *) htab_find (opcode_htab, &opcode); | |
621 | ||
622 | nds32_special_opcode (insn, &opc); | |
623 | nds32_filter_unknown_insn (insn, &opc); | |
624 | nds32_parse_opcode (opc, pc, info, insn, parse_mode); | |
35c08157 KLC |
625 | } |
626 | ||
627 | static void | |
40c7a7cb KLC |
628 | print_insn16 (bfd_vma pc, disassemble_info *info, |
629 | uint32_t insn, uint32_t parse_mode) | |
35c08157 | 630 | { |
40c7a7cb KLC |
631 | struct nds32_opcode *opc; |
632 | uint32_t opcode; | |
633 | ||
634 | /* Get highest 7 bit in default. */ | |
635 | unsigned int mask = 0xfe00; | |
35c08157 | 636 | |
40c7a7cb KLC |
637 | /* Classify 16-bit instruction to 4 sets by bit 13 and 14. */ |
638 | switch (__GF (insn, 13, 2)) | |
35c08157 | 639 | { |
40c7a7cb KLC |
640 | case 0x0: |
641 | /* mov55 movi55 */ | |
642 | if (__GF (insn, 11, 2) == 0) | |
35c08157 | 643 | { |
40c7a7cb KLC |
644 | mask = 0xfc00; |
645 | /* ifret16 = mov55 $sp, $sp*/ | |
646 | if (__GF (insn, 0, 11) == 0x3ff) | |
647 | mask = 0xffff; | |
35c08157 | 648 | } |
40c7a7cb KLC |
649 | else if (__GF (insn, 9, 4) == 0xb) |
650 | mask = 0xfe07; | |
651 | break; | |
652 | case 0x1: | |
653 | /* lwi37 swi37 */ | |
654 | if (__GF (insn, 11, 2) == 0x3) | |
655 | mask = 0xf880; | |
656 | break; | |
657 | case 0x2: | |
658 | mask = 0xf800; | |
659 | /* Exclude beqz38, bnez38, beqs38, and bnes38. */ | |
660 | if (__GF (insn, 12, 1) == 0x1 | |
661 | && __GF (insn, 8, 3) == 0x5) | |
35c08157 | 662 | { |
40c7a7cb KLC |
663 | if (__GF (insn, 11, 1) == 0x0) |
664 | mask = 0xff00; | |
665 | else | |
666 | mask = 0xffe0; | |
35c08157 | 667 | } |
40c7a7cb KLC |
668 | break; |
669 | case 0x3: | |
670 | switch (__GF (insn, 11, 2)) | |
35c08157 | 671 | { |
35c08157 | 672 | case 0x1: |
40c7a7cb KLC |
673 | /* beqzs8 bnezs8 */ |
674 | if (__GF (insn, 9, 2) == 0x0) | |
675 | mask = 0xff00; | |
676 | /* addi10s */ | |
677 | else if (__GF(insn, 10, 1) == 0x1) | |
678 | mask = 0xfc00; | |
679 | break; | |
35c08157 | 680 | case 0x2: |
40c7a7cb KLC |
681 | /* lwi37.sp swi37.sp */ |
682 | mask = 0xf880; | |
683 | break; | |
35c08157 | 684 | case 0x3: |
40c7a7cb KLC |
685 | if (__GF (insn, 8, 3) == 0x5) |
686 | mask = 0xff00; | |
687 | else if (__GF (insn, 8, 3) == 0x4) | |
688 | mask = 0xff80; | |
689 | else if (__GF (insn, 9 , 2) == 0x3) | |
690 | mask = 0xfe07; | |
691 | break; | |
692 | } | |
693 | break; | |
694 | } | |
695 | opcode = insn & mask; | |
696 | opc = (struct nds32_opcode *) htab_find (opcode_htab, &opcode); | |
697 | ||
698 | nds32_special_opcode (insn, &opc); | |
699 | /* Get the final correct opcode and parse it. */ | |
700 | nds32_parse_opcode (opc, pc, info, insn, parse_mode); | |
701 | } | |
702 | ||
703 | static hashval_t | |
704 | htab_hash_hash (const void *p) | |
705 | { | |
706 | return (*(unsigned int *) p) % 49; | |
707 | } | |
708 | ||
709 | static int | |
710 | htab_hash_eq (const void *p, const void *q) | |
711 | { | |
712 | uint32_t pinsn = ((struct nds32_opcode *) p)->value; | |
713 | uint32_t qinsn = *((uint32_t *) q); | |
714 | ||
715 | return (pinsn == qinsn); | |
716 | } | |
717 | ||
718 | /* Get the format of instruction. */ | |
35c08157 | 719 | |
40c7a7cb KLC |
720 | static uint32_t |
721 | nds32_mask_opcode (uint32_t insn) | |
722 | { | |
723 | uint32_t opcode = N32_OP6 (insn); | |
724 | switch (opcode) | |
725 | { | |
726 | case N32_OP6_LBI: | |
727 | case N32_OP6_LHI: | |
728 | case N32_OP6_LWI: | |
729 | case N32_OP6_LDI: | |
730 | case N32_OP6_LBI_BI: | |
731 | case N32_OP6_LHI_BI: | |
732 | case N32_OP6_LWI_BI: | |
733 | case N32_OP6_LDI_BI: | |
734 | case N32_OP6_SBI: | |
735 | case N32_OP6_SHI: | |
736 | case N32_OP6_SWI: | |
737 | case N32_OP6_SDI: | |
738 | case N32_OP6_SBI_BI: | |
739 | case N32_OP6_SHI_BI: | |
740 | case N32_OP6_SWI_BI: | |
741 | case N32_OP6_SDI_BI: | |
742 | case N32_OP6_LBSI: | |
743 | case N32_OP6_LHSI: | |
744 | case N32_OP6_LWSI: | |
745 | case N32_OP6_LBSI_BI: | |
746 | case N32_OP6_LHSI_BI: | |
747 | case N32_OP6_LWSI_BI: | |
748 | case N32_OP6_MOVI: | |
749 | case N32_OP6_SETHI: | |
750 | case N32_OP6_ADDI: | |
751 | case N32_OP6_SUBRI: | |
752 | case N32_OP6_ANDI: | |
753 | case N32_OP6_XORI: | |
754 | case N32_OP6_ORI: | |
755 | case N32_OP6_SLTI: | |
756 | case N32_OP6_SLTSI: | |
757 | case N32_OP6_CEXT: | |
758 | case N32_OP6_BITCI: | |
759 | return MASK_OP (insn, 0); | |
760 | case N32_OP6_ALU2: | |
761 | /* FFBI */ | |
762 | if (__GF (insn, 0, 7) == (N32_ALU2_FFBI | __BIT (6))) | |
763 | return MASK_OP (insn, 0x7f); | |
764 | else if (__GF (insn, 0, 7) == (N32_ALU2_MFUSR | __BIT (6)) | |
765 | || __GF (insn, 0, 7) == (N32_ALU2_MTUSR | __BIT (6))) | |
766 | /* RDOV CLROV */ | |
767 | return MASK_OP (insn, 0xf81ff); | |
768 | return MASK_OP (insn, 0x1ff); | |
769 | case N32_OP6_ALU1: | |
770 | case N32_OP6_SIMD: | |
771 | return MASK_OP (insn, 0x1f); | |
772 | case N32_OP6_MEM: | |
773 | return MASK_OP (insn, 0xff); | |
774 | case N32_OP6_JREG: | |
775 | return MASK_OP (insn, 0x7f); | |
776 | case N32_OP6_LSMW: | |
777 | return MASK_OP (insn, 0x23); | |
778 | case N32_OP6_SBGP: | |
779 | case N32_OP6_LBGP: | |
780 | return MASK_OP (insn, 0x1 << 19); | |
781 | case N32_OP6_HWGP: | |
782 | if (__GF (insn, 18, 2) == 0x3) | |
783 | return MASK_OP (insn, 0x7 << 17); | |
784 | return MASK_OP (insn, 0x3 << 18); | |
785 | case N32_OP6_DPREFI: | |
786 | return MASK_OP (insn, 0x1 << 24); | |
787 | case N32_OP6_LWC: | |
788 | case N32_OP6_SWC: | |
789 | case N32_OP6_LDC: | |
790 | case N32_OP6_SDC: | |
791 | return MASK_OP (insn, 0x1 << 12); | |
792 | case N32_OP6_JI: | |
793 | return MASK_OP (insn, 0x1 << 24); | |
794 | case N32_OP6_BR1: | |
795 | return MASK_OP (insn, 0x1 << 14); | |
796 | case N32_OP6_BR2: | |
797 | return MASK_OP (insn, 0xf << 16); | |
798 | case N32_OP6_BR3: | |
799 | return MASK_OP (insn, 0x1 << 19); | |
800 | case N32_OP6_MISC: | |
801 | switch (__GF (insn, 0, 5)) | |
802 | { | |
803 | case N32_MISC_MTSR: | |
804 | /* SETGIE and SETEND */ | |
805 | if (__GF (insn, 5, 5) == 0x1 || __GF (insn, 5, 5) == 0x2) | |
806 | return MASK_OP (insn, 0x1fffff); | |
807 | return MASK_OP (insn, 0x1f); | |
808 | case N32_MISC_TLBOP: | |
809 | if (__GF (insn, 5, 5) == 5 || __GF (insn, 5, 5) == 7) | |
810 | /* PB FLUA */ | |
811 | return MASK_OP (insn, 0x3ff); | |
812 | return MASK_OP (insn, 0x1f); | |
813 | default: | |
814 | return MASK_OP (insn, 0x1f); | |
815 | } | |
816 | case N32_OP6_COP: | |
817 | if (__GF (insn, 4, 2) == 0) | |
818 | { | |
819 | /* FPU */ | |
820 | switch (__GF (insn, 0, 4)) | |
35c08157 KLC |
821 | { |
822 | case 0x0: | |
35c08157 | 823 | case 0x8: |
40c7a7cb KLC |
824 | /* FS1/F2OP FD1/F2OP */ |
825 | if (__GF (insn, 6, 4) == 0xf) | |
826 | return MASK_OP (insn, 0x7fff); | |
827 | /* FS1 FD1 */ | |
828 | return MASK_OP (insn, 0x3ff); | |
829 | case 0x4: | |
35c08157 | 830 | case 0xc: |
40c7a7cb KLC |
831 | /* FS2 */ |
832 | return MASK_OP (insn, 0x3ff); | |
833 | case 0x1: | |
834 | case 0x9: | |
835 | /* XR */ | |
836 | if (__GF (insn, 6, 4) == 0xc) | |
837 | return MASK_OP (insn, 0x7fff); | |
838 | /* MFCP MTCP */ | |
839 | return MASK_OP (insn, 0x3ff); | |
840 | default: | |
841 | return MASK_OP (insn, 0xff); | |
35c08157 KLC |
842 | } |
843 | } | |
40c7a7cb KLC |
844 | else if (__GF (insn, 0, 2) == 0) |
845 | return MASK_OP (insn, 0xf); | |
846 | return MASK_OP (insn, 0xcf); | |
847 | case N32_OP6_AEXT: | |
848 | /* AUDIO */ | |
849 | switch (__GF (insn, 23, 2)) | |
35c08157 KLC |
850 | { |
851 | case 0x0: | |
40c7a7cb KLC |
852 | if (__GF (insn, 5, 4) == 0) |
853 | /* AMxxx AMAyyS AMyyS AMAWzS AMWzS */ | |
854 | return MASK_OP (insn, (0x1f << 20) | 0x1ff); | |
855 | else if (__GF (insn, 5, 4) == 1) | |
856 | /* ALR ASR ALA ASA AUPI */ | |
857 | return MASK_OP (insn, (0x1f << 20) | (0xf << 5)); | |
858 | else if (__GF (insn, 20, 3) == 0 && __GF (insn, 6, 3) == 1) | |
859 | /* ALR2 */ | |
860 | return MASK_OP (insn, (0x1f << 20) | (0x7 << 6)); | |
861 | else if (__GF (insn, 20 ,3) == 2 && __GF (insn, 6, 3) == 1) | |
862 | /* AWEXT ASATS48 */ | |
863 | return MASK_OP (insn, (0x1f << 20) | (0xf << 5)); | |
864 | else if (__GF (insn, 20 ,3) == 3 && __GF (insn, 6, 3) == 1) | |
865 | /* AMTAR AMTAR2 AMFAR AMFAR2 */ | |
866 | return MASK_OP (insn, (0x1f << 20) | (0x1f << 5)); | |
867 | else if (__GF (insn, 7, 2) == 3) | |
868 | /* AMxxxSA */ | |
869 | return MASK_OP (insn, (0x1f << 20) | (0x3 << 7)); | |
870 | else if (__GF (insn, 6, 3) == 2) | |
871 | /* AMxxxL.S */ | |
872 | return MASK_OP (insn, (0x1f << 20) | (0xf << 5)); | |
35c08157 | 873 | else |
40c7a7cb KLC |
874 | /* AmxxxL.l AmxxxL2.S AMxxxL2.L */ |
875 | return MASK_OP (insn, (0x1f << 20) | (0x7 << 6)); | |
35c08157 | 876 | case 0x1: |
40c7a7cb KLC |
877 | if (__GF (insn, 20, 3) == 0) |
878 | /* AADDL ASUBL */ | |
879 | return MASK_OP (insn, (0x1f << 20) | (0x1 << 5)); | |
880 | else if (__GF (insn, 20, 3) == 1) | |
881 | /* AMTARI Ix AMTARI Mx */ | |
882 | return MASK_OP (insn, (0x1f << 20)); | |
883 | else if (__GF (insn, 6, 3) == 2) | |
884 | /* AMAWzSl.S AMWzSl.S */ | |
885 | return MASK_OP (insn, (0x1f << 20) | (0xf << 5)); | |
886 | else if (__GF (insn, 7, 2) == 3) | |
887 | /* AMAWzSSA AMWzSSA */ | |
888 | return MASK_OP (insn, (0x1f << 20) | (0x3 << 7)); | |
889 | else | |
890 | /* AMAWzSL.L AMAWzSL2.S AMAWzSL2.L AMWzSL.L AMWzSL.L AMWzSL2.S */ | |
891 | return MASK_OP (insn, (0x1f << 20) | (0x7 << 6)); | |
892 | case 0x2: | |
893 | if (__GF (insn, 6, 3) == 2) | |
894 | /* AMAyySl.S AMWyySl.S */ | |
895 | return MASK_OP (insn, (0x1f << 20) | (0xf << 5)); | |
896 | else if (__GF (insn, 7, 2) == 3) | |
897 | /* AMAWyySSA AMWyySSA */ | |
898 | return MASK_OP (insn, (0x1f << 20) | (0x3 << 7)); | |
899 | else | |
900 | /* AMAWyySL.L AMAWyySL2.S AMAWyySL2.L AMWyySL.L AMWyySL.L AMWyySL2.S */ | |
901 | return MASK_OP (insn, (0x1f << 20) | (0x7 << 6)); | |
35c08157 | 902 | } |
40c7a7cb KLC |
903 | return MASK_OP (insn, 0x1f << 20); |
904 | default: | |
905 | return (1 << 31); | |
35c08157 KLC |
906 | } |
907 | } | |
908 | ||
40c7a7cb KLC |
909 | /* Define cctl subtype. */ |
910 | static char *cctl_subtype [] = | |
35c08157 | 911 | { |
40c7a7cb KLC |
912 | /* 0x0 */ |
913 | "st0", "st0", "st0", "st2", "st2", "st3", "st3", "st4", | |
914 | "st1", "st1", "st1", "st0", "st0", NULL, NULL, "st5", | |
915 | /* 0x10 */ | |
916 | "st0", NULL, NULL, "st2", "st2", "st3", "st3", NULL, | |
917 | "st1", NULL, NULL, "st0", "st0", NULL, NULL, NULL | |
918 | }; | |
35c08157 | 919 | |
40c7a7cb | 920 | /* Check the subset of opcode. */ |
35c08157 | 921 | |
40c7a7cb KLC |
922 | static void |
923 | nds32_special_opcode (uint32_t insn, struct nds32_opcode **opc) | |
924 | { | |
925 | char *string = NULL; | |
926 | uint32_t op; | |
35c08157 | 927 | |
40c7a7cb KLC |
928 | if (!(*opc)) |
929 | return; | |
35c08157 | 930 | |
40c7a7cb KLC |
931 | /* Check if special case. */ |
932 | switch ((*opc)->value) | |
933 | { | |
934 | case OP6 (LWC): | |
935 | case OP6 (SWC): | |
936 | case OP6 (LDC): | |
937 | case OP6 (SDC): | |
938 | case FPU_RA_IMMBI (LWC): | |
939 | case FPU_RA_IMMBI (SWC): | |
940 | case FPU_RA_IMMBI (LDC): | |
941 | case FPU_RA_IMMBI (SDC): | |
942 | /* Check if cp0 => FPU. */ | |
35c08157 | 943 | if (__GF (insn, 13, 2) == 0) |
35c08157 | 944 | { |
40c7a7cb KLC |
945 | while (!((*opc)->attr & ATTR (FPU)) && (*opc)->next) |
946 | *opc = (*opc)->next; | |
35c08157 | 947 | } |
40c7a7cb KLC |
948 | break; |
949 | case ALU1 (ADD): | |
950 | case ALU1 (SUB): | |
951 | case ALU1 (AND): | |
952 | case ALU1 (XOR): | |
953 | case ALU1 (OR): | |
954 | /* Check if (add/add_slli) (sub/sub_slli) (and/and_slli). */ | |
955 | if (N32_SH5(insn) != 0) | |
956 | string = "sh"; | |
957 | break; | |
958 | case ALU1 (SRLI): | |
959 | /* Check if nop. */ | |
960 | if (__GF (insn, 10, 15) == 0) | |
961 | string = "nop"; | |
962 | break; | |
963 | case MISC (CCTL): | |
964 | string = cctl_subtype [__GF (insn, 5, 5)]; | |
965 | break; | |
966 | case JREG (JR): | |
967 | case JREG (JRAL): | |
968 | case JREG (JR) | JREG_RET: | |
969 | if (__GF (insn, 8, 2) != 0) | |
970 | string = "tit"; | |
971 | break; | |
972 | case N32_OP6_COP: | |
973 | break; | |
974 | case 0xea00: | |
975 | /* break16 ex9 */ | |
976 | if (__GF (insn, 5, 4) != 0) | |
977 | string = "ex9"; | |
978 | break; | |
979 | case 0x9200: | |
980 | /* nop16 */ | |
981 | if (__GF (insn, 0, 9) == 0) | |
982 | string = "nop16"; | |
983 | break; | |
984 | } | |
985 | ||
986 | if (string) | |
987 | { | |
988 | while (strstr ((*opc)->opcode, string) == NULL | |
989 | && strstr ((*opc)->instruction, string) == NULL && (*opc)->next) | |
990 | *opc = (*opc)->next; | |
35c08157 KLC |
991 | return; |
992 | } | |
40c7a7cb KLC |
993 | |
994 | /* Classify instruction is COP or FPU. */ | |
995 | op = N32_OP6 (insn); | |
996 | if (op == N32_OP6_COP && __GF (insn, 4, 2) != 0) | |
997 | { | |
998 | while (((*opc)->attr & ATTR (FPU)) != 0 && (*opc)->next) | |
999 | *opc = (*opc)->next; | |
1000 | } | |
35c08157 KLC |
1001 | } |
1002 | ||
1003 | int | |
1004 | print_insn_nds32 (bfd_vma pc, disassemble_info *info) | |
1005 | { | |
1006 | int status; | |
1007 | bfd_byte buf[4]; | |
1008 | uint32_t insn; | |
40c7a7cb KLC |
1009 | static int init = 1; |
1010 | int i = 0; | |
1011 | struct nds32_opcode *opc; | |
1012 | struct nds32_opcode **slot; | |
1013 | ||
1014 | if (init) | |
1015 | { | |
1016 | /* Build opcode table. */ | |
1017 | opcode_htab = htab_create_alloc (1024, htab_hash_hash, htab_hash_eq, | |
1018 | NULL, xcalloc, free); | |
35c08157 | 1019 | |
40c7a7cb KLC |
1020 | while (nds32_opcodes[i].opcode != NULL) |
1021 | { | |
1022 | opc = &nds32_opcodes[i]; | |
1023 | slot = | |
1024 | (struct nds32_opcode **) htab_find_slot (opcode_htab, &opc->value, | |
1025 | INSERT); | |
1026 | if (*slot == NULL) | |
1027 | { | |
1028 | /* This is the new one. */ | |
1029 | *slot = opc; | |
1030 | } | |
1031 | else | |
1032 | { | |
1033 | /* Already exists. Append to the list. */ | |
1034 | opc = *slot; | |
1035 | while (opc->next) | |
1036 | opc = opc->next; | |
1037 | opc->next = &nds32_opcodes[i]; | |
1038 | } | |
1039 | i++; | |
1040 | } | |
1041 | init = 0; | |
1042 | } | |
1043 | ||
1044 | status = info->read_memory_func (pc, (bfd_byte *) buf, 4, info); | |
35c08157 | 1045 | if (status) |
40c7a7cb KLC |
1046 | { |
1047 | /* for the last 16-bit instruction. */ | |
1048 | status = info->read_memory_func (pc, (bfd_byte *) buf, 2, info); | |
1049 | if (status) | |
1050 | { | |
1051 | (*info->memory_error_func)(status, pc, info); | |
1052 | return -1; | |
1053 | } | |
1054 | } | |
35c08157 | 1055 | |
40c7a7cb | 1056 | insn = bfd_getb32 (buf); |
35c08157 | 1057 | /* 16-bit instruction. */ |
40c7a7cb | 1058 | if (insn & 0x80000000) |
35c08157 | 1059 | { |
40c7a7cb KLC |
1060 | if (info->section && strstr (info->section->name, ".ex9.itable") != NULL) |
1061 | { | |
1062 | print_insn16 (pc, info, (insn & 0x0000FFFF), | |
1063 | NDS32_PARSE_INSN16 | NDS32_PARSE_EX9TAB); | |
1064 | return 4; | |
1065 | } | |
1066 | print_insn16 (pc, info, (insn >> 16), NDS32_PARSE_INSN16); | |
35c08157 KLC |
1067 | return 2; |
1068 | } | |
1069 | ||
1070 | /* 32-bit instructions. */ | |
40c7a7cb KLC |
1071 | else |
1072 | { | |
1073 | if (info->section | |
1074 | && strstr (info->section->name, ".ex9.itable") != NULL) | |
1075 | print_insn32 (pc, info, insn, NDS32_PARSE_INSN32 | NDS32_PARSE_EX9TAB); | |
1076 | else | |
1077 | print_insn32 (pc, info, insn, NDS32_PARSE_INSN32); | |
1078 | return 4; | |
1079 | } | |
35c08157 | 1080 | } |