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