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