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