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