blob: 9deea5ee13f652cd6c8a8b7f1f7d58a9229f31ae [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* ppc-dis.c -- Disassemble PowerPC instructions
Balbir Singh08d96e02017-02-02 10:33:43 +05302 Copyright (C) 1994-2016 Free Software Foundation, Inc.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 Written by Ian Lance Taylor, Cygnus Support
4
5This file is part of GDB, GAS, and the GNU binutils.
6
7GDB, GAS, and the GNU binutils are free software; you can redistribute
8them and/or modify them under the terms of the GNU General Public
9License as published by the Free Software Foundation; either version
102, or (at your option) any later version.
11
12GDB, GAS, and the GNU binutils are distributed in the hope that they
13will be useful, but WITHOUT ANY WARRANTY; without even the implied
14warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
15the GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with this file; see the file COPYING. If not, write to the Free
Michael Ellerman897f112b2006-11-23 00:46:47 +010019Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070020
Balbir Singh5b102782017-02-02 10:33:44 +053021#include <asm/cputable.h>
22#include <asm/cpu_has_feature.h>
23#include "nonstdio.h"
24#include "ansidecl.h"
25#include "ppc.h"
Michael Ellermane0426042006-11-23 00:46:45 +010026#include "dis-asm.h"
Balbir Singhcc7639c2017-02-02 10:33:42 +053027
28/* This file provides several disassembler functions, all of which use
29 the disassembler interface defined in dis-asm.h. Several functions
30 are provided because this file handles disassembly for the PowerPC
31 in both big and little endian mode and also for the POWER (RS/6000)
32 chip. */
Balbir Singhcc7639c2017-02-02 10:33:42 +053033
34/* Extract the operand value from the PowerPC or POWER instruction. */
35
36static long
37operand_value_powerpc (const struct powerpc_operand *operand,
Balbir Singh08d96e02017-02-02 10:33:43 +053038 unsigned long insn, ppc_cpu_t dialect)
Balbir Singhcc7639c2017-02-02 10:33:42 +053039{
40 long value;
41 int invalid;
42 /* Extract the value from the instruction. */
43 if (operand->extract)
44 value = (*operand->extract) (insn, dialect, &invalid);
45 else
46 {
Balbir Singh08d96e02017-02-02 10:33:43 +053047 if (operand->shift >= 0)
48 value = (insn >> operand->shift) & operand->bitm;
49 else
50 value = (insn << -operand->shift) & operand->bitm;
Balbir Singhcc7639c2017-02-02 10:33:42 +053051 if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
52 {
53 /* BITM is always some number of zeros followed by some
Balbir Singh08d96e02017-02-02 10:33:43 +053054 number of ones, followed by some number of zeros. */
Balbir Singhcc7639c2017-02-02 10:33:42 +053055 unsigned long top = operand->bitm;
56 /* top & -top gives the rightmost 1 bit, so this
57 fills in any trailing zeros. */
58 top |= (top & -top) - 1;
59 top &= ~(top >> 1);
60 value = (value ^ top) - top;
61 }
62 }
63
64 return value;
65}
66
67/* Determine whether the optional operand(s) should be printed. */
68
69static int
70skip_optional_operands (const unsigned char *opindex,
Balbir Singh08d96e02017-02-02 10:33:43 +053071 unsigned long insn, ppc_cpu_t dialect)
Balbir Singhcc7639c2017-02-02 10:33:42 +053072{
73 const struct powerpc_operand *operand;
74
75 for (; *opindex != 0; opindex++)
76 {
77 operand = &powerpc_operands[*opindex];
78 if ((operand->flags & PPC_OPERAND_NEXT) != 0
79 || ((operand->flags & PPC_OPERAND_OPTIONAL) != 0
Balbir Singh08d96e02017-02-02 10:33:43 +053080 && operand_value_powerpc (operand, insn, dialect) !=
81 ppc_optional_operand_value (operand)))
Balbir Singhcc7639c2017-02-02 10:33:42 +053082 return 0;
83 }
84
85 return 1;
86}
Linus Torvalds1da177e2005-04-16 15:20:36 -070087
Balbir Singh08d96e02017-02-02 10:33:43 +053088/* Find a match for INSN in the opcode table, given machine DIALECT.
89 A DIALECT of -1 is special, matching all machine opcode variations. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070090
Balbir Singh08d96e02017-02-02 10:33:43 +053091static const struct powerpc_opcode *
92lookup_powerpc (unsigned long insn, ppc_cpu_t dialect)
Linus Torvalds1da177e2005-04-16 15:20:36 -070093{
94 const struct powerpc_opcode *opcode;
95 const struct powerpc_opcode *opcode_end;
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
Balbir Singh5b102782017-02-02 10:33:44 +053097 opcode_end = powerpc_opcodes + powerpc_num_opcodes;
Balbir Singh08d96e02017-02-02 10:33:43 +053098 /* Find the first match in the opcode table for this major opcode. */
Balbir Singh5b102782017-02-02 10:33:44 +053099 for (opcode = powerpc_opcodes; opcode < opcode_end; ++opcode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100 {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 const unsigned char *opindex;
102 const struct powerpc_operand *operand;
103 int invalid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104
105 if ((insn & opcode->mask) != opcode->opcode
Balbir Singh08d96e02017-02-02 10:33:43 +0530106 || (dialect != (ppc_cpu_t) -1
107 && ((opcode->flags & dialect) == 0
108 || (opcode->deprecated & dialect) != 0)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 continue;
110
Balbir Singh08d96e02017-02-02 10:33:43 +0530111 /* Check validity of operands. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 invalid = 0;
113 for (opindex = opcode->operands; *opindex != 0; opindex++)
114 {
115 operand = powerpc_operands + *opindex;
116 if (operand->extract)
117 (*operand->extract) (insn, dialect, &invalid);
118 }
119 if (invalid)
120 continue;
121
Balbir Singh08d96e02017-02-02 10:33:43 +0530122 return opcode;
123 }
124
125 return NULL;
126}
127
Balbir Singh08d96e02017-02-02 10:33:43 +0530128/* Print a PowerPC or POWER instruction. */
129
Balbir Singh5b102782017-02-02 10:33:44 +0530130int print_insn_powerpc (unsigned long insn, unsigned long memaddr)
Balbir Singh08d96e02017-02-02 10:33:43 +0530131{
Balbir Singh08d96e02017-02-02 10:33:43 +0530132 const struct powerpc_opcode *opcode;
Balbir Singh5b102782017-02-02 10:33:44 +0530133 bool insn_is_short;
134 ppc_cpu_t dialect;
Balbir Singh08d96e02017-02-02 10:33:43 +0530135
Balbir Singh5b102782017-02-02 10:33:44 +0530136 dialect = PPC_OPCODE_PPC | PPC_OPCODE_COMMON
137 | PPC_OPCODE_64 | PPC_OPCODE_POWER4 | PPC_OPCODE_ALTIVEC;
Balbir Singh08d96e02017-02-02 10:33:43 +0530138
Balbir Singh5b102782017-02-02 10:33:44 +0530139 if (cpu_has_feature(CPU_FTRS_POWER5))
140 dialect |= PPC_OPCODE_POWER5;
141
142 if (cpu_has_feature(CPU_FTRS_CELL))
143 dialect |= (PPC_OPCODE_CELL | PPC_OPCODE_ALTIVEC);
144
145 if (cpu_has_feature(CPU_FTRS_POWER6))
146 dialect |= (PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_ALTIVEC);
147
148 if (cpu_has_feature(CPU_FTRS_POWER7))
149 dialect |= (PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7
150 | PPC_OPCODE_ALTIVEC | PPC_OPCODE_VSX);
151
152 if (cpu_has_feature(CPU_FTRS_POWER8))
153 dialect |= (PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7
154 | PPC_OPCODE_POWER8 | PPC_OPCODE_HTM
155 | PPC_OPCODE_ALTIVEC | PPC_OPCODE_ALTIVEC2 | PPC_OPCODE_VSX);
156
157 if (cpu_has_feature(CPU_FTRS_POWER9))
158 dialect |= (PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7
159 | PPC_OPCODE_POWER8 | PPC_OPCODE_POWER9 | PPC_OPCODE_HTM
160 | PPC_OPCODE_ALTIVEC | PPC_OPCODE_ALTIVEC2
161 | PPC_OPCODE_VSX | PPC_OPCODE_VSX3),
Balbir Singh08d96e02017-02-02 10:33:43 +0530162
163 /* Get the major opcode of the insn. */
164 opcode = NULL;
Balbir Singh5b102782017-02-02 10:33:44 +0530165 insn_is_short = false;
166
Balbir Singh08d96e02017-02-02 10:33:43 +0530167 if (opcode == NULL)
168 opcode = lookup_powerpc (insn, dialect);
169 if (opcode == NULL && (dialect & PPC_OPCODE_ANY) != 0)
170 opcode = lookup_powerpc (insn, (ppc_cpu_t) -1);
171
172 if (opcode != NULL)
173 {
174 const unsigned char *opindex;
175 const struct powerpc_operand *operand;
176 int need_comma;
177 int need_paren;
178 int skip_optional;
179
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 if (opcode->operands[0] != 0)
Balbir Singh5b102782017-02-02 10:33:44 +0530181 printf("%-7s ", opcode->name);
Balbir Singhcc7639c2017-02-02 10:33:42 +0530182 else
Balbir Singh5b102782017-02-02 10:33:44 +0530183 printf("%s", opcode->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184
Balbir Singh08d96e02017-02-02 10:33:43 +0530185 if (insn_is_short)
186 /* The operands will be fetched out of the 16-bit instruction. */
187 insn >>= 16;
188
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 /* Now extract and print the operands. */
190 need_comma = 0;
191 need_paren = 0;
Balbir Singhcc7639c2017-02-02 10:33:42 +0530192 skip_optional = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 for (opindex = opcode->operands; *opindex != 0; opindex++)
194 {
195 long value;
196
197 operand = powerpc_operands + *opindex;
198
199 /* Operands that are marked FAKE are simply ignored. We
200 already made sure that the extract function considered
201 the instruction to be valid. */
202 if ((operand->flags & PPC_OPERAND_FAKE) != 0)
203 continue;
204
Balbir Singhcc7639c2017-02-02 10:33:42 +0530205 /* If all of the optional operands have the value zero,
206 then don't print any of them. */
207 if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 {
Balbir Singhcc7639c2017-02-02 10:33:42 +0530209 if (skip_optional < 0)
210 skip_optional = skip_optional_operands (opindex, insn,
211 dialect);
212 if (skip_optional)
213 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 }
215
Balbir Singhcc7639c2017-02-02 10:33:42 +0530216 value = operand_value_powerpc (operand, insn, dialect);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217
218 if (need_comma)
219 {
Balbir Singh5b102782017-02-02 10:33:44 +0530220 printf(",");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 need_comma = 0;
222 }
223
224 /* Print the operand as directed by the flags. */
Michael Ellerman897f112b2006-11-23 00:46:47 +0100225 if ((operand->flags & PPC_OPERAND_GPR) != 0
226 || ((operand->flags & PPC_OPERAND_GPR_0) != 0 && value != 0))
Balbir Singh5b102782017-02-02 10:33:44 +0530227 printf("r%ld", value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 else if ((operand->flags & PPC_OPERAND_FPR) != 0)
Balbir Singh5b102782017-02-02 10:33:44 +0530229 printf("f%ld", value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 else if ((operand->flags & PPC_OPERAND_VR) != 0)
Balbir Singh5b102782017-02-02 10:33:44 +0530231 printf("v%ld", value);
Balbir Singh08d96e02017-02-02 10:33:43 +0530232 else if ((operand->flags & PPC_OPERAND_VSR) != 0)
Balbir Singh5b102782017-02-02 10:33:44 +0530233 printf("vs%ld", value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0)
Balbir Singh5b102782017-02-02 10:33:44 +0530235 print_address(memaddr + value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
Balbir Singh5b102782017-02-02 10:33:44 +0530237 print_address(value & 0xffffffff);
Balbir Singh08d96e02017-02-02 10:33:43 +0530238 else if ((operand->flags & PPC_OPERAND_FSL) != 0)
Balbir Singh5b102782017-02-02 10:33:44 +0530239 printf("fsl%ld", value);
Balbir Singh08d96e02017-02-02 10:33:43 +0530240 else if ((operand->flags & PPC_OPERAND_FCR) != 0)
Balbir Singh5b102782017-02-02 10:33:44 +0530241 printf("fcr%ld", value);
Balbir Singh08d96e02017-02-02 10:33:43 +0530242 else if ((operand->flags & PPC_OPERAND_UDI) != 0)
Balbir Singh5b102782017-02-02 10:33:44 +0530243 printf("%ld", value);
Balbir Singh08d96e02017-02-02 10:33:43 +0530244 else if ((operand->flags & PPC_OPERAND_CR_REG) != 0
245 && (((dialect & PPC_OPCODE_PPC) != 0)
246 || ((dialect & PPC_OPCODE_VLE) != 0)))
Balbir Singh5b102782017-02-02 10:33:44 +0530247 printf("cr%ld", value);
Balbir Singh08d96e02017-02-02 10:33:43 +0530248 else if (((operand->flags & PPC_OPERAND_CR_BIT) != 0)
249 && (((dialect & PPC_OPCODE_PPC) != 0)
250 || ((dialect & PPC_OPCODE_VLE) != 0)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 {
Balbir Singh08d96e02017-02-02 10:33:43 +0530252 static const char *cbnames[4] = { "lt", "gt", "eq", "so" };
253 int cr;
254 int cc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255
Balbir Singh08d96e02017-02-02 10:33:43 +0530256 cr = value >> 2;
257 if (cr != 0)
Balbir Singh5b102782017-02-02 10:33:44 +0530258 printf("4*cr%d+", cr);
Balbir Singh08d96e02017-02-02 10:33:43 +0530259 cc = value & 3;
Balbir Singh5b102782017-02-02 10:33:44 +0530260 printf("%s", cbnames[cc]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 }
Balbir Singh08d96e02017-02-02 10:33:43 +0530262 else
Balbir Singh5b102782017-02-02 10:33:44 +0530263 printf("%d", (int) value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264
265 if (need_paren)
266 {
Balbir Singh5b102782017-02-02 10:33:44 +0530267 printf(")");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 need_paren = 0;
269 }
270
271 if ((operand->flags & PPC_OPERAND_PARENS) == 0)
272 need_comma = 1;
273 else
274 {
Balbir Singh5b102782017-02-02 10:33:44 +0530275 printf("(");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 need_paren = 1;
277 }
278 }
279
Balbir Singh08d96e02017-02-02 10:33:43 +0530280 /* We have found and printed an instruction.
281 If it was a short VLE instruction we have more to do. */
282 if (insn_is_short)
283 {
284 memaddr += 2;
285 return 2;
286 }
287 else
288 /* Otherwise, return. */
289 return 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 }
291
292 /* We could not find a match. */
Balbir Singh5b102782017-02-02 10:33:44 +0530293 printf(".long 0x%lx", insn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
295 return 4;
296}