Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /* Disassemble SPU instructions
0003 
0004    Copyright 2006 Free Software Foundation, Inc.
0005 
0006    This file is part of GDB, GAS, and the GNU binutils.
0007 
0008  */
0009 
0010 #include <linux/string.h>
0011 #include "nonstdio.h"
0012 #include "ansidecl.h"
0013 #include "spu.h"
0014 #include "dis-asm.h"
0015 
0016 /* This file provides a disassembler function which uses
0017    the disassembler interface defined in dis-asm.h.   */
0018 
0019 extern const struct spu_opcode spu_opcodes[];
0020 extern const int spu_num_opcodes;
0021 
0022 #define SPU_DISASM_TBL_SIZE (1 << 11)
0023 static const struct spu_opcode *spu_disassemble_table[SPU_DISASM_TBL_SIZE];
0024 
0025 static void
0026 init_spu_disassemble (void)
0027 {
0028   int i;
0029 
0030   /* If two instructions have the same opcode then we prefer the first
0031    * one.  In most cases it is just an alternate mnemonic. */
0032   for (i = 0; i < spu_num_opcodes; i++)
0033     {
0034       int o = spu_opcodes[i].opcode;
0035       if (o >= SPU_DISASM_TBL_SIZE)
0036     continue; /* abort (); */
0037       if (spu_disassemble_table[o] == 0)
0038     spu_disassemble_table[o] = &spu_opcodes[i];
0039     }
0040 }
0041 
0042 /* Determine the instruction from the 10 least significant bits. */
0043 static const struct spu_opcode *
0044 get_index_for_opcode (unsigned int insn)
0045 {
0046   const struct spu_opcode *index;
0047   unsigned int opcode = insn >> (32-11);
0048 
0049   /* Init the table.  This assumes that element 0/opcode 0 (currently
0050    * NOP) is always used */
0051   if (spu_disassemble_table[0] == 0)
0052     init_spu_disassemble ();
0053 
0054   if ((index = spu_disassemble_table[opcode & 0x780]) != 0
0055       && index->insn_type == RRR)
0056     return index;
0057 
0058   if ((index = spu_disassemble_table[opcode & 0x7f0]) != 0
0059       && (index->insn_type == RI18 || index->insn_type == LBT))
0060     return index;
0061 
0062   if ((index = spu_disassemble_table[opcode & 0x7f8]) != 0
0063       && index->insn_type == RI10)
0064     return index;
0065 
0066   if ((index = spu_disassemble_table[opcode & 0x7fc]) != 0
0067       && (index->insn_type == RI16))
0068     return index;
0069 
0070   if ((index = spu_disassemble_table[opcode & 0x7fe]) != 0
0071       && (index->insn_type == RI8))
0072     return index;
0073 
0074   if ((index = spu_disassemble_table[opcode & 0x7ff]) != 0)
0075     return index;
0076 
0077   return NULL;
0078 }
0079 
0080 /* Print a Spu instruction.  */
0081 
0082 int
0083 print_insn_spu (unsigned long insn, unsigned long memaddr)
0084 {
0085   int value;
0086   int hex_value;
0087   const struct spu_opcode *index;
0088   enum spu_insns tag;
0089 
0090   index = get_index_for_opcode (insn);
0091 
0092   if (index == 0)
0093     {
0094       printf(".long 0x%lx", insn);
0095     }
0096   else
0097     {
0098       int i;
0099       int paren = 0;
0100       tag = (enum spu_insns)(index - spu_opcodes);
0101       printf("%s", index->mnemonic);
0102       if (tag == M_BI || tag == M_BISL || tag == M_IRET || tag == M_BISLED
0103       || tag == M_BIHNZ || tag == M_BIHZ || tag == M_BINZ || tag == M_BIZ
0104           || tag == M_SYNC || tag == M_HBR)
0105     {
0106       int fb = (insn >> (32-18)) & 0x7f;
0107       if (fb & 0x40)
0108         printf(tag == M_SYNC ? "c" : "p");
0109       if (fb & 0x20)
0110         printf("d");
0111       if (fb & 0x10)
0112         printf("e");
0113     }
0114       if (index->arg[0] != 0)
0115     printf("\t");
0116       hex_value = 0;
0117       for (i = 1;  i <= index->arg[0]; i++)
0118     {
0119       int arg = index->arg[i];
0120       if (arg != A_P && !paren && i > 1)
0121         printf(",");
0122 
0123       switch (arg)
0124         {
0125         case A_T:
0126           printf("$%lu",
0127                      DECODE_INSN_RT (insn));
0128           break;
0129         case A_A:
0130           printf("$%lu",
0131                      DECODE_INSN_RA (insn));
0132           break;
0133         case A_B:
0134           printf("$%lu",
0135                      DECODE_INSN_RB (insn));
0136           break;
0137         case A_C:
0138           printf("$%lu",
0139                      DECODE_INSN_RC (insn));
0140           break;
0141         case A_S:
0142           printf("$sp%lu",
0143                      DECODE_INSN_RA (insn));
0144           break;
0145         case A_H:
0146           printf("$ch%lu",
0147                      DECODE_INSN_RA (insn));
0148           break;
0149         case A_P:
0150           paren++;
0151           printf("(");
0152           break;
0153         case A_U7A:
0154           printf("%lu",
0155                      173 - DECODE_INSN_U8 (insn));
0156           break;
0157         case A_U7B:
0158           printf("%lu",
0159                      155 - DECODE_INSN_U8 (insn));
0160           break;
0161         case A_S3:
0162         case A_S6:
0163         case A_S7:
0164         case A_S7N:
0165         case A_U3:
0166         case A_U5:
0167         case A_U6:
0168         case A_U7:
0169           hex_value = DECODE_INSN_I7 (insn);
0170           printf("%d", hex_value);
0171           break;
0172         case A_S11:
0173           print_address(memaddr + DECODE_INSN_I9a (insn) * 4);
0174           break;
0175         case A_S11I:
0176           print_address(memaddr + DECODE_INSN_I9b (insn) * 4);
0177           break;
0178         case A_S10:
0179         case A_S10B:
0180           hex_value = DECODE_INSN_I10 (insn);
0181           printf("%d", hex_value);
0182           break;
0183         case A_S14:
0184           hex_value = DECODE_INSN_I10 (insn) * 16;
0185           printf("%d", hex_value);
0186           break;
0187         case A_S16:
0188           hex_value = DECODE_INSN_I16 (insn);
0189           printf("%d", hex_value);
0190           break;
0191         case A_X16:
0192           hex_value = DECODE_INSN_U16 (insn);
0193           printf("%u", hex_value);
0194           break;
0195         case A_R18:
0196           value = DECODE_INSN_I16 (insn) * 4;
0197           if (value == 0)
0198         printf("%d", value);
0199           else
0200         {
0201           hex_value = memaddr + value;
0202           print_address(hex_value & 0x3ffff);
0203         }
0204           break;
0205         case A_S18:
0206           value = DECODE_INSN_U16 (insn) * 4;
0207           if (value == 0)
0208         printf("%d", value);
0209           else
0210         print_address(value);
0211           break;
0212         case A_U18:
0213           value = DECODE_INSN_U18 (insn);
0214           if (value == 0 || 1)
0215         {
0216           hex_value = value;
0217           printf("%u", value);
0218         }
0219           else
0220         print_address(value);
0221           break;
0222         case A_U14:
0223           hex_value = DECODE_INSN_U14 (insn);
0224           printf("%u", hex_value);
0225           break;
0226         }
0227       if (arg != A_P && paren)
0228         {
0229           printf(")");
0230           paren--;
0231         }
0232     }
0233       if (hex_value > 16)
0234     printf("\t# %x", hex_value);
0235     }
0236   return 4;
0237 }