96fd092e8db2acbc6dec0f4abb1ff2d725735731
[deliverable/binutils-gdb.git] / opcodes / arc-dis.c
1 /* Instruction printing code for the ARC.
2 Copyright (C) 1994-2016 Free Software Foundation, Inc.
3
4 Contributed by Claudiu Zissulescu (claziss@synopsys.com)
5
6 This file is part of libopcodes.
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 program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21 MA 02110-1301, USA. */
22
23 #include "sysdep.h"
24 #include <stdio.h>
25 #include <assert.h>
26 #include "dis-asm.h"
27 #include "opcode/arc.h"
28 #include "arc-dis.h"
29 #include "arc-ext.h"
30
31
32 /* Globals variables. */
33
34 static const char * const regnames[64] =
35 {
36 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
37 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
38 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
39 "r24", "r25", "gp", "fp", "sp", "ilink", "r30", "blink",
40
41 "r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39",
42 "r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47",
43 "r48", "r49", "r50", "r51", "r52", "r53", "r54", "r55",
44 "r56", "r57", "ACCL", "ACCH", "lp_count", "rezerved", "LIMM", "pcl"
45 };
46
47 /* Macros section. */
48
49 #ifdef DEBUG
50 # define pr_debug(fmt, args...) fprintf (stderr, fmt, ##args)
51 #else
52 # define pr_debug(fmt, args...)
53 #endif
54
55 #define ARRANGE_ENDIAN(info, buf) \
56 (info->endian == BFD_ENDIAN_LITTLE ? bfd_getm32 (bfd_getl32 (buf)) \
57 : bfd_getb32 (buf))
58
59 #define BITS(word,s,e) (((word) << (sizeof (word) * 8 - 1 - e)) >> \
60 (s + (sizeof (word) * 8 - 1 - e)))
61 #define OPCODE(word) (BITS ((word), 27, 31))
62
63 #define OPCODE_AC(word) (BITS ((word), 11, 15))
64
65 /* Functions implementation. */
66
67 static bfd_vma
68 bfd_getm32 (unsigned int data)
69 {
70 bfd_vma value = 0;
71
72 value = ((data & 0xff00) | (data & 0xff)) << 16;
73 value |= ((data & 0xff0000) | (data & 0xff000000)) >> 16;
74 return value;
75 }
76
77 static int
78 special_flag_p (const char *opname,
79 const char *flgname)
80 {
81 const struct arc_flag_special *flg_spec;
82 unsigned i, j, flgidx;
83
84 for (i = 0; i < arc_num_flag_special; i++)
85 {
86 flg_spec = &arc_flag_special_cases[i];
87
88 if (strcmp (opname, flg_spec->name))
89 continue;
90
91 /* Found potential special case instruction. */
92 for (j=0;; ++j)
93 {
94 flgidx = flg_spec->flags[j];
95 if (flgidx == 0)
96 break; /* End of the array. */
97
98 if (strcmp (flgname, arc_flag_operands[flgidx].name) == 0)
99 return 1;
100 }
101 }
102 return 0;
103 }
104
105 /* Find proper format for the given opcode. */
106 static const struct arc_opcode *
107 find_format (const struct arc_opcode *arc_table,
108 unsigned *insn, unsigned int insnLen,
109 unsigned isa_mask)
110 {
111 unsigned int i = 0;
112 const struct arc_opcode *opcode = NULL;
113 const unsigned char *opidx;
114 const unsigned char *flgidx;
115
116 do {
117 bfd_boolean invalid = FALSE;
118
119 opcode = &arc_table[i++];
120
121 if (ARC_SHORT (opcode->mask) && (insnLen == 2))
122 {
123 if (OPCODE_AC (opcode->opcode) != OPCODE_AC (insn[0]))
124 continue;
125 }
126 else if (!ARC_SHORT (opcode->mask) && (insnLen == 4))
127 {
128 if (OPCODE (opcode->opcode) != OPCODE (insn[0]))
129 continue;
130 }
131 else
132 continue;
133
134 if ((insn[0] ^ opcode->opcode) & opcode->mask)
135 continue;
136
137 if (!(opcode->cpu & isa_mask))
138 continue;
139
140 /* Possible candidate, check the operands. */
141 for (opidx = opcode->operands; *opidx; opidx++)
142 {
143 int value;
144 const struct arc_operand *operand = &arc_operands[*opidx];
145
146 if (operand->flags & ARC_OPERAND_FAKE)
147 continue;
148
149 if (operand->extract)
150 value = (*operand->extract) (insn[0], &invalid);
151 else
152 value = (insn[0] >> operand->shift) & ((1 << operand->bits) - 1);
153
154 /* Check for LIMM indicator. If it is there, then make sure
155 we pick the right format. */
156 if (operand->flags & ARC_OPERAND_IR
157 && !(operand->flags & ARC_OPERAND_LIMM))
158 {
159 if ((value == 0x3E && insnLen == 4)
160 || (value == 0x1E && insnLen == 2))
161 {
162 invalid = TRUE;
163 break;
164 }
165 }
166 }
167
168 /* Check the flags. */
169 for (flgidx = opcode->flags; *flgidx; flgidx++)
170 {
171 /* Get a valid flag class. */
172 const struct arc_flag_class *cl_flags = &arc_flag_classes[*flgidx];
173 const unsigned *flgopridx;
174 int foundA = 0, foundB = 0;
175 unsigned int value;
176
177 /* Check first the extensions. */
178 if (cl_flags->flag_class & F_CLASS_EXTEND)
179 {
180 value = (insn[0] & 0x1F);
181 if (arcExtMap_condCodeName (value))
182 continue;
183 }
184 for (flgopridx = cl_flags->flags; *flgopridx; ++flgopridx)
185 {
186 const struct arc_flag_operand *flg_operand =
187 &arc_flag_operands[*flgopridx];
188
189 value = (insn[0] >> flg_operand->shift)
190 & ((1 << flg_operand->bits) - 1);
191 if (value == flg_operand->code)
192 foundA = 1;
193 if (value)
194 foundB = 1;
195 }
196 if (!foundA && foundB)
197 {
198 invalid = TRUE;
199 break;
200 }
201 }
202
203 if (invalid)
204 continue;
205
206 /* The instruction is valid. */
207 return opcode;
208 } while (opcode->mask);
209
210 return NULL;
211 }
212
213 static void
214 print_flags (const struct arc_opcode *opcode,
215 unsigned *insn,
216 struct disassemble_info *info)
217 {
218 const unsigned char *flgidx;
219 unsigned int value;
220
221 /* Now extract and print the flags. */
222 for (flgidx = opcode->flags; *flgidx; flgidx++)
223 {
224 /* Get a valid flag class. */
225 const struct arc_flag_class *cl_flags = &arc_flag_classes[*flgidx];
226 const unsigned *flgopridx;
227
228 /* Check first the extensions. */
229 if (cl_flags->flag_class & F_CLASS_EXTEND)
230 {
231 const char *name;
232 value = (insn[0] & 0x1F);
233
234 name = arcExtMap_condCodeName (value);
235 if (name)
236 {
237 (*info->fprintf_func) (info->stream, ".%s", name);
238 continue;
239 }
240 }
241
242 for (flgopridx = cl_flags->flags; *flgopridx; ++flgopridx)
243 {
244 const struct arc_flag_operand *flg_operand =
245 &arc_flag_operands[*flgopridx];
246
247 if (!flg_operand->favail)
248 continue;
249
250 value = (insn[0] >> flg_operand->shift)
251 & ((1 << flg_operand->bits) - 1);
252 if (value == flg_operand->code)
253 {
254 /* FIXME!: print correctly nt/t flag. */
255 if (!special_flag_p (opcode->name, flg_operand->name))
256 (*info->fprintf_func) (info->stream, ".");
257 else if (info->insn_type == dis_dref)
258 {
259 switch (flg_operand->name[0])
260 {
261 case 'b':
262 info->data_size = 1;
263 break;
264 case 'h':
265 case 'w':
266 info->data_size = 2;
267 break;
268 default:
269 info->data_size = 4;
270 break;
271 }
272 }
273 (*info->fprintf_func) (info->stream, "%s", flg_operand->name);
274 }
275
276 if (flg_operand->name[0] == 'd'
277 && flg_operand->name[1] == 0)
278 info->branch_delay_insns = 1;
279 }
280 }
281 }
282
283 static const char *
284 get_auxreg (const struct arc_opcode *opcode,
285 int value,
286 unsigned isa_mask)
287 {
288 const char *name;
289 unsigned int i;
290 const struct arc_aux_reg *auxr = &arc_aux_regs[0];
291
292 if (opcode->insn_class != AUXREG)
293 return NULL;
294
295 name = arcExtMap_auxRegName (value);
296 if (name)
297 return name;
298
299 for (i = 0; i < arc_num_aux_regs; i++, auxr++)
300 {
301 if (!(auxr->cpu & isa_mask))
302 continue;
303
304 if (auxr->subclass != NONE)
305 return NULL;
306
307 if (auxr->address == value)
308 return auxr->name;
309 }
310 return NULL;
311 }
312
313 /* Calculate the instruction length for an instruction starting with MSB
314 and LSB, the most and least significant byte. The ISA_MASK is used to
315 filter the instructions considered to only those that are part of the
316 current architecture.
317
318 The instruction lengths are calculated from the ARC_OPCODE table, and
319 cached for later use. */
320
321 static unsigned int
322 arc_insn_length (bfd_byte msb, struct disassemble_info *info)
323 {
324 bfd_byte major_opcode = msb >> 3;
325
326 switch (info->mach)
327 {
328 case bfd_mach_arc_nps400:
329 case bfd_mach_arc_arc700:
330 case bfd_mach_arc_arc600:
331 return (major_opcode > 0xb) ? 2 : 4;
332 break;
333
334 case bfd_mach_arc_arcv2:
335 return (major_opcode > 0x7) ? 2 : 4;
336 break;
337
338 default:
339 abort ();
340 }
341 }
342
343 /* Disassemble ARC instructions. */
344
345 static int
346 print_insn_arc (bfd_vma memaddr,
347 struct disassemble_info *info)
348 {
349 bfd_byte buffer[4];
350 unsigned int lowbyte, highbyte;
351 int status;
352 unsigned int insnLen;
353 unsigned insn[2] = { 0, 0 };
354 unsigned isa_mask;
355 const unsigned char *opidx;
356 const struct arc_opcode *opcode;
357 const extInstruction_t *einsn;
358 bfd_boolean need_comma;
359 bfd_boolean open_braket;
360 int size;
361
362 lowbyte = ((info->endian == BFD_ENDIAN_LITTLE) ? 1 : 0);
363 highbyte = ((info->endian == BFD_ENDIAN_LITTLE) ? 0 : 1);
364
365 switch (info->mach)
366 {
367 case bfd_mach_arc_nps400:
368 isa_mask = ARC_OPCODE_ARC700 | ARC_OPCODE_NPS400;
369 break;
370
371 case bfd_mach_arc_arc700:
372 isa_mask = ARC_OPCODE_ARC700;
373 break;
374
375 case bfd_mach_arc_arc600:
376 isa_mask = ARC_OPCODE_ARC600;
377 break;
378
379 case bfd_mach_arc_arcv2:
380 default:
381 isa_mask = ARC_OPCODE_ARCv2HS | ARC_OPCODE_ARCv2EM;
382 break;
383 }
384
385 /* This variable may be set by the instruction decoder. It suggests
386 the number of bytes objdump should display on a single line. If
387 the instruction decoder sets this, it should always set it to
388 the same value in order to get reasonable looking output. */
389
390 info->bytes_per_line = 8;
391
392 /* In the next lines, we set two info variables control the way
393 objdump displays the raw data. For example, if bytes_per_line is
394 8 and bytes_per_chunk is 4, the output will look like this:
395 00: 00000000 00000000
396 with the chunks displayed according to "display_endian". */
397
398 if (info->section
399 && !(info->section->flags & SEC_CODE))
400 {
401 /* This is not a CODE section. */
402 switch (info->section->size)
403 {
404 case 1:
405 case 2:
406 case 4:
407 size = info->section->size;
408 break;
409 default:
410 size = (info->section->size & 0x01) ? 1 : 4;
411 break;
412 }
413 info->bytes_per_chunk = 1;
414 info->display_endian = info->endian;
415 }
416 else
417 {
418 size = 2;
419 info->bytes_per_chunk = 2;
420 info->display_endian = info->endian;
421 }
422
423 /* Read the insn into a host word. */
424 status = (*info->read_memory_func) (memaddr, buffer, size, info);
425 if (status != 0)
426 {
427 (*info->memory_error_func) (status, memaddr, info);
428 return -1;
429 }
430
431 if (info->section
432 && !(info->section->flags & SEC_CODE))
433 {
434 /* Data section. */
435 unsigned long data;
436
437 data = bfd_get_bits (buffer, size * 8,
438 info->display_endian == BFD_ENDIAN_BIG);
439 switch (size)
440 {
441 case 1:
442 (*info->fprintf_func) (info->stream, ".byte\t0x%02lx", data);
443 break;
444 case 2:
445 (*info->fprintf_func) (info->stream, ".short\t0x%04lx", data);
446 break;
447 case 4:
448 (*info->fprintf_func) (info->stream, ".word\t0x%08lx", data);
449 break;
450 default:
451 abort ();
452 }
453 return size;
454 }
455
456 insnLen = arc_insn_length (buffer[lowbyte], info);
457 switch (insnLen)
458 {
459 case 2:
460 insn[0] = (buffer[lowbyte] << 8) | buffer[highbyte];
461 break;
462
463 default:
464 /* An unknown instruction is treated as being length 4. This is
465 possibly not the best solution, but matches the behaviour that was
466 in place before the table based instruction length look-up was
467 introduced. */
468 case 4:
469 /* This is a long instruction: Read the remaning 2 bytes. */
470 status = (*info->read_memory_func) (memaddr + 2, &buffer[2], 2, info);
471 if (status != 0)
472 {
473 (*info->memory_error_func) (status, memaddr + 2, info);
474 return -1;
475 }
476 insn[0] = ARRANGE_ENDIAN (info, buffer);
477 break;
478 }
479
480 /* Set some defaults for the insn info. */
481 info->insn_info_valid = 1;
482 info->branch_delay_insns = 0;
483 info->data_size = 0;
484 info->insn_type = dis_nonbranch;
485 info->target = 0;
486 info->target2 = 0;
487
488 /* FIXME to be moved in dissasemble_init_for_target. */
489 info->disassembler_needs_relocs = TRUE;
490
491 /* Find the first match in the opcode table. */
492 opcode = find_format (arc_opcodes, insn, insnLen, isa_mask);
493
494 if (!opcode)
495 {
496 /* No instruction found. Try the extensions. */
497 einsn = arcExtMap_insn (OPCODE (insn[0]), insn[0]);
498 if (einsn)
499 {
500 const char *errmsg = NULL;
501 opcode = arcExtMap_genOpcode (einsn, isa_mask, &errmsg);
502 if (opcode == NULL)
503 {
504 (*info->fprintf_func) (info->stream,
505 "An error occured while "
506 "generating the extension instruction "
507 "operations");
508 return -1;
509 }
510
511 opcode = find_format (opcode, insn, insnLen, isa_mask);
512 assert (opcode != NULL);
513 }
514 else
515 {
516 if (insnLen == 2)
517 (*info->fprintf_func) (info->stream, ".long %#04x", insn[0]);
518 else
519 (*info->fprintf_func) (info->stream, ".long %#08x", insn[0]);
520
521 info->insn_type = dis_noninsn;
522 return insnLen;
523 }
524 }
525
526 /* Print the mnemonic. */
527 (*info->fprintf_func) (info->stream, "%s", opcode->name);
528
529 /* Preselect the insn class. */
530 switch (opcode->insn_class)
531 {
532 case BRANCH:
533 case JUMP:
534 if (!strncmp (opcode->name, "bl", 2)
535 || !strncmp (opcode->name, "jl", 2))
536 info->insn_type = dis_jsr;
537 else
538 info->insn_type = dis_branch;
539 break;
540 case MEMORY:
541 info->insn_type = dis_dref; /* FIXME! DB indicates mov as memory! */
542 break;
543 default:
544 info->insn_type = dis_nonbranch;
545 break;
546 }
547
548 pr_debug ("%s: 0x%08x\n", opcode->name, opcode->opcode);
549
550 print_flags (opcode, insn, info);
551
552 if (opcode->operands[0] != 0)
553 (*info->fprintf_func) (info->stream, "\t");
554
555 need_comma = FALSE;
556 open_braket = FALSE;
557
558 /* Now extract and print the operands. */
559 for (opidx = opcode->operands; *opidx; opidx++)
560 {
561 const struct arc_operand *operand = &arc_operands[*opidx];
562 int value;
563
564 if (open_braket && (operand->flags & ARC_OPERAND_BRAKET))
565 {
566 (*info->fprintf_func) (info->stream, "]");
567 open_braket = FALSE;
568 continue;
569 }
570
571 /* Only take input from real operands. */
572 if ((operand->flags & ARC_OPERAND_FAKE)
573 && !(operand->flags & ARC_OPERAND_BRAKET))
574 continue;
575
576 if (operand->extract)
577 value = (*operand->extract) (insn[0], (int *) NULL);
578 else
579 {
580 if (operand->flags & ARC_OPERAND_ALIGNED32)
581 {
582 value = (insn[0] >> operand->shift)
583 & ((1 << (operand->bits - 2)) - 1);
584 value = value << 2;
585 }
586 else
587 {
588 value = (insn[0] >> operand->shift) & ((1 << operand->bits) - 1);
589 }
590 if (operand->flags & ARC_OPERAND_SIGNED)
591 {
592 int signbit = 1 << (operand->bits - 1);
593 value = (value ^ signbit) - signbit;
594 }
595 }
596
597 if (operand->flags & ARC_OPERAND_IGNORE
598 && (operand->flags & ARC_OPERAND_IR
599 && value == -1))
600 continue;
601
602 if (need_comma)
603 (*info->fprintf_func) (info->stream, ",");
604
605 if (!open_braket && (operand->flags & ARC_OPERAND_BRAKET))
606 {
607 (*info->fprintf_func) (info->stream, "[");
608 open_braket = TRUE;
609 need_comma = FALSE;
610 continue;
611 }
612
613 /* Read the limm operand, if required. */
614 if (operand->flags & ARC_OPERAND_LIMM
615 && !(operand->flags & ARC_OPERAND_DUPLICATE))
616 {
617 status = (*info->read_memory_func) (memaddr + insnLen, buffer,
618 4, info);
619 if (status != 0)
620 {
621 (*info->memory_error_func) (status, memaddr + insnLen, info);
622 return -1;
623 }
624 insn[1] = ARRANGE_ENDIAN (info, buffer);
625 }
626
627 /* Print the operand as directed by the flags. */
628 if (operand->flags & ARC_OPERAND_IR)
629 {
630 const char *rname;
631
632 assert (value >=0 && value < 64);
633 rname = arcExtMap_coreRegName (value);
634 if (!rname)
635 rname = regnames[value];
636 (*info->fprintf_func) (info->stream, "%s", rname);
637 if (operand->flags & ARC_OPERAND_TRUNCATE)
638 {
639 rname = arcExtMap_coreRegName (value + 1);
640 if (!rname)
641 rname = regnames[value + 1];
642 (*info->fprintf_func) (info->stream, "%s", rname);
643 }
644 }
645 else if (operand->flags & ARC_OPERAND_LIMM)
646 {
647 const char *rname = get_auxreg (opcode, insn[1], isa_mask);
648 if (rname && open_braket)
649 (*info->fprintf_func) (info->stream, "%s", rname);
650 else
651 {
652 (*info->fprintf_func) (info->stream, "%#x", insn[1]);
653 if (info->insn_type == dis_branch
654 || info->insn_type == dis_jsr)
655 info->target = (bfd_vma) insn[1];
656 }
657 }
658 else if (operand->flags & ARC_OPERAND_PCREL)
659 {
660 /* PCL relative. */
661 if (info->flags & INSN_HAS_RELOC)
662 memaddr = 0;
663 (*info->print_address_func) ((memaddr & ~3) + value, info);
664
665 info->target = (bfd_vma) (memaddr & ~3) + value;
666 }
667 else if (operand->flags & ARC_OPERAND_SIGNED)
668 {
669 const char *rname = get_auxreg (opcode, value, isa_mask);
670 if (rname && open_braket)
671 (*info->fprintf_func) (info->stream, "%s", rname);
672 else
673 (*info->fprintf_func) (info->stream, "%d", value);
674 }
675 else
676 {
677 if (operand->flags & ARC_OPERAND_TRUNCATE
678 && !(operand->flags & ARC_OPERAND_ALIGNED32)
679 && !(operand->flags & ARC_OPERAND_ALIGNED16)
680 && value > 0 && value <= 14)
681 (*info->fprintf_func) (info->stream, "r13-%s",
682 regnames[13 + value - 1]);
683 else
684 {
685 const char *rname = get_auxreg (opcode, value, isa_mask);
686 if (rname && open_braket)
687 (*info->fprintf_func) (info->stream, "%s", rname);
688 else
689 (*info->fprintf_func) (info->stream, "%#x", value);
690 }
691 }
692
693 need_comma = TRUE;
694
695 /* Adjust insn len. */
696 if (operand->flags & ARC_OPERAND_LIMM
697 && !(operand->flags & ARC_OPERAND_DUPLICATE))
698 insnLen += 4;
699 }
700
701 return insnLen;
702 }
703
704
705 disassembler_ftype
706 arc_get_disassembler (bfd *abfd)
707 {
708 /* Read the extenssion insns and registers, if any. */
709 build_ARC_extmap (abfd);
710 #ifdef DEBUG
711 dump_ARC_extmap ();
712 #endif
713
714 return print_insn_arc;
715 }
716
717 /* Disassemble ARC instructions. Used by debugger. */
718
719 struct arcDisState
720 arcAnalyzeInstr (bfd_vma memaddr,
721 struct disassemble_info *info)
722 {
723 struct arcDisState ret;
724 memset (&ret, 0, sizeof (struct arcDisState));
725
726 ret.instructionLen = print_insn_arc (memaddr, info);
727
728 #if 0
729 ret.words[0] = insn[0];
730 ret.words[1] = insn[1];
731 ret._this = &ret;
732 ret.coreRegName = _coreRegName;
733 ret.auxRegName = _auxRegName;
734 ret.condCodeName = _condCodeName;
735 ret.instName = _instName;
736 #endif
737
738 return ret;
739 }
740
741 /* Local variables:
742 eval: (c-set-style "gnu")
743 indent-tabs-mode: t
744 End: */
This page took 0.054348 seconds and 3 git commands to generate.