linux/arch/powerpc/xmon/ppc-dis.c
<<
>>
Prefs
   1/* ppc-dis.c -- Disassemble PowerPC instructions
   2   Copyright (C) 1994-2016 Free Software Foundation, Inc.
   3   Written by Ian Lance Taylor, Cygnus Support
   4
   5This file is part of GDB, GAS, and the GNU binutils.
   6
   7GDB, GAS, and the GNU binutils are free software; you can redistribute
   8them and/or modify them under the terms of the GNU General Public
   9License as published by the Free Software Foundation; either version
  102, or (at your option) any later version.
  11
  12GDB, GAS, and the GNU binutils are distributed in the hope that they
  13will be useful, but WITHOUT ANY WARRANTY; without even the implied
  14warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
  15the GNU General Public License for more details.
  16
  17You should have received a copy of the GNU General Public License
  18along with this file; see the file COPYING.  If not, write to the Free
  19Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
  20
  21#include <asm/cputable.h>
  22#include <asm/cpu_has_feature.h>
  23#include "nonstdio.h"
  24#include "ansidecl.h"
  25#include "ppc.h"
  26#include "dis-asm.h"
  27
  28/* This file provides several disassembler functions, all of which use
  29   the disassembler interface defined in dis-asm.h.  Several functions
  30   are provided because this file handles disassembly for the PowerPC
  31   in both big and little endian mode and also for the POWER (RS/6000)
  32   chip.  */
  33
  34/* Extract the operand value from the PowerPC or POWER instruction.  */
  35
  36static long
  37operand_value_powerpc (const struct powerpc_operand *operand,
  38                       unsigned long insn, ppc_cpu_t dialect)
  39{
  40  long value;
  41  int invalid;
  42  /* Extract the value from the instruction.  */
  43  if (operand->extract)
  44    value = (*operand->extract) (insn, dialect, &invalid);
  45  else
  46    {
  47      if (operand->shift >= 0)
  48        value = (insn >> operand->shift) & operand->bitm;
  49      else
  50        value = (insn << -operand->shift) & operand->bitm;
  51      if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
  52        {
  53          /* BITM is always some number of zeros followed by some
  54             number of ones, followed by some number of zeros.  */
  55          unsigned long top = operand->bitm;
  56          /* top & -top gives the rightmost 1 bit, so this
  57             fills in any trailing zeros.  */
  58          top |= (top & -top) - 1;
  59          top &= ~(top >> 1);
  60          value = (value ^ top) - top;
  61        }
  62    }
  63
  64  return value;
  65}
  66
  67/* Determine whether the optional operand(s) should be printed.  */
  68
  69static int
  70skip_optional_operands (const unsigned char *opindex,
  71                        unsigned long insn, ppc_cpu_t dialect)
  72{
  73  const struct powerpc_operand *operand;
  74
  75  for (; *opindex != 0; opindex++)
  76    {
  77      operand = &powerpc_operands[*opindex];
  78      if ((operand->flags & PPC_OPERAND_NEXT) != 0
  79          || ((operand->flags & PPC_OPERAND_OPTIONAL) != 0
  80              && operand_value_powerpc (operand, insn, dialect) !=
  81                 ppc_optional_operand_value (operand)))
  82        return 0;
  83    }
  84
  85  return 1;
  86}
  87
  88/* Find a match for INSN in the opcode table, given machine DIALECT.
  89   A DIALECT of -1 is special, matching all machine opcode variations.  */
  90
  91static const struct powerpc_opcode *
  92lookup_powerpc (unsigned long insn, ppc_cpu_t dialect)
  93{
  94  const struct powerpc_opcode *opcode;
  95  const struct powerpc_opcode *opcode_end;
  96  unsigned long op;
  97
  98  /* Get the major opcode of the instruction.  */
  99  op = PPC_OP (insn);
 100
 101  opcode_end = powerpc_opcodes + powerpc_num_opcodes;
 102  /* Find the first match in the opcode table for this major opcode.  */
 103  for (opcode = powerpc_opcodes; opcode < opcode_end; ++opcode)
 104    {
 105      const unsigned char *opindex;
 106      const struct powerpc_operand *operand;
 107      int invalid;
 108
 109      if ((insn & opcode->mask) != opcode->opcode
 110          || (dialect != (ppc_cpu_t) -1
 111              && ((opcode->flags & dialect) == 0
 112                  || (opcode->deprecated & dialect) != 0)))
 113        continue;
 114
 115      /* Check validity of operands.  */
 116      invalid = 0;
 117      for (opindex = opcode->operands; *opindex != 0; opindex++)
 118        {
 119          operand = powerpc_operands + *opindex;
 120          if (operand->extract)
 121            (*operand->extract) (insn, dialect, &invalid);
 122        }
 123      if (invalid)
 124        continue;
 125
 126      return opcode;
 127    }
 128
 129  return NULL;
 130}
 131
 132/* Print a PowerPC or POWER instruction.  */
 133
 134int print_insn_powerpc (unsigned long insn, unsigned long memaddr)
 135{
 136  const struct powerpc_opcode *opcode;
 137  bool insn_is_short;
 138  ppc_cpu_t dialect;
 139
 140  dialect = PPC_OPCODE_PPC | PPC_OPCODE_COMMON
 141            | PPC_OPCODE_64 | PPC_OPCODE_POWER4 | PPC_OPCODE_ALTIVEC;
 142
 143  if (cpu_has_feature(CPU_FTRS_POWER5))
 144    dialect |= PPC_OPCODE_POWER5;
 145
 146  if (cpu_has_feature(CPU_FTRS_CELL))
 147    dialect |= (PPC_OPCODE_CELL | PPC_OPCODE_ALTIVEC);
 148
 149  if (cpu_has_feature(CPU_FTRS_POWER6))
 150    dialect |= (PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_ALTIVEC);
 151
 152  if (cpu_has_feature(CPU_FTRS_POWER7))
 153    dialect |= (PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7
 154                | PPC_OPCODE_ALTIVEC | PPC_OPCODE_VSX);
 155
 156  if (cpu_has_feature(CPU_FTRS_POWER8))
 157    dialect |= (PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7
 158                | PPC_OPCODE_POWER8 | PPC_OPCODE_HTM
 159                | PPC_OPCODE_ALTIVEC | PPC_OPCODE_ALTIVEC2 | PPC_OPCODE_VSX);
 160
 161  if (cpu_has_feature(CPU_FTRS_POWER9))
 162    dialect |= (PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7
 163                | PPC_OPCODE_POWER8 | PPC_OPCODE_POWER9 | PPC_OPCODE_HTM
 164                | PPC_OPCODE_ALTIVEC | PPC_OPCODE_ALTIVEC2
 165                | PPC_OPCODE_VSX | PPC_OPCODE_VSX3),
 166
 167  /* Get the major opcode of the insn.  */
 168  opcode = NULL;
 169  insn_is_short = false;
 170
 171  if (opcode == NULL)
 172    opcode = lookup_powerpc (insn, dialect);
 173  if (opcode == NULL && (dialect & PPC_OPCODE_ANY) != 0)
 174    opcode = lookup_powerpc (insn, (ppc_cpu_t) -1);
 175
 176  if (opcode != NULL)
 177    {
 178      const unsigned char *opindex;
 179      const struct powerpc_operand *operand;
 180      int need_comma;
 181      int need_paren;
 182      int skip_optional;
 183
 184      if (opcode->operands[0] != 0)
 185        printf("%-7s ", opcode->name);
 186      else
 187        printf("%s", opcode->name);
 188
 189      if (insn_is_short)
 190        /* The operands will be fetched out of the 16-bit instruction.  */
 191        insn >>= 16;
 192
 193      /* Now extract and print the operands.  */
 194      need_comma = 0;
 195      need_paren = 0;
 196      skip_optional = -1;
 197      for (opindex = opcode->operands; *opindex != 0; opindex++)
 198        {
 199          long value;
 200
 201          operand = powerpc_operands + *opindex;
 202
 203          /* Operands that are marked FAKE are simply ignored.  We
 204             already made sure that the extract function considered
 205             the instruction to be valid.  */
 206          if ((operand->flags & PPC_OPERAND_FAKE) != 0)
 207            continue;
 208
 209          /* If all of the optional operands have the value zero,
 210             then don't print any of them.  */
 211          if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0)
 212            {
 213              if (skip_optional < 0)
 214                skip_optional = skip_optional_operands (opindex, insn,
 215                                                        dialect);
 216              if (skip_optional)
 217                continue;
 218            }
 219
 220          value = operand_value_powerpc (operand, insn, dialect);
 221
 222          if (need_comma)
 223            {
 224              printf(",");
 225              need_comma = 0;
 226            }
 227
 228          /* Print the operand as directed by the flags.  */
 229          if ((operand->flags & PPC_OPERAND_GPR) != 0
 230              || ((operand->flags & PPC_OPERAND_GPR_0) != 0 && value != 0))
 231            printf("r%ld", value);
 232          else if ((operand->flags & PPC_OPERAND_FPR) != 0)
 233            printf("f%ld", value);
 234          else if ((operand->flags & PPC_OPERAND_VR) != 0)
 235            printf("v%ld", value);
 236          else if ((operand->flags & PPC_OPERAND_VSR) != 0)
 237            printf("vs%ld", value);
 238          else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0)
 239            print_address(memaddr + value);
 240          else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
 241            print_address(value & 0xffffffff);
 242          else if ((operand->flags & PPC_OPERAND_FSL) != 0)
 243            printf("fsl%ld", value);
 244          else if ((operand->flags & PPC_OPERAND_FCR) != 0)
 245            printf("fcr%ld", value);
 246          else if ((operand->flags & PPC_OPERAND_UDI) != 0)
 247            printf("%ld", value);
 248          else if ((operand->flags & PPC_OPERAND_CR_REG) != 0
 249                   && (((dialect & PPC_OPCODE_PPC) != 0)
 250                       || ((dialect & PPC_OPCODE_VLE) != 0)))
 251            printf("cr%ld", value);
 252          else if (((operand->flags & PPC_OPERAND_CR_BIT) != 0)
 253                   && (((dialect & PPC_OPCODE_PPC) != 0)
 254                       || ((dialect & PPC_OPCODE_VLE) != 0)))
 255            {
 256              static const char *cbnames[4] = { "lt", "gt", "eq", "so" };
 257              int cr;
 258              int cc;
 259
 260              cr = value >> 2;
 261              if (cr != 0)
 262                printf("4*cr%d+", cr);
 263              cc = value & 3;
 264              printf("%s", cbnames[cc]);
 265            }
 266          else
 267            printf("%d", (int) value);
 268
 269          if (need_paren)
 270            {
 271              printf(")");
 272              need_paren = 0;
 273            }
 274
 275          if ((operand->flags & PPC_OPERAND_PARENS) == 0)
 276            need_comma = 1;
 277          else
 278            {
 279              printf("(");
 280              need_paren = 1;
 281            }
 282        }
 283
 284      /* We have found and printed an instruction.
 285         If it was a short VLE instruction we have more to do.  */
 286      if (insn_is_short)
 287        {
 288          memaddr += 2;
 289          return 2;
 290        }
 291      else
 292        /* Otherwise, return.  */
 293        return 4;
 294    }
 295
 296  /* We could not find a match.  */
 297  printf(".long 0x%lx", insn);
 298
 299  return 4;
 300}
 301