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