1/* Disassemble SPU instructions 2 3 Copyright (C) 2006-2017 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 "dis-asm.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 30extern const struct spu_opcode spu_opcodes[]; 31extern const int spu_num_opcodes; 32 33static const struct spu_opcode *spu_disassemble_table[(1<<11)]; 34 35static void 36init_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. */ 53static const struct spu_opcode * 54get_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 92int 93print_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} 262