133965Sjdp/* alpha-dis.c -- Disassemble Alpha AXP instructions 2218822Sdim Copyright 1996, 1998, 1999, 2000, 2001, 2002 3218822Sdim Free Software Foundation, Inc. 433965Sjdp Contributed by Richard Henderson <rth@tamu.edu>, 533965Sjdp patterned after the PPC opcode handling written by Ian Lance Taylor. 633965Sjdp 733965SjdpThis file is part of GDB, GAS, and the GNU binutils. 833965Sjdp 933965SjdpGDB, GAS, and the GNU binutils are free software; you can redistribute 1033965Sjdpthem and/or modify them under the terms of the GNU General Public 1133965SjdpLicense as published by the Free Software Foundation; either version 1233965Sjdp2, or (at your option) any later version. 1333965Sjdp 1433965SjdpGDB, GAS, and the GNU binutils are distributed in the hope that they 1533965Sjdpwill be useful, but WITHOUT ANY WARRANTY; without even the implied 1633965Sjdpwarranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 1733965Sjdpthe GNU General Public License for more details. 1833965Sjdp 1933965SjdpYou should have received a copy of the GNU General Public License 2033965Sjdpalong with this file; see the file COPYING. If not, write to the Free 21218822SdimSoftware Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 22218822Sdim02110-1301, USA. */ 2333965Sjdp 2433965Sjdp#include <stdio.h> 2533965Sjdp#include "sysdep.h" 2633965Sjdp#include "dis-asm.h" 2733965Sjdp#include "opcode/alpha.h" 2833965Sjdp 2933965Sjdp/* OSF register names. */ 3033965Sjdp 3189857Sobrienstatic const char * const osf_regnames[64] = { 3233965Sjdp "v0", "t0", "t1", "t2", "t3", "t4", "t5", "t6", 3333965Sjdp "t7", "s0", "s1", "s2", "s3", "s4", "s5", "fp", 3433965Sjdp "a0", "a1", "a2", "a3", "a4", "a5", "t8", "t9", 3533965Sjdp "t10", "t11", "ra", "t12", "at", "gp", "sp", "zero", 3633965Sjdp "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", 3733965Sjdp "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", 3833965Sjdp "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23", 3933965Sjdp "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31" 4033965Sjdp}; 4133965Sjdp 4233965Sjdp/* VMS register names. */ 4333965Sjdp 4489857Sobrienstatic const char * const vms_regnames[64] = { 4533965Sjdp "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", 4633965Sjdp "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15", 4733965Sjdp "R16", "R17", "R18", "R19", "R20", "R21", "R22", "R23", 4833965Sjdp "R24", "AI", "RA", "PV", "AT", "FP", "SP", "RZ", 4933965Sjdp "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", 5033965Sjdp "F8", "F9", "F10", "F11", "F12", "F13", "F14", "F15", 5133965Sjdp "F16", "F17", "F18", "F19", "F20", "F21", "F22", "F23", 5233965Sjdp "F24", "F25", "F26", "F27", "F28", "F29", "F30", "FZ" 5333965Sjdp}; 5433965Sjdp 5533965Sjdp/* Disassemble Alpha instructions. */ 5633965Sjdp 5733965Sjdpint 5833965Sjdpprint_insn_alpha (memaddr, info) 5933965Sjdp bfd_vma memaddr; 6033965Sjdp struct disassemble_info *info; 6133965Sjdp{ 6233965Sjdp static const struct alpha_opcode *opcode_index[AXP_NOPS+1]; 6333965Sjdp const char * const * regnames; 6433965Sjdp const struct alpha_opcode *opcode, *opcode_end; 6533965Sjdp const unsigned char *opindex; 6660484Sobrien unsigned insn, op, isa_mask; 6733965Sjdp int need_comma; 6833965Sjdp 6933965Sjdp /* Initialize the majorop table the first time through */ 7033965Sjdp if (!opcode_index[0]) 7133965Sjdp { 7233965Sjdp opcode = alpha_opcodes; 7333965Sjdp opcode_end = opcode + alpha_num_opcodes; 7433965Sjdp 7533965Sjdp for (op = 0; op < AXP_NOPS; ++op) 7689857Sobrien { 7789857Sobrien opcode_index[op] = opcode; 7889857Sobrien while (opcode < opcode_end && op == AXP_OP (opcode->opcode)) 7933965Sjdp ++opcode; 8089857Sobrien } 8133965Sjdp opcode_index[op] = opcode; 8233965Sjdp } 8333965Sjdp 8433965Sjdp if (info->flavour == bfd_target_evax_flavour) 8533965Sjdp regnames = vms_regnames; 8633965Sjdp else 8733965Sjdp regnames = osf_regnames; 8833965Sjdp 8960484Sobrien isa_mask = AXP_OPCODE_NOPAL; 9060484Sobrien switch (info->mach) 9160484Sobrien { 9260484Sobrien case bfd_mach_alpha_ev4: 9360484Sobrien isa_mask |= AXP_OPCODE_EV4; 9460484Sobrien break; 9560484Sobrien case bfd_mach_alpha_ev5: 9660484Sobrien isa_mask |= AXP_OPCODE_EV5; 9760484Sobrien break; 9860484Sobrien case bfd_mach_alpha_ev6: 9960484Sobrien isa_mask |= AXP_OPCODE_EV6; 10060484Sobrien break; 10160484Sobrien } 10260484Sobrien 10333965Sjdp /* Read the insn into a host word */ 10433965Sjdp { 10533965Sjdp bfd_byte buffer[4]; 10633965Sjdp int status = (*info->read_memory_func) (memaddr, buffer, 4, info); 10733965Sjdp if (status != 0) 10833965Sjdp { 10989857Sobrien (*info->memory_error_func) (status, memaddr, info); 11089857Sobrien return -1; 11133965Sjdp } 11233965Sjdp insn = bfd_getl32 (buffer); 11333965Sjdp } 11433965Sjdp 11533965Sjdp /* Get the major opcode of the instruction. */ 11633965Sjdp op = AXP_OP (insn); 11733965Sjdp 11833965Sjdp /* Find the first match in the opcode table. */ 11989857Sobrien opcode_end = opcode_index[op + 1]; 12033965Sjdp for (opcode = opcode_index[op]; opcode < opcode_end; ++opcode) 12133965Sjdp { 12289857Sobrien if ((insn ^ opcode->opcode) & opcode->mask) 12333965Sjdp continue; 12433965Sjdp 12560484Sobrien if (!(opcode->flags & isa_mask)) 12633965Sjdp continue; 12733965Sjdp 12833965Sjdp /* Make two passes over the operands. First see if any of them 12933965Sjdp have extraction functions, and, if they do, make sure the 13033965Sjdp instruction is valid. */ 13133965Sjdp { 13289857Sobrien int invalid = 0; 13389857Sobrien for (opindex = opcode->operands; *opindex != 0; opindex++) 13433965Sjdp { 13589857Sobrien const struct alpha_operand *operand = alpha_operands + *opindex; 13633965Sjdp if (operand->extract) 13733965Sjdp (*operand->extract) (insn, &invalid); 13833965Sjdp } 13989857Sobrien if (invalid) 14033965Sjdp continue; 14133965Sjdp } 14233965Sjdp 14333965Sjdp /* The instruction is valid. */ 14433965Sjdp goto found; 14533965Sjdp } 14633965Sjdp 14733965Sjdp /* No instruction found */ 14833965Sjdp (*info->fprintf_func) (info->stream, ".long %#08x", insn); 14989857Sobrien 15033965Sjdp return 4; 15133965Sjdp 15233965Sjdpfound: 15333965Sjdp (*info->fprintf_func) (info->stream, "%s", opcode->name); 15433965Sjdp if (opcode->operands[0] != 0) 15533965Sjdp (*info->fprintf_func) (info->stream, "\t"); 15633965Sjdp 15733965Sjdp /* Now extract and print the operands. */ 15833965Sjdp need_comma = 0; 15933965Sjdp for (opindex = opcode->operands; *opindex != 0; opindex++) 16033965Sjdp { 16133965Sjdp const struct alpha_operand *operand = alpha_operands + *opindex; 16233965Sjdp int value; 16333965Sjdp 16433965Sjdp /* Operands that are marked FAKE are simply ignored. We 16533965Sjdp already made sure that the extract function considered 16633965Sjdp the instruction to be valid. */ 16733965Sjdp if ((operand->flags & AXP_OPERAND_FAKE) != 0) 16833965Sjdp continue; 16933965Sjdp 17033965Sjdp /* Extract the value from the instruction. */ 17133965Sjdp if (operand->extract) 17233965Sjdp value = (*operand->extract) (insn, (int *) NULL); 17333965Sjdp else 17433965Sjdp { 17533965Sjdp value = (insn >> operand->shift) & ((1 << operand->bits) - 1); 17633965Sjdp if (operand->flags & AXP_OPERAND_SIGNED) 17733965Sjdp { 17833965Sjdp int signbit = 1 << (operand->bits - 1); 17933965Sjdp value = (value ^ signbit) - signbit; 18033965Sjdp } 18133965Sjdp } 18233965Sjdp 18333965Sjdp if (need_comma && 18489857Sobrien ((operand->flags & (AXP_OPERAND_PARENS | AXP_OPERAND_COMMA)) 18533965Sjdp != AXP_OPERAND_PARENS)) 18633965Sjdp { 18733965Sjdp (*info->fprintf_func) (info->stream, ","); 18833965Sjdp } 18933965Sjdp if (operand->flags & AXP_OPERAND_PARENS) 19033965Sjdp (*info->fprintf_func) (info->stream, "("); 19133965Sjdp 19233965Sjdp /* Print the operand as directed by the flags. */ 19333965Sjdp if (operand->flags & AXP_OPERAND_IR) 19433965Sjdp (*info->fprintf_func) (info->stream, "%s", regnames[value]); 19533965Sjdp else if (operand->flags & AXP_OPERAND_FPR) 19689857Sobrien (*info->fprintf_func) (info->stream, "%s", regnames[value + 32]); 19733965Sjdp else if (operand->flags & AXP_OPERAND_RELATIVE) 19833965Sjdp (*info->print_address_func) (memaddr + 4 + value, info); 19933965Sjdp else if (operand->flags & AXP_OPERAND_SIGNED) 20033965Sjdp (*info->fprintf_func) (info->stream, "%d", value); 20133965Sjdp else 20233965Sjdp (*info->fprintf_func) (info->stream, "%#x", value); 20333965Sjdp 20433965Sjdp if (operand->flags & AXP_OPERAND_PARENS) 20533965Sjdp (*info->fprintf_func) (info->stream, ")"); 20633965Sjdp need_comma = 1; 20733965Sjdp } 20833965Sjdp 20933965Sjdp return 4; 21033965Sjdp} 211