alpha-dis.c revision 33965
133965Sjdp/* alpha-dis.c -- Disassemble Alpha AXP instructions
233965Sjdp   Copyright 1996 Free Software Foundation, Inc.
333965Sjdp   Contributed by Richard Henderson <rth@tamu.edu>,
433965Sjdp   patterned after the PPC opcode handling written by Ian Lance Taylor.
533965Sjdp
633965SjdpThis file is part of GDB, GAS, and the GNU binutils.
733965Sjdp
833965SjdpGDB, GAS, and the GNU binutils are free software; you can redistribute
933965Sjdpthem and/or modify them under the terms of the GNU General Public
1033965SjdpLicense as published by the Free Software Foundation; either version
1133965Sjdp2, or (at your option) any later version.
1233965Sjdp
1333965SjdpGDB, GAS, and the GNU binutils are distributed in the hope that they
1433965Sjdpwill be useful, but WITHOUT ANY WARRANTY; without even the implied
1533965Sjdpwarranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
1633965Sjdpthe GNU General Public License for more details.
1733965Sjdp
1833965SjdpYou should have received a copy of the GNU General Public License
1933965Sjdpalong with this file; see the file COPYING.  If not, write to the Free
2033965SjdpSoftware Foundation, 59 Temple Place - Suite 330, Boston, MA
2133965Sjdp02111-1307, USA.  */
2233965Sjdp
2333965Sjdp#include <stdlib.h>
2433965Sjdp#include <stdio.h>
2533965Sjdp#include "ansidecl.h"
2633965Sjdp#include "sysdep.h"
2733965Sjdp#include "dis-asm.h"
2833965Sjdp#include "opcode/alpha.h"
2933965Sjdp
3033965Sjdp/* OSF register names.  */
3133965Sjdp
3233965Sjdpstatic const char * const osf_regnames[64] =
3333965Sjdp{
3433965Sjdp  "v0", "t0", "t1", "t2", "t3", "t4", "t5", "t6",
3533965Sjdp  "t7", "s0", "s1", "s2", "s3", "s4", "s5", "fp",
3633965Sjdp  "a0", "a1", "a2", "a3", "a4", "a5", "t8", "t9",
3733965Sjdp  "t10", "t11", "ra", "t12", "at", "gp", "sp", "zero",
3833965Sjdp  "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7",
3933965Sjdp  "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15",
4033965Sjdp  "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",
4133965Sjdp  "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31"
4233965Sjdp};
4333965Sjdp
4433965Sjdp/* VMS register names.  */
4533965Sjdp
4633965Sjdpstatic const char * const vms_regnames[64] =
4733965Sjdp{
4833965Sjdp  "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7",
4933965Sjdp  "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15",
5033965Sjdp  "R16", "R17", "R18", "R19", "R20", "R21", "R22", "R23",
5133965Sjdp  "R24", "AI", "RA", "PV", "AT", "FP", "SP", "RZ",
5233965Sjdp  "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7",
5333965Sjdp  "F8", "F9", "F10", "F11", "F12", "F13", "F14", "F15",
5433965Sjdp  "F16", "F17", "F18", "F19", "F20", "F21", "F22", "F23",
5533965Sjdp  "F24", "F25", "F26", "F27", "F28", "F29", "F30", "FZ"
5633965Sjdp};
5733965Sjdp
5833965Sjdp/* Disassemble Alpha instructions.  */
5933965Sjdp
6033965Sjdpint
6133965Sjdpprint_insn_alpha (memaddr, info)
6233965Sjdp     bfd_vma memaddr;
6333965Sjdp     struct disassemble_info *info;
6433965Sjdp{
6533965Sjdp  static const struct alpha_opcode *opcode_index[AXP_NOPS+1];
6633965Sjdp  const char * const * regnames;
6733965Sjdp  const struct alpha_opcode *opcode, *opcode_end;
6833965Sjdp  const unsigned char *opindex;
6933965Sjdp  unsigned insn, op;
7033965Sjdp  int need_comma;
7133965Sjdp
7233965Sjdp  /* Initialize the majorop table the first time through */
7333965Sjdp  if (!opcode_index[0])
7433965Sjdp    {
7533965Sjdp      opcode = alpha_opcodes;
7633965Sjdp      opcode_end = opcode + alpha_num_opcodes;
7733965Sjdp
7833965Sjdp      for (op = 0; op < AXP_NOPS; ++op)
7933965Sjdp        {
8033965Sjdp          opcode_index[op] = opcode;
8133965Sjdp          while (opcode < opcode_end && op == AXP_OP (opcode->opcode))
8233965Sjdp	    ++opcode;
8333965Sjdp        }
8433965Sjdp      opcode_index[op] = opcode;
8533965Sjdp    }
8633965Sjdp
8733965Sjdp  if (info->flavour == bfd_target_evax_flavour)
8833965Sjdp    regnames = vms_regnames;
8933965Sjdp  else
9033965Sjdp    regnames = osf_regnames;
9133965Sjdp
9233965Sjdp  /* Read the insn into a host word */
9333965Sjdp  {
9433965Sjdp    bfd_byte buffer[4];
9533965Sjdp    int status = (*info->read_memory_func) (memaddr, buffer, 4, info);
9633965Sjdp    if (status != 0)
9733965Sjdp      {
9833965Sjdp        (*info->memory_error_func) (status, memaddr, info);
9933965Sjdp        return -1;
10033965Sjdp      }
10133965Sjdp    insn = bfd_getl32 (buffer);
10233965Sjdp  }
10333965Sjdp
10433965Sjdp  /* Get the major opcode of the instruction.  */
10533965Sjdp  op = AXP_OP (insn);
10633965Sjdp
10733965Sjdp  /* Find the first match in the opcode table.  */
10833965Sjdp  opcode_end = opcode_index[op+1];
10933965Sjdp  for (opcode = opcode_index[op]; opcode < opcode_end; ++opcode)
11033965Sjdp    {
11133965Sjdp      if ((insn & opcode->mask) != opcode->opcode)
11233965Sjdp	continue;
11333965Sjdp
11433965Sjdp      if (!(opcode->flags & AXP_OPCODE_NOPAL))
11533965Sjdp	continue;
11633965Sjdp
11733965Sjdp      /* Make two passes over the operands.  First see if any of them
11833965Sjdp	 have extraction functions, and, if they do, make sure the
11933965Sjdp	 instruction is valid.  */
12033965Sjdp      {
12133965Sjdp        int invalid = 0;
12233965Sjdp        for (opindex = opcode->operands; *opindex != 0; opindex++)
12333965Sjdp	  {
12433965Sjdp            const struct alpha_operand *operand = alpha_operands + *opindex;
12533965Sjdp	    if (operand->extract)
12633965Sjdp	      (*operand->extract) (insn, &invalid);
12733965Sjdp	  }
12833965Sjdp        if (invalid)
12933965Sjdp	  continue;
13033965Sjdp      }
13133965Sjdp
13233965Sjdp      /* The instruction is valid.  */
13333965Sjdp      goto found;
13433965Sjdp    }
13533965Sjdp
13633965Sjdp  /* No instruction found */
13733965Sjdp  (*info->fprintf_func) (info->stream, ".long %#08x", insn);
13833965Sjdp
13933965Sjdp  return 4;
14033965Sjdp
14133965Sjdpfound:
14233965Sjdp  (*info->fprintf_func) (info->stream, "%s", opcode->name);
14333965Sjdp  if (opcode->operands[0] != 0)
14433965Sjdp    (*info->fprintf_func) (info->stream, "\t");
14533965Sjdp
14633965Sjdp  /* Now extract and print the operands.  */
14733965Sjdp  need_comma = 0;
14833965Sjdp  for (opindex = opcode->operands; *opindex != 0; opindex++)
14933965Sjdp    {
15033965Sjdp      const struct alpha_operand *operand = alpha_operands + *opindex;
15133965Sjdp      int value;
15233965Sjdp
15333965Sjdp      /* Operands that are marked FAKE are simply ignored.  We
15433965Sjdp	 already made sure that the extract function considered
15533965Sjdp	 the instruction to be valid.  */
15633965Sjdp      if ((operand->flags & AXP_OPERAND_FAKE) != 0)
15733965Sjdp	continue;
15833965Sjdp
15933965Sjdp      /* Extract the value from the instruction.  */
16033965Sjdp      if (operand->extract)
16133965Sjdp	value = (*operand->extract) (insn, (int *) NULL);
16233965Sjdp      else
16333965Sjdp	{
16433965Sjdp	  value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
16533965Sjdp	  if (operand->flags & AXP_OPERAND_SIGNED)
16633965Sjdp	    {
16733965Sjdp	      int signbit = 1 << (operand->bits - 1);
16833965Sjdp	      value = (value ^ signbit) - signbit;
16933965Sjdp	    }
17033965Sjdp	}
17133965Sjdp
17233965Sjdp      if (need_comma &&
17333965Sjdp	  ((operand->flags & (AXP_OPERAND_PARENS|AXP_OPERAND_COMMA))
17433965Sjdp	   != AXP_OPERAND_PARENS))
17533965Sjdp	{
17633965Sjdp	  (*info->fprintf_func) (info->stream, ",");
17733965Sjdp	}
17833965Sjdp      if (operand->flags & AXP_OPERAND_PARENS)
17933965Sjdp	(*info->fprintf_func) (info->stream, "(");
18033965Sjdp
18133965Sjdp      /* Print the operand as directed by the flags.  */
18233965Sjdp      if (operand->flags & AXP_OPERAND_IR)
18333965Sjdp	(*info->fprintf_func) (info->stream, "%s", regnames[value]);
18433965Sjdp      else if (operand->flags & AXP_OPERAND_FPR)
18533965Sjdp	(*info->fprintf_func) (info->stream, "%s", regnames[value+32]);
18633965Sjdp      else if (operand->flags & AXP_OPERAND_RELATIVE)
18733965Sjdp	(*info->print_address_func) (memaddr + 4 + value, info);
18833965Sjdp      else if (operand->flags & AXP_OPERAND_SIGNED)
18933965Sjdp	(*info->fprintf_func) (info->stream, "%d", value);
19033965Sjdp      else
19133965Sjdp	(*info->fprintf_func) (info->stream, "%#x", value);
19233965Sjdp
19333965Sjdp      if (operand->flags & AXP_OPERAND_PARENS)
19433965Sjdp	(*info->fprintf_func) (info->stream, ")");
19533965Sjdp      need_comma = 1;
19633965Sjdp    }
19733965Sjdp
19833965Sjdp  return 4;
19933965Sjdp}
200