Upload Tizen:Base source
[external/binutils.git] / opcodes / spu-dis.c
1 /* Disassemble SPU instructions
2
3    Copyright 2006, 2007 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 <stdio.h>
23 #include "sysdep.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
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 }