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