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