merge from gcc
[binutils.git] / opcodes / spu-dis.c
blobeae950323b019ceaec5d050ddeaa2e633f0cd8c3
1 /* Disassemble SPU instructions
3 Copyright 2006, 2007 Free Software Foundation, Inc.
5 This file is part of the GNU opcodes library.
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.
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.
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. */
22 #include <stdio.h>
23 #include "sysdep.h"
24 #include "dis-asm.h"
25 #include "opcode/spu.h"
27 /* This file provides a disassembler function which uses
28 the disassembler interface defined in dis-asm.h. */
30 extern const struct spu_opcode spu_opcodes[];
31 extern const int spu_num_opcodes;
33 static const struct spu_opcode *spu_disassemble_table[(1<<11)];
35 static void
36 init_spu_disassemble (void)
38 int i;
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++)
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];
52 /* Determine the instruction from the 10 least significant bits. */
53 static const struct spu_opcode *
54 get_index_for_opcode (unsigned int insn)
56 const struct spu_opcode *index;
57 unsigned int opcode = insn >> (32-11);
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 ();
64 if ((index = spu_disassemble_table[opcode & 0x780]) != 0
65 && index->insn_type == RRR)
66 return index;
68 if ((index = spu_disassemble_table[opcode & 0x7f0]) != 0
69 && (index->insn_type == RI18 || index->insn_type == LBT))
70 return index;
72 if ((index = spu_disassemble_table[opcode & 0x7f8]) != 0
73 && index->insn_type == RI10)
74 return index;
76 if ((index = spu_disassemble_table[opcode & 0x7fc]) != 0
77 && (index->insn_type == RI16))
78 return index;
80 if ((index = spu_disassemble_table[opcode & 0x7fe]) != 0
81 && (index->insn_type == RI8))
82 return index;
84 if ((index = spu_disassemble_table[opcode & 0x7ff]) != 0)
85 return index;
87 return 0;
90 /* Print a Spu instruction. */
92 int
93 print_insn_spu (bfd_vma memaddr, struct disassemble_info *info)
95 bfd_byte buffer[4];
96 int value;
97 int hex_value;
98 int status;
99 unsigned int insn;
100 const struct spu_opcode *index;
101 enum spu_insns tag;
103 status = (*info->read_memory_func) (memaddr, buffer, 4, info);
104 if (status != 0)
106 (*info->memory_error_func) (status, memaddr, info);
107 return -1;
110 insn = bfd_getb32 (buffer);
112 index = get_index_for_opcode (insn);
114 if (index == 0)
116 (*info->fprintf_func) (info->stream, ".long 0x%x", insn);
118 else
120 int i;
121 int paren = 0;
122 tag = (enum spu_insns)(index - spu_opcodes);
123 (*info->fprintf_func) (info->stream, "%s", 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)
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");
136 if (index->arg[0] != 0)
137 (*info->fprintf_func) (info->stream, "\t");
138 hex_value = 0;
139 for (i = 1; i <= index->arg[0]; i++)
141 int arg = index->arg[i];
142 if (arg != A_P && !paren && i > 1)
143 (*info->fprintf_func) (info->stream, ",");
145 switch (arg)
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
225 hex_value = memaddr + value;
226 (*info->print_address_func) (hex_value & 0x3ffff, info);
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))
240 hex_value = value;
241 (*info->fprintf_func) (info->stream, "%u", value);
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;
251 if (arg != A_P && paren)
253 (*info->fprintf_func) (info->stream, ")");
254 paren--;
257 if (hex_value > 16)
258 (*info->fprintf_func) (info->stream, "\t# %x", hex_value);
260 return 4;