xref: /openbmc/linux/arch/powerpc/xmon/ppc-dis.c (revision d135b9cf)
1d135b9cfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2f78541dcSPaul Mackerras /* ppc-dis.c -- Disassemble PowerPC instructions
308d96e0bSBalbir Singh    Copyright (C) 1994-2016 Free Software Foundation, Inc.
4f78541dcSPaul Mackerras    Written by Ian Lance Taylor, Cygnus Support
5f78541dcSPaul Mackerras 
6f78541dcSPaul Mackerras This file is part of GDB, GAS, and the GNU binutils.
7f78541dcSPaul Mackerras 
8d135b9cfSThomas Gleixner  */
9f78541dcSPaul Mackerras 
105b102782SBalbir Singh #include <asm/cputable.h>
115b102782SBalbir Singh #include <asm/cpu_has_feature.h>
125b102782SBalbir Singh #include "nonstdio.h"
135b102782SBalbir Singh #include "ansidecl.h"
145b102782SBalbir Singh #include "ppc.h"
15e0426047SMichael Ellerman #include "dis-asm.h"
16cc7639ceSBalbir Singh 
17cc7639ceSBalbir Singh /* This file provides several disassembler functions, all of which use
18cc7639ceSBalbir Singh    the disassembler interface defined in dis-asm.h.  Several functions
19cc7639ceSBalbir Singh    are provided because this file handles disassembly for the PowerPC
20cc7639ceSBalbir Singh    in both big and little endian mode and also for the POWER (RS/6000)
21cc7639ceSBalbir Singh    chip.  */
22cc7639ceSBalbir Singh 
23cc7639ceSBalbir Singh /* Extract the operand value from the PowerPC or POWER instruction.  */
24cc7639ceSBalbir Singh 
25cc7639ceSBalbir Singh static long
operand_value_powerpc(const struct powerpc_operand * operand,unsigned long insn,ppc_cpu_t dialect)26cc7639ceSBalbir Singh operand_value_powerpc (const struct powerpc_operand *operand,
2708d96e0bSBalbir Singh 		       unsigned long insn, ppc_cpu_t dialect)
28cc7639ceSBalbir Singh {
29cc7639ceSBalbir Singh   long value;
30cc7639ceSBalbir Singh   int invalid;
31cc7639ceSBalbir Singh   /* Extract the value from the instruction.  */
32cc7639ceSBalbir Singh   if (operand->extract)
33cc7639ceSBalbir Singh     value = (*operand->extract) (insn, dialect, &invalid);
34cc7639ceSBalbir Singh   else
35cc7639ceSBalbir Singh     {
3608d96e0bSBalbir Singh       if (operand->shift >= 0)
37cc7639ceSBalbir Singh 	value = (insn >> operand->shift) & operand->bitm;
3808d96e0bSBalbir Singh       else
3908d96e0bSBalbir Singh 	value = (insn << -operand->shift) & operand->bitm;
40cc7639ceSBalbir Singh       if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
41cc7639ceSBalbir Singh 	{
42cc7639ceSBalbir Singh 	  /* BITM is always some number of zeros followed by some
4308d96e0bSBalbir Singh 	     number of ones, followed by some number of zeros.  */
44cc7639ceSBalbir Singh 	  unsigned long top = operand->bitm;
45cc7639ceSBalbir Singh 	  /* top & -top gives the rightmost 1 bit, so this
46cc7639ceSBalbir Singh 	     fills in any trailing zeros.  */
47cc7639ceSBalbir Singh 	  top |= (top & -top) - 1;
48cc7639ceSBalbir Singh 	  top &= ~(top >> 1);
49cc7639ceSBalbir Singh 	  value = (value ^ top) - top;
50cc7639ceSBalbir Singh 	}
51cc7639ceSBalbir Singh     }
52cc7639ceSBalbir Singh 
53cc7639ceSBalbir Singh   return value;
54cc7639ceSBalbir Singh }
55cc7639ceSBalbir Singh 
56cc7639ceSBalbir Singh /* Determine whether the optional operand(s) should be printed.  */
57cc7639ceSBalbir Singh 
58cc7639ceSBalbir Singh static int
skip_optional_operands(const unsigned char * opindex,unsigned long insn,ppc_cpu_t dialect)59cc7639ceSBalbir Singh skip_optional_operands (const unsigned char *opindex,
6008d96e0bSBalbir Singh 			unsigned long insn, ppc_cpu_t dialect)
61cc7639ceSBalbir Singh {
62cc7639ceSBalbir Singh   const struct powerpc_operand *operand;
63cc7639ceSBalbir Singh 
64cc7639ceSBalbir Singh   for (; *opindex != 0; opindex++)
65cc7639ceSBalbir Singh     {
66cc7639ceSBalbir Singh       operand = &powerpc_operands[*opindex];
67cc7639ceSBalbir Singh       if ((operand->flags & PPC_OPERAND_NEXT) != 0
68cc7639ceSBalbir Singh 	  || ((operand->flags & PPC_OPERAND_OPTIONAL) != 0
6908d96e0bSBalbir Singh 	      && operand_value_powerpc (operand, insn, dialect) !=
7008d96e0bSBalbir Singh 		 ppc_optional_operand_value (operand)))
71cc7639ceSBalbir Singh 	return 0;
72cc7639ceSBalbir Singh     }
73cc7639ceSBalbir Singh 
74cc7639ceSBalbir Singh   return 1;
75cc7639ceSBalbir Singh }
76f78541dcSPaul Mackerras 
7708d96e0bSBalbir Singh /* Find a match for INSN in the opcode table, given machine DIALECT.
7808d96e0bSBalbir Singh    A DIALECT of -1 is special, matching all machine opcode variations.  */
79f78541dcSPaul Mackerras 
8008d96e0bSBalbir Singh static const struct powerpc_opcode *
lookup_powerpc(unsigned long insn,ppc_cpu_t dialect)8108d96e0bSBalbir Singh lookup_powerpc (unsigned long insn, ppc_cpu_t dialect)
82f78541dcSPaul Mackerras {
83f78541dcSPaul Mackerras   const struct powerpc_opcode *opcode;
84f78541dcSPaul Mackerras   const struct powerpc_opcode *opcode_end;
85f78541dcSPaul Mackerras 
865b102782SBalbir Singh   opcode_end = powerpc_opcodes + powerpc_num_opcodes;
8708d96e0bSBalbir Singh   /* Find the first match in the opcode table for this major opcode.  */
885b102782SBalbir Singh   for (opcode = powerpc_opcodes; opcode < opcode_end; ++opcode)
89f78541dcSPaul Mackerras     {
90f78541dcSPaul Mackerras       const unsigned char *opindex;
91f78541dcSPaul Mackerras       const struct powerpc_operand *operand;
92f78541dcSPaul Mackerras       int invalid;
93f78541dcSPaul Mackerras 
94f78541dcSPaul Mackerras       if ((insn & opcode->mask) != opcode->opcode
9508d96e0bSBalbir Singh 	  || (dialect != (ppc_cpu_t) -1
9608d96e0bSBalbir Singh 	      && ((opcode->flags & dialect) == 0
9708d96e0bSBalbir Singh 		  || (opcode->deprecated & dialect) != 0)))
98f78541dcSPaul Mackerras 	continue;
99f78541dcSPaul Mackerras 
10008d96e0bSBalbir Singh       /* Check validity of operands.  */
101f78541dcSPaul Mackerras       invalid = 0;
102f78541dcSPaul Mackerras       for (opindex = opcode->operands; *opindex != 0; opindex++)
103f78541dcSPaul Mackerras 	{
104f78541dcSPaul Mackerras 	  operand = powerpc_operands + *opindex;
105f78541dcSPaul Mackerras 	  if (operand->extract)
106f78541dcSPaul Mackerras 	    (*operand->extract) (insn, dialect, &invalid);
107f78541dcSPaul Mackerras 	}
108f78541dcSPaul Mackerras       if (invalid)
109f78541dcSPaul Mackerras 	continue;
110f78541dcSPaul Mackerras 
11108d96e0bSBalbir Singh       return opcode;
11208d96e0bSBalbir Singh     }
11308d96e0bSBalbir Singh 
11408d96e0bSBalbir Singh   return NULL;
11508d96e0bSBalbir Singh }
11608d96e0bSBalbir Singh 
11708d96e0bSBalbir Singh /* Print a PowerPC or POWER instruction.  */
11808d96e0bSBalbir Singh 
print_insn_powerpc(unsigned long insn,unsigned long memaddr)1195b102782SBalbir Singh int print_insn_powerpc (unsigned long insn, unsigned long memaddr)
12008d96e0bSBalbir Singh {
12108d96e0bSBalbir Singh   const struct powerpc_opcode *opcode;
1225b102782SBalbir Singh   bool insn_is_short;
1235b102782SBalbir Singh   ppc_cpu_t dialect;
12408d96e0bSBalbir Singh 
1255b102782SBalbir Singh   dialect = PPC_OPCODE_PPC | PPC_OPCODE_COMMON
1265b102782SBalbir Singh             | PPC_OPCODE_64 | PPC_OPCODE_POWER4 | PPC_OPCODE_ALTIVEC;
12708d96e0bSBalbir Singh 
1285b102782SBalbir Singh   if (cpu_has_feature(CPU_FTRS_POWER5))
1295b102782SBalbir Singh     dialect |= PPC_OPCODE_POWER5;
1305b102782SBalbir Singh 
1315b102782SBalbir Singh   if (cpu_has_feature(CPU_FTRS_CELL))
1325b102782SBalbir Singh     dialect |= (PPC_OPCODE_CELL | PPC_OPCODE_ALTIVEC);
1335b102782SBalbir Singh 
1345b102782SBalbir Singh   if (cpu_has_feature(CPU_FTRS_POWER6))
1355b102782SBalbir Singh     dialect |= (PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_ALTIVEC);
1365b102782SBalbir Singh 
1375b102782SBalbir Singh   if (cpu_has_feature(CPU_FTRS_POWER7))
1385b102782SBalbir Singh     dialect |= (PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7
1395b102782SBalbir Singh                 | PPC_OPCODE_ALTIVEC | PPC_OPCODE_VSX);
1405b102782SBalbir Singh 
1415b102782SBalbir Singh   if (cpu_has_feature(CPU_FTRS_POWER8))
1425b102782SBalbir Singh     dialect |= (PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7
1435b102782SBalbir Singh 		| PPC_OPCODE_POWER8 | PPC_OPCODE_HTM
1445b102782SBalbir Singh 		| PPC_OPCODE_ALTIVEC | PPC_OPCODE_ALTIVEC2 | PPC_OPCODE_VSX);
1455b102782SBalbir Singh 
1465b102782SBalbir Singh   if (cpu_has_feature(CPU_FTRS_POWER9))
1475b102782SBalbir Singh     dialect |= (PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7
1485b102782SBalbir Singh 		| PPC_OPCODE_POWER8 | PPC_OPCODE_POWER9 | PPC_OPCODE_HTM
1495b102782SBalbir Singh 		| PPC_OPCODE_ALTIVEC | PPC_OPCODE_ALTIVEC2
150e7140639SNathan Chancellor 		| PPC_OPCODE_VSX | PPC_OPCODE_VSX3);
15108d96e0bSBalbir Singh 
15208d96e0bSBalbir Singh   /* Get the major opcode of the insn.  */
15308d96e0bSBalbir Singh   opcode = NULL;
1545b102782SBalbir Singh   insn_is_short = false;
1555b102782SBalbir Singh 
15608d96e0bSBalbir Singh   if (opcode == NULL)
15708d96e0bSBalbir Singh     opcode = lookup_powerpc (insn, dialect);
15808d96e0bSBalbir Singh   if (opcode == NULL && (dialect & PPC_OPCODE_ANY) != 0)
15908d96e0bSBalbir Singh     opcode = lookup_powerpc (insn, (ppc_cpu_t) -1);
16008d96e0bSBalbir Singh 
16108d96e0bSBalbir Singh   if (opcode != NULL)
16208d96e0bSBalbir Singh     {
16308d96e0bSBalbir Singh       const unsigned char *opindex;
16408d96e0bSBalbir Singh       const struct powerpc_operand *operand;
16508d96e0bSBalbir Singh       int need_comma;
16608d96e0bSBalbir Singh       int need_paren;
16708d96e0bSBalbir Singh       int skip_optional;
16808d96e0bSBalbir Singh 
169f78541dcSPaul Mackerras       if (opcode->operands[0] != 0)
1705b102782SBalbir Singh 	printf("%-7s ", opcode->name);
171cc7639ceSBalbir Singh       else
1725b102782SBalbir Singh 	printf("%s", opcode->name);
173f78541dcSPaul Mackerras 
17408d96e0bSBalbir Singh       if (insn_is_short)
17508d96e0bSBalbir Singh         /* The operands will be fetched out of the 16-bit instruction.  */
17608d96e0bSBalbir Singh         insn >>= 16;
17708d96e0bSBalbir Singh 
178f78541dcSPaul Mackerras       /* Now extract and print the operands.  */
179f78541dcSPaul Mackerras       need_comma = 0;
180f78541dcSPaul Mackerras       need_paren = 0;
181cc7639ceSBalbir Singh       skip_optional = -1;
182f78541dcSPaul Mackerras       for (opindex = opcode->operands; *opindex != 0; opindex++)
183f78541dcSPaul Mackerras 	{
184f78541dcSPaul Mackerras 	  long value;
185f78541dcSPaul Mackerras 
186f78541dcSPaul Mackerras 	  operand = powerpc_operands + *opindex;
187f78541dcSPaul Mackerras 
188f78541dcSPaul Mackerras 	  /* Operands that are marked FAKE are simply ignored.  We
189f78541dcSPaul Mackerras 	     already made sure that the extract function considered
190f78541dcSPaul Mackerras 	     the instruction to be valid.  */
191f78541dcSPaul Mackerras 	  if ((operand->flags & PPC_OPERAND_FAKE) != 0)
192f78541dcSPaul Mackerras 	    continue;
193f78541dcSPaul Mackerras 
194cc7639ceSBalbir Singh 	  /* If all of the optional operands have the value zero,
195cc7639ceSBalbir Singh 	     then don't print any of them.  */
196cc7639ceSBalbir Singh 	  if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0)
197f78541dcSPaul Mackerras 	    {
198cc7639ceSBalbir Singh 	      if (skip_optional < 0)
199cc7639ceSBalbir Singh 		skip_optional = skip_optional_operands (opindex, insn,
200cc7639ceSBalbir Singh 							dialect);
201cc7639ceSBalbir Singh 	      if (skip_optional)
202cc7639ceSBalbir Singh 		continue;
203f78541dcSPaul Mackerras 	    }
204f78541dcSPaul Mackerras 
205cc7639ceSBalbir Singh 	  value = operand_value_powerpc (operand, insn, dialect);
206f78541dcSPaul Mackerras 
207f78541dcSPaul Mackerras 	  if (need_comma)
208f78541dcSPaul Mackerras 	    {
2095b102782SBalbir Singh 	      printf(",");
210f78541dcSPaul Mackerras 	      need_comma = 0;
211f78541dcSPaul Mackerras 	    }
212f78541dcSPaul Mackerras 
213f78541dcSPaul Mackerras 	  /* Print the operand as directed by the flags.  */
214897f112bSMichael Ellerman 	  if ((operand->flags & PPC_OPERAND_GPR) != 0
215897f112bSMichael Ellerman 	      || ((operand->flags & PPC_OPERAND_GPR_0) != 0 && value != 0))
2165b102782SBalbir Singh 	    printf("r%ld", value);
217f78541dcSPaul Mackerras 	  else if ((operand->flags & PPC_OPERAND_FPR) != 0)
2185b102782SBalbir Singh 	    printf("f%ld", value);
219f78541dcSPaul Mackerras 	  else if ((operand->flags & PPC_OPERAND_VR) != 0)
2205b102782SBalbir Singh 	    printf("v%ld", value);
22108d96e0bSBalbir Singh 	  else if ((operand->flags & PPC_OPERAND_VSR) != 0)
2225b102782SBalbir Singh 	    printf("vs%ld", value);
223f78541dcSPaul Mackerras 	  else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0)
2245b102782SBalbir Singh 	    print_address(memaddr + value);
225f78541dcSPaul Mackerras 	  else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
2265b102782SBalbir Singh 	    print_address(value & 0xffffffff);
22708d96e0bSBalbir Singh 	  else if ((operand->flags & PPC_OPERAND_FSL) != 0)
2285b102782SBalbir Singh 	    printf("fsl%ld", value);
22908d96e0bSBalbir Singh 	  else if ((operand->flags & PPC_OPERAND_FCR) != 0)
2305b102782SBalbir Singh 	    printf("fcr%ld", value);
23108d96e0bSBalbir Singh 	  else if ((operand->flags & PPC_OPERAND_UDI) != 0)
2325b102782SBalbir Singh 	    printf("%ld", value);
23308d96e0bSBalbir Singh 	  else if ((operand->flags & PPC_OPERAND_CR_REG) != 0
23408d96e0bSBalbir Singh 		   && (((dialect & PPC_OPCODE_PPC) != 0)
23508d96e0bSBalbir Singh 		       || ((dialect & PPC_OPCODE_VLE) != 0)))
2365b102782SBalbir Singh 	    printf("cr%ld", value);
23708d96e0bSBalbir Singh 	  else if (((operand->flags & PPC_OPERAND_CR_BIT) != 0)
23808d96e0bSBalbir Singh 		   && (((dialect & PPC_OPCODE_PPC) != 0)
23908d96e0bSBalbir Singh 		       || ((dialect & PPC_OPCODE_VLE) != 0)))
240f78541dcSPaul Mackerras 	    {
241f78541dcSPaul Mackerras 	      static const char *cbnames[4] = { "lt", "gt", "eq", "so" };
242f78541dcSPaul Mackerras 	      int cr;
243f78541dcSPaul Mackerras 	      int cc;
244f78541dcSPaul Mackerras 
245f78541dcSPaul Mackerras 	      cr = value >> 2;
246f78541dcSPaul Mackerras 	      if (cr != 0)
2475b102782SBalbir Singh 		printf("4*cr%d+", cr);
248f78541dcSPaul Mackerras 	      cc = value & 3;
2495b102782SBalbir Singh 	      printf("%s", cbnames[cc]);
250f78541dcSPaul Mackerras 	    }
25108d96e0bSBalbir Singh 	  else
2525b102782SBalbir Singh 	    printf("%d", (int) value);
253f78541dcSPaul Mackerras 
254f78541dcSPaul Mackerras 	  if (need_paren)
255f78541dcSPaul Mackerras 	    {
2565b102782SBalbir Singh 	      printf(")");
257f78541dcSPaul Mackerras 	      need_paren = 0;
258f78541dcSPaul Mackerras 	    }
259f78541dcSPaul Mackerras 
260f78541dcSPaul Mackerras 	  if ((operand->flags & PPC_OPERAND_PARENS) == 0)
261f78541dcSPaul Mackerras 	    need_comma = 1;
262f78541dcSPaul Mackerras 	  else
263f78541dcSPaul Mackerras 	    {
2645b102782SBalbir Singh 	      printf("(");
265f78541dcSPaul Mackerras 	      need_paren = 1;
266f78541dcSPaul Mackerras 	    }
267f78541dcSPaul Mackerras 	}
268f78541dcSPaul Mackerras 
26908d96e0bSBalbir Singh       /* We have found and printed an instruction.
27008d96e0bSBalbir Singh          If it was a short VLE instruction we have more to do.  */
27108d96e0bSBalbir Singh       if (insn_is_short)
272f78541dcSPaul Mackerras         {
27308d96e0bSBalbir Singh           memaddr += 2;
27408d96e0bSBalbir Singh           return 2;
27508d96e0bSBalbir Singh         }
27608d96e0bSBalbir Singh       else
27708d96e0bSBalbir Singh         /* Otherwise, return.  */
27808d96e0bSBalbir Singh         return 4;
279f78541dcSPaul Mackerras     }
280f78541dcSPaul Mackerras 
281f78541dcSPaul Mackerras   /* We could not find a match.  */
2825b102782SBalbir Singh   printf(".long 0x%lx", insn);
283f78541dcSPaul Mackerras 
284f78541dcSPaul Mackerras   return 4;
285f78541dcSPaul Mackerras }
286