diff options
-rw-r--r-- | gdb/ChangeLog | 4 | ||||
-rw-r--r-- | gdb/sparc-pinsn.c | 133 |
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 (®_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 |