1 /* Instruction printing code for the ARC.
2 Copyright (C) 1994-2016 Free Software Foundation, Inc.
4 Contributed by Claudiu Zissulescu (claziss@synopsys.com)
6 This file is part of libopcodes.
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)
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.
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. */
27 #include "opcode/arc.h"
32 /* Globals variables. */
34 static const char * const regnames[64] =
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",
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"
50 # define pr_debug(fmt, args...) fprintf (stderr, fmt, ##args)
52 # define pr_debug(fmt, args...)
55 #define ARRANGE_ENDIAN(info, buf) \
56 (info->endian == BFD_ENDIAN_LITTLE ? bfd_getm32 (bfd_getl32 (buf)) \
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))
63 #define OPCODE_AC(word) (BITS ((word), 11, 15))
65 /* Functions implementation. */
68 bfd_getm32 (unsigned int data)
72 value = ((data & 0xff00) | (data & 0xff)) << 16;
73 value |= ((data & 0xff0000) | (data & 0xff000000)) >> 16;
78 special_flag_p (const char *opname,
81 const struct arc_flag_special *flg_spec;
82 unsigned i, j, flgidx;
84 for (i = 0; i < arc_num_flag_special; i++)
86 flg_spec = &arc_flag_special_cases[i];
88 if (strcmp (opname, flg_spec->name))
91 /* Found potential special case instruction. */
94 flgidx = flg_spec->flags[j];
96 break; /* End of the array. */
98 if (strcmp (flgname, arc_flag_operands[flgidx].name) == 0)
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,
112 const struct arc_opcode *opcode = NULL;
113 const unsigned char *opidx;
114 const unsigned char *flgidx;
117 bfd_boolean invalid = FALSE;
119 opcode = &arc_table[i++];
121 if (ARC_SHORT (opcode->mask) && (insnLen == 2))
123 if (OPCODE_AC (opcode->opcode) != OPCODE_AC (insn[0]))
126 else if (!ARC_SHORT (opcode->mask) && (insnLen == 4))
128 if (OPCODE (opcode->opcode) != OPCODE (insn[0]))
134 if ((insn[0] ^ opcode->opcode) & opcode->mask)
137 if (!(opcode->cpu & isa_mask))
140 /* Possible candidate, check the operands. */
141 for (opidx = opcode->operands; *opidx; opidx++)
144 const struct arc_operand *operand = &arc_operands[*opidx];
146 if (operand->flags & ARC_OPERAND_FAKE)
149 if (operand->extract)
150 value = (*operand->extract) (insn[0], &invalid);
152 value = (insn[0] >> operand->shift) & ((1 << operand->bits) - 1);
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))
159 if ((value == 0x3E && insnLen == 4)
160 || (value == 0x1E && insnLen == 2))
168 /* Check the flags. */
169 for (flgidx = opcode->flags; *flgidx; flgidx++)
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;
177 /* Check first the extensions. */
178 if (cl_flags->flag_class & F_CLASS_EXTEND)
180 value = (insn[0] & 0x1F);
181 if (arcExtMap_condCodeName (value))
184 for (flgopridx = cl_flags->flags; *flgopridx; ++flgopridx)
186 const struct arc_flag_operand *flg_operand =
187 &arc_flag_operands[*flgopridx];
189 value = (insn[0] >> flg_operand->shift)
190 & ((1 << flg_operand->bits) - 1);
191 if (value == flg_operand->code)
196 if (!foundA && foundB)
206 /* The instruction is valid. */
208 } while (opcode->mask);
214 print_flags (const struct arc_opcode *opcode,
216 struct disassemble_info *info)
218 const unsigned char *flgidx;
221 /* Now extract and print the flags. */
222 for (flgidx = opcode->flags; *flgidx; flgidx++)
224 /* Get a valid flag class. */
225 const struct arc_flag_class *cl_flags = &arc_flag_classes[*flgidx];
226 const unsigned *flgopridx;
228 /* Check first the extensions. */
229 if (cl_flags->flag_class & F_CLASS_EXTEND)
232 value = (insn[0] & 0x1F);
234 name = arcExtMap_condCodeName (value);
237 (*info->fprintf_func) (info->stream, ".%s", name);
242 for (flgopridx = cl_flags->flags; *flgopridx; ++flgopridx)
244 const struct arc_flag_operand *flg_operand =
245 &arc_flag_operands[*flgopridx];
247 if (!flg_operand->favail)
250 value = (insn[0] >> flg_operand->shift)
251 & ((1 << flg_operand->bits) - 1);
252 if (value == flg_operand->code)
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)
259 switch (flg_operand->name[0])
273 (*info->fprintf_func) (info->stream, "%s", flg_operand->name);
276 if (flg_operand->name[0] == 'd'
277 && flg_operand->name[1] == 0)
278 info->branch_delay_insns = 1;
284 get_auxreg (const struct arc_opcode *opcode,
290 const struct arc_aux_reg *auxr = &arc_aux_regs[0];
292 if (opcode->insn_class != AUXREG)
295 name = arcExtMap_auxRegName (value);
299 for (i = 0; i < arc_num_aux_regs; i++, auxr++)
301 if (!(auxr->cpu & isa_mask))
304 if (auxr->subclass != NONE)
307 if (auxr->address == value)
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.
318 The instruction lengths are calculated from the ARC_OPCODE table, and
319 cached for later use. */
322 arc_insn_length (bfd_byte msb, struct disassemble_info *info)
324 bfd_byte major_opcode = msb >> 3;
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;
334 case bfd_mach_arc_arcv2:
335 return (major_opcode > 0x7) ? 2 : 4;
343 /* Disassemble ARC instructions. */
346 print_insn_arc (bfd_vma memaddr,
347 struct disassemble_info *info)
350 unsigned int lowbyte, highbyte;
352 unsigned int insnLen;
353 unsigned insn[2] = { 0, 0 };
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;
362 lowbyte = ((info->endian == BFD_ENDIAN_LITTLE) ? 1 : 0);
363 highbyte = ((info->endian == BFD_ENDIAN_LITTLE) ? 0 : 1);
367 case bfd_mach_arc_nps400:
368 isa_mask = ARC_OPCODE_ARC700 | ARC_OPCODE_NPS400;
371 case bfd_mach_arc_arc700:
372 isa_mask = ARC_OPCODE_ARC700;
375 case bfd_mach_arc_arc600:
376 isa_mask = ARC_OPCODE_ARC600;
379 case bfd_mach_arc_arcv2:
381 isa_mask = ARC_OPCODE_ARCv2HS | ARC_OPCODE_ARCv2EM;
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. */
390 info->bytes_per_line = 8;
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". */
399 && !(info->section->flags & SEC_CODE))
401 /* This is not a CODE section. */
402 switch (info->section->size)
407 size = info->section->size;
410 size = (info->section->size & 0x01) ? 1 : 4;
413 info->bytes_per_chunk = 1;
414 info->display_endian = info->endian;
419 info->bytes_per_chunk = 2;
420 info->display_endian = info->endian;
423 /* Read the insn into a host word. */
424 status = (*info->read_memory_func) (memaddr, buffer, size, info);
427 (*info->memory_error_func) (status, memaddr, info);
432 && !(info->section->flags & SEC_CODE))
437 data = bfd_get_bits (buffer, size * 8,
438 info->display_endian == BFD_ENDIAN_BIG);
442 (*info->fprintf_func) (info->stream, ".byte\t0x%02lx", data);
445 (*info->fprintf_func) (info->stream, ".short\t0x%04lx", data);
448 (*info->fprintf_func) (info->stream, ".word\t0x%08lx", data);
456 insnLen = arc_insn_length (buffer[lowbyte], info);
460 insn[0] = (buffer[lowbyte] << 8) | buffer[highbyte];
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
469 /* This is a long instruction: Read the remaning 2 bytes. */
470 status = (*info->read_memory_func) (memaddr + 2, &buffer[2], 2, info);
473 (*info->memory_error_func) (status, memaddr + 2, info);
476 insn[0] = ARRANGE_ENDIAN (info, buffer);
480 /* Set some defaults for the insn info. */
481 info->insn_info_valid = 1;
482 info->branch_delay_insns = 0;
484 info->insn_type = dis_nonbranch;
488 /* FIXME to be moved in dissasemble_init_for_target. */
489 info->disassembler_needs_relocs = TRUE;
491 /* Find the first match in the opcode table. */
492 opcode = find_format (arc_opcodes, insn, insnLen, isa_mask);
496 /* No instruction found. Try the extensions. */
497 einsn = arcExtMap_insn (OPCODE (insn[0]), insn[0]);
500 const char *errmsg = NULL;
501 opcode = arcExtMap_genOpcode (einsn, isa_mask, &errmsg);
504 (*info->fprintf_func) (info->stream,
505 "An error occured while "
506 "generating the extension instruction "
511 opcode = find_format (opcode, insn, insnLen, isa_mask);
512 assert (opcode != NULL);
517 (*info->fprintf_func) (info->stream, ".long %#04x", insn[0]);
519 (*info->fprintf_func) (info->stream, ".long %#08x", insn[0]);
521 info->insn_type = dis_noninsn;
526 /* Print the mnemonic. */
527 (*info->fprintf_func) (info->stream, "%s", opcode->name);
529 /* Preselect the insn class. */
530 switch (opcode->insn_class)
534 if (!strncmp (opcode->name, "bl", 2)
535 || !strncmp (opcode->name, "jl", 2))
536 info->insn_type = dis_jsr;
538 info->insn_type = dis_branch;
541 info->insn_type = dis_dref; /* FIXME! DB indicates mov as memory! */
544 info->insn_type = dis_nonbranch;
548 pr_debug ("%s: 0x%08x\n", opcode->name, opcode->opcode);
550 print_flags (opcode, insn, info);
552 if (opcode->operands[0] != 0)
553 (*info->fprintf_func) (info->stream, "\t");
558 /* Now extract and print the operands. */
559 for (opidx = opcode->operands; *opidx; opidx++)
561 const struct arc_operand *operand = &arc_operands[*opidx];
564 if (open_braket && (operand->flags & ARC_OPERAND_BRAKET))
566 (*info->fprintf_func) (info->stream, "]");
571 /* Only take input from real operands. */
572 if ((operand->flags & ARC_OPERAND_FAKE)
573 && !(operand->flags & ARC_OPERAND_BRAKET))
576 if (operand->extract)
577 value = (*operand->extract) (insn[0], (int *) NULL);
580 if (operand->flags & ARC_OPERAND_ALIGNED32)
582 value = (insn[0] >> operand->shift)
583 & ((1 << (operand->bits - 2)) - 1);
588 value = (insn[0] >> operand->shift) & ((1 << operand->bits) - 1);
590 if (operand->flags & ARC_OPERAND_SIGNED)
592 int signbit = 1 << (operand->bits - 1);
593 value = (value ^ signbit) - signbit;
597 if (operand->flags & ARC_OPERAND_IGNORE
598 && (operand->flags & ARC_OPERAND_IR
603 (*info->fprintf_func) (info->stream, ",");
605 if (!open_braket && (operand->flags & ARC_OPERAND_BRAKET))
607 (*info->fprintf_func) (info->stream, "[");
613 /* Read the limm operand, if required. */
614 if (operand->flags & ARC_OPERAND_LIMM
615 && !(operand->flags & ARC_OPERAND_DUPLICATE))
617 status = (*info->read_memory_func) (memaddr + insnLen, buffer,
621 (*info->memory_error_func) (status, memaddr + insnLen, info);
624 insn[1] = ARRANGE_ENDIAN (info, buffer);
627 /* Print the operand as directed by the flags. */
628 if (operand->flags & ARC_OPERAND_IR)
632 assert (value >=0 && value < 64);
633 rname = arcExtMap_coreRegName (value);
635 rname = regnames[value];
636 (*info->fprintf_func) (info->stream, "%s", rname);
637 if (operand->flags & ARC_OPERAND_TRUNCATE)
639 rname = arcExtMap_coreRegName (value + 1);
641 rname = regnames[value + 1];
642 (*info->fprintf_func) (info->stream, "%s", rname);
645 else if (operand->flags & ARC_OPERAND_LIMM)
647 const char *rname = get_auxreg (opcode, insn[1], isa_mask);
648 if (rname && open_braket)
649 (*info->fprintf_func) (info->stream, "%s", rname);
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];
658 else if (operand->flags & ARC_OPERAND_PCREL)
661 if (info->flags & INSN_HAS_RELOC)
663 (*info->print_address_func) ((memaddr & ~3) + value, info);
665 info->target = (bfd_vma) (memaddr & ~3) + value;
667 else if (operand->flags & ARC_OPERAND_SIGNED)
669 const char *rname = get_auxreg (opcode, value, isa_mask);
670 if (rname && open_braket)
671 (*info->fprintf_func) (info->stream, "%s", rname);
673 (*info->fprintf_func) (info->stream, "%d", value);
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]);
685 const char *rname = get_auxreg (opcode, value, isa_mask);
686 if (rname && open_braket)
687 (*info->fprintf_func) (info->stream, "%s", rname);
689 (*info->fprintf_func) (info->stream, "%#x", value);
695 /* Adjust insn len. */
696 if (operand->flags & ARC_OPERAND_LIMM
697 && !(operand->flags & ARC_OPERAND_DUPLICATE))
706 arc_get_disassembler (bfd *abfd)
708 /* Read the extenssion insns and registers, if any. */
709 build_ARC_extmap (abfd);
714 return print_insn_arc;
717 /* Disassemble ARC instructions. Used by debugger. */
720 arcAnalyzeInstr (bfd_vma memaddr,
721 struct disassemble_info *info)
723 struct arcDisState ret;
724 memset (&ret, 0, sizeof (struct arcDisState));
726 ret.instructionLen = print_insn_arc (memaddr, info);
729 ret.words[0] = insn[0];
730 ret.words[1] = insn[1];
732 ret.coreRegName = _coreRegName;
733 ret.auxRegName = _auxRegName;
734 ret.condCodeName = _condCodeName;
735 ret.instName = _instName;
742 eval: (c-set-style "gnu")