1 /* alpha-dis.c -- Disassemble Alpha AXP instructions
2    Copyright 1996, 1999 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 {
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 {
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 
58 int
59 print_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 
153 found:
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