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