Back to index

cell-binutils  2.17cvs20070401
alpha-dis.c
Go to the documentation of this file.
00001 /* alpha-dis.c -- Disassemble Alpha AXP instructions
00002    Copyright 1996, 1998, 1999, 2000, 2001, 2002
00003    Free Software Foundation, Inc.
00004    Contributed by Richard Henderson <rth@tamu.edu>,
00005    patterned after the PPC opcode handling written by Ian Lance Taylor.
00006 
00007 This file is part of GDB, GAS, and the GNU binutils.
00008 
00009 GDB, GAS, and the GNU binutils are free software; you can redistribute
00010 them and/or modify them under the terms of the GNU General Public
00011 License as published by the Free Software Foundation; either version
00012 2, or (at your option) any later version.
00013 
00014 GDB, GAS, and the GNU binutils are distributed in the hope that they
00015 will be useful, but WITHOUT ANY WARRANTY; without even the implied
00016 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
00017 the GNU General Public License for more details.
00018 
00019 You should have received a copy of the GNU General Public License
00020 along with this file; see the file COPYING.  If not, write to the Free
00021 Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
00022 02110-1301, USA.  */
00023 
00024 #include <stdio.h>
00025 #include "sysdep.h"
00026 #include "dis-asm.h"
00027 #include "opcode/alpha.h"
00028 
00029 /* OSF register names.  */
00030 
00031 static const char * const osf_regnames[64] = {
00032   "v0", "t0", "t1", "t2", "t3", "t4", "t5", "t6",
00033   "t7", "s0", "s1", "s2", "s3", "s4", "s5", "fp",
00034   "a0", "a1", "a2", "a3", "a4", "a5", "t8", "t9",
00035   "t10", "t11", "ra", "t12", "at", "gp", "sp", "zero",
00036   "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7",
00037   "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15",
00038   "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",
00039   "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31"
00040 };
00041 
00042 /* VMS register names.  */
00043 
00044 static const char * const vms_regnames[64] = {
00045   "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7",
00046   "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15",
00047   "R16", "R17", "R18", "R19", "R20", "R21", "R22", "R23",
00048   "R24", "AI", "RA", "PV", "AT", "FP", "SP", "RZ",
00049   "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7",
00050   "F8", "F9", "F10", "F11", "F12", "F13", "F14", "F15",
00051   "F16", "F17", "F18", "F19", "F20", "F21", "F22", "F23",
00052   "F24", "F25", "F26", "F27", "F28", "F29", "F30", "FZ"
00053 };
00054 
00055 /* Disassemble Alpha instructions.  */
00056 
00057 int
00058 print_insn_alpha (memaddr, info)
00059      bfd_vma memaddr;
00060      struct disassemble_info *info;
00061 {
00062   static const struct alpha_opcode *opcode_index[AXP_NOPS+1];
00063   const char * const * regnames;
00064   const struct alpha_opcode *opcode, *opcode_end;
00065   const unsigned char *opindex;
00066   unsigned insn, op, isa_mask;
00067   int need_comma;
00068 
00069   /* Initialize the majorop table the first time through */
00070   if (!opcode_index[0])
00071     {
00072       opcode = alpha_opcodes;
00073       opcode_end = opcode + alpha_num_opcodes;
00074 
00075       for (op = 0; op < AXP_NOPS; ++op)
00076        {
00077          opcode_index[op] = opcode;
00078          while (opcode < opcode_end && op == AXP_OP (opcode->opcode))
00079            ++opcode;
00080        }
00081       opcode_index[op] = opcode;
00082     }
00083 
00084   if (info->flavour == bfd_target_evax_flavour)
00085     regnames = vms_regnames;
00086   else
00087     regnames = osf_regnames;
00088 
00089   isa_mask = AXP_OPCODE_NOPAL;
00090   switch (info->mach)
00091     {
00092     case bfd_mach_alpha_ev4:
00093       isa_mask |= AXP_OPCODE_EV4;
00094       break;
00095     case bfd_mach_alpha_ev5:
00096       isa_mask |= AXP_OPCODE_EV5;
00097       break;
00098     case bfd_mach_alpha_ev6:
00099       isa_mask |= AXP_OPCODE_EV6;
00100       break;
00101     }
00102 
00103   /* Read the insn into a host word */
00104   {
00105     bfd_byte buffer[4];
00106     int status = (*info->read_memory_func) (memaddr, buffer, 4, info);
00107     if (status != 0)
00108       {
00109        (*info->memory_error_func) (status, memaddr, info);
00110        return -1;
00111       }
00112     insn = bfd_getl32 (buffer);
00113   }
00114 
00115   /* Get the major opcode of the instruction.  */
00116   op = AXP_OP (insn);
00117 
00118   /* Find the first match in the opcode table.  */
00119   opcode_end = opcode_index[op + 1];
00120   for (opcode = opcode_index[op]; opcode < opcode_end; ++opcode)
00121     {
00122       if ((insn ^ opcode->opcode) & opcode->mask)
00123        continue;
00124 
00125       if (!(opcode->flags & isa_mask))
00126        continue;
00127 
00128       /* Make two passes over the operands.  First see if any of them
00129         have extraction functions, and, if they do, make sure the
00130         instruction is valid.  */
00131       {
00132        int invalid = 0;
00133        for (opindex = opcode->operands; *opindex != 0; opindex++)
00134          {
00135            const struct alpha_operand *operand = alpha_operands + *opindex;
00136            if (operand->extract)
00137              (*operand->extract) (insn, &invalid);
00138          }
00139        if (invalid)
00140          continue;
00141       }
00142 
00143       /* The instruction is valid.  */
00144       goto found;
00145     }
00146 
00147   /* No instruction found */
00148   (*info->fprintf_func) (info->stream, ".long %#08x", insn);
00149 
00150   return 4;
00151 
00152 found:
00153   (*info->fprintf_func) (info->stream, "%s", opcode->name);
00154   if (opcode->operands[0] != 0)
00155     (*info->fprintf_func) (info->stream, "\t");
00156 
00157   /* Now extract and print the operands.  */
00158   need_comma = 0;
00159   for (opindex = opcode->operands; *opindex != 0; opindex++)
00160     {
00161       const struct alpha_operand *operand = alpha_operands + *opindex;
00162       int value;
00163 
00164       /* Operands that are marked FAKE are simply ignored.  We
00165         already made sure that the extract function considered
00166         the instruction to be valid.  */
00167       if ((operand->flags & AXP_OPERAND_FAKE) != 0)
00168        continue;
00169 
00170       /* Extract the value from the instruction.  */
00171       if (operand->extract)
00172        value = (*operand->extract) (insn, (int *) NULL);
00173       else
00174        {
00175          value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
00176          if (operand->flags & AXP_OPERAND_SIGNED)
00177            {
00178              int signbit = 1 << (operand->bits - 1);
00179              value = (value ^ signbit) - signbit;
00180            }
00181        }
00182 
00183       if (need_comma &&
00184          ((operand->flags & (AXP_OPERAND_PARENS | AXP_OPERAND_COMMA))
00185           != AXP_OPERAND_PARENS))
00186        {
00187          (*info->fprintf_func) (info->stream, ",");
00188        }
00189       if (operand->flags & AXP_OPERAND_PARENS)
00190        (*info->fprintf_func) (info->stream, "(");
00191 
00192       /* Print the operand as directed by the flags.  */
00193       if (operand->flags & AXP_OPERAND_IR)
00194        (*info->fprintf_func) (info->stream, "%s", regnames[value]);
00195       else if (operand->flags & AXP_OPERAND_FPR)
00196        (*info->fprintf_func) (info->stream, "%s", regnames[value + 32]);
00197       else if (operand->flags & AXP_OPERAND_RELATIVE)
00198        (*info->print_address_func) (memaddr + 4 + value, info);
00199       else if (operand->flags & AXP_OPERAND_SIGNED)
00200        (*info->fprintf_func) (info->stream, "%d", value);
00201       else
00202        (*info->fprintf_func) (info->stream, "%#x", value);
00203 
00204       if (operand->flags & AXP_OPERAND_PARENS)
00205        (*info->fprintf_func) (info->stream, ")");
00206       need_comma = 1;
00207     }
00208 
00209   return 4;
00210 }