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