150477Speter/* alpha-dis.c -- Disassemble Alpha AXP instructions
21817Sdg   Copyright (C) 1996-2017 Free Software Foundation, Inc.
31817Sdg   Contributed by Richard Henderson <rth@tamu.edu>,
41541Srgrimes   patterned after the PPC opcode handling written by Ian Lance Taylor.
51541Srgrimes
61541Srgrimes   This file is part of libopcodes.
7160798Sjhb
81541Srgrimes   This library is free software; you can redistribute it and/or modify
9146806Srwatson   it under the terms of the GNU General Public License as published by
10146806Srwatson   the Free Software Foundation; either version 3, or (at your option)
11146806Srwatson   any later version.
12146806Srwatson
13146806Srwatson   It is distributed in the hope that it will be useful, but WITHOUT
14160798Sjhb   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15160798Sjhb   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
1611294Sswallace   License for more details.
1710905Sbde
181541Srgrimes   You should have received a copy of the GNU General Public License
1910905Sbde   along with this file; see the file COPYING.  If not, write to the Free
2010905Sbde   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
211541Srgrimes   02110-1301, USA.  */
221541Srgrimes
231541Srgrimes#include "sysdep.h"
241541Srgrimes#include <stdio.h>
251541Srgrimes#include "dis-asm.h"
2699855Salfred#include "opcode/alpha.h"
271541Srgrimes
281541Srgrimes/* OSF register names.  */
291541Srgrimes
3069449Salfredstatic const char * const osf_regnames[64] = {
31160797Sjhb  "v0", "t0", "t1", "t2", "t3", "t4", "t5", "t6",
32160797Sjhb  "t7", "s0", "s1", "s2", "s3", "s4", "s5", "fp",
33104747Srwatson  "a0", "a1", "a2", "a3", "a4", "a5", "t8", "t9",
34104747Srwatson  "t10", "t11", "ra", "t12", "at", "gp", "sp", "zero",
35123408Speter  "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7",
36123408Speter  "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15",
371541Srgrimes  "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",
381541Srgrimes  "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31"
3911294Sswallace};
4011294Sswallace
4111294Sswallace/* VMS register names.  */
4211294Sswallace
431541Srgrimesstatic const char * const vms_regnames[64] = {
441541Srgrimes  "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7",
451541Srgrimes  "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15",
461541Srgrimes  "R16", "R17", "R18", "R19", "R20", "R21", "R22", "R23",
471541Srgrimes  "R24", "AI", "RA", "PV", "AT", "FP", "SP", "RZ",
481541Srgrimes  "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7",
49160798Sjhb  "F8", "F9", "F10", "F11", "F12", "F13", "F14", "F15",
50160798Sjhb  "F16", "F17", "F18", "F19", "F20", "F21", "F22", "F23",
51146806Srwatson  "F24", "F25", "F26", "F27", "F28", "F29", "F30", "FZ"
52160798Sjhb};
53160798Sjhb
54146806Srwatson/* Disassemble Alpha instructions.  */
55160798Sjhb
56146806Srwatsonint
57160798Sjhbprint_insn_alpha (bfd_vma memaddr, struct disassemble_info *info)
5812216Sbde{
5912216Sbde  static const struct alpha_opcode *opcode_index[AXP_NOPS+1];
6012216Sbde  const char * const * regnames;
61160798Sjhb  const struct alpha_opcode *opcode, *opcode_end;
62160798Sjhb  const unsigned char *opindex;
63146806Srwatson  unsigned insn, op, isa_mask;
64146806Srwatson  int need_comma;
65160798Sjhb
66160798Sjhb  /* Initialize the majorop table the first time through */
67160798Sjhb  if (!opcode_index[0])
68146806Srwatson    {
69160798Sjhb      opcode = alpha_opcodes;
70160798Sjhb      opcode_end = opcode + alpha_num_opcodes;
71160798Sjhb
72160798Sjhb      for (op = 0; op < AXP_NOPS; ++op)
73160798Sjhb	{
74160798Sjhb	  opcode_index[op] = opcode;
75146806Srwatson	  while (opcode < opcode_end && op == AXP_OP (opcode->opcode))
76160798Sjhb	    ++opcode;
77146806Srwatson	}
78160798Sjhb      opcode_index[op] = opcode;
79146806Srwatson    }
80160798Sjhb
81160798Sjhb  if (info->flavour == bfd_target_evax_flavour)
82146806Srwatson    regnames = vms_regnames;
8312216Sbde  else
84160798Sjhb    regnames = osf_regnames;
85160798Sjhb
86160798Sjhb  isa_mask = AXP_OPCODE_NOPAL;
87160798Sjhb  switch (info->mach)
88160798Sjhb    {
89146806Srwatson    case bfd_mach_alpha_ev4:
90160798Sjhb      isa_mask |= AXP_OPCODE_EV4;
91146806Srwatson      break;
92160798Sjhb    case bfd_mach_alpha_ev5:
93146806Srwatson      isa_mask |= AXP_OPCODE_EV5;
94160798Sjhb      break;
95146806Srwatson    case bfd_mach_alpha_ev6:
96146806Srwatson      isa_mask |= AXP_OPCODE_EV6;
97146806Srwatson      break;
98160798Sjhb    }
99146806Srwatson
100146806Srwatson  /* Read the insn into a host word */
101160798Sjhb  {
102146806Srwatson    bfd_byte buffer[4];
103146806Srwatson    int status = (*info->read_memory_func) (memaddr, buffer, 4, info);
104160798Sjhb    if (status != 0)
105146806Srwatson      {
106146806Srwatson	(*info->memory_error_func) (status, memaddr, info);
107160798Sjhb	return -1;
108160798Sjhb      }
109160798Sjhb    insn = bfd_getl32 (buffer);
110160798Sjhb  }
111160798Sjhb
112160798Sjhb  /* Get the major opcode of the instruction.  */
113160798Sjhb  op = AXP_OP (insn);
114160798Sjhb
115160798Sjhb  /* Find the first match in the opcode table.  */
116160798Sjhb  opcode_end = opcode_index[op + 1];
117160798Sjhb  for (opcode = opcode_index[op]; opcode < opcode_end; ++opcode)
118160798Sjhb    {
119146806Srwatson      if ((insn ^ opcode->opcode) & opcode->mask)
120160798Sjhb	continue;
121146806Srwatson
122160798Sjhb      if (!(opcode->flags & isa_mask))
123146806Srwatson	continue;
124146806Srwatson
125160798Sjhb      /* Make two passes over the operands.  First see if any of them
126160798Sjhb	 have extraction functions, and, if they do, make sure the
12721776Sbde	 instruction is valid.  */
12821776Sbde      {
12921776Sbde	int invalid = 0;
130160798Sjhb	for (opindex = opcode->operands; *opindex != 0; opindex++)
131146806Srwatson	  {
132160798Sjhb	    const struct alpha_operand *operand = alpha_operands + *opindex;
133160798Sjhb	    if (operand->extract)
134160798Sjhb	      (*operand->extract) (insn, &invalid);
135160798Sjhb	  }
136146806Srwatson	if (invalid)
137160798Sjhb	  continue;
138146806Srwatson      }
139160798Sjhb
140160798Sjhb      /* The instruction is valid.  */
141160798Sjhb      goto found;
142160798Sjhb    }
143146806Srwatson
144160798Sjhb  /* No instruction found */
145146806Srwatson  (*info->fprintf_func) (info->stream, ".long %#08x", insn);
146160798Sjhb
147146806Srwatson  return 4;
148160798Sjhb
149160798Sjhbfound:
150160798Sjhb  (*info->fprintf_func) (info->stream, "%s", opcode->name);
151146806Srwatson  if (opcode->operands[0] != 0)
152146806Srwatson    (*info->fprintf_func) (info->stream, "\t");
153160798Sjhb
154146806Srwatson  /* Now extract and print the operands.  */
155160798Sjhb  need_comma = 0;
156146806Srwatson  for (opindex = opcode->operands; *opindex != 0; opindex++)
157160798Sjhb    {
158146806Srwatson      const struct alpha_operand *operand = alpha_operands + *opindex;
159146806Srwatson      int value;
160160798Sjhb
161160798Sjhb      /* Operands that are marked FAKE are simply ignored.  We
162160798Sjhb	 already made sure that the extract function considered
163146806Srwatson	 the instruction to be valid.  */
164160798Sjhb      if ((operand->flags & AXP_OPERAND_FAKE) != 0)
165146806Srwatson	continue;
166160798Sjhb
167160798Sjhb      /* Extract the value from the instruction.  */
168146806Srwatson      if (operand->extract)
169160798Sjhb	value = (*operand->extract) (insn, (int *) NULL);
170146806Srwatson      else
171146806Srwatson	{
172146806Srwatson	  value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
173160798Sjhb	  if (operand->flags & AXP_OPERAND_SIGNED)
174146806Srwatson	    {
175160798Sjhb	      int signbit = 1 << (operand->bits - 1);
176146806Srwatson	      value = (value ^ signbit) - signbit;
177160798Sjhb	    }
178146806Srwatson	}
179160798Sjhb
180160798Sjhb      if (need_comma &&
181160798Sjhb	  ((operand->flags & (AXP_OPERAND_PARENS | AXP_OPERAND_COMMA))
182146806Srwatson	   != AXP_OPERAND_PARENS))
183160798Sjhb	{
184160798Sjhb	  (*info->fprintf_func) (info->stream, ",");
185160798Sjhb	}
186146806Srwatson      if (operand->flags & AXP_OPERAND_PARENS)
187160798Sjhb	(*info->fprintf_func) (info->stream, "(");
188146806Srwatson
189146806Srwatson      /* Print the operand as directed by the flags.  */
190160798Sjhb      if (operand->flags & AXP_OPERAND_IR)
191146806Srwatson	(*info->fprintf_func) (info->stream, "%s", regnames[value]);
192146806Srwatson      else if (operand->flags & AXP_OPERAND_FPR)
193160798Sjhb	(*info->fprintf_func) (info->stream, "%s", regnames[value + 32]);
194160798Sjhb      else if (operand->flags & AXP_OPERAND_RELATIVE)
195146806Srwatson	(*info->print_address_func) (memaddr + 4 + value, info);
196160798Sjhb      else if (operand->flags & AXP_OPERAND_SIGNED)
197123750Speter	(*info->fprintf_func) (info->stream, "%d", value);
19812216Sbde      else
199160798Sjhb	(*info->fprintf_func) (info->stream, "%#x", value);
200146806Srwatson
201146806Srwatson      if (operand->flags & AXP_OPERAND_PARENS)
202160798Sjhb	(*info->fprintf_func) (info->stream, ")");
203160798Sjhb      need_comma = 1;
204146806Srwatson    }
205160798Sjhb
206146806Srwatson  return 4;
207160798Sjhb}
208146806Srwatson