xref: /openbmc/linux/arch/powerpc/xmon/ppc-dis.c (revision 7e24a55b2122746c2eef192296fc84624354f895)
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 
125*4af27306SMichael Ellerman   dialect = PPC_OPCODE_PPC | PPC_OPCODE_COMMON;
12608d96e0bSBalbir Singh 
127*4af27306SMichael Ellerman   if (IS_ENABLED(CONFIG_PPC64))
128*4af27306SMichael Ellerman     dialect |= PPC_OPCODE_64 | PPC_OPCODE_POWER4 | PPC_OPCODE_CELL |
129*4af27306SMichael Ellerman 	PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7 | PPC_OPCODE_POWER8 |
130*4af27306SMichael Ellerman 	PPC_OPCODE_POWER9;
1315b102782SBalbir Singh 
132*4af27306SMichael Ellerman   if (cpu_has_feature(CPU_FTR_TM))
133*4af27306SMichael Ellerman     dialect |= PPC_OPCODE_HTM;
1345b102782SBalbir Singh 
135*4af27306SMichael Ellerman   if (cpu_has_feature(CPU_FTR_ALTIVEC))
136*4af27306SMichael Ellerman     dialect |= PPC_OPCODE_ALTIVEC | PPC_OPCODE_ALTIVEC2;
1375b102782SBalbir Singh 
138*4af27306SMichael Ellerman   if (cpu_has_feature(CPU_FTR_VSX))
139*4af27306SMichael Ellerman     dialect |= PPC_OPCODE_VSX | PPC_OPCODE_VSX3;
14008d96e0bSBalbir Singh 
14108d96e0bSBalbir Singh   /* Get the major opcode of the insn.  */
14208d96e0bSBalbir Singh   opcode = NULL;
1435b102782SBalbir Singh   insn_is_short = false;
1445b102782SBalbir Singh 
14508d96e0bSBalbir Singh   if (opcode == NULL)
14608d96e0bSBalbir Singh     opcode = lookup_powerpc (insn, dialect);
14708d96e0bSBalbir Singh   if (opcode == NULL && (dialect & PPC_OPCODE_ANY) != 0)
14808d96e0bSBalbir Singh     opcode = lookup_powerpc (insn, (ppc_cpu_t) -1);
14908d96e0bSBalbir Singh 
15008d96e0bSBalbir Singh   if (opcode != NULL)
15108d96e0bSBalbir Singh     {
15208d96e0bSBalbir Singh       const unsigned char *opindex;
15308d96e0bSBalbir Singh       const struct powerpc_operand *operand;
15408d96e0bSBalbir Singh       int need_comma;
15508d96e0bSBalbir Singh       int need_paren;
15608d96e0bSBalbir Singh       int skip_optional;
15708d96e0bSBalbir Singh 
158f78541dcSPaul Mackerras       if (opcode->operands[0] != 0)
1595b102782SBalbir Singh 	printf("%-7s ", opcode->name);
160cc7639ceSBalbir Singh       else
1615b102782SBalbir Singh 	printf("%s", opcode->name);
162f78541dcSPaul Mackerras 
16308d96e0bSBalbir Singh       if (insn_is_short)
16408d96e0bSBalbir Singh         /* The operands will be fetched out of the 16-bit instruction.  */
16508d96e0bSBalbir Singh         insn >>= 16;
16608d96e0bSBalbir Singh 
167f78541dcSPaul Mackerras       /* Now extract and print the operands.  */
168f78541dcSPaul Mackerras       need_comma = 0;
169f78541dcSPaul Mackerras       need_paren = 0;
170cc7639ceSBalbir Singh       skip_optional = -1;
171f78541dcSPaul Mackerras       for (opindex = opcode->operands; *opindex != 0; opindex++)
172f78541dcSPaul Mackerras 	{
173f78541dcSPaul Mackerras 	  long value;
174f78541dcSPaul Mackerras 
175f78541dcSPaul Mackerras 	  operand = powerpc_operands + *opindex;
176f78541dcSPaul Mackerras 
177f78541dcSPaul Mackerras 	  /* Operands that are marked FAKE are simply ignored.  We
178f78541dcSPaul Mackerras 	     already made sure that the extract function considered
179f78541dcSPaul Mackerras 	     the instruction to be valid.  */
180f78541dcSPaul Mackerras 	  if ((operand->flags & PPC_OPERAND_FAKE) != 0)
181f78541dcSPaul Mackerras 	    continue;
182f78541dcSPaul Mackerras 
183cc7639ceSBalbir Singh 	  /* If all of the optional operands have the value zero,
184cc7639ceSBalbir Singh 	     then don't print any of them.  */
185cc7639ceSBalbir Singh 	  if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0)
186f78541dcSPaul Mackerras 	    {
187cc7639ceSBalbir Singh 	      if (skip_optional < 0)
188cc7639ceSBalbir Singh 		skip_optional = skip_optional_operands (opindex, insn,
189cc7639ceSBalbir Singh 							dialect);
190cc7639ceSBalbir Singh 	      if (skip_optional)
191cc7639ceSBalbir Singh 		continue;
192f78541dcSPaul Mackerras 	    }
193f78541dcSPaul Mackerras 
194cc7639ceSBalbir Singh 	  value = operand_value_powerpc (operand, insn, dialect);
195f78541dcSPaul Mackerras 
196f78541dcSPaul Mackerras 	  if (need_comma)
197f78541dcSPaul Mackerras 	    {
1985b102782SBalbir Singh 	      printf(",");
199f78541dcSPaul Mackerras 	      need_comma = 0;
200f78541dcSPaul Mackerras 	    }
201f78541dcSPaul Mackerras 
202f78541dcSPaul Mackerras 	  /* Print the operand as directed by the flags.  */
203897f112bSMichael Ellerman 	  if ((operand->flags & PPC_OPERAND_GPR) != 0
204897f112bSMichael Ellerman 	      || ((operand->flags & PPC_OPERAND_GPR_0) != 0 && value != 0))
2055b102782SBalbir Singh 	    printf("r%ld", value);
206f78541dcSPaul Mackerras 	  else if ((operand->flags & PPC_OPERAND_FPR) != 0)
2075b102782SBalbir Singh 	    printf("f%ld", value);
208f78541dcSPaul Mackerras 	  else if ((operand->flags & PPC_OPERAND_VR) != 0)
2095b102782SBalbir Singh 	    printf("v%ld", value);
21008d96e0bSBalbir Singh 	  else if ((operand->flags & PPC_OPERAND_VSR) != 0)
2115b102782SBalbir Singh 	    printf("vs%ld", value);
212f78541dcSPaul Mackerras 	  else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0)
2135b102782SBalbir Singh 	    print_address(memaddr + value);
214f78541dcSPaul Mackerras 	  else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
2155b102782SBalbir Singh 	    print_address(value & 0xffffffff);
21608d96e0bSBalbir Singh 	  else if ((operand->flags & PPC_OPERAND_FSL) != 0)
2175b102782SBalbir Singh 	    printf("fsl%ld", value);
21808d96e0bSBalbir Singh 	  else if ((operand->flags & PPC_OPERAND_FCR) != 0)
2195b102782SBalbir Singh 	    printf("fcr%ld", value);
22008d96e0bSBalbir Singh 	  else if ((operand->flags & PPC_OPERAND_UDI) != 0)
2215b102782SBalbir Singh 	    printf("%ld", value);
22208d96e0bSBalbir Singh 	  else if ((operand->flags & PPC_OPERAND_CR_REG) != 0
22308d96e0bSBalbir Singh 		   && (((dialect & PPC_OPCODE_PPC) != 0)
22408d96e0bSBalbir Singh 		       || ((dialect & PPC_OPCODE_VLE) != 0)))
2255b102782SBalbir Singh 	    printf("cr%ld", value);
22608d96e0bSBalbir Singh 	  else if (((operand->flags & PPC_OPERAND_CR_BIT) != 0)
22708d96e0bSBalbir Singh 		   && (((dialect & PPC_OPCODE_PPC) != 0)
22808d96e0bSBalbir Singh 		       || ((dialect & PPC_OPCODE_VLE) != 0)))
229f78541dcSPaul Mackerras 	    {
230f78541dcSPaul Mackerras 	      static const char *cbnames[4] = { "lt", "gt", "eq", "so" };
231f78541dcSPaul Mackerras 	      int cr;
232f78541dcSPaul Mackerras 	      int cc;
233f78541dcSPaul Mackerras 
234f78541dcSPaul Mackerras 	      cr = value >> 2;
235f78541dcSPaul Mackerras 	      if (cr != 0)
2365b102782SBalbir Singh 		printf("4*cr%d+", cr);
237f78541dcSPaul Mackerras 	      cc = value & 3;
2385b102782SBalbir Singh 	      printf("%s", cbnames[cc]);
239f78541dcSPaul Mackerras 	    }
24008d96e0bSBalbir Singh 	  else
2415b102782SBalbir Singh 	    printf("%d", (int) value);
242f78541dcSPaul Mackerras 
243f78541dcSPaul Mackerras 	  if (need_paren)
244f78541dcSPaul Mackerras 	    {
2455b102782SBalbir Singh 	      printf(")");
246f78541dcSPaul Mackerras 	      need_paren = 0;
247f78541dcSPaul Mackerras 	    }
248f78541dcSPaul Mackerras 
249f78541dcSPaul Mackerras 	  if ((operand->flags & PPC_OPERAND_PARENS) == 0)
250f78541dcSPaul Mackerras 	    need_comma = 1;
251f78541dcSPaul Mackerras 	  else
252f78541dcSPaul Mackerras 	    {
2535b102782SBalbir Singh 	      printf("(");
254f78541dcSPaul Mackerras 	      need_paren = 1;
255f78541dcSPaul Mackerras 	    }
256f78541dcSPaul Mackerras 	}
257f78541dcSPaul Mackerras 
25808d96e0bSBalbir Singh       /* We have found and printed an instruction.
25908d96e0bSBalbir Singh          If it was a short VLE instruction we have more to do.  */
26008d96e0bSBalbir Singh       if (insn_is_short)
261f78541dcSPaul Mackerras         {
26208d96e0bSBalbir Singh           memaddr += 2;
26308d96e0bSBalbir Singh           return 2;
26408d96e0bSBalbir Singh         }
26508d96e0bSBalbir Singh       else
26608d96e0bSBalbir Singh         /* Otherwise, return.  */
26708d96e0bSBalbir Singh         return 4;
268f78541dcSPaul Mackerras     }
269f78541dcSPaul Mackerras 
270f78541dcSPaul Mackerras   /* We could not find a match.  */
2715b102782SBalbir Singh   printf(".long 0x%lx", insn);
272f78541dcSPaul Mackerras 
273f78541dcSPaul Mackerras   return 4;
274f78541dcSPaul Mackerras }
275