]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/rs6000-pinsn.c
Clean up rs6000 opcode stuff.
[thirdparty/binutils-gdb.git] / gdb / rs6000-pinsn.c
1 /* Print IBM RS/6000 instructions for GNU software.
2 Copyright 1991 Free Software Foundation, Inc.
3 Contributed by IBM Corporation.
4
5 This file is part of GDB and the GNU binutils.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 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 program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
20
21 #include <stdio.h>
22 #include "defs.h"
23 #include "rs6k-opcode.h"
24
25 /* Print the rs6k instruction at address MEMADDR in debugged memory,
26 on STREAM. Returns length of the instruction, in bytes. */
27
28 int
29 print_insn (memaddr, stream)
30 CORE_ADDR memaddr;
31 FILE *stream;
32 {
33 int pop, eop; /* primary and extended opcodes */
34 int min, max;
35 int best = -1; /* found best opcode index */
36 int oldbest = -1;
37 unsigned int the_insn;
38
39 read_memory (memaddr, &the_insn, sizeof (the_insn));
40 pop = (unsigned)(the_insn >> 26);
41 eop = ((the_insn) >> 1) & 0x3ff;
42 min = 0, max = NOPCODES-1;
43
44 while (min < max) {
45 best = (min + max) / 2;
46
47 /* see if we are running in loops */
48 if (best == oldbest)
49 goto not_found;
50 oldbest = best;
51
52 if (pop < rs6k_ops [best].p_opcode)
53 max = best;
54
55 else if (pop > rs6k_ops [best].p_opcode)
56 min = best;
57
58 else {
59 /* opcode matched, check extended opcode. */
60
61 if (rs6k_ops [best].e_opcode == -1) {
62 /* there is no valid extended opcode, what we've got is
63 just fine. */
64 goto insn_found;
65 }
66
67 else if (eop < rs6k_ops [best].e_opcode) {
68
69 while (pop == rs6k_ops [best].p_opcode) {
70 if (eop == rs6k_ops [best].e_opcode) /* found it! */
71 goto insn_found;
72 --best;
73 }
74 goto not_found;
75 }
76
77 else if (eop > rs6k_ops [best].e_opcode) {
78
79 while (pop == rs6k_ops [best].p_opcode) {
80 if (eop == rs6k_ops [best].e_opcode) /* found it! */
81 goto insn_found;
82 ++best;
83 }
84 goto not_found;
85 }
86
87 else /* eop == rs6k_ops [best].e_opcode */
88 goto insn_found;
89 }
90 }
91
92 best = min;
93 if (pop == rs6k_ops [best].p_opcode &&
94 (rs6k_ops [best].e_opcode == -1 || rs6k_ops [best].e_opcode == eop))
95 goto insn_found;
96
97 else
98 goto not_found;
99
100
101 insn_found:
102 print_operator (stream, memaddr, the_insn, best);
103 return 4;
104
105 not_found:
106 fprintf (stream, "0x%08x", the_insn);
107 return 4;
108 }
109
110
111
112 /* condition code names */
113 static char *cond_code [] = {
114 "lt", "gt", "eq", "so", "ge", "le", "ne", "ns", "nl", "ng", "z", "nz" };
115
116
117 print_operator (stream, memaddr, insn_word, insn_no)
118 FILE *stream;
119 long memaddr;
120 long insn_word;
121 int insn_no;
122 {
123 char buf [BUFSIZ];
124 char *qq = buf;
125 char *pp = rs6k_ops[insn_no].opr_ext;
126 int tmp;
127 int nocomma = 0; /* true if no comma needed */
128
129 *qq = '\0';
130 if (pp) {
131 while (*pp) {
132
133 switch ( *pp ) {
134 case '.':
135 if (insn_word & 0x1)
136 *qq++ = '.';
137 break;
138
139 case 'l':
140 if (insn_word & 0x1)
141 *qq++ = 'l';
142 break;
143
144 case 't':
145 if ((insn_word & 0x03e00000) == 0x01800000)
146 *qq++ = 't';
147 break;
148
149 case 'f':
150 if ((insn_word & 0x03e00000) == 0x00800000)
151 *qq++ = 'f';
152 break;
153
154 case 'a':
155 if (insn_word & 0x2)
156 *qq++ = 'a';
157 break;
158
159 case 'o':
160 if (insn_word & 0x4000)
161 *qq++ = 'o';
162 break;
163
164 case '1': /* exception #1 for bb/bc ambiguity */
165 tmp = (insn_word >> 21) & 0x1f; /* extract BO */
166 if (tmp != 0xc && tmp != 0x4) {
167 /* you can't use `bb' now. switch to `bc' */
168 *(qq-1) = 'c';
169 ++insn_no;
170 pp = rs6k_ops[insn_no].opr_ext;
171 continue;
172 }
173 break;
174
175 default:
176 abort ();
177 }
178 ++pp;
179 }
180 }
181
182 /* tab between operator and operand */
183 *qq++ = '\t';
184
185 /* parse the operand now. */
186 pp = rs6k_ops[insn_no].oprnd_format;
187
188 while (1) {
189 switch (*pp) {
190 case TO :
191 sprintf (qq, "%d", (insn_word >> 21) & 0x1f);
192 break;
193
194 case RT :
195 case RS :
196 sprintf (qq, "r%d", (insn_word >> 21) & 0x1f);
197 break;
198
199 case LI :
200 tmp = (insn_word >> 16) & 0x1f;
201 if (tmp > 11) {
202 fprintf (stderr, "Internal error: unknown cond code: 0x%x\n", insn_word);
203 tmp = 0;
204 }
205 sprintf (qq, "%s", cond_code [tmp]);
206 break;
207
208 case A2 :
209 case TA14 :
210 tmp = (insn_word & 0xfffc);
211 if (tmp & 0x8000) /* fix sign extension */
212 tmp -= 0x10000;
213
214 if ((insn_word & 0x2) == 0) /* if AA not set */
215 tmp += memaddr;
216
217 sprintf (qq, "0x%x", tmp);
218 break;
219
220 case TA24 :
221 tmp = insn_word & 0x03fffffc;
222 if (tmp & 0x2000000)
223 tmp -= 0x4000000;
224
225 if ((insn_word & 0x2) == 0) /* if no AA bit set */
226 tmp += memaddr;
227
228 sprintf (qq, "0x%x", tmp);
229 break;
230
231 case LEV : /* for svc only */
232 if (insn_word & 0x2) { /* SA is set */
233 nocomma = 1;
234 *qq = '\0';
235 }
236 else
237 sprintf (qq, "%d", (insn_word >> 5) & 0x7f);
238 break;
239
240 case FL1 : /* for svc only */
241 if (insn_word & 0x2) { /* SA is set */
242 nocomma = 1;
243 *qq = '\0';
244 }
245 else
246 sprintf (qq, "%d", (insn_word >> 12) & 0xf);
247 break;
248
249 case FL2 : /* for svc only */
250 nocomma = 0;
251 if (insn_word & 0x2) /* SA is set */
252 sprintf (qq, "%d", (insn_word >> 2) & 0x3fff);
253 else
254 sprintf (qq, "%d", (insn_word >> 2) & 0x7);
255 break;
256
257 case RA :
258 if (nocomma) {
259 sprintf (qq, "r%d)", (insn_word >> 16) & 0x1f);
260 nocomma = 0;
261 }
262 else
263 sprintf (qq, "r%d", (insn_word >> 16) & 0x1f);
264 break;
265
266 case RB :
267 sprintf (qq, "r%d", (insn_word >> 11) & 0x1f);
268 break;
269
270 case SI :
271 tmp = insn_word & 0xffff;
272 if (tmp & 0x8000)
273 tmp -= 0x10000;
274 sprintf (qq, "%d", tmp);
275 break;
276
277 case UI :
278 sprintf (qq, "%d", insn_word & 0xffff);
279 break;
280
281 case BF :
282 sprintf (qq, "%d", (insn_word >> 23) & 0x7);
283 break;
284
285 case BFA :
286 sprintf (qq, "%d", (insn_word >> 18) & 0x7);
287 break;
288
289 case BT :
290 sprintf (qq, "%d", (insn_word >> 21) & 0x1f);
291 break;
292
293 case BA :
294 sprintf (qq, "%d", (insn_word >> 16) & 0x1f);
295 break;
296
297 case BB :
298 sprintf (qq, "%d", (insn_word >> 11) & 0x1f);
299 break;
300
301 case BO :
302 sprintf (qq, "%d", (insn_word >> 21) & 0x1f);
303 break;
304
305 case BI :
306 sprintf (qq, "%d", (insn_word >> 16) & 0x1f);
307 break;
308
309 case SH :
310 sprintf (qq, "%d", (insn_word >> 11) & 0x1f);
311 break;
312
313 case MB :
314 sprintf (qq, "0x%x", (insn_word >> 6) & 0x1f);
315 break;
316
317 case ME :
318 sprintf (qq, "0x%x", (insn_word >> 1) & 0x1f);
319 break;
320
321 case SPR :
322 sprintf (qq, "%d", (insn_word >> 16) & 0x1f);
323 break;
324
325 case DIS :
326 nocomma = 1;
327 tmp = insn_word & 0xffff;
328 if (tmp & 0x8000)
329 tmp -= 0x10000;
330 sprintf (qq, "%d(", tmp);
331 break;
332
333 case FXM :
334 sprintf (qq, "0x%x", (insn_word >> 12) & 0xff);
335 break;
336
337 case FRT :
338 case FRS :
339 sprintf (qq, "f%d", (insn_word >> 21) & 0x1f);
340 break;
341
342 case FRA :
343 sprintf (qq, "f%d", (insn_word >> 16) & 0x1f);
344 break;
345
346 case FRB :
347 sprintf (qq, "f%d", (insn_word >> 11) & 0x1f);
348 break;
349
350 case FRC :
351 sprintf (qq, "f%d", (insn_word >> 6) & 0x1f);
352 break;
353
354 case FLM :
355 sprintf (qq, "0x%x", (insn_word >> 17) & 0xff);
356 break;
357
358 case NB :
359 sprintf (qq, "%d", (insn_word >> 11) & 0x1f);
360 break;
361
362 case I :
363 sprintf (qq, "%d", (insn_word >> 12) & 0xf);
364 break;
365
366 default :
367 sprintf (qq, "Unknown operand format identifier %d????", *pp);
368 abort ();
369 }
370 while (*qq) ++qq; /* Walk to end of string printed so far. */
371 ++pp;
372
373 if (*pp == '\0')
374 break;
375 else if (!nocomma)
376 *qq++ = ',';
377 }
378 *qq = '\0';
379
380 fprintf (stream, "0x%08x\t%s%s",
381 insn_word, rs6k_ops[insn_no].operator, buf);
382 }