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