xref: /OK3568_Linux_fs/kernel/arch/powerpc/xmon/ppc-dis.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /* ppc-dis.c -- Disassemble PowerPC instructions
3*4882a593Smuzhiyun    Copyright (C) 1994-2016 Free Software Foundation, Inc.
4*4882a593Smuzhiyun    Written by Ian Lance Taylor, Cygnus Support
5*4882a593Smuzhiyun 
6*4882a593Smuzhiyun This file is part of GDB, GAS, and the GNU binutils.
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <asm/cputable.h>
11*4882a593Smuzhiyun #include <asm/cpu_has_feature.h>
12*4882a593Smuzhiyun #include "nonstdio.h"
13*4882a593Smuzhiyun #include "ansidecl.h"
14*4882a593Smuzhiyun #include "ppc.h"
15*4882a593Smuzhiyun #include "dis-asm.h"
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun /* This file provides several disassembler functions, all of which use
18*4882a593Smuzhiyun    the disassembler interface defined in dis-asm.h.  Several functions
19*4882a593Smuzhiyun    are provided because this file handles disassembly for the PowerPC
20*4882a593Smuzhiyun    in both big and little endian mode and also for the POWER (RS/6000)
21*4882a593Smuzhiyun    chip.  */
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun /* Extract the operand value from the PowerPC or POWER instruction.  */
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun static long
operand_value_powerpc(const struct powerpc_operand * operand,unsigned long insn,ppc_cpu_t dialect)26*4882a593Smuzhiyun operand_value_powerpc (const struct powerpc_operand *operand,
27*4882a593Smuzhiyun 		       unsigned long insn, ppc_cpu_t dialect)
28*4882a593Smuzhiyun {
29*4882a593Smuzhiyun   long value;
30*4882a593Smuzhiyun   int invalid;
31*4882a593Smuzhiyun   /* Extract the value from the instruction.  */
32*4882a593Smuzhiyun   if (operand->extract)
33*4882a593Smuzhiyun     value = (*operand->extract) (insn, dialect, &invalid);
34*4882a593Smuzhiyun   else
35*4882a593Smuzhiyun     {
36*4882a593Smuzhiyun       if (operand->shift >= 0)
37*4882a593Smuzhiyun 	value = (insn >> operand->shift) & operand->bitm;
38*4882a593Smuzhiyun       else
39*4882a593Smuzhiyun 	value = (insn << -operand->shift) & operand->bitm;
40*4882a593Smuzhiyun       if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
41*4882a593Smuzhiyun 	{
42*4882a593Smuzhiyun 	  /* BITM is always some number of zeros followed by some
43*4882a593Smuzhiyun 	     number of ones, followed by some number of zeros.  */
44*4882a593Smuzhiyun 	  unsigned long top = operand->bitm;
45*4882a593Smuzhiyun 	  /* top & -top gives the rightmost 1 bit, so this
46*4882a593Smuzhiyun 	     fills in any trailing zeros.  */
47*4882a593Smuzhiyun 	  top |= (top & -top) - 1;
48*4882a593Smuzhiyun 	  top &= ~(top >> 1);
49*4882a593Smuzhiyun 	  value = (value ^ top) - top;
50*4882a593Smuzhiyun 	}
51*4882a593Smuzhiyun     }
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun   return value;
54*4882a593Smuzhiyun }
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun /* Determine whether the optional operand(s) should be printed.  */
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun static int
skip_optional_operands(const unsigned char * opindex,unsigned long insn,ppc_cpu_t dialect)59*4882a593Smuzhiyun skip_optional_operands (const unsigned char *opindex,
60*4882a593Smuzhiyun 			unsigned long insn, ppc_cpu_t dialect)
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun   const struct powerpc_operand *operand;
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun   for (; *opindex != 0; opindex++)
65*4882a593Smuzhiyun     {
66*4882a593Smuzhiyun       operand = &powerpc_operands[*opindex];
67*4882a593Smuzhiyun       if ((operand->flags & PPC_OPERAND_NEXT) != 0
68*4882a593Smuzhiyun 	  || ((operand->flags & PPC_OPERAND_OPTIONAL) != 0
69*4882a593Smuzhiyun 	      && operand_value_powerpc (operand, insn, dialect) !=
70*4882a593Smuzhiyun 		 ppc_optional_operand_value (operand)))
71*4882a593Smuzhiyun 	return 0;
72*4882a593Smuzhiyun     }
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun   return 1;
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun /* Find a match for INSN in the opcode table, given machine DIALECT.
78*4882a593Smuzhiyun    A DIALECT of -1 is special, matching all machine opcode variations.  */
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun static const struct powerpc_opcode *
lookup_powerpc(unsigned long insn,ppc_cpu_t dialect)81*4882a593Smuzhiyun lookup_powerpc (unsigned long insn, ppc_cpu_t dialect)
82*4882a593Smuzhiyun {
83*4882a593Smuzhiyun   const struct powerpc_opcode *opcode;
84*4882a593Smuzhiyun   const struct powerpc_opcode *opcode_end;
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun   opcode_end = powerpc_opcodes + powerpc_num_opcodes;
87*4882a593Smuzhiyun   /* Find the first match in the opcode table for this major opcode.  */
88*4882a593Smuzhiyun   for (opcode = powerpc_opcodes; opcode < opcode_end; ++opcode)
89*4882a593Smuzhiyun     {
90*4882a593Smuzhiyun       const unsigned char *opindex;
91*4882a593Smuzhiyun       const struct powerpc_operand *operand;
92*4882a593Smuzhiyun       int invalid;
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun       if ((insn & opcode->mask) != opcode->opcode
95*4882a593Smuzhiyun 	  || (dialect != (ppc_cpu_t) -1
96*4882a593Smuzhiyun 	      && ((opcode->flags & dialect) == 0
97*4882a593Smuzhiyun 		  || (opcode->deprecated & dialect) != 0)))
98*4882a593Smuzhiyun 	continue;
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun       /* Check validity of operands.  */
101*4882a593Smuzhiyun       invalid = 0;
102*4882a593Smuzhiyun       for (opindex = opcode->operands; *opindex != 0; opindex++)
103*4882a593Smuzhiyun 	{
104*4882a593Smuzhiyun 	  operand = powerpc_operands + *opindex;
105*4882a593Smuzhiyun 	  if (operand->extract)
106*4882a593Smuzhiyun 	    (*operand->extract) (insn, dialect, &invalid);
107*4882a593Smuzhiyun 	}
108*4882a593Smuzhiyun       if (invalid)
109*4882a593Smuzhiyun 	continue;
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun       return opcode;
112*4882a593Smuzhiyun     }
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun   return NULL;
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun /* Print a PowerPC or POWER instruction.  */
118*4882a593Smuzhiyun 
print_insn_powerpc(unsigned long insn,unsigned long memaddr)119*4882a593Smuzhiyun int print_insn_powerpc (unsigned long insn, unsigned long memaddr)
120*4882a593Smuzhiyun {
121*4882a593Smuzhiyun   const struct powerpc_opcode *opcode;
122*4882a593Smuzhiyun   bool insn_is_short;
123*4882a593Smuzhiyun   ppc_cpu_t dialect;
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun   dialect = PPC_OPCODE_PPC | PPC_OPCODE_COMMON
126*4882a593Smuzhiyun             | PPC_OPCODE_64 | PPC_OPCODE_POWER4 | PPC_OPCODE_ALTIVEC;
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun   if (cpu_has_feature(CPU_FTRS_POWER5))
129*4882a593Smuzhiyun     dialect |= PPC_OPCODE_POWER5;
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun   if (cpu_has_feature(CPU_FTRS_CELL))
132*4882a593Smuzhiyun     dialect |= (PPC_OPCODE_CELL | PPC_OPCODE_ALTIVEC);
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun   if (cpu_has_feature(CPU_FTRS_POWER6))
135*4882a593Smuzhiyun     dialect |= (PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_ALTIVEC);
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun   if (cpu_has_feature(CPU_FTRS_POWER7))
138*4882a593Smuzhiyun     dialect |= (PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7
139*4882a593Smuzhiyun                 | PPC_OPCODE_ALTIVEC | PPC_OPCODE_VSX);
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun   if (cpu_has_feature(CPU_FTRS_POWER8))
142*4882a593Smuzhiyun     dialect |= (PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7
143*4882a593Smuzhiyun 		| PPC_OPCODE_POWER8 | PPC_OPCODE_HTM
144*4882a593Smuzhiyun 		| PPC_OPCODE_ALTIVEC | PPC_OPCODE_ALTIVEC2 | PPC_OPCODE_VSX);
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun   if (cpu_has_feature(CPU_FTRS_POWER9))
147*4882a593Smuzhiyun     dialect |= (PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7
148*4882a593Smuzhiyun 		| PPC_OPCODE_POWER8 | PPC_OPCODE_POWER9 | PPC_OPCODE_HTM
149*4882a593Smuzhiyun 		| PPC_OPCODE_ALTIVEC | PPC_OPCODE_ALTIVEC2
150*4882a593Smuzhiyun 		| PPC_OPCODE_VSX | PPC_OPCODE_VSX3);
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun   /* Get the major opcode of the insn.  */
153*4882a593Smuzhiyun   opcode = NULL;
154*4882a593Smuzhiyun   insn_is_short = false;
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun   if (opcode == NULL)
157*4882a593Smuzhiyun     opcode = lookup_powerpc (insn, dialect);
158*4882a593Smuzhiyun   if (opcode == NULL && (dialect & PPC_OPCODE_ANY) != 0)
159*4882a593Smuzhiyun     opcode = lookup_powerpc (insn, (ppc_cpu_t) -1);
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun   if (opcode != NULL)
162*4882a593Smuzhiyun     {
163*4882a593Smuzhiyun       const unsigned char *opindex;
164*4882a593Smuzhiyun       const struct powerpc_operand *operand;
165*4882a593Smuzhiyun       int need_comma;
166*4882a593Smuzhiyun       int need_paren;
167*4882a593Smuzhiyun       int skip_optional;
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun       if (opcode->operands[0] != 0)
170*4882a593Smuzhiyun 	printf("%-7s ", opcode->name);
171*4882a593Smuzhiyun       else
172*4882a593Smuzhiyun 	printf("%s", opcode->name);
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun       if (insn_is_short)
175*4882a593Smuzhiyun         /* The operands will be fetched out of the 16-bit instruction.  */
176*4882a593Smuzhiyun         insn >>= 16;
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun       /* Now extract and print the operands.  */
179*4882a593Smuzhiyun       need_comma = 0;
180*4882a593Smuzhiyun       need_paren = 0;
181*4882a593Smuzhiyun       skip_optional = -1;
182*4882a593Smuzhiyun       for (opindex = opcode->operands; *opindex != 0; opindex++)
183*4882a593Smuzhiyun 	{
184*4882a593Smuzhiyun 	  long value;
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 	  operand = powerpc_operands + *opindex;
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	  /* Operands that are marked FAKE are simply ignored.  We
189*4882a593Smuzhiyun 	     already made sure that the extract function considered
190*4882a593Smuzhiyun 	     the instruction to be valid.  */
191*4882a593Smuzhiyun 	  if ((operand->flags & PPC_OPERAND_FAKE) != 0)
192*4882a593Smuzhiyun 	    continue;
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	  /* If all of the optional operands have the value zero,
195*4882a593Smuzhiyun 	     then don't print any of them.  */
196*4882a593Smuzhiyun 	  if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0)
197*4882a593Smuzhiyun 	    {
198*4882a593Smuzhiyun 	      if (skip_optional < 0)
199*4882a593Smuzhiyun 		skip_optional = skip_optional_operands (opindex, insn,
200*4882a593Smuzhiyun 							dialect);
201*4882a593Smuzhiyun 	      if (skip_optional)
202*4882a593Smuzhiyun 		continue;
203*4882a593Smuzhiyun 	    }
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	  value = operand_value_powerpc (operand, insn, dialect);
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 	  if (need_comma)
208*4882a593Smuzhiyun 	    {
209*4882a593Smuzhiyun 	      printf(",");
210*4882a593Smuzhiyun 	      need_comma = 0;
211*4882a593Smuzhiyun 	    }
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	  /* Print the operand as directed by the flags.  */
214*4882a593Smuzhiyun 	  if ((operand->flags & PPC_OPERAND_GPR) != 0
215*4882a593Smuzhiyun 	      || ((operand->flags & PPC_OPERAND_GPR_0) != 0 && value != 0))
216*4882a593Smuzhiyun 	    printf("r%ld", value);
217*4882a593Smuzhiyun 	  else if ((operand->flags & PPC_OPERAND_FPR) != 0)
218*4882a593Smuzhiyun 	    printf("f%ld", value);
219*4882a593Smuzhiyun 	  else if ((operand->flags & PPC_OPERAND_VR) != 0)
220*4882a593Smuzhiyun 	    printf("v%ld", value);
221*4882a593Smuzhiyun 	  else if ((operand->flags & PPC_OPERAND_VSR) != 0)
222*4882a593Smuzhiyun 	    printf("vs%ld", value);
223*4882a593Smuzhiyun 	  else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0)
224*4882a593Smuzhiyun 	    print_address(memaddr + value);
225*4882a593Smuzhiyun 	  else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
226*4882a593Smuzhiyun 	    print_address(value & 0xffffffff);
227*4882a593Smuzhiyun 	  else if ((operand->flags & PPC_OPERAND_FSL) != 0)
228*4882a593Smuzhiyun 	    printf("fsl%ld", value);
229*4882a593Smuzhiyun 	  else if ((operand->flags & PPC_OPERAND_FCR) != 0)
230*4882a593Smuzhiyun 	    printf("fcr%ld", value);
231*4882a593Smuzhiyun 	  else if ((operand->flags & PPC_OPERAND_UDI) != 0)
232*4882a593Smuzhiyun 	    printf("%ld", value);
233*4882a593Smuzhiyun 	  else if ((operand->flags & PPC_OPERAND_CR_REG) != 0
234*4882a593Smuzhiyun 		   && (((dialect & PPC_OPCODE_PPC) != 0)
235*4882a593Smuzhiyun 		       || ((dialect & PPC_OPCODE_VLE) != 0)))
236*4882a593Smuzhiyun 	    printf("cr%ld", value);
237*4882a593Smuzhiyun 	  else if (((operand->flags & PPC_OPERAND_CR_BIT) != 0)
238*4882a593Smuzhiyun 		   && (((dialect & PPC_OPCODE_PPC) != 0)
239*4882a593Smuzhiyun 		       || ((dialect & PPC_OPCODE_VLE) != 0)))
240*4882a593Smuzhiyun 	    {
241*4882a593Smuzhiyun 	      static const char *cbnames[4] = { "lt", "gt", "eq", "so" };
242*4882a593Smuzhiyun 	      int cr;
243*4882a593Smuzhiyun 	      int cc;
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	      cr = value >> 2;
246*4882a593Smuzhiyun 	      if (cr != 0)
247*4882a593Smuzhiyun 		printf("4*cr%d+", cr);
248*4882a593Smuzhiyun 	      cc = value & 3;
249*4882a593Smuzhiyun 	      printf("%s", cbnames[cc]);
250*4882a593Smuzhiyun 	    }
251*4882a593Smuzhiyun 	  else
252*4882a593Smuzhiyun 	    printf("%d", (int) value);
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 	  if (need_paren)
255*4882a593Smuzhiyun 	    {
256*4882a593Smuzhiyun 	      printf(")");
257*4882a593Smuzhiyun 	      need_paren = 0;
258*4882a593Smuzhiyun 	    }
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun 	  if ((operand->flags & PPC_OPERAND_PARENS) == 0)
261*4882a593Smuzhiyun 	    need_comma = 1;
262*4882a593Smuzhiyun 	  else
263*4882a593Smuzhiyun 	    {
264*4882a593Smuzhiyun 	      printf("(");
265*4882a593Smuzhiyun 	      need_paren = 1;
266*4882a593Smuzhiyun 	    }
267*4882a593Smuzhiyun 	}
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun       /* We have found and printed an instruction.
270*4882a593Smuzhiyun          If it was a short VLE instruction we have more to do.  */
271*4882a593Smuzhiyun       if (insn_is_short)
272*4882a593Smuzhiyun         {
273*4882a593Smuzhiyun           memaddr += 2;
274*4882a593Smuzhiyun           return 2;
275*4882a593Smuzhiyun         }
276*4882a593Smuzhiyun       else
277*4882a593Smuzhiyun         /* Otherwise, return.  */
278*4882a593Smuzhiyun         return 4;
279*4882a593Smuzhiyun     }
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun   /* We could not find a match.  */
282*4882a593Smuzhiyun   printf(".long 0x%lx", insn);
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun   return 4;
285*4882a593Smuzhiyun }
286