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