linux/arch/powerpc/xmon/spu-dis.c
<<
>>
Prefs
   1/* Disassemble SPU instructions
   2
   3   Copyright 2006 Free Software Foundation, Inc.
   4
   5   This file is part of GDB, GAS, and the GNU binutils.
   6
   7   This program is free software; you can redistribute it and/or modify
   8   it under the terms of the GNU General Public License as published by
   9   the Free Software Foundation; either version 2 of the License, or
  10   (at your option) any later version.
  11
  12   This program is distributed in the hope that it will be useful,
  13   but WITHOUT ANY WARRANTY; without even the implied warranty of
  14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15   GNU General Public License for more details.
  16
  17   You should have received a copy of the GNU General Public License along
  18   with this program; if not, write to the Free Software Foundation, Inc.,
  19   51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
  20
  21#include <linux/string.h>
  22#include "nonstdio.h"
  23#include "ansidecl.h"
  24#include "spu.h"
  25#include "dis-asm.h"
  26
  27/* This file provides a disassembler function which uses
  28   the disassembler interface defined in dis-asm.h.   */
  29
  30extern const struct spu_opcode spu_opcodes[];
  31extern const int spu_num_opcodes;
  32
  33#define SPU_DISASM_TBL_SIZE (1 << 11)
  34static const struct spu_opcode *spu_disassemble_table[SPU_DISASM_TBL_SIZE];
  35
  36static void
  37init_spu_disassemble (void)
  38{
  39  int i;
  40
  41  /* If two instructions have the same opcode then we prefer the first
  42   * one.  In most cases it is just an alternate mnemonic. */
  43  for (i = 0; i < spu_num_opcodes; i++)
  44    {
  45      int o = spu_opcodes[i].opcode;
  46      if (o >= SPU_DISASM_TBL_SIZE)
  47        continue; /* abort (); */
  48      if (spu_disassemble_table[o] == 0)
  49        spu_disassemble_table[o] = &spu_opcodes[i];
  50    }
  51}
  52
  53/* Determine the instruction from the 10 least significant bits. */
  54static const struct spu_opcode *
  55get_index_for_opcode (unsigned int insn)
  56{
  57  const struct spu_opcode *index;
  58  unsigned int opcode = insn >> (32-11);
  59
  60  /* Init the table.  This assumes that element 0/opcode 0 (currently
  61   * NOP) is always used */
  62  if (spu_disassemble_table[0] == 0)
  63    init_spu_disassemble ();
  64
  65  if ((index = spu_disassemble_table[opcode & 0x780]) != 0
  66      && index->insn_type == RRR)
  67    return index;
  68
  69  if ((index = spu_disassemble_table[opcode & 0x7f0]) != 0
  70      && (index->insn_type == RI18 || index->insn_type == LBT))
  71    return index;
  72
  73  if ((index = spu_disassemble_table[opcode & 0x7f8]) != 0
  74      && index->insn_type == RI10)
  75    return index;
  76
  77  if ((index = spu_disassemble_table[opcode & 0x7fc]) != 0
  78      && (index->insn_type == RI16))
  79    return index;
  80
  81  if ((index = spu_disassemble_table[opcode & 0x7fe]) != 0
  82      && (index->insn_type == RI8))
  83    return index;
  84
  85  if ((index = spu_disassemble_table[opcode & 0x7ff]) != 0)
  86    return index;
  87
  88  return NULL;
  89}
  90
  91/* Print a Spu instruction.  */
  92
  93int
  94print_insn_spu (unsigned long insn, unsigned long memaddr)
  95{
  96  int value;
  97  int hex_value;
  98  const struct spu_opcode *index;
  99  enum spu_insns tag;
 100
 101  index = get_index_for_opcode (insn);
 102
 103  if (index == 0)
 104    {
 105      printf(".long 0x%x", insn);
 106    }
 107  else
 108    {
 109      int i;
 110      int paren = 0;
 111      tag = (enum spu_insns)(index - spu_opcodes);
 112      printf("%s", index->mnemonic);
 113      if (tag == M_BI || tag == M_BISL || tag == M_IRET || tag == M_BISLED
 114          || tag == M_BIHNZ || tag == M_BIHZ || tag == M_BINZ || tag == M_BIZ
 115          || tag == M_SYNC || tag == M_HBR)
 116        {
 117          int fb = (insn >> (32-18)) & 0x7f;
 118          if (fb & 0x40)
 119            printf(tag == M_SYNC ? "c" : "p");
 120          if (fb & 0x20)
 121            printf("d");
 122          if (fb & 0x10)
 123            printf("e");
 124        }
 125      if (index->arg[0] != 0)
 126        printf("\t");
 127      hex_value = 0;
 128      for (i = 1;  i <= index->arg[0]; i++)
 129        {
 130          int arg = index->arg[i];
 131          if (arg != A_P && !paren && i > 1)
 132            printf(",");
 133
 134          switch (arg)
 135            {
 136            case A_T:
 137              printf("$%d",
 138                                     DECODE_INSN_RT (insn));
 139              break;
 140            case A_A:
 141              printf("$%d",
 142                                     DECODE_INSN_RA (insn));
 143              break;
 144            case A_B:
 145              printf("$%d",
 146                                     DECODE_INSN_RB (insn));
 147              break;
 148            case A_C:
 149              printf("$%d",
 150                                     DECODE_INSN_RC (insn));
 151              break;
 152            case A_S:
 153              printf("$sp%d",
 154                                     DECODE_INSN_RA (insn));
 155              break;
 156            case A_H:
 157              printf("$ch%d",
 158                                     DECODE_INSN_RA (insn));
 159              break;
 160            case A_P:
 161              paren++;
 162              printf("(");
 163              break;
 164            case A_U7A:
 165              printf("%d",
 166                                     173 - DECODE_INSN_U8 (insn));
 167              break;
 168            case A_U7B:
 169              printf("%d",
 170                                     155 - DECODE_INSN_U8 (insn));
 171              break;
 172            case A_S3:
 173            case A_S6:
 174            case A_S7:
 175            case A_S7N:
 176            case A_U3:
 177            case A_U5:
 178            case A_U6:
 179            case A_U7:
 180              hex_value = DECODE_INSN_I7 (insn);
 181              printf("%d", hex_value);
 182              break;
 183            case A_S11:
 184              print_address(memaddr + DECODE_INSN_I9a (insn) * 4);
 185              break;
 186            case A_S11I:
 187              print_address(memaddr + DECODE_INSN_I9b (insn) * 4);
 188              break;
 189            case A_S10:
 190            case A_S10B:
 191              hex_value = DECODE_INSN_I10 (insn);
 192              printf("%d", hex_value);
 193              break;
 194            case A_S14:
 195              hex_value = DECODE_INSN_I10 (insn) * 16;
 196              printf("%d", hex_value);
 197              break;
 198            case A_S16:
 199              hex_value = DECODE_INSN_I16 (insn);
 200              printf("%d", hex_value);
 201              break;
 202            case A_X16:
 203              hex_value = DECODE_INSN_U16 (insn);
 204              printf("%u", hex_value);
 205              break;
 206            case A_R18:
 207              value = DECODE_INSN_I16 (insn) * 4;
 208              if (value == 0)
 209                printf("%d", value);
 210              else
 211                {
 212                  hex_value = memaddr + value;
 213                  print_address(hex_value & 0x3ffff);
 214                }
 215              break;
 216            case A_S18:
 217              value = DECODE_INSN_U16 (insn) * 4;
 218              if (value == 0)
 219                printf("%d", value);
 220              else
 221                print_address(value);
 222              break;
 223            case A_U18:
 224              value = DECODE_INSN_U18 (insn);
 225              if (value == 0 || 1)
 226                {
 227                  hex_value = value;
 228                  printf("%u", value);
 229                }
 230              else
 231                print_address(value);
 232              break;
 233            case A_U14:
 234              hex_value = DECODE_INSN_U14 (insn);
 235              printf("%u", hex_value);
 236              break;
 237            }
 238          if (arg != A_P && paren)
 239            {
 240              printf(")");
 241              paren--;
 242            }
 243        }
 244      if (hex_value > 16)
 245        printf("\t# %x", hex_value);
 246    }
 247  return 4;
 248}
 249