xref: /openbmc/linux/arch/powerpc/xmon/spu-dis.c (revision 58e16d792a6a8c6b750f637a4649967fcac853dc)
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