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