diff options
Diffstat (limited to 'arch/powerpc/xmon/ppc-dis.c')
-rw-r--r-- | arch/powerpc/xmon/ppc-dis.c | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/arch/powerpc/xmon/ppc-dis.c b/arch/powerpc/xmon/ppc-dis.c new file mode 100644 index 000000000000..ac0a9d2427e0 --- /dev/null +++ b/arch/powerpc/xmon/ppc-dis.c | |||
@@ -0,0 +1,184 @@ | |||
1 | /* ppc-dis.c -- Disassemble PowerPC instructions | ||
2 | Copyright 1994 Free Software Foundation, Inc. | ||
3 | Written by Ian Lance Taylor, Cygnus Support | ||
4 | |||
5 | This file is part of GDB, GAS, and the GNU binutils. | ||
6 | |||
7 | GDB, GAS, and the GNU binutils are free software; you can redistribute | ||
8 | them and/or modify them under the terms of the GNU General Public | ||
9 | License as published by the Free Software Foundation; either version | ||
10 | 2, or (at your option) any later version. | ||
11 | |||
12 | GDB, GAS, and the GNU binutils are distributed in the hope that they | ||
13 | will be useful, but WITHOUT ANY WARRANTY; without even the implied | ||
14 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
15 | the GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this file; see the file COPYING. If not, write to the Free | ||
19 | Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | ||
20 | |||
21 | #include "nonstdio.h" | ||
22 | #include "ansidecl.h" | ||
23 | #include "ppc.h" | ||
24 | |||
25 | extern void print_address (unsigned long memaddr); | ||
26 | |||
27 | /* Print a PowerPC or POWER instruction. */ | ||
28 | |||
29 | int | ||
30 | print_insn_powerpc (unsigned long insn, unsigned long memaddr, int dialect) | ||
31 | { | ||
32 | const struct powerpc_opcode *opcode; | ||
33 | const struct powerpc_opcode *opcode_end; | ||
34 | unsigned long op; | ||
35 | |||
36 | if (dialect == 0) | ||
37 | dialect = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_COMMON | ||
38 | | PPC_OPCODE_64 | PPC_OPCODE_POWER4 | PPC_OPCODE_ALTIVEC; | ||
39 | |||
40 | /* Get the major opcode of the instruction. */ | ||
41 | op = PPC_OP (insn); | ||
42 | |||
43 | /* Find the first match in the opcode table. We could speed this up | ||
44 | a bit by doing a binary search on the major opcode. */ | ||
45 | opcode_end = powerpc_opcodes + powerpc_num_opcodes; | ||
46 | again: | ||
47 | for (opcode = powerpc_opcodes; opcode < opcode_end; opcode++) | ||
48 | { | ||
49 | unsigned long table_op; | ||
50 | const unsigned char *opindex; | ||
51 | const struct powerpc_operand *operand; | ||
52 | int invalid; | ||
53 | int need_comma; | ||
54 | int need_paren; | ||
55 | |||
56 | table_op = PPC_OP (opcode->opcode); | ||
57 | if (op < table_op) | ||
58 | break; | ||
59 | if (op > table_op) | ||
60 | continue; | ||
61 | |||
62 | if ((insn & opcode->mask) != opcode->opcode | ||
63 | || (opcode->flags & dialect) == 0) | ||
64 | continue; | ||
65 | |||
66 | /* Make two passes over the operands. First see if any of them | ||
67 | have extraction functions, and, if they do, make sure the | ||
68 | instruction is valid. */ | ||
69 | invalid = 0; | ||
70 | for (opindex = opcode->operands; *opindex != 0; opindex++) | ||
71 | { | ||
72 | operand = powerpc_operands + *opindex; | ||
73 | if (operand->extract) | ||
74 | (*operand->extract) (insn, dialect, &invalid); | ||
75 | } | ||
76 | if (invalid) | ||
77 | continue; | ||
78 | |||
79 | /* The instruction is valid. */ | ||
80 | printf("%s", opcode->name); | ||
81 | if (opcode->operands[0] != 0) | ||
82 | printf("\t"); | ||
83 | |||
84 | /* Now extract and print the operands. */ | ||
85 | need_comma = 0; | ||
86 | need_paren = 0; | ||
87 | for (opindex = opcode->operands; *opindex != 0; opindex++) | ||
88 | { | ||
89 | long value; | ||
90 | |||
91 | operand = powerpc_operands + *opindex; | ||
92 | |||
93 | /* Operands that are marked FAKE are simply ignored. We | ||
94 | already made sure that the extract function considered | ||
95 | the instruction to be valid. */ | ||
96 | if ((operand->flags & PPC_OPERAND_FAKE) != 0) | ||
97 | continue; | ||
98 | |||
99 | /* Extract the value from the instruction. */ | ||
100 | if (operand->extract) | ||
101 | value = (*operand->extract) (insn, dialect, &invalid); | ||
102 | else | ||
103 | { | ||
104 | value = (insn >> operand->shift) & ((1 << operand->bits) - 1); | ||
105 | if ((operand->flags & PPC_OPERAND_SIGNED) != 0 | ||
106 | && (value & (1 << (operand->bits - 1))) != 0) | ||
107 | value -= 1 << operand->bits; | ||
108 | } | ||
109 | |||
110 | /* If the operand is optional, and the value is zero, don't | ||
111 | print anything. */ | ||
112 | if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0 | ||
113 | && (operand->flags & PPC_OPERAND_NEXT) == 0 | ||
114 | && value == 0) | ||
115 | continue; | ||
116 | |||
117 | if (need_comma) | ||
118 | { | ||
119 | printf(","); | ||
120 | need_comma = 0; | ||
121 | } | ||
122 | |||
123 | /* Print the operand as directed by the flags. */ | ||
124 | if ((operand->flags & PPC_OPERAND_GPR) != 0) | ||
125 | printf("r%ld", value); | ||
126 | else if ((operand->flags & PPC_OPERAND_FPR) != 0) | ||
127 | printf("f%ld", value); | ||
128 | else if ((operand->flags & PPC_OPERAND_VR) != 0) | ||
129 | printf("v%ld", value); | ||
130 | else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0) | ||
131 | print_address (memaddr + value); | ||
132 | else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0) | ||
133 | print_address (value & 0xffffffff); | ||
134 | else if ((operand->flags & PPC_OPERAND_CR) == 0 | ||
135 | || (dialect & PPC_OPCODE_PPC) == 0) | ||
136 | printf("%ld", value); | ||
137 | else | ||
138 | { | ||
139 | if (operand->bits == 3) | ||
140 | printf("cr%d", value); | ||
141 | else | ||
142 | { | ||
143 | static const char *cbnames[4] = { "lt", "gt", "eq", "so" }; | ||
144 | int cr; | ||
145 | int cc; | ||
146 | |||
147 | cr = value >> 2; | ||
148 | if (cr != 0) | ||
149 | printf("4*cr%d+", cr); | ||
150 | cc = value & 3; | ||
151 | printf("%s", cbnames[cc]); | ||
152 | } | ||
153 | } | ||
154 | |||
155 | if (need_paren) | ||
156 | { | ||
157 | printf(")"); | ||
158 | need_paren = 0; | ||
159 | } | ||
160 | |||
161 | if ((operand->flags & PPC_OPERAND_PARENS) == 0) | ||
162 | need_comma = 1; | ||
163 | else | ||
164 | { | ||
165 | printf("("); | ||
166 | need_paren = 1; | ||
167 | } | ||
168 | } | ||
169 | |||
170 | /* We have found and printed an instruction; return. */ | ||
171 | return 4; | ||
172 | } | ||
173 | |||
174 | if ((dialect & PPC_OPCODE_ANY) != 0) | ||
175 | { | ||
176 | dialect = ~PPC_OPCODE_ANY; | ||
177 | goto again; | ||
178 | } | ||
179 | |||
180 | /* We could not find a match. */ | ||
181 | printf(".long 0x%lx", insn); | ||
182 | |||
183 | return 4; | ||
184 | } | ||