Lots of changes from Jeff Law for HPPA support:

Clean up cruft in opcode table; improve opcodes library disassembler; make
gdb use opcodes library disassembler.
This commit is contained in:
Ken Raeburn 1993-06-11 23:20:54 +00:00
parent 57cb418a93
commit 112087edcc
4 changed files with 645 additions and 426 deletions

View file

@ -1,3 +1,9 @@
Fri Jun 11 18:39:38 1993 Ken Raeburn (raeburn@cygnus.com)
Patches from Jeff Law, law@cs.utah.edu:
* hppa-pinsn.c: Now uses disassembler from opcode library,
this contains only the stub function print_insn.
Fri Jun 11 15:19:59 1993 K. Richard Pixley (rich@cygnus.com)
* main.c (main): back to two periods for elipse.

View file

@ -21,438 +21,18 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "defs.h"
#include "symtab.h"
#define OLD_TABLE
#include "opcode/hppa.h"
#include "dis-asm.h"
static char *control_reg[] =
{ "rctr", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7",
"pidr1", "pidr2", "ccr", "sar", "pidr3", "pidr4",
"iva", "eiem", "itmr", "pcsq", "pcoq", "iir", "isr",
"ior", "ipsw", "eirr", "tr0", "tr1", "tr2", "tr3",
"tr4", "tr5", "tr6", "tr7"
};
static char *compare_cond_names[] =
{ "", ",=", ",<", ",<=", ",<<", ",<<=", ",sv",
",od", ",tr", ",<>", ",>=", ",>", ",>>=",
",>>", ",nsv", ",ev"
};
static char *add_cond_names[] =
{ "", ",=", ",<", ",<=", ",nuv", ",znv", ",sv",
",od", ",tr", ",<>", ",>=", ",>", ",uv",
",vnz", ",nsv", ",ev"
};
static char *logical_cond_names[] =
{ "", ",=", ",<", ",<=", 0, 0, 0, ",od",
",tr", ",<>", ",>=", ",>", 0, 0, 0, ",ev"
};
static char *unit_cond_names[] =
{ "", 0, ",sbz", ",shz", ",sdc", 0, ",sbc", ",shc",
",tr", 0, ",nbz", ",nhz", ",ndc", 0, ",nbc", ",nhc"
};
static char *shift_cond_names[] =
{"", ",=", ",<", ",od", ",tr", ",<>", ",>=", ",ev"};
static char *index_compl_names[] = {"", ",m", ",s", ",sm"};
static char *short_ldst_compl_names[] = {"", ",ma", "", ",mb"};
static char *short_bytes_compl_names[] = {"", ",b,m", ",e", ",e,m"};
static char *float_format_names[] = {",sgl", ",dbl", ",quad"};
static char *float_comp_names[] =
{",false?", ",false", ",?", ",!<=>", ",=", ",=t", ",?=", ",!<>",
",!?>=", ",<", ",?<", ",!>=", ",!?>", ",<=", ",?<=", ",!>",
",!?<=", ",>", ",?>", ",!<=", ",!?<", ",>=", ",?>=", ",!<",
",!?=", ",<>", ",!=", ",!=t", ",!?", ",<=>", ",true?", ",true"
};
/* For a bunch of different instructions form an index into a
completer name table. */
#define GET_COMPL(insn) (GET_FIELD (insn, 26, 26) | \
GET_FIELD (insn, 18, 18) << 1)
#define GET_COND(insn) (GET_FIELD ((insn), 16, 18) + \
(GET_FIELD ((insn), 19, 19) ? 8 : 0))
static void fput_reg PARAMS ((unsigned reg, FILE *stream));
static void fput_const PARAMS ((unsigned num, FILE *stream));
static void fput_reg_r PARAMS ((unsigned reg, FILE *stream));
static void fput_creg PARAMS ((unsigned reg, FILE *stream));
/* Print one instruction from MEMADDR on STREAM. */
/* Print the 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;
{
long insn;
unsigned int i, op;
disassemble_info info;
insn = read_memory_integer (memaddr, sizeof (insn));
GDB_INIT_DISASSEMBLE_INFO (info, stream);
for (i = 0; i < NUMOPCODES; ++i)
{
const struct pa_opcode *opcode = &pa_opcodes[i];
if ((insn & opcode->mask) == opcode->match)
{
register const char *s;
fputs_filtered (opcode->name, stream);
if (!index ("cCY<?!@-+&U>~nZFIM", opcode->args[0]))
fputs_filtered (" ", stream);
for (s = opcode->args; *s != '\0'; ++s)
{
switch (*s)
{
case 'x':
fput_reg (GET_FIELD (insn, 11, 15), stream);
break;
case 'X':
if (GET_FIELD (insn, 25, 25))
fput_reg_r (GET_FIELD (insn, 11, 15), stream);
else
fput_reg (GET_FIELD (insn, 11, 15), stream);
break;
case 'b':
fput_reg (GET_FIELD (insn, 6, 10), stream);
break;
case '^':
fput_creg (GET_FIELD (insn, 6, 10), stream);
break;
case 'E':
if (GET_FIELD (insn, 25, 25))
fput_reg_r (GET_FIELD (insn, 6, 10), stream);
else
fput_reg (GET_FIELD (insn, 6, 10), stream);
break;
case 't':
fput_reg (GET_FIELD (insn, 27, 31), stream);
break;
case 'v':
if (GET_FIELD (insn, 25, 25))
fput_reg_r (GET_FIELD (insn, 27, 31), stream);
else
fput_reg (GET_FIELD (insn, 27, 31), stream);
break;
case '4':
fput_creg (GET_FIELD (insn, 6, 10), stream);
break;
case '6':
fput_reg (GET_FIELD (insn, 11, 15), stream);
break;
case '7':
fput_reg (GET_FIELD (insn, 27, 31), stream);
break;
case '8':
fput_reg (GET_FIELD (insn, 16, 20), stream);
break;
case '9':
fput_reg (GET_FIELD (insn, 21, 25), stream);
break;
case '5':
fput_const (extract_5_load (insn), stream);
break;
/* case 's': */
case 'S':
fprintf_filtered (stream, "sr%d", extract_3 (insn));
break;
case 'c':
fprintf_filtered (stream, "%s ",
index_compl_names[GET_COMPL (insn)]);
break;
case 'C':
fprintf_filtered (stream, "%s ",
short_ldst_compl_names[GET_COMPL (insn)]);
break;
case 'Y':
fprintf_filtered (stream, "%s ",
short_bytes_compl_names[GET_COMPL (insn)]);
break;
/* these four conditions are for the set of instructions
which distinguish true/false conditions by opcode rather
than by the 'f' bit (sigh): comb, comib, addb, addib */
case '<':
fputs_filtered (compare_cond_names[GET_FIELD (insn, 16, 18)],
stream);
break;
case '?':
fputs_filtered (compare_cond_names[GET_FIELD (insn, 16, 18) + 8],
stream);
break;
case '!':
fputs_filtered (add_cond_names[GET_FIELD (insn, 16, 18)],
stream);
break;
case '@':
fputs_filtered (add_cond_names[GET_FIELD (insn, 16, 18) + 8],
stream);
break;
case '-':
fprintf_filtered (stream, "%s ",
compare_cond_names[GET_COND (insn)]);
break;
case '+':
fprintf_filtered (stream, "%s ",
add_cond_names[GET_FIELD (insn, 16, 18)]);
break;
case '&':
fprintf_filtered (stream, "%s ",
logical_cond_names[GET_COND (insn)]);
break;
case 'U':
fprintf_filtered (stream, "%s ",
unit_cond_names[GET_COND (insn)]);
break;
case '>':
case '~':
fprintf_filtered (stream, "%s ",
shift_cond_names[GET_FIELD (insn, 16, 18)]);
break;
case 'V':
fput_const (extract_5_store (insn), stream);
break;
case 'r':
fput_const (extract_5r_store (insn), stream);
break;
case 'R':
fput_const (extract_5R_store (insn), stream);
break;
case 'i':
fput_const (extract_11 (insn), stream);
break;
case 'j':
fput_const (extract_14 (insn), stream);
break;
case 'k':
fput_const (extract_21 (insn), stream);
break;
case 'n':
if (insn & 0x2)
fprintf_filtered (stream, ",n ");
else
fprintf_filtered (stream, " ");
break;
case 'w':
print_address (memaddr + 8 + extract_12 (insn), stream);
break;
case 'W':
op = GET_FIELD (insn, 0, 5);
if (op == 0x38 /* be */ || op == 0x39 /* ble */)
fput_const (extract_17 (insn), stream);
else
print_address (memaddr + 8 + extract_17 (insn), stream);
break;
case 'B':
{
int space;
if (space = GET_FIELD (insn, 16, 17))
fprintf_filtered (stream, "sr%d,", space);
fput_reg (GET_FIELD (insn, 6, 10), stream);
break;
}
case 'p':
fprintf_filtered (stream, "%d",
31 - GET_FIELD (insn, 22, 26));
break;
case 'P':
fprintf_filtered (stream, "%d",
GET_FIELD (insn, 22, 26));
break;
case 'Q':
fprintf_filtered (stream, "%d",
GET_FIELD (insn, 11, 15));
break;
case 'T':
fprintf_filtered (stream, "%d",
32 - GET_FIELD (insn, 27, 31));
break;
case 'A':
fput_const (GET_FIELD (insn, 6, 18), stream);
break;
case 'Z':
if (GET_FIELD (insn, 26, 26))
fprintf_filtered (stream, ",m ");
else
fprintf_filtered (stream, " ");
break;
case 'D':
fput_const (GET_FIELD (insn, 6, 31), stream);
break;
case 'f':
fprintf_filtered (stream, ",%d", GET_FIELD (insn, 23, 25));
break;
case 'O':
fput_const ((GET_FIELD (insn, 6,20) << 5 |
GET_FIELD (insn, 27, 31)), stream);
break;
case 'o':
fput_const (GET_FIELD (insn, 6, 20), stream);
break;
case '2':
fput_const ((GET_FIELD (insn, 6, 22) << 5 |
GET_FIELD (insn, 27, 31)), stream);
break;
case '1':
fput_const ((GET_FIELD (insn, 11, 20) << 5 |
GET_FIELD (insn, 27, 31)), stream);
break;
case '0':
fput_const ((GET_FIELD (insn, 16, 20) << 5 |
GET_FIELD (insn, 27, 31)), stream);
break;
case 'u':
fprintf_filtered (stream, "%d", GET_FIELD (insn, 23, 25));
break;
case 'F':
/* if no destination completer, need a space here */
if (GET_FIELD (insn, 21, 22) == 1)
fputs_filtered (float_format_names[GET_FIELD (insn, 19, 20)],
stream);
else
fprintf_filtered (stream, "%s ",
float_format_names[GET_FIELD
(insn, 19, 20)]);
break;
case 'G':
fprintf_filtered (stream, "%s ",
float_format_names[GET_FIELD (insn,
17, 18)]);
break;
case 'H':
fputs_filtered (float_format_names[GET_FIELD
(insn, 26, 26)], stream);
break;
case 'I':
/* if no destination completer, need a space here */
if (GET_FIELD (insn, 21, 22) == 1)
fputs_filtered (float_format_names[GET_FIELD (insn, 20, 20)],
stream);
else
fprintf_filtered (stream, "%s ",
float_format_names[GET_FIELD
(insn, 20, 20)]);
break;
case 'J':
if (GET_FIELD (insn, 24, 24))
fput_reg_r (GET_FIELD (insn, 6, 10), stream);
else
fput_reg (GET_FIELD (insn, 6, 10), stream);
break;
case 'K':
if (GET_FIELD (insn, 19, 19))
fput_reg_r (GET_FIELD (insn, 11, 15), stream);
else
fput_reg (GET_FIELD (insn, 11, 15), stream);
break;
case 'M':
fputs_filtered (float_comp_names[GET_FIELD (insn, 27, 31)],
stream);
break;
case '}':
fprintf_filtered (stream, "fp%d", GET_FIELD (insn, 6, 10));
break;
case '|':
fprintf_filtered (stream, "fp%d", GET_FIELD (insn, 11, 15));
break;
case '{':
if (GET_FIELD (insn, 23, 25) == 0)
fprintf_filtered (stream, "fp%d",
GET_FIELD (insn, 27, 31));
else
fprintf_filtered (stream, "cp%d",
GET_FIELD (insn, 27, 31));
break;
default:
fprintf_filtered (stream, "%c", *s);
break;
}
}
/* If this is an external branch, examine the previous instruction and see if
it was an ldil that loaded something into the same base reg. If so, then
calculate the branch target from the constants in both instructions, and
print it out. */
op = GET_FIELD (insn, 0, 5);
if (op == 0x38 /* be */ || op == 0x39 /* ble */)
{
CORE_ADDR target_address;
long prev_insn;
int basereg, basereg_prev;
target_address = extract_17 (insn);
basereg = GET_FIELD (insn, 6, 10);
if (basereg != 0)
{
prev_insn = read_memory_integer (memaddr - 4,
sizeof(prev_insn));
basereg_prev = GET_FIELD (prev_insn, 6, 10);
if ((prev_insn & 0xfc000000) == 0x20000000 /* ldil */
&& basereg == basereg_prev)
target_address += extract_21 (prev_insn);
}
fprintf_filtered (stream, "\t! ");
print_address (target_address, stream);
}
return sizeof(insn);
}
}
fprintf_filtered (stream, "%#8x", insn);
return sizeof(insn);
}
/* Utility function to print registers */
static void
fput_reg (reg, stream)
unsigned reg;
FILE *stream;
{
if (reg)
fputs_filtered (reg_names[reg], stream);
else
fputs_filtered ("r0", stream);
}
void
fput_reg_r (reg, stream)
unsigned reg;
FILE *stream;
{
if (reg)
fputs_filtered (reg_names[reg], stream);
else
fputs_filtered ("r0", stream);
fputs_filtered ("R", stream);
}
void
fput_creg (reg, stream)
unsigned reg;
FILE *stream;
{
fputs_filtered (control_reg[reg], stream);
}
/* print constants with sign */
void
fput_const (num, stream)
unsigned num;
FILE *stream;
{
if ((int)num < 0)
fprintf_filtered (stream, "-%x", -(int)num);
else
fprintf_filtered (stream, "%x", num);
return print_insn_hppa (memaddr, &info);
}

