Back to index

cell-binutils  2.17cvs20070401
spu-dis.c
Go to the documentation of this file.
00001 /* Disassemble SPU instructions
00002 
00003    Copyright 2006 Free Software Foundation, Inc.
00004 
00005    This file is part of GDB, GAS, and the GNU binutils.
00006 
00007    This program is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License as published by
00009    the Free Software Foundation; either version 2 of the License, or
00010    (at your option) any later version.
00011 
00012    This program is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015    GNU General Public License for more details.
00016 
00017    You should have received a copy of the GNU General Public License along
00018    with this program; if not, write to the Free Software Foundation, Inc.,
00019    51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
00020 
00021 #include <stdio.h>
00022 #include "sysdep.h"
00023 #include "dis-asm.h"
00024 #include "opcode/spu.h"
00025 
00026 /* This file provides a disassembler function which uses
00027    the disassembler interface defined in dis-asm.h.   */
00028 
00029 extern const struct spu_opcode spu_opcodes[];
00030 extern const int spu_num_opcodes;
00031 
00032 static const struct spu_opcode *spu_disassemble_table[(1<<11)];
00033 
00034 static void
00035 init_spu_disassemble (void)
00036 {
00037   int i;
00038 
00039   /* If two instructions have the same opcode then we prefer the first
00040    * one.  In most cases it is just an alternate mnemonic. */
00041   for (i = 0; i < spu_num_opcodes; i++)
00042     {
00043       int o = spu_opcodes[i].opcode;
00044       if (o >= (1 << 11))
00045        abort ();
00046       if (spu_disassemble_table[o] == 0)
00047        spu_disassemble_table[o] = &spu_opcodes[i];
00048     }
00049 }
00050 
00051 /* Determine the instruction from the 10 least significant bits. */
00052 static const struct spu_opcode *
00053 get_index_for_opcode (unsigned int insn)
00054 {
00055   const struct spu_opcode *index;
00056   unsigned int opcode = insn >> (32-11);
00057 
00058   /* Init the table.  This assumes that element 0/opcode 0 (currently
00059    * NOP) is always used */
00060   if (spu_disassemble_table[0] == 0)
00061     init_spu_disassemble ();
00062 
00063   if ((index = spu_disassemble_table[opcode & 0x780]) != 0
00064       && index->insn_type == RRR)
00065     return index;
00066 
00067   if ((index = spu_disassemble_table[opcode & 0x7f0]) != 0
00068       && (index->insn_type == RI18 || index->insn_type == LBT))
00069     return index;
00070 
00071   if ((index = spu_disassemble_table[opcode & 0x7f8]) != 0
00072       && index->insn_type == RI10)
00073     return index;
00074 
00075   if ((index = spu_disassemble_table[opcode & 0x7fc]) != 0
00076       && (index->insn_type == RI16))
00077     return index;
00078 
00079   if ((index = spu_disassemble_table[opcode & 0x7fe]) != 0
00080       && (index->insn_type == RI8))
00081     return index;
00082 
00083   if ((index = spu_disassemble_table[opcode & 0x7ff]) != 0)
00084     return index;
00085 
00086   return 0;
00087 }
00088 
00089 /* Print a Spu instruction.  */
00090 
00091 int
00092 print_insn_spu (bfd_vma memaddr, struct disassemble_info *info)
00093 {
00094   bfd_byte buffer[4];
00095   int value;
00096   int hex_value;
00097   int status;
00098   unsigned int insn;
00099   const struct spu_opcode *index;
00100   enum spu_insns tag;
00101 
00102   status = (*info->read_memory_func) (memaddr, buffer, 4, info);
00103   if (status != 0)
00104     {
00105       (*info->memory_error_func) (status, memaddr, info);
00106       return -1;
00107     }
00108 
00109   insn = bfd_getb32 (buffer);
00110 
00111   index = get_index_for_opcode (insn);
00112 
00113   if (index == 0)
00114     {
00115       (*info->fprintf_func) (info->stream, ".long 0x%x", insn);
00116     }
00117   else
00118     {
00119       int i;
00120       int paren = 0;
00121       tag = (enum spu_insns)(index - spu_opcodes);
00122       (*info->fprintf_func) (info->stream, "%s", index->mnemonic);
00123       if (tag == M_BI || tag == M_BISL || tag == M_IRET || tag == M_BISLED
00124          || tag == M_BIHNZ || tag == M_BIHZ || tag == M_BINZ || tag == M_BIZ
00125           || tag == M_SYNC || tag == M_HBR)
00126        {
00127          int fb = (insn >> (32-18)) & 0x7f;
00128          if (fb & 0x40)
00129            (*info->fprintf_func) (info->stream, tag == M_SYNC ? "c" : "p");
00130          if (fb & 0x20)
00131            (*info->fprintf_func) (info->stream, "d");
00132          if (fb & 0x10)
00133            (*info->fprintf_func) (info->stream, "e");
00134        }
00135       if (index->arg[0] != 0)
00136        (*info->fprintf_func) (info->stream, "\t");
00137       hex_value = 0;
00138       for (i = 1;  i <= index->arg[0]; i++)
00139        {
00140          int arg = index->arg[i];
00141          if (arg != A_P && !paren && i > 1)
00142            (*info->fprintf_func) (info->stream, ",");
00143 
00144          switch (arg)
00145            {
00146            case A_T:
00147              (*info->fprintf_func) (info->stream, "$%d",
00148                                  DECODE_INSN_RT (insn));
00149              break;
00150            case A_A:
00151              (*info->fprintf_func) (info->stream, "$%d",
00152                                  DECODE_INSN_RA (insn));
00153              break;
00154            case A_B:
00155              (*info->fprintf_func) (info->stream, "$%d",
00156                                  DECODE_INSN_RB (insn));
00157              break;
00158            case A_C:
00159              (*info->fprintf_func) (info->stream, "$%d",
00160                                  DECODE_INSN_RC (insn));
00161              break;
00162            case A_S:
00163              (*info->fprintf_func) (info->stream, "$sp%d",
00164                                  DECODE_INSN_RA (insn));
00165              break;
00166            case A_H:
00167              (*info->fprintf_func) (info->stream, "$ch%d",
00168                                  DECODE_INSN_RA (insn));
00169              break;
00170            case A_P:
00171              paren++;
00172              (*info->fprintf_func) (info->stream, "(");
00173              break;
00174            case A_U7A:
00175              (*info->fprintf_func) (info->stream, "%d",
00176                                  173 - DECODE_INSN_U8 (insn));
00177              break;
00178            case A_U7B:
00179              (*info->fprintf_func) (info->stream, "%d",
00180                                  155 - DECODE_INSN_U8 (insn));
00181              break;
00182            case A_S3:
00183            case A_S6:
00184            case A_S7:
00185            case A_S7N:
00186            case A_U3:
00187            case A_U5:
00188            case A_U6:
00189            case A_U7:
00190              hex_value = DECODE_INSN_I7 (insn);
00191              (*info->fprintf_func) (info->stream, "%d", hex_value);
00192              break;
00193            case A_S11:
00194              (*info->print_address_func) (memaddr + DECODE_INSN_I9a (insn) * 4,
00195                                       info);
00196              break;
00197            case A_S11I:
00198              (*info->print_address_func) (memaddr + DECODE_INSN_I9b (insn) * 4,
00199                                       info);
00200              break;
00201            case A_S10:
00202            case A_S10B:
00203              hex_value = DECODE_INSN_I10 (insn);
00204              (*info->fprintf_func) (info->stream, "%d", hex_value);
00205              break;
00206            case A_S14:
00207              hex_value = DECODE_INSN_I10 (insn) * 16;
00208              (*info->fprintf_func) (info->stream, "%d", hex_value);
00209              break;
00210            case A_S16:
00211              hex_value = DECODE_INSN_I16 (insn);
00212              (*info->fprintf_func) (info->stream, "%d", hex_value);
00213              break;
00214            case A_X16:
00215              hex_value = DECODE_INSN_U16 (insn);
00216              (*info->fprintf_func) (info->stream, "%u", hex_value);
00217              break;
00218            case A_R18:
00219              value = DECODE_INSN_I16 (insn) * 4;
00220              if (value == 0)
00221               (*info->fprintf_func) (info->stream, "%d", value);
00222              else
00223               {
00224                 hex_value = memaddr + value;
00225                 (*info->print_address_func) (hex_value & 0x3ffff, info);
00226               }
00227              break;
00228            case A_S18:
00229              value = DECODE_INSN_U16 (insn) * 4;
00230              if (value == 0)
00231               (*info->fprintf_func) (info->stream, "%d", value);
00232              else
00233               (*info->print_address_func) (value, info);
00234              break;
00235            case A_U18:
00236              value = DECODE_INSN_U18 (insn);
00237              if (value == 0 || !(*info->symbol_at_address_func)(0, info))
00238               {
00239                 hex_value = value;
00240                 (*info->fprintf_func) (info->stream, "%u", value);
00241               }
00242              else
00243               (*info->print_address_func) (value, info);
00244              break;
00245            case A_U14:
00246              hex_value = DECODE_INSN_U14 (insn);
00247              (*info->fprintf_func) (info->stream, "%u", hex_value);
00248              break;
00249            }
00250          if (arg != A_P && paren)
00251            {
00252              (*info->fprintf_func) (info->stream, ")");
00253              paren--;
00254            }
00255        }
00256       if (hex_value > 16)
00257        (*info->fprintf_func) (info->stream, "\t# %x", hex_value);
00258     }
00259   return 4;
00260 }