-/* Print rs6000 instructions for objdump.
- This file is part of the binutils.
-*/
+/* Print IBM RS/6000 instructions for GNU software.
+ Copyright 1991 Free Software Foundation, Inc.
+ Contributed by IBM Corporation.
+This file is part of GDB and the GNU binutils.
-#include <stdio.h>
-#include "defs.h"
-#include "rs6k-opcode.h"
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "defs.h"
+#include "opcode/rs6k.h"
/* Print the rs6k instruction at address MEMADDR in debugged memory,
on STREAM. Returns length of the instruction, in bytes. */
int
print_insn (memaddr, stream)
CORE_ADDR memaddr;
- FILE *stream;
+ GDB_FILE *stream;
{
- int pop, eop; /* primary and extended opcodes */
+ int pop, eop, probable_eop; /* primary and extended opcodes */
int min, max;
int best = -1; /* found best opcode index */
int oldbest = -1;
read_memory (memaddr, &the_insn, sizeof (the_insn));
pop = (unsigned)(the_insn >> 26);
- eop = ((the_insn) >> 1) & 0x3ff;
min = 0, max = NOPCODES-1;
while (min < max) {
min = best;
else {
- /* opcode matched, check extended opcode. */
+ /* Opcode matched, check extended opcode. */
if (rs6k_ops [best].e_opcode == -1) {
/* there is no valid extended opcode, what we've got is
goto insn_found;
}
- else if (eop < rs6k_ops [best].e_opcode) {
+ /* Largest possible value of extended opcode. */
+ probable_eop = ((the_insn) >> 1) & 0x3ff;
+
+ eop = probable_eop & eopMask [rs6k_ops [best].format];
+
+ if (eop < rs6k_ops [best].e_opcode) {
while (pop == rs6k_ops [best].p_opcode) {
if (eop == rs6k_ops [best].e_opcode) /* found it! */
goto insn_found;
--best;
+ eop = probable_eop & eopMask [rs6k_ops [best].format];
}
goto not_found;
}
if (eop == rs6k_ops [best].e_opcode) /* found it! */
goto insn_found;
++best;
+ eop = probable_eop & eopMask [rs6k_ops [best].format];
}
goto not_found;
}
return 4;
not_found:
- fprintf (stream, "0x%08x", the_insn);
+ fprintf_unfiltered (stream, "0x%08x", the_insn);
return 4;
}
long insn_word;
int insn_no;
{
- char buf [BUFSIZ];
+ char buf [20];
char *qq = buf;
char *pp = rs6k_ops[insn_no].opr_ext;
int tmp;
int nocomma = 0; /* true if no comma needed */
- *qq = '\0';
if (pp) {
while (*pp) {
switch ( *pp ) {
case '.':
if (insn_word & 0x1)
- *qq++ = '.';
+ *qq++ = '.';
break;
case 'l':
++pp;
}
}
+ *qq = '\0';
- /* tab between orerator and operand */
- *qq++ = '\t';
+ fprintf_unfiltered (stream, "%s%s\t", rs6k_ops[insn_no].operator, buf);
/* parse the operand now. */
pp = rs6k_ops[insn_no].oprnd_format;
- while (1) {
+ while (*pp != 0) {
switch (*pp) {
case TO :
- sprintf (qq, "%d", (insn_word >> 21) & 0x1f);
+ fprintf_unfiltered (stream, "%d", (insn_word >> 21) & 0x1f);
break;
case RT :
case RS :
- sprintf (qq, "r%d", (insn_word >> 21) & 0x1f);
+ fprintf_unfiltered (stream, "r%d", (insn_word >> 21) & 0x1f);
break;
case LI :
tmp = (insn_word >> 16) & 0x1f;
+#if 0
+ /* This is wrong, wrong, wrong. The condition code only goes
+ from 0 to 3 (for the instructions which can use extended
+ mnemonics of this type), and the XX (lt, gt, eq etc.) goes
+ into the mnemonic, not as an operand.
+
+ Probably the best way to get this right in both assembler
+ and disassembler is to switch to a match/lose style opcode
+ table like the sparc. */
if (tmp > 11) {
- fprintf (stderr, "Internal error: unknown cond code: 0x%x\n", insn_word);
+ fprintf_unfiltered (stream, "{unknown cond code: 0x%x}", insn_word);
tmp = 0;
}
- sprintf (qq, "%s", cond_code [tmp]);
- break;
+ fprintf_unfiltered (stream, "%s", cond_code [tmp]);
+#else
+ /* So for just always use the "bbf/bbt" form. This is perfectly
+ correct, just not necessarily as legible.
-#if 0
- case A2 :
- tmp = (insn_word >> 2) & 0x3fff;
- if (tmp & 0x2000)
- tmp -= 0x4000;
- sprintf (qq, "0x%x", tmp * 4 + memaddr);
- break;
+ If tmp is not in the range 0-3, we can't use an XX form anyway. */
+ fprintf_unfiltered (stream, "%d", tmp);
#endif
+ break;
+
case A2 :
case TA14 :
tmp = (insn_word & 0xfffc);
if ((insn_word & 0x2) == 0) /* if AA not set */
tmp += memaddr;
- sprintf (qq, "0x%x", tmp);
+ print_address (tmp, stream);
break;
case TA24 :
if ((insn_word & 0x2) == 0) /* if no AA bit set */
tmp += memaddr;
- sprintf (qq, "0x%x", tmp);
+ print_address (tmp, stream);
break;
case LEV : /* for svc only */
if (insn_word & 0x2) { /* SA is set */
nocomma = 1;
- *qq = '\0';
}
else
- sprintf (qq, "%d", (insn_word >> 5) & 0x7f);
+ fprintf_unfiltered (stream, "%d", (insn_word >> 5) & 0x7f);
break;
case FL1 : /* for svc only */
if (insn_word & 0x2) { /* SA is set */
nocomma = 1;
- *qq = '\0';
}
else
- sprintf (qq, "%d", (insn_word >> 12) & 0xf);
+ fprintf_unfiltered (stream, "%d", (insn_word >> 12) & 0xf);
break;
case FL2 : /* for svc only */
nocomma = 0;
if (insn_word & 0x2) /* SA is set */
- sprintf (qq, "%d", (insn_word >> 2) & 0x3fff);
+ fprintf_unfiltered (stream, "%d", (insn_word >> 2) & 0x3fff);
else
- sprintf (qq, "%d", (insn_word >> 2) & 0x7);
+ fprintf_unfiltered (stream, "%d", (insn_word >> 2) & 0x7);
break;
case RA :
if (nocomma) {
- sprintf (qq, "r%d)", (insn_word >> 16) & 0x1f);
+ fprintf_unfiltered (stream, "r%d)", (insn_word >> 16) & 0x1f);
nocomma = 0;
}
else
- sprintf (qq, "r%d", (insn_word >> 16) & 0x1f);
+ fprintf_unfiltered (stream, "r%d", (insn_word >> 16) & 0x1f);
break;
case RB :
- sprintf (qq, "r%d", (insn_word >> 11) & 0x1f);
+ fprintf_unfiltered (stream, "r%d", (insn_word >> 11) & 0x1f);
break;
case SI :
tmp = insn_word & 0xffff;
if (tmp & 0x8000)
tmp -= 0x10000;
- sprintf (qq, "%d", tmp);
+ fprintf_unfiltered (stream, "%d", tmp);
break;
case UI :
- sprintf (qq, "%d", insn_word & 0xffff);
+ fprintf_unfiltered (stream, "%d", insn_word & 0xffff);
break;
case BF :
- sprintf (qq, "%d", (insn_word >> 23) & 0x7);
+ fprintf_unfiltered (stream, "%d", (insn_word >> 23) & 0x7);
break;
case BFA :
- sprintf (qq, "%d", (insn_word >> 18) & 0x7);
+ fprintf_unfiltered (stream, "%d", (insn_word >> 18) & 0x7);
break;
case BT :
- sprintf (qq, "%d", (insn_word >> 21) & 0x1f);
+ fprintf_unfiltered (stream, "%d", (insn_word >> 21) & 0x1f);
break;
case BA :
- sprintf (qq, "%d", (insn_word >> 16) & 0x1f);
+ fprintf_unfiltered (stream, "%d", (insn_word >> 16) & 0x1f);
break;
case BB :
- sprintf (qq, "%d", (insn_word >> 11) & 0x1f);
+ fprintf_unfiltered (stream, "%d", (insn_word >> 11) & 0x1f);
break;
case BO :
- sprintf (qq, "%d", (insn_word >> 21) & 0x1f);
+ fprintf_unfiltered (stream, "%d", (insn_word >> 21) & 0x1f);
break;
case BI :
- sprintf (qq, "%d", (insn_word >> 16) & 0x1f);
+ fprintf_unfiltered (stream, "%d", (insn_word >> 16) & 0x1f);
break;
case SH :
- sprintf (qq, "%d", (insn_word >> 11) & 0x1f);
+ fprintf_unfiltered (stream, "%d", (insn_word >> 11) & 0x1f);
break;
case MB :
- sprintf (qq, "0x%x", (insn_word >> 6) & 0x1f);
+ fprintf_unfiltered (stream, "0x%x", (insn_word >> 6) & 0x1f);
break;
case ME :
- sprintf (qq, "0x%x", (insn_word >> 1) & 0x1f);
+ fprintf_unfiltered (stream, "0x%x", (insn_word >> 1) & 0x1f);
break;
case SPR :
- sprintf (qq, "%d", (insn_word >> 16) & 0x1f);
+ fprintf_unfiltered (stream, "%d", (insn_word >> 16) & 0x1f);
break;
case DIS :
tmp = insn_word & 0xffff;
if (tmp & 0x8000)
tmp -= 0x10000;
- sprintf (qq, "%d(", tmp);
+ fprintf_unfiltered (stream, "%d(", tmp);
break;
case FXM :
- sprintf (qq, "0x%x", (insn_word >> 12) & 0xff);
+ fprintf_unfiltered (stream, "0x%x", (insn_word >> 12) & 0xff);
break;
case FRT :
case FRS :
- sprintf (qq, "f%d", (insn_word >> 21) & 0x1f);
+ fprintf_unfiltered (stream, "f%d", (insn_word >> 21) & 0x1f);
break;
case FRA :
- sprintf (qq, "f%d", (insn_word >> 16) & 0x1f);
+ fprintf_unfiltered (stream, "f%d", (insn_word >> 16) & 0x1f);
break;
case FRB :
- sprintf (qq, "f%d", (insn_word >> 11) & 0x1f);
+ fprintf_unfiltered (stream, "f%d", (insn_word >> 11) & 0x1f);
break;
case FRC :
- sprintf (qq, "f%d", (insn_word >> 6) & 0x1f);
+ fprintf_unfiltered (stream, "f%d", (insn_word >> 6) & 0x1f);
break;
case FLM :
- sprintf (qq, "0x%x", (insn_word >> 17) & 0xff);
+ fprintf_unfiltered (stream, "0x%x", (insn_word >> 17) & 0xff);
break;
case NB :
- sprintf (qq, "%d", (insn_word >> 11) & 0x1f);
+ fprintf_unfiltered (stream, "%d", (insn_word >> 11) & 0x1f);
break;
case I :
- sprintf (qq, "%d", (insn_word >> 12) & 0xf);
+ fprintf_unfiltered (stream, "%d", (insn_word >> 12) & 0xf);
break;
default :
- sprintf (qq, "Unknown operand format identifier????");
- abort ();
+ fprintf_unfiltered (stream,
+ "{Internal error: Unknown operand format identifier %d}",
+ *pp);
}
- while (*qq) ++qq;
++pp;
- if (*pp == '\0')
- break;
- else if (!nocomma)
- *qq++ = ',';
+ if (*pp != '\0' && !nocomma)
+ fputc_unfiltered(',', stream);
}
- *qq = '\0';
-
- fprintf (stream, "0x%08x\t%s%s",
- insn_word, rs6k_ops[insn_no].operator, buf);
}
-