1 /* Print IBM RS/6000 instructions for GNU software.
2 Copyright 1991 Free Software Foundation, Inc.
3 Contributed by IBM Corporation.
5 This file is part of GDB and the GNU binutils.
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.
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.
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. */
22 #include "opcode/rs6k.h"
24 /* Print the rs6k instruction at address MEMADDR in debugged memory,
25 on STREAM. Returns length of the instruction, in bytes. */
28 print_insn (memaddr, stream)
32 int pop, eop, probable_eop; /* primary and extended opcodes */
34 int best = -1; /* found best opcode index */
36 unsigned int the_insn;
38 read_memory (memaddr, &the_insn, sizeof (the_insn));
39 pop = (unsigned)(the_insn >> 26);
40 min = 0, max = NOPCODES-1;
43 best = (min + max) / 2;
45 /* see if we are running in loops */
50 if (pop < rs6k_ops [best].p_opcode)
53 else if (pop > rs6k_ops [best].p_opcode)
57 /* Opcode matched, check extended opcode. */
59 if (rs6k_ops [best].e_opcode == -1) {
60 /* there is no valid extended opcode, what we've got is
65 /* Largest possible value of extended opcode. */
66 probable_eop = ((the_insn) >> 1) & 0x3ff;
68 eop = probable_eop & eopMask [rs6k_ops [best].format];
70 if (eop < rs6k_ops [best].e_opcode) {
72 while (pop == rs6k_ops [best].p_opcode) {
73 if (eop == rs6k_ops [best].e_opcode) /* found it! */
76 eop = probable_eop & eopMask [rs6k_ops [best].format];
81 else if (eop > rs6k_ops [best].e_opcode) {
83 while (pop == rs6k_ops [best].p_opcode) {
84 if (eop == rs6k_ops [best].e_opcode) /* found it! */
87 eop = probable_eop & eopMask [rs6k_ops [best].format];
92 else /* eop == rs6k_ops [best].e_opcode */
98 if (pop == rs6k_ops [best].p_opcode &&
99 (rs6k_ops [best].e_opcode == -1 || rs6k_ops [best].e_opcode == eop))
107 print_operator (stream, memaddr, the_insn, best);
111 fprintf (stream, "0x%08x", the_insn);
117 /* condition code names */
118 static char *cond_code [] = {
119 "lt", "gt", "eq", "so", "ge", "le", "ne", "ns", "nl", "ng", "z", "nz" };
122 print_operator (stream, memaddr, insn_word, insn_no)
130 char *pp = rs6k_ops[insn_no].opr_ext;
132 int nocomma = 0; /* true if no comma needed */
149 if ((insn_word & 0x03e00000) == 0x01800000)
154 if ((insn_word & 0x03e00000) == 0x00800000)
164 if (insn_word & 0x4000)
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' */
174 pp = rs6k_ops[insn_no].opr_ext;
187 fprintf (stream, "%s%s\t", rs6k_ops[insn_no].operator, buf);
189 /* parse the operand now. */
190 pp = rs6k_ops[insn_no].oprnd_format;
195 fprintf (stream, "%d", (insn_word >> 21) & 0x1f);
200 fprintf (stream, "r%d", (insn_word >> 21) & 0x1f);
204 tmp = (insn_word >> 16) & 0x1f;
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.
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. */
215 fprintf (stream, "{unknown cond code: 0x%x}", insn_word);
218 fprintf (stream, "%s", cond_code [tmp]);
220 /* So for just always use the "bbf/bbt" form. This is perfectly
221 correct, just not necessarily as legible.
223 If tmp is not in the range 0-3, we can't use an XX form anyway. */
224 fprintf (stream, "%d", tmp);
230 tmp = (insn_word & 0xfffc);
231 if (tmp & 0x8000) /* fix sign extension */
234 if ((insn_word & 0x2) == 0) /* if AA not set */
237 print_address (tmp, stream);
241 tmp = insn_word & 0x03fffffc;
245 if ((insn_word & 0x2) == 0) /* if no AA bit set */
248 print_address (tmp, stream);
251 case LEV : /* for svc only */
252 if (insn_word & 0x2) { /* SA is set */
256 fprintf (stream, "%d", (insn_word >> 5) & 0x7f);
259 case FL1 : /* for svc only */
260 if (insn_word & 0x2) { /* SA is set */
264 fprintf (stream, "%d", (insn_word >> 12) & 0xf);
267 case FL2 : /* for svc only */
269 if (insn_word & 0x2) /* SA is set */
270 fprintf (stream, "%d", (insn_word >> 2) & 0x3fff);
272 fprintf (stream, "%d", (insn_word >> 2) & 0x7);
277 fprintf (stream, "r%d)", (insn_word >> 16) & 0x1f);
281 fprintf (stream, "r%d", (insn_word >> 16) & 0x1f);
285 fprintf (stream, "r%d", (insn_word >> 11) & 0x1f);
289 tmp = insn_word & 0xffff;
292 fprintf (stream, "%d", tmp);
296 fprintf (stream, "%d", insn_word & 0xffff);
300 fprintf (stream, "%d", (insn_word >> 23) & 0x7);
304 fprintf (stream, "%d", (insn_word >> 18) & 0x7);
308 fprintf (stream, "%d", (insn_word >> 21) & 0x1f);
312 fprintf (stream, "%d", (insn_word >> 16) & 0x1f);
316 fprintf (stream, "%d", (insn_word >> 11) & 0x1f);
320 fprintf (stream, "%d", (insn_word >> 21) & 0x1f);
324 fprintf (stream, "%d", (insn_word >> 16) & 0x1f);
328 fprintf (stream, "%d", (insn_word >> 11) & 0x1f);
332 fprintf (stream, "0x%x", (insn_word >> 6) & 0x1f);
336 fprintf (stream, "0x%x", (insn_word >> 1) & 0x1f);
340 fprintf (stream, "%d", (insn_word >> 16) & 0x1f);
345 tmp = insn_word & 0xffff;
348 fprintf (stream, "%d(", tmp);
352 fprintf (stream, "0x%x", (insn_word >> 12) & 0xff);
357 fprintf (stream, "f%d", (insn_word >> 21) & 0x1f);
361 fprintf (stream, "f%d", (insn_word >> 16) & 0x1f);
365 fprintf (stream, "f%d", (insn_word >> 11) & 0x1f);
369 fprintf (stream, "f%d", (insn_word >> 6) & 0x1f);
373 fprintf (stream, "0x%x", (insn_word >> 17) & 0xff);
377 fprintf (stream, "%d", (insn_word >> 11) & 0x1f);
381 fprintf (stream, "%d", (insn_word >> 12) & 0xf);
386 "{Internal error: Unknown operand format identifier %d}",
391 if (*pp != '\0' && !nocomma)