/* Instruction printing code for the ARC.
- Copyright (C) 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1994, 1995, 1997, 1998 Free Software Foundation, Inc.
Contributed by Doug Evans (dje@cygnus.com).
This program is free software; you can redistribute it and/or modify
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+#include "sysdep.h"
#include "dis-asm.h"
#include "opcode/arc.h"
-#include "libelf.h"
+#include "elf-bfd.h"
#include "elf/arc.h"
+#include "opintl.h"
-static int print_insn_arc_base PARAMS ((bfd_vma, disassemble_info *));
-static int print_insn_arc_host PARAMS ((bfd_vma, disassemble_info *));
-static int print_insn_arc_graphics PARAMS ((bfd_vma, disassemble_info *));
-static int print_insn_arc_audio PARAMS ((bfd_vma, disassemble_info *));
+static int print_insn_arc_base_little PARAMS ((bfd_vma, disassemble_info *));
+static int print_insn_arc_base_big PARAMS ((bfd_vma, disassemble_info *));
+
+static int print_insn PARAMS ((bfd_vma, disassemble_info *, int, int));
/* Print one instruction from PC on INFO->STREAM.
Return the size of the instruction (4 or 8 for the ARC). */
static int
-print_insn (pc, info, cpu)
+print_insn (pc, info, mach, big_p)
bfd_vma pc;
disassemble_info *info;
- int cpu;
+ int mach;
+ int big_p;
{
- const struct arc_opcode *opcode,*opcode_end;
+ const struct arc_opcode *opcode;
bfd_byte buffer[4];
void *stream = info->stream;
fprintf_ftype func = info->fprintf_func;
arc_insn insn[2];
int got_limm_p = 0;
static int initialized = 0;
- static int current_cpu = 0;
- /* Not used yet. Here to record byte order dependencies. */
- int bigendian_p = 0;
+ static int current_mach = 0;
- if (!initialized || cpu != current_cpu)
+ if (!initialized || mach != current_mach)
{
- arc_opcode_init_tables (cpu);
initialized = 1;
- current_cpu = cpu;
+ current_mach = arc_get_opcode_mach (mach, big_p);
+ arc_opcode_init_tables (current_mach);
}
status = (*info->read_memory_func) (pc, buffer, 4, info);
(*info->memory_error_func) (status, pc, info);
return -1;
}
- if (bigendian_p)
+ if (big_p)
insn[0] = bfd_getb32 (buffer);
else
insn[0] = bfd_getl32 (buffer);
- func (stream, "%08lx\t", insn[0]);
+ (*func) (stream, "%08lx\t", insn[0]);
+
+ /* The instructions are stored in lists hashed by the insn code
+ (though we needn't care how they're hashed). */
- opcode_end = arc_opcodes + arc_opcodes_count;
- for (opcode = arc_opcodes; opcode < opcode_end; opcode++)
+ opcode = arc_opcode_lookup_dis (insn[0]);
+ for ( ; opcode != NULL; opcode = ARC_OPCODE_NEXT_DIS (opcode))
{
char *syn;
int mods,invalid;
for (syn = opcode->syntax; *syn; ++syn)
{
+ int c;
+
if (*syn != '%' || *++syn == '%')
continue;
mods = 0;
- while (ARC_MOD_P (arc_operands[arc_operand_map[*syn]].flags))
+ c = *syn;
+ while (ARC_MOD_P (arc_operands[arc_operand_map[c]].flags))
{
- mods |= arc_operands[arc_operand_map[*syn]].flags & ARC_MOD_BITS;
+ mods |= arc_operands[arc_operand_map[c]].flags & ARC_MOD_BITS;
++syn;
+ c = *syn;
}
- operand = arc_operands + arc_operand_map[*syn];
+ operand = arc_operands + arc_operand_map[c];
if (operand->extract)
(*operand->extract) (insn, operand, mods,
(const struct arc_operand_value **) NULL,
(*info->memory_error_func) (status, pc, info);
return -1;
}
- if (bigendian_p)
+ if (big_p)
insn[1] = bfd_getb32 (buffer);
else
insn[1] = bfd_getl32 (buffer);
for (syn = opcode->syntax; *syn; ++syn)
{
+ int c;
+
if (*syn != '%' || *++syn == '%')
{
- func (stream, "%c", *syn);
+ (*func) (stream, "%c", *syn);
continue;
}
/* We have an operand. Fetch any special modifiers. */
mods = 0;
- while (ARC_MOD_P (arc_operands[arc_operand_map[*syn]].flags))
+ c = *syn;
+ while (ARC_MOD_P (arc_operands[arc_operand_map[c]].flags))
{
- mods |= arc_operands[arc_operand_map[*syn]].flags & ARC_MOD_BITS;
+ mods |= arc_operands[arc_operand_map[c]].flags & ARC_MOD_BITS;
++syn;
+ c = *syn;
}
- operand = arc_operands + arc_operand_map[*syn];
+ operand = arc_operands + arc_operand_map[c];
/* Extract the value from the instruction. */
opval = NULL;
aren't defined yet. For these cases just print the
number suitably decorated. */
if (opval)
- func (stream, "%s%s",
- mods & ARC_MOD_DOT ? "." : "",
- opval->name);
+ (*func) (stream, "%s%s",
+ mods & ARC_MOD_DOT ? "." : "",
+ opval->name);
else
- func (stream, "%s%c%d",
- mods & ARC_MOD_DOT ? "." : "",
- operand->fmt, value);
+ (*func) (stream, "%s%c%d",
+ mods & ARC_MOD_DOT ? "." : "",
+ operand->fmt, value);
}
}
- else if (operand->flags & ARC_OPERAND_RELATIVE)
+ else if (operand->flags & ARC_OPERAND_RELATIVE_BRANCH)
(*info->print_address_func) (pc + 4 + value, info);
/* ??? Not all cases of this are currently caught. */
- else if (operand->flags & ARC_OPERAND_ABSOLUTE)
+ else if (operand->flags & ARC_OPERAND_ABSOLUTE_BRANCH)
+ (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info);
+ else if (operand->flags & ARC_OPERAND_ADDRESS)
(*info->print_address_func) ((bfd_vma) value & 0xffffffff, info);
else if (opval)
/* Note that this case catches both normal and auxiliary regs. */
- func (stream, "%s", opval->name);
+ (*func) (stream, "%s", opval->name);
else
- func (stream, "%ld", value);
+ (*func) (stream, "%ld", value);
}
/* We have found and printed an instruction; return. */
return got_limm_p ? 8 : 4;
}
- func (stream, "*unknown*");
+ (*func) (stream, _("*unknown*"));
return 4;
}
-/* Given ABFD, return the print_insn function to use.
+/* Given MACH, one of bfd_mach_arc_xxx, return the print_insn function to use.
This does things a non-standard way (the "standard" way would be to copy
this code into disassemble.c). Since there are more than a couple of
variants, hiding all this crud here seems cleaner. */
disassembler_ftype
-arc_disassembler (bfd *abfd)
+arc_get_disassembler (mach, big_p)
+ int mach;
+ int big_p;
{
- int mach = bfd_get_mach (abfd);
-
switch (mach)
{
case bfd_mach_arc_base:
- return print_insn_arc_base;
- case bfd_mach_arc_host:
- return print_insn_arc_host;
- case bfd_mach_arc_graphics:
- return print_insn_arc_graphics;
- case bfd_mach_arc_audio:
- return print_insn_arc_audio;
+ return big_p ? print_insn_arc_base_big : print_insn_arc_base_little;
}
- return print_insn_arc_base;
+ return print_insn_arc_base_little;
}
static int
-print_insn_arc_base (pc, info)
+print_insn_arc_base_little (pc, info)
bfd_vma pc;
disassemble_info *info;
{
- return print_insn (pc, info, ARC_MACH_BASE);
+ return print_insn (pc, info, bfd_mach_arc_base, 0);
}
-/* Host CPU. */
-
-static int
-print_insn_arc_host (pc, info)
- bfd_vma pc;
- disassemble_info *info;
-{
- return print_insn (pc, info, ARC_MACH_HOST);
-}
-
-/* Graphics CPU. */
-
-static int
-print_insn_arc_graphics (pc, info)
- bfd_vma pc;
- disassemble_info *info;
-{
- return print_insn (pc, info, ARC_MACH_GRAPHICS);
-}
-
-/* Audio CPU. */
-
static int
-print_insn_arc_audio (pc, info)
+print_insn_arc_base_big (pc, info)
bfd_vma pc;
disassemble_info *info;
{
- return print_insn (pc, info, ARC_MACH_AUDIO);
+ return print_insn (pc, info, bfd_mach_arc_base, 1);
}