aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog4
-rw-r--r--gdb/sparc-pinsn.c133
2 files changed, 137 insertions, 0 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 0169cc4..80336be 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,7 @@
+Tue Jan 28 17:32:13 1992 Per Bothner (bothner at cygnus.com)
+
+ * sparc-pinsn.c: Put the qsort() back in.
+
Mon Jan 27 18:51:03 1992 John Gilmore (gnu at cygnus.com)
* findvar.c (read_register, write_register): Handle machines
diff --git a/gdb/sparc-pinsn.c b/gdb/sparc-pinsn.c
index ba2237b..3fddb13 100644
--- a/gdb/sparc-pinsn.c
+++ b/gdb/sparc-pinsn.c
@@ -26,6 +26,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "string.h"
#include "target.h"
+#define SORT_NEEDED
+
extern char *reg_names[];
#define freg_names (&reg_names[4 * 8])
@@ -89,6 +91,11 @@ is_delayed_branch (insn)
return 0;
}
+#ifdef SORT_NEEDED
+static int opcodes_sorted = 0;
+extern void qsort ();
+#endif
+
/* Print one instruction from MEMADDR on STREAM. */
int
print_insn (memaddr, stream)
@@ -99,6 +106,16 @@ print_insn (memaddr, stream)
register unsigned int i;
+#ifdef SORT_NEEDED
+ if (!opcodes_sorted)
+ {
+ static int compare_opcodes ();
+ qsort ((char *) sparc_opcodes, NUMOPCODES,
+ sizeof (sparc_opcodes[0]), compare_opcodes);
+ opcodes_sorted = 1;
+ }
+#endif
+
read_memory (memaddr, &insn, sizeof (insn));
for (i = 0; i < NUMOPCODES; ++i)
@@ -178,14 +195,20 @@ print_insn (memaddr, stream)
#define freg(n) fprintf_filtered (stream, "%%%s", freg_names[n])
case 'e':
+ case 'v': /* double/even */
+ case 'V': /* quad/multiple of 4 */
freg (insn.rs1);
break;
case 'f':
+ case 'B': /* double/even */
+ case 'R': /* quad/multiple of 4 */
freg (insn.rs2);
break;
case 'g':
+ case 'H': /* double/even */
+ case 'J': /* quad/multiple of 4 */
freg (insn.rd);
break;
#undef freg
@@ -346,3 +369,113 @@ print_insn (memaddr, stream)
printf_filtered ("%#8x", insn.code);
return sizeof (insn);
}
+
+#ifdef SORT_NEEDED
+/* Compare opcodes A and B. */
+
+static int
+compare_opcodes (a, b)
+ char *a, *b;
+{
+ struct sparc_opcode *op0 = (struct sparc_opcode *) a;
+ struct sparc_opcode *op1 = (struct sparc_opcode *) b;
+ unsigned long int match0 = op0->match, match1 = op1->match;
+ unsigned long int lose0 = op0->lose, lose1 = op1->lose;
+ register unsigned int i;
+
+ /* If a bit is set in both match and lose, there is something
+ wrong with the opcode table. */
+ if (match0 & lose0)
+ {
+ fprintf (stderr, "Internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n",
+ op0->name, match0, lose0);
+ op0->lose &= ~op0->match;
+ lose0 = op0->lose;
+ }
+
+ if (match1 & lose1)
+ {
+ fprintf (stderr, "Internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n",
+ op1->name, match1, lose1);
+ op1->lose &= ~op1->match;
+ lose1 = op1->lose;
+ }
+
+ /* Because the bits that are variable in one opcode are constant in
+ another, it is important to order the opcodes in the right order. */
+ for (i = 0; i < 32; ++i)
+ {
+ unsigned long int x = 1 << i;
+ int x0 = (match0 & x) != 0;
+ int x1 = (match1 & x) != 0;
+
+ if (x0 != x1)
+ return x1 - x0;
+ }
+
+ for (i = 0; i < 32; ++i)
+ {
+ unsigned long int x = 1 << i;
+ int x0 = (lose0 & x) != 0;
+ int x1 = (lose1 & x) != 0;
+
+ if (x0 != x1)
+ return x1 - x0;
+ }
+
+ /* They are functionally equal. So as long as the opcode table is
+ valid, we can put whichever one first we want, on aesthetic grounds. */
+
+ /* Our first aesthetic ground is that aliases defer to real insns. */
+ {
+ int alias_diff = (op0->flags & F_ALIAS) - (op1->flags & F_ALIAS);
+ if (alias_diff != 0)
+ /* Put the one that isn't an alias first. */
+ return alias_diff;
+ }
+
+ /* Except for aliases, two "identical" instructions had
+ better have the same opcode. This is a sanity check on the table. */
+ i = strcmp (op0->name, op1->name);
+ if (i)
+ if (op0->flags & F_ALIAS) /* If they're both aliases, be arbitrary. */
+ return i;
+ else
+ fprintf (stderr,
+ "Internal error: bad sparc-opcode.h: \"%s\" == \"%s\"\n",
+ op0->name, op1->name);
+
+ /* Fewer arguments are preferred. */
+ {
+ int length_diff = strlen (op0->args) - strlen (op1->args);
+ if (length_diff != 0)
+ /* Put the one with fewer arguments first. */
+ return length_diff;
+ }
+
+ /* Put 1+i before i+1. */
+ {
+ char *p0 = (char *) strchr(op0->args, '+');
+ char *p1 = (char *) strchr(op1->args, '+');
+
+ if (p0 && p1)
+ {
+ /* There is a plus in both operands. Note that a plus
+ sign cannot be the first character in args,
+ so the following [-1]'s are valid. */
+ if (p0[-1] == 'i' && p1[1] == 'i')
+ /* op0 is i+1 and op1 is 1+i, so op1 goes first. */
+ return 1;
+ if (p0[1] == 'i' && p1[-1] == 'i')
+ /* op0 is 1+i and op1 is i+1, so op0 goes first. */
+ return -1;
+ }
+ }
+
+ /* They are, as far as we can tell, identical.
+ Since qsort may have rearranged the table partially, there is
+ no way to tell which one was first in the opcode table as
+ written, so just say there are equal. */
+ return 0;
+}
+#endif