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