12a6b7db3Sskrll /* alpha-dis.c -- Disassemble Alpha AXP instructions
2*f22f0ef4Schristos    Copyright (C) 1996-2022 Free Software Foundation, Inc.
32a6b7db3Sskrll    Contributed by Richard Henderson <rth@tamu.edu>,
42a6b7db3Sskrll    patterned after the PPC opcode handling written by Ian Lance Taylor.
52a6b7db3Sskrll 
62a6b7db3Sskrll    This file is part of libopcodes.
72a6b7db3Sskrll 
82a6b7db3Sskrll    This library is free software; you can redistribute it and/or modify
92a6b7db3Sskrll    it under the terms of the GNU General Public License as published by
102a6b7db3Sskrll    the Free Software Foundation; either version 3, or (at your option)
112a6b7db3Sskrll    any later version.
122a6b7db3Sskrll 
132a6b7db3Sskrll    It is distributed in the hope that it will be useful, but WITHOUT
142a6b7db3Sskrll    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
152a6b7db3Sskrll    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
162a6b7db3Sskrll    License for more details.
172a6b7db3Sskrll 
182a6b7db3Sskrll    You should have received a copy of the GNU General Public License
192a6b7db3Sskrll    along with this file; see the file COPYING.  If not, write to the Free
202a6b7db3Sskrll    Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
212a6b7db3Sskrll    02110-1301, USA.  */
222a6b7db3Sskrll 
232a6b7db3Sskrll #include "sysdep.h"
2405caefcfSchristos #include <stdio.h>
2598f124a6Schristos #include "disassemble.h"
262a6b7db3Sskrll #include "opcode/alpha.h"
272a6b7db3Sskrll 
282a6b7db3Sskrll /* OSF register names.  */
292a6b7db3Sskrll 
302a6b7db3Sskrll static const char * const osf_regnames[64] = {
312a6b7db3Sskrll   "v0", "t0", "t1", "t2", "t3", "t4", "t5", "t6",
322a6b7db3Sskrll   "t7", "s0", "s1", "s2", "s3", "s4", "s5", "fp",
332a6b7db3Sskrll   "a0", "a1", "a2", "a3", "a4", "a5", "t8", "t9",
342a6b7db3Sskrll   "t10", "t11", "ra", "t12", "at", "gp", "sp", "zero",
352a6b7db3Sskrll   "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7",
362a6b7db3Sskrll   "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15",
372a6b7db3Sskrll   "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",
382a6b7db3Sskrll   "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31"
392a6b7db3Sskrll };
402a6b7db3Sskrll 
412a6b7db3Sskrll /* VMS register names.  */
422a6b7db3Sskrll 
432a6b7db3Sskrll static const char * const vms_regnames[64] = {
442a6b7db3Sskrll   "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7",
452a6b7db3Sskrll   "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15",
462a6b7db3Sskrll   "R16", "R17", "R18", "R19", "R20", "R21", "R22", "R23",
472a6b7db3Sskrll   "R24", "AI", "RA", "PV", "AT", "FP", "SP", "RZ",
482a6b7db3Sskrll   "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7",
492a6b7db3Sskrll   "F8", "F9", "F10", "F11", "F12", "F13", "F14", "F15",
502a6b7db3Sskrll   "F16", "F17", "F18", "F19", "F20", "F21", "F22", "F23",
512a6b7db3Sskrll   "F24", "F25", "F26", "F27", "F28", "F29", "F30", "FZ"
522a6b7db3Sskrll };
532a6b7db3Sskrll 
542a6b7db3Sskrll /* Disassemble Alpha instructions.  */
552a6b7db3Sskrll 
562a6b7db3Sskrll int
print_insn_alpha(bfd_vma memaddr,struct disassemble_info * info)5775f9f1baSchristos print_insn_alpha (bfd_vma memaddr, struct disassemble_info *info)
582a6b7db3Sskrll {
592a6b7db3Sskrll   static const struct alpha_opcode *opcode_index[AXP_NOPS+1];
602a6b7db3Sskrll   const char * const * regnames;
612a6b7db3Sskrll   const struct alpha_opcode *opcode, *opcode_end;
622a6b7db3Sskrll   const unsigned char *opindex;
632a6b7db3Sskrll   unsigned insn, op, isa_mask;
642a6b7db3Sskrll   int need_comma;
652a6b7db3Sskrll 
662a6b7db3Sskrll   /* Initialize the majorop table the first time through */
672a6b7db3Sskrll   if (!opcode_index[0])
682a6b7db3Sskrll     {
692a6b7db3Sskrll       opcode = alpha_opcodes;
702a6b7db3Sskrll       opcode_end = opcode + alpha_num_opcodes;
712a6b7db3Sskrll 
722a6b7db3Sskrll       for (op = 0; op < AXP_NOPS; ++op)
732a6b7db3Sskrll 	{
742a6b7db3Sskrll 	  opcode_index[op] = opcode;
752a6b7db3Sskrll 	  while (opcode < opcode_end && op == AXP_OP (opcode->opcode))
762a6b7db3Sskrll 	    ++opcode;
772a6b7db3Sskrll 	}
782a6b7db3Sskrll       opcode_index[op] = opcode;
792a6b7db3Sskrll     }
802a6b7db3Sskrll 
812a6b7db3Sskrll   if (info->flavour == bfd_target_evax_flavour)
822a6b7db3Sskrll     regnames = vms_regnames;
832a6b7db3Sskrll   else
842a6b7db3Sskrll     regnames = osf_regnames;
852a6b7db3Sskrll 
862a6b7db3Sskrll   isa_mask = AXP_OPCODE_NOPAL;
872a6b7db3Sskrll   switch (info->mach)
882a6b7db3Sskrll     {
892a6b7db3Sskrll     case bfd_mach_alpha_ev4:
902a6b7db3Sskrll       isa_mask |= AXP_OPCODE_EV4;
912a6b7db3Sskrll       break;
922a6b7db3Sskrll     case bfd_mach_alpha_ev5:
932a6b7db3Sskrll       isa_mask |= AXP_OPCODE_EV5;
942a6b7db3Sskrll       break;
952a6b7db3Sskrll     case bfd_mach_alpha_ev6:
962a6b7db3Sskrll       isa_mask |= AXP_OPCODE_EV6;
972a6b7db3Sskrll       break;
982a6b7db3Sskrll     }
992a6b7db3Sskrll 
1002a6b7db3Sskrll   /* Read the insn into a host word */
1012a6b7db3Sskrll   {
1022a6b7db3Sskrll     bfd_byte buffer[4];
1032a6b7db3Sskrll     int status = (*info->read_memory_func) (memaddr, buffer, 4, info);
1042a6b7db3Sskrll     if (status != 0)
1052a6b7db3Sskrll       {
1062a6b7db3Sskrll 	(*info->memory_error_func) (status, memaddr, info);
1072a6b7db3Sskrll 	return -1;
1082a6b7db3Sskrll       }
1092a6b7db3Sskrll     insn = bfd_getl32 (buffer);
1102a6b7db3Sskrll   }
1112a6b7db3Sskrll 
1122a6b7db3Sskrll   /* Get the major opcode of the instruction.  */
1132a6b7db3Sskrll   op = AXP_OP (insn);
1142a6b7db3Sskrll 
1152a6b7db3Sskrll   /* Find the first match in the opcode table.  */
1162a6b7db3Sskrll   opcode_end = opcode_index[op + 1];
1172a6b7db3Sskrll   for (opcode = opcode_index[op]; opcode < opcode_end; ++opcode)
1182a6b7db3Sskrll     {
1192a6b7db3Sskrll       if ((insn ^ opcode->opcode) & opcode->mask)
1202a6b7db3Sskrll 	continue;
1212a6b7db3Sskrll 
1222a6b7db3Sskrll       if (!(opcode->flags & isa_mask))
1232a6b7db3Sskrll 	continue;
1242a6b7db3Sskrll 
1252a6b7db3Sskrll       /* Make two passes over the operands.  First see if any of them
1262a6b7db3Sskrll 	 have extraction functions, and, if they do, make sure the
1272a6b7db3Sskrll 	 instruction is valid.  */
1282a6b7db3Sskrll       {
1292a6b7db3Sskrll 	int invalid = 0;
1302a6b7db3Sskrll 	for (opindex = opcode->operands; *opindex != 0; opindex++)
1312a6b7db3Sskrll 	  {
1322a6b7db3Sskrll 	    const struct alpha_operand *operand = alpha_operands + *opindex;
1332a6b7db3Sskrll 	    if (operand->extract)
1342a6b7db3Sskrll 	      (*operand->extract) (insn, &invalid);
1352a6b7db3Sskrll 	  }
1362a6b7db3Sskrll 	if (invalid)
1372a6b7db3Sskrll 	  continue;
1382a6b7db3Sskrll       }
1392a6b7db3Sskrll 
1402a6b7db3Sskrll       /* The instruction is valid.  */
1412a6b7db3Sskrll       goto found;
1422a6b7db3Sskrll     }
1432a6b7db3Sskrll 
1442a6b7db3Sskrll   /* No instruction found */
1452a6b7db3Sskrll   (*info->fprintf_func) (info->stream, ".long %#08x", insn);
1462a6b7db3Sskrll 
1472a6b7db3Sskrll   return 4;
1482a6b7db3Sskrll 
1492a6b7db3Sskrll  found:
1502a6b7db3Sskrll   (*info->fprintf_func) (info->stream, "%s", opcode->name);
1512a6b7db3Sskrll   if (opcode->operands[0] != 0)
1522a6b7db3Sskrll     (*info->fprintf_func) (info->stream, "\t");
1532a6b7db3Sskrll 
1542a6b7db3Sskrll   /* Now extract and print the operands.  */
1552a6b7db3Sskrll   need_comma = 0;
1562a6b7db3Sskrll   for (opindex = opcode->operands; *opindex != 0; opindex++)
1572a6b7db3Sskrll     {
1582a6b7db3Sskrll       const struct alpha_operand *operand = alpha_operands + *opindex;
1592a6b7db3Sskrll       int value;
1602a6b7db3Sskrll 
1612a6b7db3Sskrll       /* Operands that are marked FAKE are simply ignored.  We
1622a6b7db3Sskrll 	 already made sure that the extract function considered
1632a6b7db3Sskrll 	 the instruction to be valid.  */
1642a6b7db3Sskrll       if ((operand->flags & AXP_OPERAND_FAKE) != 0)
1652a6b7db3Sskrll 	continue;
1662a6b7db3Sskrll 
1672a6b7db3Sskrll       /* Extract the value from the instruction.  */
1682a6b7db3Sskrll       if (operand->extract)
1692a6b7db3Sskrll 	value = (*operand->extract) (insn, (int *) NULL);
1702a6b7db3Sskrll       else
1712a6b7db3Sskrll 	{
1722a6b7db3Sskrll 	  value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
1732a6b7db3Sskrll 	  if (operand->flags & AXP_OPERAND_SIGNED)
1742a6b7db3Sskrll 	    {
1752a6b7db3Sskrll 	      int signbit = 1 << (operand->bits - 1);
1762a6b7db3Sskrll 	      value = (value ^ signbit) - signbit;
1772a6b7db3Sskrll 	    }
1782a6b7db3Sskrll 	}
1792a6b7db3Sskrll 
1802a6b7db3Sskrll       if (need_comma &&
1812a6b7db3Sskrll 	  ((operand->flags & (AXP_OPERAND_PARENS | AXP_OPERAND_COMMA))
1822a6b7db3Sskrll 	   != AXP_OPERAND_PARENS))
1832a6b7db3Sskrll 	{
1842a6b7db3Sskrll 	  (*info->fprintf_func) (info->stream, ",");
1852a6b7db3Sskrll 	}
1862a6b7db3Sskrll       if (operand->flags & AXP_OPERAND_PARENS)
1872a6b7db3Sskrll 	(*info->fprintf_func) (info->stream, "(");
1882a6b7db3Sskrll 
1892a6b7db3Sskrll       /* Print the operand as directed by the flags.  */
1902a6b7db3Sskrll       if (operand->flags & AXP_OPERAND_IR)
1912a6b7db3Sskrll 	(*info->fprintf_func) (info->stream, "%s", regnames[value]);
1922a6b7db3Sskrll       else if (operand->flags & AXP_OPERAND_FPR)
1932a6b7db3Sskrll 	(*info->fprintf_func) (info->stream, "%s", regnames[value + 32]);
1942a6b7db3Sskrll       else if (operand->flags & AXP_OPERAND_RELATIVE)
1952a6b7db3Sskrll 	(*info->print_address_func) (memaddr + 4 + value, info);
1962a6b7db3Sskrll       else if (operand->flags & AXP_OPERAND_SIGNED)
1972a6b7db3Sskrll 	(*info->fprintf_func) (info->stream, "%d", value);
1982a6b7db3Sskrll       else
1992a6b7db3Sskrll 	(*info->fprintf_func) (info->stream, "%#x", value);
2002a6b7db3Sskrll 
2012a6b7db3Sskrll       if (operand->flags & AXP_OPERAND_PARENS)
2022a6b7db3Sskrll 	(*info->fprintf_func) (info->stream, ")");
2032a6b7db3Sskrll       need_comma = 1;
2042a6b7db3Sskrll     }
2052a6b7db3Sskrll 
2062a6b7db3Sskrll   return 4;
2072a6b7db3Sskrll }
208