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