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