alpha-dis.c revision 78828
1/* alpha-dis.c -- Disassemble Alpha AXP instructions
2   Copyright 1996, 1998, 1999, 2000 Free Software Foundation, Inc.
3   Contributed by Richard Henderson <rth@tamu.edu>,
4   patterned after the PPC opcode handling written by Ian Lance Taylor.
5
6This file is part of GDB, GAS, and the GNU binutils.
7
8GDB, GAS, and the GNU binutils are free software; you can redistribute
9them and/or modify them under the terms of the GNU General Public
10License as published by the Free Software Foundation; either version
112, or (at your option) any later version.
12
13GDB, GAS, and the GNU binutils are distributed in the hope that they
14will be useful, but WITHOUT ANY WARRANTY; without even the implied
15warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
16the GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with this file; see the file COPYING.  If not, write to the Free
20Software Foundation, 59 Temple Place - Suite 330, Boston, MA
2102111-1307, USA.  */
22
23#include <stdio.h>
24#include "sysdep.h"
25#include "dis-asm.h"
26#include "opcode/alpha.h"
27
28/* OSF register names.  */
29
30static const char * const osf_regnames[64] =
31{
32  "v0", "t0", "t1", "t2", "t3", "t4", "t5", "t6",
33  "t7", "s0", "s1", "s2", "s3", "s4", "s5", "fp",
34  "a0", "a1", "a2", "a3", "a4", "a5", "t8", "t9",
35  "t10", "t11", "ra", "t12", "at", "gp", "sp", "zero",
36  "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7",
37  "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15",
38  "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",
39  "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31"
40};
41
42/* VMS register names.  */
43
44static const char * const vms_regnames[64] =
45{
46  "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7",
47  "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15",
48  "R16", "R17", "R18", "R19", "R20", "R21", "R22", "R23",
49  "R24", "AI", "RA", "PV", "AT", "FP", "SP", "RZ",
50  "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7",
51  "F8", "F9", "F10", "F11", "F12", "F13", "F14", "F15",
52  "F16", "F17", "F18", "F19", "F20", "F21", "F22", "F23",
53  "F24", "F25", "F26", "F27", "F28", "F29", "F30", "FZ"
54};
55
56/* Disassemble Alpha instructions.  */
57
58int
59print_insn_alpha (memaddr, info)
60     bfd_vma memaddr;
61     struct disassemble_info *info;
62{
63  static const struct alpha_opcode *opcode_index[AXP_NOPS+1];
64  const char * const * regnames;
65  const struct alpha_opcode *opcode, *opcode_end;
66  const unsigned char *opindex;
67  unsigned insn, op, isa_mask;
68  int need_comma;
69
70  /* Initialize the majorop table the first time through */
71  if (!opcode_index[0])
72    {
73      opcode = alpha_opcodes;
74      opcode_end = opcode + alpha_num_opcodes;
75
76      for (op = 0; op < AXP_NOPS; ++op)
77        {
78          opcode_index[op] = opcode;
79          while (opcode < opcode_end && op == AXP_OP (opcode->opcode))
80	    ++opcode;
81        }
82      opcode_index[op] = opcode;
83    }
84
85  if (info->flavour == bfd_target_evax_flavour)
86    regnames = vms_regnames;
87  else
88    regnames = osf_regnames;
89
90  isa_mask = AXP_OPCODE_NOPAL;
91  switch (info->mach)
92    {
93    case bfd_mach_alpha_ev4:
94      isa_mask |= AXP_OPCODE_EV4;
95      break;
96    case bfd_mach_alpha_ev5:
97      isa_mask |= AXP_OPCODE_EV5;
98      break;
99    case bfd_mach_alpha_ev6:
100      isa_mask |= AXP_OPCODE_EV6;
101      break;
102    }
103
104  /* Read the insn into a host word */
105  {
106    bfd_byte buffer[4];
107    int status = (*info->read_memory_func) (memaddr, buffer, 4, info);
108    if (status != 0)
109      {
110        (*info->memory_error_func) (status, memaddr, info);
111        return -1;
112      }
113    insn = bfd_getl32 (buffer);
114  }
115
116  /* Get the major opcode of the instruction.  */
117  op = AXP_OP (insn);
118
119  /* Find the first match in the opcode table.  */
120  opcode_end = opcode_index[op+1];
121  for (opcode = opcode_index[op]; opcode < opcode_end; ++opcode)
122    {
123      if ((insn & opcode->mask) != opcode->opcode)
124	continue;
125
126      if (!(opcode->flags & isa_mask))
127	continue;
128
129      /* Make two passes over the operands.  First see if any of them
130	 have extraction functions, and, if they do, make sure the
131	 instruction is valid.  */
132      {
133        int invalid = 0;
134        for (opindex = opcode->operands; *opindex != 0; opindex++)
135	  {
136            const struct alpha_operand *operand = alpha_operands + *opindex;
137	    if (operand->extract)
138	      (*operand->extract) (insn, &invalid);
139	  }
140        if (invalid)
141	  continue;
142      }
143
144      /* The instruction is valid.  */
145      goto found;
146    }
147
148  /* No instruction found */
149  (*info->fprintf_func) (info->stream, ".long %#08x", insn);
150
151  return 4;
152
153found:
154  (*info->fprintf_func) (info->stream, "%s", opcode->name);
155  if (opcode->operands[0] != 0)
156    (*info->fprintf_func) (info->stream, "\t");
157
158  /* Now extract and print the operands.  */
159  need_comma = 0;
160  for (opindex = opcode->operands; *opindex != 0; opindex++)
161    {
162      const struct alpha_operand *operand = alpha_operands + *opindex;
163      int value;
164
165      /* Operands that are marked FAKE are simply ignored.  We
166	 already made sure that the extract function considered
167	 the instruction to be valid.  */
168      if ((operand->flags & AXP_OPERAND_FAKE) != 0)
169	continue;
170
171      /* Extract the value from the instruction.  */
172      if (operand->extract)
173	value = (*operand->extract) (insn, (int *) NULL);
174      else
175	{
176	  value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
177	  if (operand->flags & AXP_OPERAND_SIGNED)
178	    {
179	      int signbit = 1 << (operand->bits - 1);
180	      value = (value ^ signbit) - signbit;
181	    }
182	}
183
184      if (need_comma &&
185	  ((operand->flags & (AXP_OPERAND_PARENS|AXP_OPERAND_COMMA))
186	   != AXP_OPERAND_PARENS))
187	{
188	  (*info->fprintf_func) (info->stream, ",");
189	}
190      if (operand->flags & AXP_OPERAND_PARENS)
191	(*info->fprintf_func) (info->stream, "(");
192
193      /* Print the operand as directed by the flags.  */
194      if (operand->flags & AXP_OPERAND_IR)
195	(*info->fprintf_func) (info->stream, "%s", regnames[value]);
196      else if (operand->flags & AXP_OPERAND_FPR)
197	(*info->fprintf_func) (info->stream, "%s", regnames[value+32]);
198      else if (operand->flags & AXP_OPERAND_RELATIVE)
199	(*info->print_address_func) (memaddr + 4 + value, info);
200      else if (operand->flags & AXP_OPERAND_SIGNED)
201	(*info->fprintf_func) (info->stream, "%d", value);
202      else
203	(*info->fprintf_func) (info->stream, "%#x", value);
204
205      if (operand->flags & AXP_OPERAND_PARENS)
206	(*info->fprintf_func) (info->stream, ")");
207      need_comma = 1;
208    }
209
210  return 4;
211}
212