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