1*16216333SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2ae06e374SMichael Ellerman /* Disassemble SPU instructions
3ae06e374SMichael Ellerman
4ae06e374SMichael Ellerman Copyright 2006 Free Software Foundation, Inc.
5ae06e374SMichael Ellerman
6ae06e374SMichael Ellerman This file is part of GDB, GAS, and the GNU binutils.
7ae06e374SMichael Ellerman
8*16216333SThomas Gleixner */
9ae06e374SMichael Ellerman
10ae06e374SMichael Ellerman #include <linux/string.h>
11ae06e374SMichael Ellerman #include "nonstdio.h"
12ae06e374SMichael Ellerman #include "ansidecl.h"
13ae06e374SMichael Ellerman #include "spu.h"
14e0426047SMichael Ellerman #include "dis-asm.h"
15ae06e374SMichael Ellerman
16ae06e374SMichael Ellerman /* This file provides a disassembler function which uses
17ae06e374SMichael Ellerman the disassembler interface defined in dis-asm.h. */
18ae06e374SMichael Ellerman
19ae06e374SMichael Ellerman extern const struct spu_opcode spu_opcodes[];
20ae06e374SMichael Ellerman extern const int spu_num_opcodes;
21ae06e374SMichael Ellerman
22ae06e374SMichael Ellerman #define SPU_DISASM_TBL_SIZE (1 << 11)
23ae06e374SMichael Ellerman static const struct spu_opcode *spu_disassemble_table[SPU_DISASM_TBL_SIZE];
24ae06e374SMichael Ellerman
25ae06e374SMichael Ellerman static void
init_spu_disassemble(void)26ae06e374SMichael Ellerman init_spu_disassemble (void)
27ae06e374SMichael Ellerman {
28ae06e374SMichael Ellerman int i;
29ae06e374SMichael Ellerman
30ae06e374SMichael Ellerman /* If two instructions have the same opcode then we prefer the first
31ae06e374SMichael Ellerman * one. In most cases it is just an alternate mnemonic. */
32ae06e374SMichael Ellerman for (i = 0; i < spu_num_opcodes; i++)
33ae06e374SMichael Ellerman {
34ae06e374SMichael Ellerman int o = spu_opcodes[i].opcode;
35ae06e374SMichael Ellerman if (o >= SPU_DISASM_TBL_SIZE)
36ae06e374SMichael Ellerman continue; /* abort (); */
37ae06e374SMichael Ellerman if (spu_disassemble_table[o] == 0)
38ae06e374SMichael Ellerman spu_disassemble_table[o] = &spu_opcodes[i];
39ae06e374SMichael Ellerman }
40ae06e374SMichael Ellerman }
41ae06e374SMichael Ellerman
42ae06e374SMichael Ellerman /* Determine the instruction from the 10 least significant bits. */
43ae06e374SMichael Ellerman static const struct spu_opcode *
get_index_for_opcode(unsigned int insn)44ae06e374SMichael Ellerman get_index_for_opcode (unsigned int insn)
45ae06e374SMichael Ellerman {
46ae06e374SMichael Ellerman const struct spu_opcode *index;
47ae06e374SMichael Ellerman unsigned int opcode = insn >> (32-11);
48ae06e374SMichael Ellerman
49ae06e374SMichael Ellerman /* Init the table. This assumes that element 0/opcode 0 (currently
50ae06e374SMichael Ellerman * NOP) is always used */
51ae06e374SMichael Ellerman if (spu_disassemble_table[0] == 0)
52ae06e374SMichael Ellerman init_spu_disassemble ();
53ae06e374SMichael Ellerman
54ae06e374SMichael Ellerman if ((index = spu_disassemble_table[opcode & 0x780]) != 0
55ae06e374SMichael Ellerman && index->insn_type == RRR)
56ae06e374SMichael Ellerman return index;
57ae06e374SMichael Ellerman
58ae06e374SMichael Ellerman if ((index = spu_disassemble_table[opcode & 0x7f0]) != 0
59ae06e374SMichael Ellerman && (index->insn_type == RI18 || index->insn_type == LBT))
60ae06e374SMichael Ellerman return index;
61ae06e374SMichael Ellerman
62ae06e374SMichael Ellerman if ((index = spu_disassemble_table[opcode & 0x7f8]) != 0
63ae06e374SMichael Ellerman && index->insn_type == RI10)
64ae06e374SMichael Ellerman return index;
65ae06e374SMichael Ellerman
66ae06e374SMichael Ellerman if ((index = spu_disassemble_table[opcode & 0x7fc]) != 0
67ae06e374SMichael Ellerman && (index->insn_type == RI16))
68ae06e374SMichael Ellerman return index;
69ae06e374SMichael Ellerman
70ae06e374SMichael Ellerman if ((index = spu_disassemble_table[opcode & 0x7fe]) != 0
71ae06e374SMichael Ellerman && (index->insn_type == RI8))
72ae06e374SMichael Ellerman return index;
73ae06e374SMichael Ellerman
74ae06e374SMichael Ellerman if ((index = spu_disassemble_table[opcode & 0x7ff]) != 0)
75ae06e374SMichael Ellerman return index;
76ae06e374SMichael Ellerman
779340b0d3SAl Viro return NULL;
78ae06e374SMichael Ellerman }
79ae06e374SMichael Ellerman
80ae06e374SMichael Ellerman /* Print a Spu instruction. */
81ae06e374SMichael Ellerman
82ae06e374SMichael Ellerman int
print_insn_spu(unsigned long insn,unsigned long memaddr)83ae06e374SMichael Ellerman print_insn_spu (unsigned long insn, unsigned long memaddr)
84ae06e374SMichael Ellerman {
85ae06e374SMichael Ellerman int value;
86ae06e374SMichael Ellerman int hex_value;
87ae06e374SMichael Ellerman const struct spu_opcode *index;
88ae06e374SMichael Ellerman enum spu_insns tag;
89ae06e374SMichael Ellerman
90ae06e374SMichael Ellerman index = get_index_for_opcode (insn);
91ae06e374SMichael Ellerman
92ae06e374SMichael Ellerman if (index == 0)
93ae06e374SMichael Ellerman {
94e70d8f55SMathieu Malaterre printf(".long 0x%lx", insn);
95ae06e374SMichael Ellerman }
96ae06e374SMichael Ellerman else
97ae06e374SMichael Ellerman {
98ae06e374SMichael Ellerman int i;
99ae06e374SMichael Ellerman int paren = 0;
100ae06e374SMichael Ellerman tag = (enum spu_insns)(index - spu_opcodes);
101ae06e374SMichael Ellerman printf("%s", index->mnemonic);
102ae06e374SMichael Ellerman if (tag == M_BI || tag == M_BISL || tag == M_IRET || tag == M_BISLED
103ae06e374SMichael Ellerman || tag == M_BIHNZ || tag == M_BIHZ || tag == M_BINZ || tag == M_BIZ
104ae06e374SMichael Ellerman || tag == M_SYNC || tag == M_HBR)
105ae06e374SMichael Ellerman {
106ae06e374SMichael Ellerman int fb = (insn >> (32-18)) & 0x7f;
107ae06e374SMichael Ellerman if (fb & 0x40)
108ae06e374SMichael Ellerman printf(tag == M_SYNC ? "c" : "p");
109ae06e374SMichael Ellerman if (fb & 0x20)
110ae06e374SMichael Ellerman printf("d");
111ae06e374SMichael Ellerman if (fb & 0x10)
112ae06e374SMichael Ellerman printf("e");
113ae06e374SMichael Ellerman }
114ae06e374SMichael Ellerman if (index->arg[0] != 0)
115ae06e374SMichael Ellerman printf("\t");
116ae06e374SMichael Ellerman hex_value = 0;
117ae06e374SMichael Ellerman for (i = 1; i <= index->arg[0]; i++)
118ae06e374SMichael Ellerman {
119ae06e374SMichael Ellerman int arg = index->arg[i];
120ae06e374SMichael Ellerman if (arg != A_P && !paren && i > 1)
121ae06e374SMichael Ellerman printf(",");
122ae06e374SMichael Ellerman
123ae06e374SMichael Ellerman switch (arg)
124ae06e374SMichael Ellerman {
125ae06e374SMichael Ellerman case A_T:
126e70d8f55SMathieu Malaterre printf("$%lu",
127ae06e374SMichael Ellerman DECODE_INSN_RT (insn));
128ae06e374SMichael Ellerman break;
129ae06e374SMichael Ellerman case A_A:
130e70d8f55SMathieu Malaterre printf("$%lu",
131ae06e374SMichael Ellerman DECODE_INSN_RA (insn));
132ae06e374SMichael Ellerman break;
133ae06e374SMichael Ellerman case A_B:
134e70d8f55SMathieu Malaterre printf("$%lu",
135ae06e374SMichael Ellerman DECODE_INSN_RB (insn));
136ae06e374SMichael Ellerman break;
137ae06e374SMichael Ellerman case A_C:
138e70d8f55SMathieu Malaterre printf("$%lu",
139ae06e374SMichael Ellerman DECODE_INSN_RC (insn));
140ae06e374SMichael Ellerman break;
141ae06e374SMichael Ellerman case A_S:
142e70d8f55SMathieu Malaterre printf("$sp%lu",
143ae06e374SMichael Ellerman DECODE_INSN_RA (insn));
144ae06e374SMichael Ellerman break;
145ae06e374SMichael Ellerman case A_H:
146e70d8f55SMathieu Malaterre printf("$ch%lu",
147ae06e374SMichael Ellerman DECODE_INSN_RA (insn));
148ae06e374SMichael Ellerman break;
149ae06e374SMichael Ellerman case A_P:
150ae06e374SMichael Ellerman paren++;
151ae06e374SMichael Ellerman printf("(");
152ae06e374SMichael Ellerman break;
153ae06e374SMichael Ellerman case A_U7A:
154e70d8f55SMathieu Malaterre printf("%lu",
155ae06e374SMichael Ellerman 173 - DECODE_INSN_U8 (insn));
156ae06e374SMichael Ellerman break;
157ae06e374SMichael Ellerman case A_U7B:
158e70d8f55SMathieu Malaterre printf("%lu",
159ae06e374SMichael Ellerman 155 - DECODE_INSN_U8 (insn));
160ae06e374SMichael Ellerman break;
161ae06e374SMichael Ellerman case A_S3:
162ae06e374SMichael Ellerman case A_S6:
163ae06e374SMichael Ellerman case A_S7:
164ae06e374SMichael Ellerman case A_S7N:
165ae06e374SMichael Ellerman case A_U3:
166ae06e374SMichael Ellerman case A_U5:
167ae06e374SMichael Ellerman case A_U6:
168ae06e374SMichael Ellerman case A_U7:
169ae06e374SMichael Ellerman hex_value = DECODE_INSN_I7 (insn);
170ae06e374SMichael Ellerman printf("%d", hex_value);
171ae06e374SMichael Ellerman break;
172ae06e374SMichael Ellerman case A_S11:
173ae06e374SMichael Ellerman print_address(memaddr + DECODE_INSN_I9a (insn) * 4);
174ae06e374SMichael Ellerman break;
175ae06e374SMichael Ellerman case A_S11I:
176ae06e374SMichael Ellerman print_address(memaddr + DECODE_INSN_I9b (insn) * 4);
177ae06e374SMichael Ellerman break;
178ae06e374SMichael Ellerman case A_S10:
179ae06e374SMichael Ellerman case A_S10B:
180ae06e374SMichael Ellerman hex_value = DECODE_INSN_I10 (insn);
181ae06e374SMichael Ellerman printf("%d", hex_value);
182ae06e374SMichael Ellerman break;
183ae06e374SMichael Ellerman case A_S14:
184ae06e374SMichael Ellerman hex_value = DECODE_INSN_I10 (insn) * 16;
185ae06e374SMichael Ellerman printf("%d", hex_value);
186ae06e374SMichael Ellerman break;
187ae06e374SMichael Ellerman case A_S16:
188ae06e374SMichael Ellerman hex_value = DECODE_INSN_I16 (insn);
189ae06e374SMichael Ellerman printf("%d", hex_value);
190ae06e374SMichael Ellerman break;
191ae06e374SMichael Ellerman case A_X16:
192ae06e374SMichael Ellerman hex_value = DECODE_INSN_U16 (insn);
193ae06e374SMichael Ellerman printf("%u", hex_value);
194ae06e374SMichael Ellerman break;
195ae06e374SMichael Ellerman case A_R18:
196ae06e374SMichael Ellerman value = DECODE_INSN_I16 (insn) * 4;
197ae06e374SMichael Ellerman if (value == 0)
198ae06e374SMichael Ellerman printf("%d", value);
199ae06e374SMichael Ellerman else
200ae06e374SMichael Ellerman {
201ae06e374SMichael Ellerman hex_value = memaddr + value;
202ae06e374SMichael Ellerman print_address(hex_value & 0x3ffff);
203ae06e374SMichael Ellerman }
204ae06e374SMichael Ellerman break;
205ae06e374SMichael Ellerman case A_S18:
206ae06e374SMichael Ellerman value = DECODE_INSN_U16 (insn) * 4;
207ae06e374SMichael Ellerman if (value == 0)
208ae06e374SMichael Ellerman printf("%d", value);
209ae06e374SMichael Ellerman else
210ae06e374SMichael Ellerman print_address(value);
211ae06e374SMichael Ellerman break;
212ae06e374SMichael Ellerman case A_U18:
213ae06e374SMichael Ellerman value = DECODE_INSN_U18 (insn);
214ae06e374SMichael Ellerman if (value == 0 || 1)
215ae06e374SMichael Ellerman {
216ae06e374SMichael Ellerman hex_value = value;
217ae06e374SMichael Ellerman printf("%u", value);
218ae06e374SMichael Ellerman }
219ae06e374SMichael Ellerman else
220ae06e374SMichael Ellerman print_address(value);
221ae06e374SMichael Ellerman break;
222ae06e374SMichael Ellerman case A_U14:
223ae06e374SMichael Ellerman hex_value = DECODE_INSN_U14 (insn);
224ae06e374SMichael Ellerman printf("%u", hex_value);
225ae06e374SMichael Ellerman break;
226ae06e374SMichael Ellerman }
227ae06e374SMichael Ellerman if (arg != A_P && paren)
228ae06e374SMichael Ellerman {
229ae06e374SMichael Ellerman printf(")");
230ae06e374SMichael Ellerman paren--;
231ae06e374SMichael Ellerman }
232ae06e374SMichael Ellerman }
233ae06e374SMichael Ellerman if (hex_value > 16)
234ae06e374SMichael Ellerman printf("\t# %x", hex_value);
235ae06e374SMichael Ellerman }
236ae06e374SMichael Ellerman return 4;
237ae06e374SMichael Ellerman }
238