1 /* Disassemble SPU instructions
3 Copyright (C) 2006-2024 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)
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. */
24 #include "disassemble.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)];
36 init_spu_disassemble (void)
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
;
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
*op_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 ((op_index
= spu_disassemble_table
[opcode
& 0x780]) != 0
65 && op_index
->insn_type
== RRR
)
68 if ((op_index
= spu_disassemble_table
[opcode
& 0x7f0]) != 0
69 && (op_index
->insn_type
== RI18
|| op_index
->insn_type
== LBT
))
72 if ((op_index
= spu_disassemble_table
[opcode
& 0x7f8]) != 0
73 && op_index
->insn_type
== RI10
)
76 if ((op_index
= spu_disassemble_table
[opcode
& 0x7fc]) != 0
77 && (op_index
->insn_type
== RI16
))
80 if ((op_index
= spu_disassemble_table
[opcode
& 0x7fe]) != 0
81 && (op_index
->insn_type
== RI8
))
84 if ((op_index
= spu_disassemble_table
[opcode
& 0x7ff]) != 0)
90 /* Print a Spu instruction. */
93 print_insn_spu (bfd_vma memaddr
, struct disassemble_info
*info
)
100 const struct spu_opcode
*op_index
;
103 status
= (*info
->read_memory_func
) (memaddr
, buffer
, 4, info
);
106 (*info
->memory_error_func
) (status
, memaddr
, info
);
110 insn
= bfd_getb32 (buffer
);
112 op_index
= get_index_for_opcode (insn
);
116 (*info
->fprintf_func
) (info
->stream
, ".long 0x%x", insn
);
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
)
128 int fb
= (insn
>> (32-18)) & 0x7f;
130 (*info
->fprintf_func
) (info
->stream
, tag
== M_SYNC
? "c" : "p");
132 (*info
->fprintf_func
) (info
->stream
, "d");
134 (*info
->fprintf_func
) (info
->stream
, "e");
136 if (op_index
->arg
[0] != 0)
137 (*info
->fprintf_func
) (info
->stream
, "\t");
139 for (i
= 1; i
<= op_index
->arg
[0]; i
++)
141 int arg
= op_index
->arg
[i
];
142 if (arg
!= A_P
&& !paren
&& i
> 1)
143 (*info
->fprintf_func
) (info
->stream
, ",");
148 (*info
->fprintf_func
) (info
->stream
, "$%d",
149 DECODE_INSN_RT (insn
));
152 (*info
->fprintf_func
) (info
->stream
, "$%d",
153 DECODE_INSN_RA (insn
));
156 (*info
->fprintf_func
) (info
->stream
, "$%d",
157 DECODE_INSN_RB (insn
));
160 (*info
->fprintf_func
) (info
->stream
, "$%d",
161 DECODE_INSN_RC (insn
));
164 (*info
->fprintf_func
) (info
->stream
, "$sp%d",
165 DECODE_INSN_RA (insn
));
168 (*info
->fprintf_func
) (info
->stream
, "$ch%d",
169 DECODE_INSN_RA (insn
));
173 (*info
->fprintf_func
) (info
->stream
, "(");
176 (*info
->fprintf_func
) (info
->stream
, "%d",
177 173 - DECODE_INSN_U8 (insn
));
180 (*info
->fprintf_func
) (info
->stream
, "%d",
181 155 - DECODE_INSN_U8 (insn
));
191 hex_value
= DECODE_INSN_I7 (insn
);
192 (*info
->fprintf_func
) (info
->stream
, "%d", hex_value
);
195 (*info
->print_address_func
) (memaddr
+ DECODE_INSN_I9a (insn
) * 4,
199 (*info
->print_address_func
) (memaddr
+ DECODE_INSN_I9b (insn
) * 4,
204 hex_value
= DECODE_INSN_I10 (insn
);
205 (*info
->fprintf_func
) (info
->stream
, "%d", hex_value
);
208 hex_value
= DECODE_INSN_I10 (insn
) * 16;
209 (*info
->fprintf_func
) (info
->stream
, "%d", hex_value
);
212 hex_value
= DECODE_INSN_I16 (insn
);
213 (*info
->fprintf_func
) (info
->stream
, "%d", hex_value
);
216 hex_value
= DECODE_INSN_U16 (insn
);
217 (*info
->fprintf_func
) (info
->stream
, "%u", hex_value
);
220 value
= DECODE_INSN_I16 (insn
) * 4;
222 (*info
->fprintf_func
) (info
->stream
, "%d", value
);
225 hex_value
= memaddr
+ value
;
226 (*info
->print_address_func
) (hex_value
& 0x3ffff, info
);
230 value
= DECODE_INSN_U16 (insn
) * 4;
232 (*info
->fprintf_func
) (info
->stream
, "%d", value
);
234 (*info
->print_address_func
) (value
, info
);
237 value
= DECODE_INSN_U18 (insn
);
238 if (value
== 0 || !(*info
->symbol_at_address_func
)(0, info
))
241 (*info
->fprintf_func
) (info
->stream
, "%u", value
);
244 (*info
->print_address_func
) (value
, info
);
247 hex_value
= DECODE_INSN_U14 (insn
);
248 (*info
->fprintf_func
) (info
->stream
, "%u", hex_value
);
251 if (arg
!= A_P
&& paren
)
253 (*info
->fprintf_func
) (info
->stream
, ")");
258 (*info
->fprintf_func
) (info
->stream
, "\t# %x", hex_value
);