View file

@ -1,3 +1,13 @@
Fri Jun 11 18:40:21 1993 Ken Raeburn (raeburn@cygnus.com)
Changes from Jeff Law, law@cs.utah.edu:
* hppa-dis.c (print_insn_hppa): Last argument to fput_reg,
fput_reg_r, fput_creg, fput_const, and fputs_filtered should
be a *disassemble_info, not a *FILE.
* hppa-dis.c: Support 'd', '!', and 'a'.
* hppa-dis.c: Support 's' to extract a 2 bit space register.
* hppa-dis.c: Delete cases which are no longer needed.
Fri Jun 11 07:53:48 1993 Jim Kingdon (kingdon@cygnus.com)
* m68k-dis.c (print_insn_{m68k,arg}): Add MMU codes.

623
opcodes/hppa-dis.c Normal file
View file

@ -0,0 +1,623 @@
/* Disassembler for the PA-RISC. Somewhat derived from sparc-pinsn.c.
Copyright 1989, 1990, 1992, 1993 Free Software Foundation, Inc.
Contributed by the Center for Software Science at the
University of Utah (pa-gdb-bugs@cs.utah.edu).
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 "dis-asm.h"
#include "sysdep.h"
#include "opcode/hppa.h"
/* Initializer for an array of names of registers.
There should be NUM_REGS strings in this initializer. */
#define REGISTER_NAMES \
{"flags", "r1", "rp", "r3", "r4", "r5", "r6", "r7", "r8", "r9", \
"r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", \
"r20", "r21", "r22", "arg3", "arg2", "arg1", "arg0", "dp", "ret0", "ret1", \
"sp", "r31", "sar", "pcoqh", "pcsqh", "pcoqt", "pcsqt", \
"eiem", "iir", "isr", "ior", "ipsw", "goto", "sr4", "sr0", "sr1", "sr2", \
"sr3", "sr5", "sr6", "sr7", "cr0", "cr8", "cr9", "ccr", "cr12", "cr13", \
"cr24", "cr25", "cr26", "mpsfu_high", "mpsfu_low", "mpsfu_ovflo", "pad", \
"fpsr", "fpe1", "fpe2", "fpe3", "fpe4", "fpe5", "fpe6", "fpe7", \
"fp4", "fp5", "fp6", "fp7", "fp8", \
"fp9", "fp10", "fp11", "fp12", "fp13", "fp14", "fp15", \
"fp16", "fp17", "fp18", "fp19", "fp20", "fp21", "fp22", "fp23", \
"fp24", "fp25", "fp26", "fp27", "fp28", "fp29", "fp30", "fp31"}
static const char *const reg_names[] = REGISTER_NAMES;
typedef unsigned int CORE_ADDR;
/* Get at various relevent fields of an instruction word. */
#define MASK_5 0x1f
#define MASK_11 0x7ff
#define MASK_14 0x3fff
#define MASK_21 0x1fffff
/* This macro gets bit fields using HP's numbering (MSB = 0) */
#define GET_FIELD(X, FROM, TO) \
((X) >> (31 - (TO)) & ((1 << ((TO) - (FROM) + 1)) - 1))
/* Some of these have been converted to 2-d arrays because they
consume less storage this way. If the maintenance becomes a
problem, convert them back to const 1-d pointer arrays. */
static const char control_reg[][6] = {
"rctr", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7",
"pidr1", "pidr2", "ccr", "sar", "pidr3", "pidr4",
"iva", "eiem", "itmr", "pcsq", "pcoq", "iir", "isr",
"ior", "ipsw", "eirr", "tr0", "tr1", "tr2", "tr3",
"tr4", "tr5", "tr6", "tr7"
};
static const char compare_cond_names[][5] = {
"", ",=", ",<", ",<=", ",<<", ",<<=", ",sv",
",od", ",tr", ",<>", ",>=", ",>", ",>>=",
",>>", ",nsv", ",ev"
};
static const char add_cond_names[][5] = {
"", ",=", ",<", ",<=", ",nuv", ",znv", ",sv",
",od", ",tr", ",<>", ",>=", ",>", ",uv",
",vnz", ",nsv", ",ev"
};
static const char *const logical_cond_names[] = {
"", ",=", ",<", ",<=", 0, 0, 0, ",od",
",tr", ",<>", ",>=", ",>", 0, 0, 0, ",ev"};
static const char *const unit_cond_names[] = {
"", 0, ",sbz", ",shz", ",sdc", 0, ",sbc", ",shc",
",tr", 0, ",nbz", ",nhz", ",ndc", 0, ",nbc", ",nhc"
};
static const char shift_cond_names[][4] = {
"", ",=", ",<", ",od", ",tr", ",<>", ",>=", ",ev"
};
static const char index_compl_names[][4] = {"", ",m", ",s", ",sm"};
static const char short_ldst_compl_names[][4] = {"", ",ma", "", ",mb"};
static const char *const short_bytes_compl_names[] = {
"", ",b,m", ",e", ",e,m"
};
static const char *const float_format_names[] = {",sgl", ",dbl", ",quad"};
static const char float_comp_names[][8] =
{
",false?", ",false", ",?", ",!<=>", ",=", ",=t", ",?=", ",!<>",
",!?>=", ",<", ",?<", ",!>=", ",!?>", ",<=", ",?<=", ",!>",
",!?<=", ",>", ",?>", ",!<=", ",!?<", ",>=", ",?>=", ",!<",
",!?=", ",<>", ",!=", ",!=t", ",!?", ",<=>", ",true?", ",true"
};
/* For a bunch of different instructions form an index into a
completer name table. */
#define GET_COMPL(insn) (GET_FIELD (insn, 26, 26) | \
GET_FIELD (insn, 18, 18) << 1)
#define GET_COND(insn) (GET_FIELD ((insn), 16, 18) + \
(GET_FIELD ((insn), 19, 19) ? 8 : 0))
/* Utility function to print registers. Put these first, so gcc's function
inlining can do its stuff. */
#define fputs_filtered(STR,F) (*info->fprintf_func) (info->stream, "%s", STR)
static void
fput_reg (reg, info)
unsigned reg;
disassemble_info *info;
{
(*info->fprintf_func) (info->stream, reg ? reg_names[reg] : "r0");
}
static void
fput_reg_r (reg, info)
unsigned reg;
disassemble_info *info;
{
(*info->fprintf_func) (info->stream, "%sR", reg ? reg_names[reg] : "r0");
}
static void
fput_creg (reg, info)
unsigned reg;
disassemble_info *info;
{
(*info->fprintf_func) (info->stream, control_reg[reg]);
}
/* print constants with sign */
static void
fput_const (num, info)
unsigned num;
disassemble_info *info;
{
if ((int)num < 0)
(*info->fprintf_func) (info->stream, "-%x", -(int)num);
else
(*info->fprintf_func) (info->stream, "%x", num);
}
/* Routines to extract various sized constants out of hppa
instructions. */
/* This assumes that no garbage lies outside of the lower bits of
value. */
static int
sign_extend (val, bits)
unsigned val, bits;
{
return (int)(val >> (bits - 1) ? (-1 << bits) | val : val);
}
/* For many immediate values the sign bit is the low bit! */
static int
low_sign_extend (val, bits)
unsigned val, bits;
{
return (int)((val & 0x1 ? (-1 << (bits - 1)) : 0) | val >> 1);
}
/* extract the immediate field from a ld{bhw}s instruction */
#if 0 /* not used */
static unsigned
get_field (val, from, to)
unsigned val, from, to;
{
val = val >> (31 - to);
return val & ((1 << (32 - from)) - 1);
}
static unsigned
set_field (val, from, to, new_val)
unsigned *val, from, to, new_val;
{
unsigned mask = ~((1 << (to - from + 1)) << (31 - from));
return *val = (*val & mask) | (new_val << (31 - from));
}
#endif
/* extract a 3-bit space register number from a be, ble, mtsp or mfsp */
static int
extract_3 (word)
unsigned word;
{
return GET_FIELD (word, 18, 18) << 2 | GET_FIELD (word, 16, 17);
}
static int
extract_5_load (word)
unsigned word;
{
return low_sign_extend (word >> 16 & MASK_5, 5);
}
/* extract the immediate field from a st{bhw}s instruction */
static int
extract_5_store (word)
unsigned word;
{
return low_sign_extend (word & MASK_5, 5);
}
/* extract the immediate field from a break instruction */
static unsigned
extract_5r_store (word)
unsigned word;
{
return (word & MASK_5);
}
/* extract the immediate field from a {sr}sm instruction */
static unsigned
extract_5R_store (word)
unsigned word;
{
return (word >> 16 & MASK_5);
}
/* extract the immediate field from a bb instruction */
static unsigned
extract_5Q_store (word)
unsigned word;
{
return (word >> 21 & MASK_5);
}
/* extract an 11 bit immediate field */
static int
extract_11 (word)
unsigned word;
{
return low_sign_extend (word & MASK_11, 11);
}
/* extract a 14 bit immediate field */
static int
extract_14 (word)
unsigned word;
{
return low_sign_extend (word & MASK_14, 14);
}
#if 0
/* deposit a 14 bit constant in a word */
static unsigned
deposit_14 (opnd, word)
int opnd;
unsigned word;
{
unsigned sign = (opnd < 0 ? 1 : 0);
return word | ((unsigned)opnd << 1 & MASK_14) | sign;
}
#endif
/* extract a 21 bit constant */
static int
extract_21 (word)
unsigned word;
{
int val;
word &= MASK_21;
word <<= 11;
val = GET_FIELD (word, 20, 20);
val <<= 11;
val |= GET_FIELD (word, 9, 19);
val <<= 2;
val |= GET_FIELD (word, 5, 6);
val <<= 5;
val |= GET_FIELD (word, 0, 4);
val <<= 2;
val |= GET_FIELD (word, 7, 8);
return sign_extend (val, 21) << 11;
}
#if 0
/* deposit a 21 bit constant in a word. Although 21 bit constants are
usually the top 21 bits of a 32 bit constant, we assume that only
the low 21 bits of opnd are relevant */
static unsigned
deposit_21 (opnd, word)
unsigned opnd, word;
{
unsigned val = 0;
val |= GET_FIELD (opnd, 11 + 14, 11 + 18);
val <<= 2;
val |= GET_FIELD (opnd, 11 + 12, 11 + 13);
val <<= 2;
val |= GET_FIELD (opnd, 11 + 19, 11 + 20);
val <<= 11;
val |= GET_FIELD (opnd, 11 + 1, 11 + 11);
val <<= 1;
val |= GET_FIELD (opnd, 11 + 0, 11 + 0);
return word | val;
}
#endif
/* extract a 12 bit constant from branch instructions */
static int
extract_12 (word)
unsigned word;
{
return sign_extend (GET_FIELD (word, 19, 28) |
GET_FIELD (word, 29, 29) << 10 |
(word & 0x1) << 11, 12) << 2;
}
/* extract a 17 bit constant from branch instructions, returning the
19 bit signed value. */
static int
extract_17 (word)
unsigned word;
{
return sign_extend (GET_FIELD (word, 19, 28) |
GET_FIELD (word, 29, 29) << 10 |
GET_FIELD (word, 11, 15) << 11 |
(word & 0x1) << 16, 17) << 2;
}
/* Print one instruction. */
int
print_insn_hppa (memaddr, info)
bfd_vma memaddr;
disassemble_info *info;
{
unsigned int insn, i, op;
FILE *stream = info->stream;
{
int status =
(*info->read_memory_func) (memaddr, (bfd_byte*) &insn, sizeof (insn),
info);
if (status != 0)
{
(*info->memory_error_func) (status, memaddr, info);
return -1;
}
}
for (i = 0; i < NUMOPCODES; ++i)
{
const struct pa_opcode *opcode = &pa_opcodes[i];
if ((insn & opcode->mask) == opcode->match)
{
register const char *s;
(*info->fprintf_func) (info->stream, "%s", opcode->name);
if (!strchr ("cCY<?!@-+&U>~nZFIM", opcode->args[0]))
(*info->fprintf_func) (info->stream, " ");
for (s = opcode->args; *s != '\0'; ++s)
{
switch (*s)
{
case 'x':
fput_reg (GET_FIELD (insn, 11, 15), info);
break;
case 'X':
if (GET_FIELD (insn, 25, 25))
fput_reg_r (GET_FIELD (insn, 11, 15), info);
else
fput_reg (GET_FIELD (insn, 11, 15), info);
break;
case 'b':
fput_reg (GET_FIELD (insn, 6, 10), info);
break;
case '^':
fput_creg (GET_FIELD (insn, 6, 10), info);
break;
case 'E':
if (GET_FIELD (insn, 25, 25))
fput_reg_r (GET_FIELD (insn, 6, 10), info);
else
fput_reg (GET_FIELD (insn, 6, 10), info);
break;
case 't':
fput_reg (GET_FIELD (insn, 27, 31), info);
break;
case 'v':
if (GET_FIELD (insn, 25, 25))
fput_reg_r (GET_FIELD (insn, 27, 31), info);
else
fput_reg (GET_FIELD (insn, 27, 31), info);
break;
case '4':
fput_creg (GET_FIELD (insn, 6, 10), info);
break;
case '6':
fput_reg (GET_FIELD (insn, 11, 15), info);
break;
case '7':
fput_reg (GET_FIELD (insn, 27, 31), info);
break;
case '8':
fput_reg (GET_FIELD (insn, 16, 20), info);
break;
case '9':
fput_reg (GET_FIELD (insn, 21, 25), info);
break;
case '5':
fput_const (extract_5_load (insn), info);
break;
case 's':
fprintf_filtered (stream, "sr%d", GET_FIELD (insn, 16, 17));
break;
case 'S':
(*info->fprintf_func) (info->stream, "sr%d", extract_3 (insn));
break;
case 'c':
(*info->fprintf_func) (info->stream, "%s ",
index_compl_names[GET_COMPL (insn)]);
break;
case 'C':
(*info->fprintf_func) (info->stream, "%s ",
short_ldst_compl_names[GET_COMPL (insn)]);
break;
case 'Y':
(*info->fprintf_func) (info->stream, "%s ",
short_bytes_compl_names[GET_COMPL (insn)]);
break;
/* these four conditions are for the set of instructions
which distinguish true/false conditions by opcode rather
than by the 'f' bit (sigh): comb, comib, addb, addib */
case '<':
fputs_filtered (compare_cond_names[GET_FIELD (insn, 16, 18)],
info);
break;
case '?':
fputs_filtered (compare_cond_names[GET_FIELD (insn, 16, 18) + 8],
info);
break;
case '@':
fputs_filtered (add_cond_names[GET_FIELD (insn, 16, 18) + 8],
info);
break;
case 'd':
(*info->fprintf_func) (info->stream, "%s",
compare_cond_names[GET_COND (insn)]);
break;
case 'a':
case '!':
(*info->fprintf_func) (info->stream, "%s",
add_cond_names[GET_FIELD (insn, 16, 18)]);
break;
case '&':
(*info->fprintf_func) (info->stream, "%s ",
logical_cond_names[GET_COND (insn)]);
break;
case 'U':
(*info->fprintf_func) (info->stream, "%s ",
unit_cond_names[GET_COND (insn)]);
break;
case '>':
case '~':
(*info->fprintf_func) (info->stream, "%s ",
shift_cond_names[GET_FIELD (insn, 16, 18)]);
break;
case 'V':
fput_const (extract_5_store (insn), info);
break;
case 'R':
fput_const (extract_5R_store (insn), info);
break;
case 'Q':
fput_const (extract_5Q_store (insn), info);
break;
case 'i':
fput_const (extract_11 (insn), info);
break;
case 'j':
fput_const (extract_14 (insn), info);
break;
case 'k':
fput_const (extract_21 (insn), info);
break;
case 'n':
if (insn & 0x2)
(*info->fprintf_func) (info->stream, ",n ");
else
(*info->fprintf_func) (info->stream, " ");
break;
case 'w':
(*info->print_address_func) (memaddr + 8 + extract_12 (insn),
info);
break;
case 'W':
/* don't interpret an address if it's an external branch
instruction. */
op = GET_FIELD (insn, 0, 5);
if (op != 0x38 /* be */ && op != 0x39 /* ble */)
(*info->print_address_func) ((memaddr + 8
+ extract_17 (insn)),
info);
else
fput_const (extract_17 (insn), info);
break;
case 'p':
(*info->fprintf_func) (info->stream, "%d",
31 - GET_FIELD (insn, 22, 26));
break;
case 'P':
(*info->fprintf_func) (info->stream, "%d",
GET_FIELD (insn, 22, 26));
break;
case 'T':
(*info->fprintf_func) (info->stream, "%d",
32 - GET_FIELD (insn, 27, 31));
break;
case 'A':
fput_const (GET_FIELD (insn, 6, 18), info);
break;
case 'Z':
if (GET_FIELD (insn, 26, 26))
(*info->fprintf_func) (info->stream, ",m ");
else
(*info->fprintf_func) (info->stream, " ");
break;
case 'D':
fput_const (GET_FIELD (insn, 6, 31), info);
break;
case 'f':
(*info->fprintf_func) (info->stream, ",%d", GET_FIELD (insn, 23, 25));
break;
case 'O':
fput_const ((GET_FIELD (insn, 6,20) << 5 |
GET_FIELD (insn, 27, 31)), info);
break;
case 'o':
fput_const (GET_FIELD (insn, 6, 20), info);
break;
case '2':
fput_const ((GET_FIELD (insn, 6, 22) << 5 |
GET_FIELD (insn, 27, 31)), info);
break;
case '1':
fput_const ((GET_FIELD (insn, 11, 20) << 5 |
GET_FIELD (insn, 27, 31)), info);
break;
case '0':
fput_const ((GET_FIELD (insn, 16, 20) << 5 |
GET_FIELD (insn, 27, 31)), info);
break;
case 'u':
(*info->fprintf_func) (info->stream, "%d", GET_FIELD (insn, 23, 25));
break;
case 'F':
/* if no destination completer, need a space here */
if (GET_FIELD (insn, 21, 22) == 1)
fputs_filtered (float_format_names[GET_FIELD (insn, 19, 20)],
info);
else
(*info->fprintf_func) (info->stream, "%s ",
float_format_names[GET_FIELD
(insn, 19, 20)]);
break;
case 'G':
(*info->fprintf_func) (info->stream, "%s ",
float_format_names[GET_FIELD (insn,
17, 18)]);
break;
case 'H':
fputs_filtered (float_format_names[GET_FIELD
(insn, 26, 26)], info);
break;
case 'I':
/* if no destination completer, need a space here */
if (GET_FIELD (insn, 21, 22) == 1)
fputs_filtered (float_format_names[GET_FIELD (insn, 20, 20)],
info);
else
fprintf_filtered (stream, "%s ",
float_format_names[GET_FIELD
(insn, 20, 20)]);
break;
case 'J':
if (GET_FIELD (insn, 24, 24))
fput_reg_r (GET_FIELD (insn, 6, 10), info);
else
fput_reg (GET_FIELD (insn, 6, 10), info);
break;
case 'K':
if (GET_FIELD (insn, 19, 19))
fput_reg_r (GET_FIELD (insn, 11, 15), info);
else
fput_reg (GET_FIELD (insn, 11, 15), info);
break;
case 'M':
fputs_filtered (float_comp_names[GET_FIELD (insn, 27, 31)],
info);
break;
default:
(*info->fprintf_func) (info->stream, "%c", *s);
break;
}
}
return sizeof(insn);
}
}
(*info->fprintf_func) (info->stream, "#%8x", insn);
return sizeof(insn);
}