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