/src/binutils-gdb/opcodes/nios2-dis.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Altera Nios II disassemble routines |
2 | | Copyright (C) 2012-2023 Free Software Foundation, Inc. |
3 | | Contributed by Nigel Gray (ngray@altera.com). |
4 | | Contributed by Mentor Graphics, Inc. |
5 | | |
6 | | This file is part of the GNU opcodes library. |
7 | | |
8 | | This library is free software; you can redistribute it and/or modify |
9 | | it under the terms of the GNU General Public License as published by |
10 | | the Free Software Foundation; either version 3, or (at your option) |
11 | | any later version. |
12 | | |
13 | | It is distributed in the hope that it will be useful, but WITHOUT |
14 | | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
15 | | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public |
16 | | License for more details. |
17 | | |
18 | | You should have received a copy of the GNU General Public License |
19 | | along with this file; see the file COPYING. If not, write to the |
20 | | Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, |
21 | | MA 02110-1301, USA. */ |
22 | | |
23 | | #include "sysdep.h" |
24 | | #include "disassemble.h" |
25 | | #include "opintl.h" |
26 | | #include "opcode/nios2.h" |
27 | | #include "libiberty.h" |
28 | | #include <string.h> |
29 | | #include <assert.h> |
30 | | |
31 | | /* No symbol table is available when this code runs out in an embedded |
32 | | system as when it is used for disassembler support in a monitor. */ |
33 | | #if !defined(EMBEDDED_ENV) |
34 | | #define SYMTAB_AVAILABLE 1 |
35 | | #include "elf-bfd.h" |
36 | | #include "elf/nios2.h" |
37 | | #endif |
38 | | |
39 | | /* Default length of Nios II instruction in bytes. */ |
40 | 1.73M | #define INSNLEN 4 |
41 | | |
42 | | /* Data structures used by the opcode hash table. */ |
43 | | typedef struct _nios2_opcode_hash |
44 | | { |
45 | | const struct nios2_opcode *opcode; |
46 | | struct _nios2_opcode_hash *next; |
47 | | } nios2_opcode_hash; |
48 | | |
49 | | /* Hash table size. */ |
50 | 260 | #define OPCODE_HASH_SIZE (IW_R1_OP_UNSHIFTED_MASK + 1) |
51 | | |
52 | | /* Extract the opcode from an instruction word. */ |
53 | | static unsigned int |
54 | | nios2_r1_extract_opcode (unsigned int x) |
55 | 102k | { |
56 | 102k | return GET_IW_R1_OP (x); |
57 | 102k | } |
58 | | |
59 | | static unsigned int |
60 | | nios2_r2_extract_opcode (unsigned int x) |
61 | 1.04M | { |
62 | 1.04M | return GET_IW_R2_OP (x); |
63 | 1.04M | } |
64 | | |
65 | | /* We maintain separate hash tables for R1 and R2 opcodes, and pseudo-ops |
66 | | are stored in a different table than regular instructions. */ |
67 | | |
68 | | typedef struct _nios2_disassembler_state |
69 | | { |
70 | | const struct nios2_opcode *opcodes; |
71 | | const int *num_opcodes; |
72 | | unsigned int (*extract_opcode) (unsigned int); |
73 | | nios2_opcode_hash *hash[OPCODE_HASH_SIZE]; |
74 | | nios2_opcode_hash *ps_hash[OPCODE_HASH_SIZE]; |
75 | | const struct nios2_opcode *nop; |
76 | | bool init; |
77 | | } nios2_disassembler_state; |
78 | | |
79 | | static nios2_disassembler_state |
80 | | nios2_r1_disassembler_state = { |
81 | | nios2_r1_opcodes, |
82 | | &nios2_num_r1_opcodes, |
83 | | nios2_r1_extract_opcode, |
84 | | {}, |
85 | | {}, |
86 | | NULL, |
87 | | 0 |
88 | | }; |
89 | | |
90 | | static nios2_disassembler_state |
91 | | nios2_r2_disassembler_state = { |
92 | | nios2_r2_opcodes, |
93 | | &nios2_num_r2_opcodes, |
94 | | nios2_r2_extract_opcode, |
95 | | {}, |
96 | | {}, |
97 | | NULL, |
98 | | 0 |
99 | | }; |
100 | | |
101 | | /* Function to initialize the opcode hash table. */ |
102 | | static void |
103 | | nios2_init_opcode_hash (nios2_disassembler_state *state) |
104 | 4 | { |
105 | 4 | unsigned int i; |
106 | 4 | register const struct nios2_opcode *op; |
107 | | |
108 | 260 | for (i = 0; i < OPCODE_HASH_SIZE; i++) |
109 | 34.1k | for (op = state->opcodes; op < &state->opcodes[*(state->num_opcodes)]; op++) |
110 | 33.9k | { |
111 | 33.9k | nios2_opcode_hash *new_hash; |
112 | 33.9k | nios2_opcode_hash **bucket = NULL; |
113 | | |
114 | 33.9k | if ((op->pinfo & NIOS2_INSN_MACRO) == NIOS2_INSN_MACRO) |
115 | 4.99k | { |
116 | 4.99k | if (i == state->extract_opcode (op->match) |
117 | 4.99k | && (op->pinfo & (NIOS2_INSN_MACRO_MOV | NIOS2_INSN_MACRO_MOVI) |
118 | 78 | & 0x7fffffff)) |
119 | 22 | { |
120 | 22 | bucket = &(state->ps_hash[i]); |
121 | 22 | if (strcmp (op->name, "nop") == 0) |
122 | 4 | state->nop = op; |
123 | 22 | } |
124 | 4.99k | } |
125 | 28.9k | else if (i == state->extract_opcode (op->match)) |
126 | 452 | bucket = &(state->hash[i]); |
127 | | |
128 | 33.9k | if (bucket) |
129 | 474 | { |
130 | 474 | new_hash = |
131 | 474 | (nios2_opcode_hash *) malloc (sizeof (nios2_opcode_hash)); |
132 | 474 | if (new_hash == NULL) |
133 | 0 | { |
134 | | /* xgettext:c-format */ |
135 | 0 | opcodes_error_handler (_("out of memory")); |
136 | 0 | exit (1); |
137 | 0 | } |
138 | 474 | new_hash->opcode = op; |
139 | 474 | new_hash->next = NULL; |
140 | 5.10k | while (*bucket) |
141 | 4.63k | bucket = &((*bucket)->next); |
142 | 474 | *bucket = new_hash; |
143 | 474 | } |
144 | 33.9k | } |
145 | 4 | state->init = 1; |
146 | | |
147 | | #ifdef DEBUG_HASHTABLE |
148 | | for (i = 0; i < OPCODE_HASH_SIZE; ++i) |
149 | | { |
150 | | nios2_opcode_hash *tmp_hash = state->hash[i]; |
151 | | printf ("index: 0x%02X ops: ", i); |
152 | | while (tmp_hash != NULL) |
153 | | { |
154 | | printf ("%s ", tmp_hash->opcode->name); |
155 | | tmp_hash = tmp_hash->next; |
156 | | } |
157 | | printf ("\n"); |
158 | | } |
159 | | |
160 | | for (i = 0; i < OPCODE_HASH_SIZE; ++i) |
161 | | { |
162 | | nios2_opcode_hash *tmp_hash = state->ps_hash[i]; |
163 | | printf ("index: 0x%02X ops: ", i); |
164 | | while (tmp_hash != NULL) |
165 | | { |
166 | | printf ("%s ", tmp_hash->opcode->name); |
167 | | tmp_hash = tmp_hash->next; |
168 | | } |
169 | | printf ("\n"); |
170 | | } |
171 | | #endif /* DEBUG_HASHTABLE */ |
172 | 4 | } |
173 | | |
174 | | /* Return a pointer to an nios2_opcode struct for a given instruction |
175 | | word OPCODE for bfd machine MACH, or NULL if there is an error. */ |
176 | | const struct nios2_opcode * |
177 | | nios2_find_opcode_hash (unsigned long opcode, unsigned long mach) |
178 | 556k | { |
179 | 556k | nios2_opcode_hash *entry; |
180 | 556k | nios2_disassembler_state *state; |
181 | | |
182 | | /* Select the right instruction set, hash tables, and opcode accessor |
183 | | for the mach variant. */ |
184 | 556k | if (mach == bfd_mach_nios2r2) |
185 | 512k | state = &nios2_r2_disassembler_state; |
186 | 44.5k | else |
187 | 44.5k | state = &nios2_r1_disassembler_state; |
188 | | |
189 | | /* Build a hash table to shorten the search time. */ |
190 | 556k | if (!state->init) |
191 | 4 | nios2_init_opcode_hash (state); |
192 | | |
193 | | /* Check for NOP first. Both NOP and MOV are macros that expand into |
194 | | an ADD instruction, and we always want to give priority to NOP. */ |
195 | 556k | if (state->nop->match == (opcode & state->nop->mask)) |
196 | 0 | return state->nop; |
197 | | |
198 | | /* First look in the pseudo-op hashtable. */ |
199 | 556k | for (entry = state->ps_hash[state->extract_opcode (opcode)]; |
200 | 595k | entry; entry = entry->next) |
201 | 41.3k | if (entry->opcode->match == (opcode & entry->opcode->mask)) |
202 | 2.28k | return entry->opcode; |
203 | | |
204 | | /* Otherwise look in the main hashtable. */ |
205 | 554k | for (entry = state->hash[state->extract_opcode (opcode)]; |
206 | 1.10M | entry; entry = entry->next) |
207 | 1.03M | if (entry->opcode->match == (opcode & entry->opcode->mask)) |
208 | 488k | return entry->opcode; |
209 | | |
210 | 65.4k | return NULL; |
211 | 554k | } |
212 | | |
213 | | /* There are 32 regular registers, 32 coprocessor registers, |
214 | | and 32 control registers. */ |
215 | 556k | #define NUMREGNAMES 32 |
216 | | |
217 | | /* Return a pointer to the base of the coprocessor register name array. */ |
218 | | static struct nios2_reg * |
219 | | nios2_coprocessor_regs (void) |
220 | 18.9k | { |
221 | 18.9k | static struct nios2_reg *cached = NULL; |
222 | | |
223 | 18.9k | if (!cached) |
224 | 2 | { |
225 | 2 | int i; |
226 | 118 | for (i = NUMREGNAMES; i < nios2_num_regs; i++) |
227 | 118 | if (!strcmp (nios2_regs[i].name, "c0")) |
228 | 2 | { |
229 | 2 | cached = nios2_regs + i; |
230 | 2 | break; |
231 | 2 | } |
232 | 2 | assert (cached); |
233 | 2 | } |
234 | 18.9k | return cached; |
235 | 18.9k | } |
236 | | |
237 | | /* Return a pointer to the base of the control register name array. */ |
238 | | static struct nios2_reg * |
239 | | nios2_control_regs (void) |
240 | 24 | { |
241 | 24 | static struct nios2_reg *cached = NULL; |
242 | | |
243 | 24 | if (!cached) |
244 | 1 | { |
245 | 1 | int i; |
246 | 12 | for (i = NUMREGNAMES; i < nios2_num_regs; i++) |
247 | 12 | if (!strcmp (nios2_regs[i].name, "status")) |
248 | 1 | { |
249 | 1 | cached = nios2_regs + i; |
250 | 1 | break; |
251 | 1 | } |
252 | 1 | assert (cached); |
253 | 1 | } |
254 | 24 | return cached; |
255 | 24 | } |
256 | | |
257 | | /* Helper routine to report internal errors. */ |
258 | | static void |
259 | | bad_opcode (const struct nios2_opcode *op) |
260 | 0 | { |
261 | 0 | opcodes_error_handler |
262 | | /* xgettext:c-format */ |
263 | 0 | (_("internal error: broken opcode descriptor for `%s %s'"), |
264 | 0 | op->name, op->args); |
265 | 0 | abort (); |
266 | 0 | } |
267 | | |
268 | | /* The function nios2_print_insn_arg uses the character pointed |
269 | | to by ARGPTR to determine how it print the next token or separator |
270 | | character in the arguments to an instruction. */ |
271 | | static int |
272 | | nios2_print_insn_arg (const char *argptr, |
273 | | unsigned long opcode, bfd_vma address, |
274 | | disassemble_info *info, |
275 | | const struct nios2_opcode *op) |
276 | 2.00M | { |
277 | 2.00M | unsigned long i = 0; |
278 | 2.00M | long s = 0; |
279 | 2.00M | int32_t o = 0; |
280 | 2.00M | struct nios2_reg *reg_base; |
281 | | |
282 | 2.00M | switch (*argptr) |
283 | 2.00M | { |
284 | 584k | case ',': |
285 | 698k | case '(': |
286 | 811k | case ')': |
287 | 811k | (*info->fprintf_func) (info->stream, "%c", *argptr); |
288 | 811k | break; |
289 | | |
290 | 24 | case 'c': |
291 | | /* Control register index. */ |
292 | 24 | switch (op->format) |
293 | 24 | { |
294 | 0 | case iw_r_type: |
295 | 0 | i = GET_IW_R_IMM5 (opcode); |
296 | 0 | break; |
297 | 24 | case iw_F3X6L5_type: |
298 | 24 | i = GET_IW_F3X6L5_IMM5 (opcode); |
299 | 24 | break; |
300 | 0 | default: |
301 | 0 | bad_opcode (op); |
302 | 24 | } |
303 | 24 | reg_base = nios2_control_regs (); |
304 | 24 | (*info->fprintf_func) (info->stream, "%s", reg_base[i].name); |
305 | 24 | break; |
306 | | |
307 | 16.5k | case 'd': |
308 | 16.5k | reg_base = nios2_regs; |
309 | 16.5k | switch (op->format) |
310 | 16.5k | { |
311 | 12 | case iw_r_type: |
312 | 12 | i = GET_IW_R_C (opcode); |
313 | 12 | break; |
314 | 1.26k | case iw_custom_type: |
315 | 1.26k | i = GET_IW_CUSTOM_C (opcode); |
316 | 1.26k | if (GET_IW_CUSTOM_READC (opcode) == 0) |
317 | 464 | reg_base = nios2_coprocessor_regs (); |
318 | 1.26k | break; |
319 | 412 | case iw_F3X6L5_type: |
320 | 535 | case iw_F3X6_type: |
321 | 535 | i = GET_IW_F3X6L5_C (opcode); |
322 | 535 | break; |
323 | 9.99k | case iw_F3X8_type: |
324 | 9.99k | i = GET_IW_F3X8_C (opcode); |
325 | 9.99k | if (GET_IW_F3X8_READC (opcode) == 0) |
326 | 7.00k | reg_base = nios2_coprocessor_regs (); |
327 | 9.99k | break; |
328 | 4.76k | case iw_F2_type: |
329 | 4.76k | i = GET_IW_F2_B (opcode); |
330 | 4.76k | break; |
331 | 0 | default: |
332 | 0 | bad_opcode (op); |
333 | 16.5k | } |
334 | 16.5k | if (i < NUMREGNAMES) |
335 | 16.5k | (*info->fprintf_func) (info->stream, "%s", reg_base[i].name); |
336 | 0 | else |
337 | 0 | (*info->fprintf_func) (info->stream, "unknown"); |
338 | 16.5k | break; |
339 | | |
340 | 269k | case 's': |
341 | 269k | reg_base = nios2_regs; |
342 | 269k | switch (op->format) |
343 | 269k | { |
344 | 12 | case iw_r_type: |
345 | 12 | i = GET_IW_R_A (opcode); |
346 | 12 | break; |
347 | 20.1k | case iw_i_type: |
348 | 20.1k | i = GET_IW_I_A (opcode); |
349 | 20.1k | break; |
350 | 1.26k | case iw_custom_type: |
351 | 1.26k | i = GET_IW_CUSTOM_A (opcode); |
352 | 1.26k | if (GET_IW_CUSTOM_READA (opcode) == 0) |
353 | 1.03k | reg_base = nios2_coprocessor_regs (); |
354 | 1.26k | break; |
355 | 203k | case iw_F2I16_type: |
356 | 203k | i = GET_IW_F2I16_A (opcode); |
357 | 203k | break; |
358 | 3.87k | case iw_F2X4I12_type: |
359 | 3.87k | i = GET_IW_F2X4I12_A (opcode); |
360 | 3.87k | break; |
361 | 16 | case iw_F1X4I12_type: |
362 | 16 | i = GET_IW_F1X4I12_A (opcode); |
363 | 16 | break; |
364 | 0 | case iw_F1X4L17_type: |
365 | 0 | i = GET_IW_F1X4L17_A (opcode); |
366 | 0 | break; |
367 | 388 | case iw_F3X6L5_type: |
368 | 511 | case iw_F3X6_type: |
369 | 511 | i = GET_IW_F3X6L5_A (opcode); |
370 | 511 | break; |
371 | 242 | case iw_F2X6L10_type: |
372 | 242 | i = GET_IW_F2X6L10_A (opcode); |
373 | 242 | break; |
374 | 9.99k | case iw_F3X8_type: |
375 | 9.99k | i = GET_IW_F3X8_A (opcode); |
376 | 9.99k | if (GET_IW_F3X8_READA (opcode) == 0) |
377 | 3.03k | reg_base = nios2_coprocessor_regs (); |
378 | 9.99k | break; |
379 | 634 | case iw_F1X1_type: |
380 | 634 | i = GET_IW_F1X1_A (opcode); |
381 | 634 | break; |
382 | 24.8k | case iw_F1I5_type: |
383 | 24.8k | i = 27; /* Implicit stack pointer reference. */ |
384 | 24.8k | break; |
385 | 4.76k | case iw_F2_type: |
386 | 4.76k | i = GET_IW_F2_A (opcode); |
387 | 4.76k | break; |
388 | 0 | default: |
389 | 0 | bad_opcode (op); |
390 | 269k | } |
391 | 269k | if (i < NUMREGNAMES) |
392 | 269k | (*info->fprintf_func) (info->stream, "%s", reg_base[i].name); |
393 | 0 | else |
394 | 0 | (*info->fprintf_func) (info->stream, "unknown"); |
395 | 269k | break; |
396 | | |
397 | 270k | case 't': |
398 | 270k | reg_base = nios2_regs; |
399 | 270k | switch (op->format) |
400 | 270k | { |
401 | 9 | case iw_r_type: |
402 | 9 | i = GET_IW_R_B (opcode); |
403 | 9 | break; |
404 | 20.2k | case iw_i_type: |
405 | 20.2k | i = GET_IW_I_B (opcode); |
406 | 20.2k | break; |
407 | 1.26k | case iw_custom_type: |
408 | 1.26k | i = GET_IW_CUSTOM_B (opcode); |
409 | 1.26k | if (GET_IW_CUSTOM_READB (opcode) == 0) |
410 | 679 | reg_base = nios2_coprocessor_regs (); |
411 | 1.26k | break; |
412 | 205k | case iw_F2I16_type: |
413 | 205k | i = GET_IW_F2I16_B (opcode); |
414 | 205k | break; |
415 | 3.87k | case iw_F2X4I12_type: |
416 | 3.87k | i = GET_IW_F2X4I12_B (opcode); |
417 | 3.87k | break; |
418 | 0 | case iw_F3X6L5_type: |
419 | 123 | case iw_F3X6_type: |
420 | 123 | i = GET_IW_F3X6L5_B (opcode); |
421 | 123 | break; |
422 | 242 | case iw_F2X6L10_type: |
423 | 242 | i = GET_IW_F2X6L10_B (opcode); |
424 | 242 | break; |
425 | 9.99k | case iw_F3X8_type: |
426 | 9.99k | i = GET_IW_F3X8_B (opcode); |
427 | 9.99k | if (GET_IW_F3X8_READB (opcode) == 0) |
428 | 6.77k | reg_base = nios2_coprocessor_regs (); |
429 | 9.99k | break; |
430 | 24.8k | case iw_F1I5_type: |
431 | 24.8k | i = GET_IW_F1I5_B (opcode); |
432 | 24.8k | break; |
433 | 0 | case iw_F2_type: |
434 | 0 | i = GET_IW_F2_B (opcode); |
435 | 0 | break; |
436 | 4.17k | case iw_T1X1I6_type: |
437 | 4.17k | i = 0; |
438 | 4.17k | break; |
439 | 0 | default: |
440 | 0 | bad_opcode (op); |
441 | 270k | } |
442 | 270k | if (i < NUMREGNAMES) |
443 | 270k | (*info->fprintf_func) (info->stream, "%s", reg_base[i].name); |
444 | 0 | else |
445 | 0 | (*info->fprintf_func) (info->stream, "unknown"); |
446 | 270k | break; |
447 | | |
448 | 34.0k | case 'D': |
449 | 34.0k | switch (op->format) |
450 | 34.0k | { |
451 | 12.8k | case iw_T1I7_type: |
452 | 12.8k | i = GET_IW_T1I7_A3 (opcode); |
453 | 12.8k | break; |
454 | 4.58k | case iw_T2X1L3_type: |
455 | 4.58k | i = GET_IW_T2X1L3_B3 (opcode); |
456 | 4.58k | break; |
457 | 4.37k | case iw_T2X1I3_type: |
458 | 4.37k | i = GET_IW_T2X1I3_B3 (opcode); |
459 | 4.37k | break; |
460 | 8.92k | case iw_T3X1_type: |
461 | 8.92k | i = GET_IW_T3X1_C3 (opcode); |
462 | 8.92k | break; |
463 | 3.32k | case iw_T2X3_type: |
464 | 3.32k | if (op->num_args == 3) |
465 | 2.79k | i = GET_IW_T2X3_A3 (opcode); |
466 | 533 | else |
467 | 533 | i = GET_IW_T2X3_B3 (opcode); |
468 | 3.32k | break; |
469 | 0 | default: |
470 | 0 | bad_opcode (op); |
471 | 34.0k | } |
472 | 34.0k | i = nios2_r2_reg3_mappings[i]; |
473 | 34.0k | (*info->fprintf_func) (info->stream, "%s", nios2_regs[i].name); |
474 | 34.0k | break; |
475 | | |
476 | 1.67k | case 'M': |
477 | | /* 6-bit unsigned immediate with no shift. */ |
478 | 1.67k | switch (op->format) |
479 | 1.67k | { |
480 | 1.67k | case iw_T1X1I6_type: |
481 | 1.67k | i = GET_IW_T1X1I6_IMM6 (opcode); |
482 | 1.67k | break; |
483 | 0 | default: |
484 | 0 | bad_opcode (op); |
485 | 1.67k | } |
486 | 1.67k | (*info->fprintf_func) (info->stream, "%ld", i); |
487 | 1.67k | break; |
488 | | |
489 | 2.50k | case 'N': |
490 | | /* 6-bit unsigned immediate with 2-bit shift. */ |
491 | 2.50k | switch (op->format) |
492 | 2.50k | { |
493 | 2.50k | case iw_T1X1I6_type: |
494 | 2.50k | i = GET_IW_T1X1I6_IMM6 (opcode) << 2; |
495 | 2.50k | break; |
496 | 0 | default: |
497 | 0 | bad_opcode (op); |
498 | 2.50k | } |
499 | 2.50k | (*info->fprintf_func) (info->stream, "%ld", i); |
500 | 2.50k | break; |
501 | | |
502 | 72.1k | case 'S': |
503 | 72.1k | switch (op->format) |
504 | 72.1k | { |
505 | 10.4k | case iw_T1I7_type: |
506 | 10.4k | i = GET_IW_T1I7_A3 (opcode); |
507 | 10.4k | break; |
508 | 36.2k | case iw_T2I4_type: |
509 | 36.2k | i = GET_IW_T2I4_A3 (opcode); |
510 | 36.2k | break; |
511 | 4.58k | case iw_T2X1L3_type: |
512 | 4.58k | i = GET_IW_T2X1L3_A3 (opcode); |
513 | 4.58k | break; |
514 | 4.37k | case iw_T2X1I3_type: |
515 | 4.37k | i = GET_IW_T2X1I3_A3 (opcode); |
516 | 4.37k | break; |
517 | 8.92k | case iw_T3X1_type: |
518 | 8.92k | i = GET_IW_T3X1_A3 (opcode); |
519 | 8.92k | break; |
520 | 3.32k | case iw_T2X3_type: |
521 | 3.32k | i = GET_IW_T2X3_A3 (opcode); |
522 | 3.32k | break; |
523 | 4.17k | case iw_T1X1I6_type: |
524 | 4.17k | i = GET_IW_T1X1I6_A3 (opcode); |
525 | 4.17k | break; |
526 | 0 | default: |
527 | 0 | bad_opcode (op); |
528 | 72.1k | } |
529 | 72.1k | i = nios2_r2_reg3_mappings[i]; |
530 | 72.1k | (*info->fprintf_func) (info->stream, "%s", nios2_regs[i].name); |
531 | 72.1k | break; |
532 | | |
533 | 47.9k | case 'T': |
534 | 47.9k | switch (op->format) |
535 | 47.9k | { |
536 | 36.2k | case iw_T2I4_type: |
537 | 36.2k | i = GET_IW_T2I4_B3 (opcode); |
538 | 36.2k | break; |
539 | 8.92k | case iw_T3X1_type: |
540 | 8.92k | i = GET_IW_T3X1_B3 (opcode); |
541 | 8.92k | break; |
542 | 2.79k | case iw_T2X3_type: |
543 | 2.79k | i = GET_IW_T2X3_B3 (opcode); |
544 | 2.79k | break; |
545 | 0 | default: |
546 | 0 | bad_opcode (op); |
547 | 47.9k | } |
548 | 47.9k | i = nios2_r2_reg3_mappings[i]; |
549 | 47.9k | (*info->fprintf_func) (info->stream, "%s", nios2_regs[i].name); |
550 | 47.9k | break; |
551 | | |
552 | 127k | case 'i': |
553 | | /* 16-bit signed immediate. */ |
554 | 127k | switch (op->format) |
555 | 127k | { |
556 | 13.4k | case iw_i_type: |
557 | 13.4k | s = ((int32_t) ((GET_IW_I_IMM16 (opcode) & 0xffff) ^ 0x8000) |
558 | 13.4k | - 0x8000); |
559 | 13.4k | break; |
560 | 113k | case iw_F2I16_type: |
561 | 113k | s = ((int32_t) ((GET_IW_F2I16_IMM16 (opcode) & 0xffff) ^ 0x8000) |
562 | 113k | - 0x8000); |
563 | 113k | break; |
564 | 0 | default: |
565 | 0 | bad_opcode (op); |
566 | 127k | } |
567 | 127k | (*info->fprintf_func) (info->stream, "%ld", s); |
568 | 127k | break; |
569 | | |
570 | 3.89k | case 'I': |
571 | | /* 12-bit signed immediate. */ |
572 | 3.89k | switch (op->format) |
573 | 3.89k | { |
574 | 3.87k | case iw_F2X4I12_type: |
575 | 3.87k | s = ((int32_t) ((GET_IW_F2X4I12_IMM12 (opcode) & 0xfff) ^ 0x800) |
576 | 3.87k | - 0x800); |
577 | 3.87k | break; |
578 | 16 | case iw_F1X4I12_type: |
579 | 16 | s = ((int32_t) ((GET_IW_F1X4I12_IMM12 (opcode) & 0xfff) ^ 0x800) |
580 | 16 | - 0x800); |
581 | 16 | break; |
582 | 0 | default: |
583 | 0 | bad_opcode (op); |
584 | 3.89k | } |
585 | 3.89k | (*info->fprintf_func) (info->stream, "%ld", s); |
586 | 3.89k | break; |
587 | | |
588 | 66.8k | case 'u': |
589 | | /* 16-bit unsigned immediate. */ |
590 | 66.8k | switch (op->format) |
591 | 66.8k | { |
592 | 4.22k | case iw_i_type: |
593 | 4.22k | i = GET_IW_I_IMM16 (opcode); |
594 | 4.22k | break; |
595 | 62.6k | case iw_F2I16_type: |
596 | 62.6k | i = GET_IW_F2I16_IMM16 (opcode); |
597 | 62.6k | break; |
598 | 0 | default: |
599 | 0 | bad_opcode (op); |
600 | 66.8k | } |
601 | 66.8k | (*info->fprintf_func) (info->stream, "%ld", i); |
602 | 66.8k | break; |
603 | | |
604 | 10.4k | case 'U': |
605 | | /* 7-bit unsigned immediate with 2-bit shift. */ |
606 | 10.4k | switch (op->format) |
607 | 10.4k | { |
608 | 5.46k | case iw_T1I7_type: |
609 | 5.46k | i = GET_IW_T1I7_IMM7 (opcode) << 2; |
610 | 5.46k | break; |
611 | 5.03k | case iw_X1I7_type: |
612 | 5.03k | i = GET_IW_X1I7_IMM7 (opcode) << 2; |
613 | 5.03k | break; |
614 | 0 | default: |
615 | 0 | bad_opcode (op); |
616 | 10.4k | } |
617 | 10.4k | (*info->fprintf_func) (info->stream, "%ld", i); |
618 | 10.4k | break; |
619 | | |
620 | 24.8k | case 'V': |
621 | | /* 5-bit unsigned immediate with 2-bit shift. */ |
622 | 24.8k | switch (op->format) |
623 | 24.8k | { |
624 | 24.8k | case iw_F1I5_type: |
625 | 24.8k | i = GET_IW_F1I5_IMM5 (opcode) << 2; |
626 | 24.8k | break; |
627 | 0 | default: |
628 | 0 | bad_opcode (op); |
629 | 24.8k | } |
630 | 24.8k | (*info->fprintf_func) (info->stream, "%ld", i); |
631 | 24.8k | break; |
632 | | |
633 | 13.6k | case 'W': |
634 | | /* 4-bit unsigned immediate with 2-bit shift. */ |
635 | 13.6k | switch (op->format) |
636 | 13.6k | { |
637 | 8.89k | case iw_T2I4_type: |
638 | 8.89k | i = GET_IW_T2I4_IMM4 (opcode) << 2; |
639 | 8.89k | break; |
640 | 4.76k | case iw_L5I4X1_type: |
641 | 4.76k | i = GET_IW_L5I4X1_IMM4 (opcode) << 2; |
642 | 4.76k | break; |
643 | 0 | default: |
644 | 0 | bad_opcode (op); |
645 | 13.6k | } |
646 | 13.6k | (*info->fprintf_func) (info->stream, "%ld", i); |
647 | 13.6k | break; |
648 | | |
649 | 10.0k | case 'X': |
650 | | /* 4-bit unsigned immediate with 1-bit shift. */ |
651 | 10.0k | switch (op->format) |
652 | 10.0k | { |
653 | 10.0k | case iw_T2I4_type: |
654 | 10.0k | i = GET_IW_T2I4_IMM4 (opcode) << 1; |
655 | 10.0k | break; |
656 | 0 | default: |
657 | 0 | bad_opcode (op); |
658 | 10.0k | } |
659 | 10.0k | (*info->fprintf_func) (info->stream, "%ld", i); |
660 | 10.0k | break; |
661 | | |
662 | 11.5k | case 'Y': |
663 | | /* 4-bit unsigned immediate without shift. */ |
664 | 11.5k | switch (op->format) |
665 | 11.5k | { |
666 | 11.5k | case iw_T2I4_type: |
667 | 11.5k | i = GET_IW_T2I4_IMM4 (opcode); |
668 | 11.5k | break; |
669 | 0 | default: |
670 | 0 | bad_opcode (op); |
671 | 11.5k | } |
672 | 11.5k | (*info->fprintf_func) (info->stream, "%ld", i); |
673 | 11.5k | break; |
674 | | |
675 | 34.1k | case 'o': |
676 | | /* 16-bit signed immediate address offset. */ |
677 | 34.1k | switch (op->format) |
678 | 34.1k | { |
679 | 2.89k | case iw_i_type: |
680 | 2.89k | o = ((GET_IW_I_IMM16 (opcode) & 0xffff) ^ 0x8000) - 0x8000; |
681 | 2.89k | break; |
682 | 31.2k | case iw_F2I16_type: |
683 | 31.2k | o = ((GET_IW_F2I16_IMM16 (opcode) & 0xffff) ^ 0x8000) - 0x8000; |
684 | 31.2k | break; |
685 | 0 | default: |
686 | 0 | bad_opcode (op); |
687 | 34.1k | } |
688 | 34.1k | address = address + 4 + o; |
689 | 34.1k | (*info->print_address_func) (address, info); |
690 | 34.1k | break; |
691 | | |
692 | 6.74k | case 'O': |
693 | | /* 10-bit signed address offset with 1-bit shift. */ |
694 | 6.74k | switch (op->format) |
695 | 6.74k | { |
696 | 6.74k | case iw_I10_type: |
697 | 6.74k | o = (((GET_IW_I10_IMM10 (opcode) & 0x3ff) ^ 0x200) - 0x200) * 2; |
698 | 6.74k | break; |
699 | 0 | default: |
700 | 0 | bad_opcode (op); |
701 | 6.74k | } |
702 | 6.74k | address = address + 2 + o; |
703 | 6.74k | (*info->print_address_func) (address, info); |
704 | 6.74k | break; |
705 | | |
706 | 10.4k | case 'P': |
707 | | /* 7-bit signed address offset with 1-bit shift. */ |
708 | 10.4k | switch (op->format) |
709 | 10.4k | { |
710 | 10.4k | case iw_T1I7_type: |
711 | 10.4k | o = (((GET_IW_T1I7_IMM7 (opcode) & 0x7f) ^ 0x40) - 0x40) * 2; |
712 | 10.4k | break; |
713 | 0 | default: |
714 | 0 | bad_opcode (op); |
715 | 10.4k | } |
716 | 10.4k | address = address + 2 + o; |
717 | 10.4k | (*info->print_address_func) (address, info); |
718 | 10.4k | break; |
719 | | |
720 | 1.42k | case 'j': |
721 | | /* 5-bit unsigned immediate. */ |
722 | 1.42k | switch (op->format) |
723 | 1.42k | { |
724 | 3 | case iw_r_type: |
725 | 3 | i = GET_IW_R_IMM5 (opcode); |
726 | 3 | break; |
727 | 147 | case iw_F3X6L5_type: |
728 | 147 | i = GET_IW_F3X6L5_IMM5 (opcode); |
729 | 147 | break; |
730 | 242 | case iw_F2X6L10_type: |
731 | 242 | i = GET_IW_F2X6L10_MSB (opcode); |
732 | 242 | break; |
733 | 1.03k | case iw_X2L5_type: |
734 | 1.03k | i = GET_IW_X2L5_IMM5 (opcode); |
735 | 1.03k | break; |
736 | 0 | default: |
737 | 0 | bad_opcode (op); |
738 | 1.42k | } |
739 | 1.42k | (*info->fprintf_func) (info->stream, "%ld", i); |
740 | 1.42k | break; |
741 | | |
742 | 242 | case 'k': |
743 | | /* Second 5-bit unsigned immediate field. */ |
744 | 242 | switch (op->format) |
745 | 242 | { |
746 | 242 | case iw_F2X6L10_type: |
747 | 242 | i = GET_IW_F2X6L10_LSB (opcode); |
748 | 242 | break; |
749 | 0 | default: |
750 | 0 | bad_opcode (op); |
751 | 242 | } |
752 | 242 | (*info->fprintf_func) (info->stream, "%ld", i); |
753 | 242 | break; |
754 | | |
755 | 11.2k | case 'l': |
756 | | /* 8-bit unsigned immediate. */ |
757 | 11.2k | switch (op->format) |
758 | 11.2k | { |
759 | 1.26k | case iw_custom_type: |
760 | 1.26k | i = GET_IW_CUSTOM_N (opcode); |
761 | 1.26k | break; |
762 | 9.99k | case iw_F3X8_type: |
763 | 9.99k | i = GET_IW_F3X8_N (opcode); |
764 | 9.99k | break; |
765 | 0 | default: |
766 | 0 | bad_opcode (op); |
767 | 11.2k | } |
768 | 11.2k | (*info->fprintf_func) (info->stream, "%lu", i); |
769 | 11.2k | break; |
770 | | |
771 | 113k | case 'm': |
772 | | /* 26-bit unsigned immediate. */ |
773 | 113k | switch (op->format) |
774 | 113k | { |
775 | 9.89k | case iw_j_type: |
776 | 9.89k | i = GET_IW_J_IMM26 (opcode); |
777 | 9.89k | break; |
778 | 103k | case iw_L26_type: |
779 | 103k | i = GET_IW_L26_IMM26 (opcode); |
780 | 103k | break; |
781 | 0 | default: |
782 | 0 | bad_opcode (op); |
783 | 113k | } |
784 | | /* This translates to an address because it's only used in call |
785 | | instructions. */ |
786 | 113k | address = (address & 0xf0000000) | (i << 2); |
787 | 113k | (*info->print_address_func) (address, info); |
788 | 113k | break; |
789 | | |
790 | 4.37k | case 'e': |
791 | | /* Encoded enumeration for addi.n/subi.n. */ |
792 | 4.37k | switch (op->format) |
793 | 4.37k | { |
794 | 4.37k | case iw_T2X1I3_type: |
795 | 4.37k | i = nios2_r2_asi_n_mappings[GET_IW_T2X1I3_IMM3 (opcode)]; |
796 | 4.37k | break; |
797 | 0 | default: |
798 | 0 | bad_opcode (op); |
799 | 4.37k | } |
800 | 4.37k | (*info->fprintf_func) (info->stream, "%lu", i); |
801 | 4.37k | break; |
802 | | |
803 | 4.58k | case 'f': |
804 | | /* Encoded enumeration for slli.n/srli.n. */ |
805 | 4.58k | switch (op->format) |
806 | 4.58k | { |
807 | 4.58k | case iw_T2X1L3_type: |
808 | 4.58k | i = nios2_r2_shi_n_mappings[GET_IW_T2X1I3_IMM3 (opcode)]; |
809 | 4.58k | break; |
810 | 0 | default: |
811 | 0 | bad_opcode (op); |
812 | 4.58k | } |
813 | 4.58k | (*info->fprintf_func) (info->stream, "%lu", i); |
814 | 4.58k | break; |
815 | | |
816 | 5.78k | case 'g': |
817 | | /* Encoded enumeration for andi.n. */ |
818 | 5.78k | switch (op->format) |
819 | 5.78k | { |
820 | 5.78k | case iw_T2I4_type: |
821 | 5.78k | i = nios2_r2_andi_n_mappings[GET_IW_T2I4_IMM4 (opcode)]; |
822 | 5.78k | break; |
823 | 0 | default: |
824 | 0 | bad_opcode (op); |
825 | 5.78k | } |
826 | 5.78k | (*info->fprintf_func) (info->stream, "%lu", i); |
827 | 5.78k | break; |
828 | | |
829 | 7.36k | case 'h': |
830 | | /* Encoded enumeration for movi.n. */ |
831 | 7.36k | switch (op->format) |
832 | 7.36k | { |
833 | 7.36k | case iw_T1I7_type: |
834 | 7.36k | i = GET_IW_T1I7_IMM7 (opcode); |
835 | 7.36k | if (i == 125) |
836 | 51 | i = 0xff; |
837 | 7.31k | else if (i == 126) |
838 | 63 | i = -2; |
839 | 7.25k | else if (i == 127) |
840 | 18 | i = -1; |
841 | 7.36k | break; |
842 | 0 | default: |
843 | 0 | bad_opcode (op); |
844 | 7.36k | } |
845 | 7.36k | (*info->fprintf_func) (info->stream, "%ld", i); |
846 | 7.36k | break; |
847 | | |
848 | 5.53k | case 'R': |
849 | 5.53k | { |
850 | 5.53k | unsigned long reglist = 0; |
851 | 5.53k | int dir = 1; |
852 | 5.53k | int k, t; |
853 | | |
854 | 5.53k | switch (op->format) |
855 | 5.53k | { |
856 | 770 | case iw_F1X4L17_type: |
857 | | /* Encoding for ldwm/stwm. */ |
858 | 770 | i = GET_IW_F1X4L17_REGMASK (opcode); |
859 | 770 | if (GET_IW_F1X4L17_RS (opcode)) |
860 | 391 | { |
861 | 391 | reglist = ((i << 14) & 0x00ffc000); |
862 | 391 | if (i & (1 << 10)) |
863 | 145 | reglist |= (1 << 28); |
864 | 391 | if (i & (1 << 11)) |
865 | 202 | reglist |= (1u << 31); |
866 | 391 | } |
867 | 379 | else |
868 | 379 | reglist = i << 2; |
869 | 770 | dir = GET_IW_F1X4L17_REGMASK (opcode) ? 1 : -1; |
870 | 770 | break; |
871 | | |
872 | 4.76k | case iw_L5I4X1_type: |
873 | | /* Encoding for push.n/pop.n. */ |
874 | 4.76k | reglist |= (1u << 31); |
875 | 4.76k | if (GET_IW_L5I4X1_FP (opcode)) |
876 | 2.67k | reglist |= (1 << 28); |
877 | 4.76k | if (GET_IW_L5I4X1_CS (opcode)) |
878 | 2.39k | { |
879 | 2.39k | int val = GET_IW_L5I4X1_REGRANGE (opcode); |
880 | 2.39k | reglist |= nios2_r2_reg_range_mappings[val]; |
881 | 2.39k | } |
882 | 4.76k | dir = (op->match == MATCH_R2_POP_N ? 1 : -1); |
883 | 4.76k | break; |
884 | | |
885 | 0 | default: |
886 | 0 | bad_opcode (op); |
887 | 5.53k | } |
888 | | |
889 | 5.53k | t = 0; |
890 | 5.53k | (*info->fprintf_func) (info->stream, "{"); |
891 | 5.53k | for (k = (dir == 1 ? 0 : 31); |
892 | 182k | (dir == 1 && k < 32) || (dir == -1 && k >= 0); |
893 | 177k | k += dir) |
894 | 177k | if (reglist & (1u << k)) |
895 | 23.1k | { |
896 | 23.1k | if (t) |
897 | 17.6k | (*info->fprintf_func) (info->stream, ","); |
898 | 5.53k | else |
899 | 5.53k | t++; |
900 | 23.1k | (*info->fprintf_func) (info->stream, "%s", nios2_regs[k].name); |
901 | 23.1k | } |
902 | 5.53k | (*info->fprintf_func) (info->stream, "}"); |
903 | 5.53k | break; |
904 | 5.53k | } |
905 | | |
906 | 770 | case 'B': |
907 | | /* Base register and options for ldwm/stwm. */ |
908 | 770 | switch (op->format) |
909 | 770 | { |
910 | 770 | case iw_F1X4L17_type: |
911 | 770 | if (GET_IW_F1X4L17_ID (opcode) == 0) |
912 | 409 | (*info->fprintf_func) (info->stream, "--"); |
913 | | |
914 | 770 | i = GET_IW_F1X4I12_A (opcode); |
915 | 770 | (*info->fprintf_func) (info->stream, "(%s)", |
916 | 770 | nios2_builtin_regs[i].name); |
917 | | |
918 | 770 | if (GET_IW_F1X4L17_ID (opcode)) |
919 | 361 | (*info->fprintf_func) (info->stream, "++"); |
920 | 770 | if (GET_IW_F1X4L17_WB (opcode)) |
921 | 423 | (*info->fprintf_func) (info->stream, ",writeback"); |
922 | 770 | if (GET_IW_F1X4L17_PC (opcode)) |
923 | 425 | (*info->fprintf_func) (info->stream, ",ret"); |
924 | 770 | break; |
925 | 0 | default: |
926 | 0 | bad_opcode (op); |
927 | 770 | } |
928 | 770 | break; |
929 | | |
930 | 770 | default: |
931 | 0 | (*info->fprintf_func) (info->stream, "unknown"); |
932 | 0 | break; |
933 | 2.00M | } |
934 | 2.00M | return 0; |
935 | 2.00M | } |
936 | | |
937 | | /* nios2_disassemble does all the work of disassembling a Nios II |
938 | | instruction opcode. */ |
939 | | static int |
940 | | nios2_disassemble (bfd_vma address, unsigned long opcode, |
941 | | disassemble_info *info) |
942 | 556k | { |
943 | 556k | const struct nios2_opcode *op; |
944 | | |
945 | 556k | info->bytes_per_line = INSNLEN; |
946 | 556k | info->bytes_per_chunk = INSNLEN; |
947 | 556k | info->display_endian = info->endian; |
948 | 556k | info->insn_info_valid = 1; |
949 | 556k | info->branch_delay_insns = 0; |
950 | 556k | info->data_size = 0; |
951 | 556k | info->insn_type = dis_nonbranch; |
952 | 556k | info->target = 0; |
953 | 556k | info->target2 = 0; |
954 | | |
955 | | /* Find the major opcode and use this to disassemble |
956 | | the instruction and its arguments. */ |
957 | 556k | op = nios2_find_opcode_hash (opcode, info->mach); |
958 | | |
959 | 556k | if (op != NULL) |
960 | 491k | { |
961 | 491k | const char *argstr = op->args; |
962 | 491k | (*info->fprintf_func) (info->stream, "%s", op->name); |
963 | 491k | if (argstr != NULL && *argstr != '\0') |
964 | 491k | { |
965 | 491k | (*info->fprintf_func) (info->stream, "\t"); |
966 | 2.49M | while (*argstr != '\0') |
967 | 2.00M | { |
968 | 2.00M | nios2_print_insn_arg (argstr, opcode, address, info, op); |
969 | 2.00M | ++argstr; |
970 | 2.00M | } |
971 | 491k | } |
972 | | /* Tell the caller how far to advance the program counter. */ |
973 | 491k | info->bytes_per_chunk = op->size; |
974 | 491k | return op->size; |
975 | 491k | } |
976 | 65.4k | else |
977 | 65.4k | { |
978 | | /* Handle undefined instructions. */ |
979 | 65.4k | info->insn_type = dis_noninsn; |
980 | 65.4k | (*info->fprintf_func) (info->stream, "0x%lx", opcode); |
981 | 65.4k | return INSNLEN; |
982 | 65.4k | } |
983 | 556k | } |
984 | | |
985 | | |
986 | | /* print_insn_nios2 is the main disassemble function for Nios II. |
987 | | The function diassembler(abfd) (source in disassemble.c) returns a |
988 | | pointer to this either print_insn_big_nios2 or |
989 | | print_insn_little_nios2, which in turn call this function when the |
990 | | bfd machine type is Nios II. print_insn_nios2 reads the |
991 | | instruction word at the address given, and prints the disassembled |
992 | | instruction on the stream info->stream using info->fprintf_func. */ |
993 | | |
994 | | static int |
995 | | print_insn_nios2 (bfd_vma address, disassemble_info *info, |
996 | | enum bfd_endian endianness) |
997 | 556k | { |
998 | 556k | bfd_byte buffer[INSNLEN]; |
999 | 556k | int status; |
1000 | | |
1001 | 556k | status = (*info->read_memory_func) (address, buffer, INSNLEN, info); |
1002 | 556k | if (status == 0) |
1003 | 556k | { |
1004 | 556k | unsigned long insn; |
1005 | 556k | if (endianness == BFD_ENDIAN_BIG) |
1006 | 515k | insn = (unsigned long) bfd_getb32 (buffer); |
1007 | 40.4k | else |
1008 | 40.4k | insn = (unsigned long) bfd_getl32 (buffer); |
1009 | 556k | return nios2_disassemble (address, insn, info); |
1010 | 556k | } |
1011 | | |
1012 | | /* We might have a 16-bit R2 instruction at the end of memory. Try that. */ |
1013 | 427 | if (info->mach == bfd_mach_nios2r2) |
1014 | 359 | { |
1015 | 359 | status = (*info->read_memory_func) (address, buffer, 2, info); |
1016 | 359 | if (status == 0) |
1017 | 284 | { |
1018 | 284 | unsigned long insn; |
1019 | 284 | if (endianness == BFD_ENDIAN_BIG) |
1020 | 281 | insn = (unsigned long) bfd_getb16 (buffer); |
1021 | 3 | else |
1022 | 3 | insn = (unsigned long) bfd_getl16 (buffer); |
1023 | 284 | return nios2_disassemble (address, insn, info); |
1024 | 284 | } |
1025 | 359 | } |
1026 | | |
1027 | | /* If we got here, we couldn't read anything. */ |
1028 | 143 | (*info->memory_error_func) (status, address, info); |
1029 | 143 | return -1; |
1030 | 427 | } |
1031 | | |
1032 | | /* These two functions are the main entry points, accessed from |
1033 | | disassemble.c. */ |
1034 | | int |
1035 | | print_insn_big_nios2 (bfd_vma address, disassemble_info *info) |
1036 | 516k | { |
1037 | 516k | return print_insn_nios2 (address, info, BFD_ENDIAN_BIG); |
1038 | 516k | } |
1039 | | |
1040 | | int |
1041 | | print_insn_little_nios2 (bfd_vma address, disassemble_info *info) |
1042 | 40.4k | { |
1043 | 40.4k | return print_insn_nios2 (address, info, BFD_ENDIAN_LITTLE); |
1044 | 40.4k | } |