/* Instruction printing code for the ARC.
- Copyright (C) 1994-2017 Free Software Foundation, Inc.
+ Copyright (C) 1994-2020 Free Software Foundation, Inc.
Contributed by Claudiu Zissulescu (claziss@synopsys.com)
"r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39",
"r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47",
"r48", "r49", "r50", "r51", "r52", "r53", "r54", "r55",
- "r56", "r57", "ACCL", "ACCH", "lp_count", "rezerved", "LIMM", "pcl"
+ "r56", "r57", "r58", "r59", "lp_count", "reserved", "LIMM", "pcl"
};
static const char * const addrtypenames[ARC_NUM_ADDRTYPES] =
static unsigned enforced_isa_mask = ARC_OPCODE_NONE;
+/* True if we want to print using only hex numbers. */
+static bfd_boolean print_hex = FALSE;
+
/* Macros section. */
#ifdef DEBUG
(info->endian == BFD_ENDIAN_LITTLE ? bfd_getm32 (bfd_getl32 (buf)) \
: bfd_getb32 (buf))
-#define BITS(word,s,e) (((word) << (sizeof (word) * 8 - 1 - e)) >> \
- (s + (sizeof (word) * 8 - 1 - e)))
+#define BITS(word,s,e) (((word) >> (s)) & ((1ull << ((e) - (s)) << 1) - 1))
#define OPCODE_32BIT_INSN(word) (BITS ((word), 27, 31))
/* Functions implementation. */
/* Check opcode for major 0x06, return if it is not in. */
if (arc_opcode_len (opcode) == 4
- && OPCODE_32BIT_INSN (opcode->opcode) != 0x06)
+ && (OPCODE_32BIT_INSN (opcode->opcode) != 0x06
+ /* Can be an APEX extensions. */
+ && OPCODE_32BIT_INSN (opcode->opcode) != 0x07))
return FALSE;
/* or not a known truble class. */
{
case FLOAT:
case DSP:
+ case ARITH:
+ case MPY:
break;
default:
return FALSE;
if (operand->extract)
value = (*operand->extract) (insn, &invalid);
else
- value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
+ value = (insn >> operand->shift) & ((1ull << operand->bits) - 1);
/* Check for LIMM indicator. If it is there, then make sure
we pick the right format. */
struct arc_operand_iterator * iter)
{
const struct arc_opcode *opcode = NULL;
- bfd_boolean needs_limm;
+ bfd_boolean needs_limm = FALSE;
const extInstruction_t *einsn, *i;
unsigned limm = 0;
struct arc_disassemble_info *arc_infop = info->private_data;
opcode = arcExtMap_genOpcode (i, isa_mask, &errmsg);
if (opcode == NULL)
{
- (*info->fprintf_func) (info->stream, "\
-An error occured while generating the extension instruction operations");
+ (*info->fprintf_func) (info->stream,
+ _("An error occured while generating the "
+ "extension instruction operations"));
*opcode_result = NULL;
return FALSE;
}
opcode = find_format_from_table (info, arc_opcodes, insn, *insn_len,
isa_mask, &needs_limm, TRUE);
- if (needs_limm && opcode != NULL)
+ if (opcode != NULL && needs_limm)
{
bfd_byte buffer[4];
int status;
/* Update private data. */
arc_infop->opcode = opcode;
- arc_infop->limm = (needs_limm) ? limm : 0;
+ arc_infop->limm = limm;
arc_infop->limm_p = needs_limm;
return TRUE;
break;
default:
- abort ();
+ return 0;
}
}
else if (disassembler_options_cmp (option, "fpuda") == 0)
add_to_decodelist (FLOAT, DPA);
+ else if (disassembler_options_cmp (option, "nps400") == 0)
+ {
+ add_to_decodelist (ACL, NPS400);
+ add_to_decodelist (ARITH, NPS400);
+ add_to_decodelist (BITOP, NPS400);
+ add_to_decodelist (BMU, NPS400);
+ add_to_decodelist (CONTROL, NPS400);
+ add_to_decodelist (DMA, NPS400);
+ add_to_decodelist (DPI, NPS400);
+ add_to_decodelist (MEMORY, NPS400);
+ add_to_decodelist (MISC, NPS400);
+ add_to_decodelist (NET, NPS400);
+ add_to_decodelist (PMU, NPS400);
+ add_to_decodelist (PROTOCOL_DECODE, NPS400);
+ add_to_decodelist (ULTRAIP, NPS400);
+ }
+
else if (disassembler_options_cmp (option, "fpus") == 0)
{
add_to_decodelist (FLOAT, SP);
add_to_decodelist (FLOAT, DP);
add_to_decodelist (FLOAT, CVT);
}
+ else if (CONST_STRNEQ (option, "hex"))
+ print_hex = TRUE;
else
- fprintf (stderr, _("Unrecognised disassembler option: %s\n"), option);
+ /* xgettext:c-format */
+ opcodes_error_handler (_("unrecognised disassembler option: %s"), option);
}
#define ARC_CPU_TYPE_A6xx(NAME,EXTRA) \
}
}
- fprintf (stderr, _("Unrecognised disassembler CPU option: %s\n"), option);
+ /* xgettext:c-format */
+ opcodes_error_handler (_("unrecognised disassembler CPU option: %s"), option);
return ARC_OPCODE_NONE;
}
static void
parse_disassembler_options (const char *options)
{
+ const char *option;
+
if (options == NULL)
return;
CPU when new options are being parsed. */
enforced_isa_mask = ARC_OPCODE_NONE;
- while (*options)
+ FOR_EACH_DISASSEMBLER_OPTION (option, options)
{
- /* Skip empty options. */
- if (*options == ',')
- {
- ++ options;
- continue;
- }
-
/* A CPU option? Cannot use STRING_COMMA_LEN because strncmp is also a
preprocessor macro. */
- if (strncmp (options, "cpu=", 4) == 0)
+ if (strncmp (option, "cpu=", 4) == 0)
/* Strip leading `cpu=`. */
- enforced_isa_mask = parse_cpu_option (options + 4);
+ enforced_isa_mask = parse_cpu_option (option + 4);
else
- parse_option (options);
-
- while (*options != ',' && *options != '\0')
- ++ options;
+ parse_option (option);
}
}
bfd_boolean open_braket;
int size;
const struct arc_operand *operand;
- int value;
+ int value, vpcl;
struct arc_operand_iterator iter;
struct arc_disassemble_info *arc_infop;
+ bfd_boolean rpcl = FALSE, rset = FALSE;
if (info->disassembler_options)
{
the number of bytes objdump should display on a single line. If
the instruction decoder sets this, it should always set it to
the same value in order to get reasonable looking output. */
-
info->bytes_per_line = 8;
/* In the next lines, we set two info variables control the way
8 and bytes_per_chunk is 4, the output will look like this:
00: 00000000 00000000
with the chunks displayed according to "display_endian". */
-
if (info->section
&& !(info->section->flags & SEC_CODE))
{
/* Read the insn into a host word. */
status = (*info->read_memory_func) (memaddr, buffer, size, info);
+
if (status != 0)
{
(*info->memory_error_func) (status, memaddr, info);
(*info->fprintf_func) (info->stream, ".word\t0x%08lx", data);
break;
default:
- abort ();
+ return -1;
}
return size;
}
insn_len = arc_insn_length (buffer[highbyte], buffer[lowbyte], info);
pr_debug ("instruction length = %d bytes\n", insn_len);
+ if (insn_len == 0)
+ return -1;
+
arc_infop = info->private_data;
arc_infop->insn_len = insn_len;
default:
/* There is no instruction whose length is not 2, 4, 6, or 8. */
- abort ();
+ return -1;
}
pr_debug ("instruction value = %llx\n", insn);
switch (insn_len)
{
case 2:
- (*info->fprintf_func) (info->stream, ".long %#04llx",
+ (*info->fprintf_func) (info->stream, ".shor\t%#04llx",
insn & 0xffff);
break;
+
case 4:
- (*info->fprintf_func) (info->stream, ".long %#08llx",
+ (*info->fprintf_func) (info->stream, ".word\t%#08llx",
insn & 0xffffffff);
break;
+
case 6:
- (*info->fprintf_func) (info->stream, ".long %#08llx",
+ (*info->fprintf_func) (info->stream, ".long\t%#08llx",
insn & 0xffffffff);
- (*info->fprintf_func) (info->stream, ".long %#04llx",
+ (*info->fprintf_func) (info->stream, ".long\t%#04llx",
(insn >> 32) & 0xffff);
break;
+
case 8:
- (*info->fprintf_func) (info->stream, ".long %#08llx",
+ (*info->fprintf_func) (info->stream, ".long\t%#08llx",
insn & 0xffffffff);
- (*info->fprintf_func) (info->stream, ".long %#08llx",
+ (*info->fprintf_func) (info->stream, ".long\t%#08llx",
insn >> 32);
break;
+
default:
- abort ();
+ return -1;
}
info->insn_type = dis_noninsn;
/* Now extract and print the operands. */
operand = NULL;
+ vpcl = 0;
while (operand_iterator_next (&iter, &operand, &value))
{
if (open_braket && (operand->flags & ARC_OPERAND_BRAKET))
need_comma = TRUE;
+ if (operand->flags & ARC_OPERAND_PCREL)
+ {
+ rpcl = TRUE;
+ vpcl = value;
+ rset = TRUE;
+
+ info->target = (bfd_vma) (memaddr & ~3) + value;
+ }
+ else if (!(operand->flags & ARC_OPERAND_IR))
+ {
+ vpcl = value;
+ rset = TRUE;
+ }
+
/* Print the operand as directed by the flags. */
if (operand->flags & ARC_OPERAND_IR)
{
rname = regnames[value + 1];
(*info->fprintf_func) (info->stream, "%s", rname);
}
+ if (value == 63)
+ rpcl = TRUE;
+ else
+ rpcl = FALSE;
}
else if (operand->flags & ARC_OPERAND_LIMM)
{
info->target = (bfd_vma) value;
}
}
- else if (operand->flags & ARC_OPERAND_PCREL)
- {
- /* PCL relative. */
- if (info->flags & INSN_HAS_RELOC)
- memaddr = 0;
- (*info->print_address_func) ((memaddr & ~3) + value, info);
-
- info->target = (bfd_vma) (memaddr & ~3) + value;
- }
else if (operand->flags & ARC_OPERAND_SIGNED)
{
const char *rname = get_auxreg (opcode, value, isa_mask);
if (rname && open_braket)
(*info->fprintf_func) (info->stream, "%s", rname);
else
- (*info->fprintf_func) (info->stream, "%d", value);
+ {
+ if (print_hex)
+ (*info->fprintf_func) (info->stream, "%#x", value);
+ else
+ (*info->fprintf_func) (info->stream, "%d", value);
+ }
}
else if (operand->flags & ARC_OPERAND_ADDRTYPE)
{
&& !(operand->flags & ARC_OPERAND_ALIGNED16)
&& value >= 0 && value <= 14)
{
+ /* Leave/Enter mnemonics. */
switch (value)
{
case 0:
regnames[13 + value - 1]);
break;
}
+ rpcl = FALSE;
+ rset = FALSE;
}
else
{
arc_infop->operands_count ++;
}
+ /* Pretty print extra info for pc-relative operands. */
+ if (rpcl && rset)
+ {
+ if (info->flags & INSN_HAS_RELOC)
+ /* If the instruction has a reloc associated with it, then the
+ offset field in the instruction will actually be the addend
+ for the reloc. (We are using REL type relocs). In such
+ cases, we can ignore the pc when computing addresses, since
+ the addend is not currently pc-relative. */
+ memaddr = 0;
+
+ (*info->fprintf_func) (info->stream, "\t;");
+ (*info->print_address_func) ((memaddr & ~3) + vpcl, info);
+ }
+
return insn_len;
}
fpus Recognize single precision FPU instructions.\n"));
fprintf (stream, _("\
fpud Recognize double precision FPU instructions.\n"));
+ fprintf (stream, _("\
+ nps400 Recognize NPS400 instructions.\n"));
+ fprintf (stream, _("\
+ hex Use only hexadecimal number to print immediates.\n"));
}
void arc_insn_decode (bfd_vma addr,