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