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