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 
6 This file is part of GDB, GAS, and the GNU binutils.
7 
8 GDB, GAS, and the GNU binutils are free software; you can redistribute
9 them and/or modify them under the terms of the GNU General Public
10 License as published by the Free Software Foundation; either version
11 2, or (at your option) any later version.
12 
13 GDB, GAS, and the GNU binutils are distributed in the hope that they
14 will be useful, but WITHOUT ANY WARRANTY; without even the implied
15 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
16 the GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with this file; see the file COPYING.  If not, write to the Free
20 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
21 02111-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 
30 static 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 
43 static 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 
56 int
57 print_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 
151 found:
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