xref: /openbsd-src/gnu/usr.bin/binutils/opcodes/alpha-dis.c (revision c074d1c999f3e07019cd5e9a2f190b057ef3b935)
10c6d0228Sniklas /* alpha-dis.c -- Disassemble Alpha AXP instructions
2*c074d1c9Sdrahn    Copyright 1996, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
30c6d0228Sniklas    Contributed by Richard Henderson <rth@tamu.edu>,
40c6d0228Sniklas    patterned after the PPC opcode handling written by Ian Lance Taylor.
52159047fSniklas 
60c6d0228Sniklas This file is part of GDB, GAS, and the GNU binutils.
72159047fSniklas 
80c6d0228Sniklas GDB, GAS, and the GNU binutils are free software; you can redistribute
90c6d0228Sniklas them and/or modify them under the terms of the GNU General Public
100c6d0228Sniklas License as published by the Free Software Foundation; either version
110c6d0228Sniklas 2, or (at your option) any later version.
122159047fSniklas 
130c6d0228Sniklas GDB, GAS, and the GNU binutils are distributed in the hope that they
140c6d0228Sniklas will be useful, but WITHOUT ANY WARRANTY; without even the implied
150c6d0228Sniklas warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
160c6d0228Sniklas the GNU General Public License for more details.
172159047fSniklas 
180c6d0228Sniklas You should have received a copy of the GNU General Public License
190c6d0228Sniklas along with this file; see the file COPYING.  If not, write to the Free
200c6d0228Sniklas Software Foundation, 59 Temple Place - Suite 330, Boston, MA
210c6d0228Sniklas 02111-1307, USA.  */
222159047fSniklas 
230c6d0228Sniklas #include <stdio.h>
240c6d0228Sniklas #include "sysdep.h"
252159047fSniklas #include "dis-asm.h"
260c6d0228Sniklas #include "opcode/alpha.h"
272159047fSniklas 
280c6d0228Sniklas /* OSF register names.  */
292159047fSniklas 
30*c074d1c9Sdrahn static const char * const osf_regnames[64] = {
310c6d0228Sniklas   "v0", "t0", "t1", "t2", "t3", "t4", "t5", "t6",
320c6d0228Sniklas   "t7", "s0", "s1", "s2", "s3", "s4", "s5", "fp",
330c6d0228Sniklas   "a0", "a1", "a2", "a3", "a4", "a5", "t8", "t9",
340c6d0228Sniklas   "t10", "t11", "ra", "t12", "at", "gp", "sp", "zero",
350c6d0228Sniklas   "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7",
360c6d0228Sniklas   "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15",
370c6d0228Sniklas   "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",
380c6d0228Sniklas   "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31"
390c6d0228Sniklas };
400c6d0228Sniklas 
410c6d0228Sniklas /* VMS register names.  */
420c6d0228Sniklas 
43*c074d1c9Sdrahn static const char * const vms_regnames[64] = {
440c6d0228Sniklas   "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7",
450c6d0228Sniklas   "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15",
460c6d0228Sniklas   "R16", "R17", "R18", "R19", "R20", "R21", "R22", "R23",
470c6d0228Sniklas   "R24", "AI", "RA", "PV", "AT", "FP", "SP", "RZ",
480c6d0228Sniklas   "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7",
490c6d0228Sniklas   "F8", "F9", "F10", "F11", "F12", "F13", "F14", "F15",
500c6d0228Sniklas   "F16", "F17", "F18", "F19", "F20", "F21", "F22", "F23",
510c6d0228Sniklas   "F24", "F25", "F26", "F27", "F28", "F29", "F30", "FZ"
520c6d0228Sniklas };
530c6d0228Sniklas 
540c6d0228Sniklas /* Disassemble Alpha instructions.  */
552159047fSniklas 
562159047fSniklas int
print_insn_alpha(memaddr,info)570c6d0228Sniklas print_insn_alpha (memaddr, info)
580c6d0228Sniklas      bfd_vma memaddr;
592159047fSniklas      struct disassemble_info *info;
602159047fSniklas {
610c6d0228Sniklas   static const struct alpha_opcode *opcode_index[AXP_NOPS+1];
620c6d0228Sniklas   const char * const * regnames;
630c6d0228Sniklas   const struct alpha_opcode *opcode, *opcode_end;
640c6d0228Sniklas   const unsigned char *opindex;
65b305b0f1Sespie   unsigned insn, op, isa_mask;
660c6d0228Sniklas   int need_comma;
672159047fSniklas 
680c6d0228Sniklas   /* Initialize the majorop table the first time through */
690c6d0228Sniklas   if (!opcode_index[0])
700c6d0228Sniklas     {
710c6d0228Sniklas       opcode = alpha_opcodes;
720c6d0228Sniklas       opcode_end = opcode + alpha_num_opcodes;
730c6d0228Sniklas 
740c6d0228Sniklas       for (op = 0; op < AXP_NOPS; ++op)
750c6d0228Sniklas 	{
760c6d0228Sniklas 	  opcode_index[op] = opcode;
770c6d0228Sniklas 	  while (opcode < opcode_end && op == AXP_OP (opcode->opcode))
780c6d0228Sniklas 	    ++opcode;
790c6d0228Sniklas 	}
800c6d0228Sniklas       opcode_index[op] = opcode;
810c6d0228Sniklas     }
820c6d0228Sniklas 
830c6d0228Sniklas   if (info->flavour == bfd_target_evax_flavour)
840c6d0228Sniklas     regnames = vms_regnames;
850c6d0228Sniklas   else
860c6d0228Sniklas     regnames = osf_regnames;
870c6d0228Sniklas 
88b305b0f1Sespie   isa_mask = AXP_OPCODE_NOPAL;
89b305b0f1Sespie   switch (info->mach)
90b305b0f1Sespie     {
91b305b0f1Sespie     case bfd_mach_alpha_ev4:
92b305b0f1Sespie       isa_mask |= AXP_OPCODE_EV4;
93b305b0f1Sespie       break;
94b305b0f1Sespie     case bfd_mach_alpha_ev5:
95b305b0f1Sespie       isa_mask |= AXP_OPCODE_EV5;
96b305b0f1Sespie       break;
97b305b0f1Sespie     case bfd_mach_alpha_ev6:
98b305b0f1Sespie       isa_mask |= AXP_OPCODE_EV6;
99b305b0f1Sespie       break;
100b305b0f1Sespie     }
101b305b0f1Sespie 
1020c6d0228Sniklas   /* Read the insn into a host word */
1030c6d0228Sniklas   {
1040c6d0228Sniklas     bfd_byte buffer[4];
1050c6d0228Sniklas     int status = (*info->read_memory_func) (memaddr, buffer, 4, info);
1060c6d0228Sniklas     if (status != 0)
1070c6d0228Sniklas       {
1080c6d0228Sniklas 	(*info->memory_error_func) (status, memaddr, info);
1092159047fSniklas 	return -1;
1102159047fSniklas       }
1110c6d0228Sniklas     insn = bfd_getl32 (buffer);
1122159047fSniklas   }
1132159047fSniklas 
1140c6d0228Sniklas   /* Get the major opcode of the instruction.  */
1150c6d0228Sniklas   op = AXP_OP (insn);
1162159047fSniklas 
1170c6d0228Sniklas   /* Find the first match in the opcode table.  */
1180c6d0228Sniklas   opcode_end = opcode_index[op + 1];
1190c6d0228Sniklas   for (opcode = opcode_index[op]; opcode < opcode_end; ++opcode)
1202159047fSniklas     {
121*c074d1c9Sdrahn       if ((insn ^ opcode->opcode) & opcode->mask)
1220c6d0228Sniklas 	continue;
1230c6d0228Sniklas 
124b305b0f1Sespie       if (!(opcode->flags & isa_mask))
1250c6d0228Sniklas 	continue;
1260c6d0228Sniklas 
1270c6d0228Sniklas       /* Make two passes over the operands.  First see if any of them
1280c6d0228Sniklas 	 have extraction functions, and, if they do, make sure the
1290c6d0228Sniklas 	 instruction is valid.  */
1302159047fSniklas       {
1310c6d0228Sniklas 	int invalid = 0;
1320c6d0228Sniklas 	for (opindex = opcode->operands; *opindex != 0; opindex++)
1330c6d0228Sniklas 	  {
1340c6d0228Sniklas 	    const struct alpha_operand *operand = alpha_operands + *opindex;
1350c6d0228Sniklas 	    if (operand->extract)
1360c6d0228Sniklas 	      (*operand->extract) (insn, &invalid);
1372159047fSniklas 	  }
1380c6d0228Sniklas 	if (invalid)
1390c6d0228Sniklas 	  continue;
1402159047fSniklas       }
1412159047fSniklas 
1420c6d0228Sniklas       /* The instruction is valid.  */
1430c6d0228Sniklas       goto found;
1442159047fSniklas     }
1452159047fSniklas 
1460c6d0228Sniklas   /* No instruction found */
1470c6d0228Sniklas   (*info->fprintf_func) (info->stream, ".long %#08x", insn);
1480c6d0228Sniklas 
1490c6d0228Sniklas   return 4;
1500c6d0228Sniklas 
1510c6d0228Sniklas found:
1520c6d0228Sniklas   (*info->fprintf_func) (info->stream, "%s", opcode->name);
1530c6d0228Sniklas   if (opcode->operands[0] != 0)
1540c6d0228Sniklas     (*info->fprintf_func) (info->stream, "\t");
1550c6d0228Sniklas 
1560c6d0228Sniklas   /* Now extract and print the operands.  */
1570c6d0228Sniklas   need_comma = 0;
1580c6d0228Sniklas   for (opindex = opcode->operands; *opindex != 0; opindex++)
1592159047fSniklas     {
1600c6d0228Sniklas       const struct alpha_operand *operand = alpha_operands + *opindex;
1610c6d0228Sniklas       int value;
1620c6d0228Sniklas 
1630c6d0228Sniklas       /* Operands that are marked FAKE are simply ignored.  We
1640c6d0228Sniklas 	 already made sure that the extract function considered
1650c6d0228Sniklas 	 the instruction to be valid.  */
1660c6d0228Sniklas       if ((operand->flags & AXP_OPERAND_FAKE) != 0)
1670c6d0228Sniklas 	continue;
1680c6d0228Sniklas 
1690c6d0228Sniklas       /* Extract the value from the instruction.  */
1700c6d0228Sniklas       if (operand->extract)
1710c6d0228Sniklas 	value = (*operand->extract) (insn, (int *) NULL);
1722159047fSniklas       else
1732159047fSniklas 	{
1740c6d0228Sniklas 	  value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
1750c6d0228Sniklas 	  if (operand->flags & AXP_OPERAND_SIGNED)
1760c6d0228Sniklas 	    {
1770c6d0228Sniklas 	      int signbit = 1 << (operand->bits - 1);
1780c6d0228Sniklas 	      value = (value ^ signbit) - signbit;
1792159047fSniklas 	    }
1802159047fSniklas 	}
1812159047fSniklas 
1820c6d0228Sniklas       if (need_comma &&
1830c6d0228Sniklas 	  ((operand->flags & (AXP_OPERAND_PARENS | AXP_OPERAND_COMMA))
1840c6d0228Sniklas 	   != AXP_OPERAND_PARENS))
1852159047fSniklas 	{
1860c6d0228Sniklas 	  (*info->fprintf_func) (info->stream, ",");
1872159047fSniklas 	}
1880c6d0228Sniklas       if (operand->flags & AXP_OPERAND_PARENS)
1890c6d0228Sniklas 	(*info->fprintf_func) (info->stream, "(");
1900c6d0228Sniklas 
1910c6d0228Sniklas       /* Print the operand as directed by the flags.  */
1920c6d0228Sniklas       if (operand->flags & AXP_OPERAND_IR)
1930c6d0228Sniklas 	(*info->fprintf_func) (info->stream, "%s", regnames[value]);
1940c6d0228Sniklas       else if (operand->flags & AXP_OPERAND_FPR)
1950c6d0228Sniklas 	(*info->fprintf_func) (info->stream, "%s", regnames[value + 32]);
1960c6d0228Sniklas       else if (operand->flags & AXP_OPERAND_RELATIVE)
1970c6d0228Sniklas 	(*info->print_address_func) (memaddr + 4 + value, info);
1980c6d0228Sniklas       else if (operand->flags & AXP_OPERAND_SIGNED)
1990c6d0228Sniklas 	(*info->fprintf_func) (info->stream, "%d", value);
2002159047fSniklas       else
2010c6d0228Sniklas 	(*info->fprintf_func) (info->stream, "%#x", value);
2022159047fSniklas 
2030c6d0228Sniklas       if (operand->flags & AXP_OPERAND_PARENS)
2040c6d0228Sniklas 	(*info->fprintf_func) (info->stream, ")");
2050c6d0228Sniklas       need_comma = 1;
2062159047fSniklas     }
2072159047fSniklas 
2082159047fSniklas   return 4;
2092159047fSniklas }
210