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 if (flg_operand->name[0] == 'd'
274 && flg_operand->name[1] == 0)
275 info->branch_delay_insns = 1;
277 /* Check if it is a conditional flag. */
278 if (cl_flags->flag_class & F_CLASS_COND)
280 if (info->insn_type == dis_jsr)
281 info->insn_type = dis_condjsr;
282 else if (info->insn_type == dis_branch)
283 info->insn_type = dis_condbranch;
286 (*info->fprintf_func) (info->stream, "%s", flg_operand->name);
293 get_auxreg (const struct arc_opcode *opcode,
299 const struct arc_aux_reg *auxr = &arc_aux_regs[0];
301 if (opcode->insn_class != AUXREG)
304 name = arcExtMap_auxRegName (value);
308 for (i = 0; i < arc_num_aux_regs; i++, auxr++)
310 if (!(auxr->cpu & isa_mask))
313 if (auxr->subclass != NONE)
316 if (auxr->address == value)
322 /* Calculate the instruction length for an instruction starting with MSB
323 and LSB, the most and least significant byte. The ISA_MASK is used to
324 filter the instructions considered to only those that are part of the
325 current architecture.
327 The instruction lengths are calculated from the ARC_OPCODE table, and
328 cached for later use. */
331 arc_insn_length (bfd_byte msb, struct disassemble_info *info)
333 bfd_byte major_opcode = msb >> 3;
337 case bfd_mach_arc_nps400:
338 case bfd_mach_arc_arc700:
339 case bfd_mach_arc_arc600:
340 return (major_opcode > 0xb) ? 2 : 4;
343 case bfd_mach_arc_arcv2:
344 return (major_opcode > 0x7) ? 2 : 4;
352 /* Disassemble ARC instructions. */
355 print_insn_arc (bfd_vma memaddr,
356 struct disassemble_info *info)
359 unsigned int lowbyte, highbyte;
361 unsigned int insnLen;
362 unsigned insn[2] = { 0, 0 };
364 const unsigned char *opidx;
365 const struct arc_opcode *opcode;
366 const extInstruction_t *einsn;
367 bfd_boolean need_comma;
368 bfd_boolean open_braket;
371 lowbyte = ((info->endian == BFD_ENDIAN_LITTLE) ? 1 : 0);
372 highbyte = ((info->endian == BFD_ENDIAN_LITTLE) ? 0 : 1);
376 case bfd_mach_arc_nps400:
377 isa_mask = ARC_OPCODE_ARC700 | ARC_OPCODE_NPS400;
380 case bfd_mach_arc_arc700:
381 isa_mask = ARC_OPCODE_ARC700;
384 case bfd_mach_arc_arc600:
385 isa_mask = ARC_OPCODE_ARC600;
388 case bfd_mach_arc_arcv2:
390 isa_mask = ARC_OPCODE_ARCv2HS | ARC_OPCODE_ARCv2EM;
394 /* This variable may be set by the instruction decoder. It suggests
395 the number of bytes objdump should display on a single line. If
396 the instruction decoder sets this, it should always set it to
397 the same value in order to get reasonable looking output. */
399 info->bytes_per_line = 8;
401 /* In the next lines, we set two info variables control the way
402 objdump displays the raw data. For example, if bytes_per_line is
403 8 and bytes_per_chunk is 4, the output will look like this:
404 00: 00000000 00000000
405 with the chunks displayed according to "display_endian". */
408 && !(info->section->flags & SEC_CODE))
410 /* This is not a CODE section. */
411 switch (info->section->size)
416 size = info->section->size;
419 size = (info->section->size & 0x01) ? 1 : 4;
422 info->bytes_per_chunk = 1;
423 info->display_endian = info->endian;
428 info->bytes_per_chunk = 2;
429 info->display_endian = info->endian;
432 /* Read the insn into a host word. */
433 status = (*info->read_memory_func) (memaddr, buffer, size, info);
436 (*info->memory_error_func) (status, memaddr, info);
441 && !(info->section->flags & SEC_CODE))
446 data = bfd_get_bits (buffer, size * 8,
447 info->display_endian == BFD_ENDIAN_BIG);
451 (*info->fprintf_func) (info->stream, ".byte\t0x%02lx", data);
454 (*info->fprintf_func) (info->stream, ".short\t0x%04lx", data);
457 (*info->fprintf_func) (info->stream, ".word\t0x%08lx", data);
465 insnLen = arc_insn_length (buffer[lowbyte], info);
469 insn[0] = (buffer[lowbyte] << 8) | buffer[highbyte];
473 /* An unknown instruction is treated as being length 4. This is
474 possibly not the best solution, but matches the behaviour that was
475 in place before the table based instruction length look-up was
478 /* This is a long instruction: Read the remaning 2 bytes. */
479 status = (*info->read_memory_func) (memaddr + 2, &buffer[2], 2, info);
482 (*info->memory_error_func) (status, memaddr + 2, info);
485 insn[0] = ARRANGE_ENDIAN (info, buffer);
489 /* Set some defaults for the insn info. */
490 info->insn_info_valid = 1;
491 info->branch_delay_insns = 0;
493 info->insn_type = dis_nonbranch;
497 /* FIXME to be moved in dissasemble_init_for_target. */
498 info->disassembler_needs_relocs = TRUE;
500 /* Find the first match in the opcode table. */
501 opcode = find_format (arc_opcodes, insn, insnLen, isa_mask);
505 /* No instruction found. Try the extensions. */
506 einsn = arcExtMap_insn (OPCODE (insn[0]), insn[0]);
509 const char *errmsg = NULL;
510 opcode = arcExtMap_genOpcode (einsn, isa_mask, &errmsg);
513 (*info->fprintf_func) (info->stream,
514 "An error occured while "
515 "generating the extension instruction "
520 opcode = find_format (opcode, insn, insnLen, isa_mask);
521 assert (opcode != NULL);
526 (*info->fprintf_func) (info->stream, ".long %#04x", insn[0]);
528 (*info->fprintf_func) (info->stream, ".long %#08x", insn[0]);
530 info->insn_type = dis_noninsn;
535 /* Print the mnemonic. */
536 (*info->fprintf_func) (info->stream, "%s", opcode->name);
538 /* Preselect the insn class. */
539 switch (opcode->insn_class)
543 if (!strncmp (opcode->name, "bl", 2)
544 || !strncmp (opcode->name, "jl", 2))
546 if (opcode->subclass == COND)
547 info->insn_type = dis_condjsr;
549 info->insn_type = dis_jsr;
553 if (opcode->subclass == COND)
554 info->insn_type = dis_condbranch;
556 info->insn_type = dis_branch;
560 info->insn_type = dis_dref; /* FIXME! DB indicates mov as memory! */
563 info->insn_type = dis_nonbranch;
567 pr_debug ("%s: 0x%08x\n", opcode->name, opcode->opcode);
569 print_flags (opcode, insn, info);
571 if (opcode->operands[0] != 0)
572 (*info->fprintf_func) (info->stream, "\t");
577 /* Now extract and print the operands. */
578 for (opidx = opcode->operands; *opidx; opidx++)
580 const struct arc_operand *operand = &arc_operands[*opidx];
583 if (open_braket && (operand->flags & ARC_OPERAND_BRAKET))
585 (*info->fprintf_func) (info->stream, "]");
590 /* Only take input from real operands. */
591 if ((operand->flags & ARC_OPERAND_FAKE)
592 && !(operand->flags & ARC_OPERAND_BRAKET))
595 if (operand->extract)
596 value = (*operand->extract) (insn[0], (int *) NULL);
599 if (operand->flags & ARC_OPERAND_ALIGNED32)
601 value = (insn[0] >> operand->shift)
602 & ((1 << (operand->bits - 2)) - 1);
607 value = (insn[0] >> operand->shift) & ((1 << operand->bits) - 1);
609 if (operand->flags & ARC_OPERAND_SIGNED)
611 int signbit = 1 << (operand->bits - 1);
612 value = (value ^ signbit) - signbit;
616 if (operand->flags & ARC_OPERAND_IGNORE
617 && (operand->flags & ARC_OPERAND_IR
622 (*info->fprintf_func) (info->stream, ",");
624 if (!open_braket && (operand->flags & ARC_OPERAND_BRAKET))
626 (*info->fprintf_func) (info->stream, "[");
632 /* Read the limm operand, if required. */
633 if (operand->flags & ARC_OPERAND_LIMM
634 && !(operand->flags & ARC_OPERAND_DUPLICATE))
636 status = (*info->read_memory_func) (memaddr + insnLen, buffer,
640 (*info->memory_error_func) (status, memaddr + insnLen, info);
643 insn[1] = ARRANGE_ENDIAN (info, buffer);
646 /* Print the operand as directed by the flags. */
647 if (operand->flags & ARC_OPERAND_IR)
651 assert (value >=0 && value < 64);
652 rname = arcExtMap_coreRegName (value);
654 rname = regnames[value];
655 (*info->fprintf_func) (info->stream, "%s", rname);
656 if (operand->flags & ARC_OPERAND_TRUNCATE)
658 rname = arcExtMap_coreRegName (value + 1);
660 rname = regnames[value + 1];
661 (*info->fprintf_func) (info->stream, "%s", rname);
664 else if (operand->flags & ARC_OPERAND_LIMM)
666 const char *rname = get_auxreg (opcode, insn[1], isa_mask);
667 if (rname && open_braket)
668 (*info->fprintf_func) (info->stream, "%s", rname);
671 (*info->fprintf_func) (info->stream, "%#x", insn[1]);
672 if (info->insn_type == dis_branch
673 || info->insn_type == dis_jsr)
674 info->target = (bfd_vma) insn[1];
677 else if (operand->flags & ARC_OPERAND_PCREL)
680 if (info->flags & INSN_HAS_RELOC)
682 (*info->print_address_func) ((memaddr & ~3) + value, info);
684 info->target = (bfd_vma) (memaddr & ~3) + value;
686 else if (operand->flags & ARC_OPERAND_SIGNED)
688 const char *rname = get_auxreg (opcode, value, isa_mask);
689 if (rname && open_braket)
690 (*info->fprintf_func) (info->stream, "%s", rname);
692 (*info->fprintf_func) (info->stream, "%d", value);
696 if (operand->flags & ARC_OPERAND_TRUNCATE
697 && !(operand->flags & ARC_OPERAND_ALIGNED32)
698 && !(operand->flags & ARC_OPERAND_ALIGNED16)
699 && value > 0 && value <= 14)
700 (*info->fprintf_func) (info->stream, "r13-%s",
701 regnames[13 + value - 1]);
704 const char *rname = get_auxreg (opcode, value, isa_mask);
705 if (rname && open_braket)
706 (*info->fprintf_func) (info->stream, "%s", rname);
708 (*info->fprintf_func) (info->stream, "%#x", value);
714 /* Adjust insn len. */
715 if (operand->flags & ARC_OPERAND_LIMM
716 && !(operand->flags & ARC_OPERAND_DUPLICATE))
725 arc_get_disassembler (bfd *abfd)
727 /* Read the extenssion insns and registers, if any. */
728 build_ARC_extmap (abfd);
733 return print_insn_arc;
736 /* Disassemble ARC instructions. Used by debugger. */
739 arcAnalyzeInstr (bfd_vma memaddr,
740 struct disassemble_info *info)
742 struct arcDisState ret;
743 memset (&ret, 0, sizeof (struct arcDisState));
745 ret.instructionLen = print_insn_arc (memaddr, info);
748 ret.words[0] = insn[0];
749 ret.words[1] = insn[1];
751 ret.coreRegName = _coreRegName;
752 ret.auxRegName = _auxRegName;
753 ret.condCodeName = _condCodeName;
754 ret.instName = _instName;
761 eval: (c-set-style "gnu")