ftp.nice.ch/Attic/openStep/developer/bundles/GDBbundle.1.0.s.tgz#/GDBbundle-1.0.s/debug/gdb/gdb/hppa/hppa-pinsn.c

This is hppa-pinsn.c in view mode; [Download] [Up]

/* Disassembler for the PA-RISC. Somewhat derived from sparc-pinsn.c.
   Copyright 1989, 1990, 1992 Free Software Foundation, Inc.

   Contributed by the Center for Software Science at the
   University of Utah (pa-gdb-bugs@cs.utah.edu).

This file is part of GDB.

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 "symtab.h"
#include "opcode/hppa.h"
#include "dis-asm.h"

#ifdef NeXT
/* Integer register names, indexed by the numbers which appear in the
   opcodes.  */
static char * reg_names[] =
{  "r0", "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"
   };

/* Floating point register names, indexed by the numbers which appear in the
   opcodes.  */
static char * fp_reg_names[] =
{  "fpsr", "fpe2", "fpe4", "fpe6",
   "fr4", "fr5", "fr6", "fr7", "fr8",
   "fr9", "fr10", "fr11", "fr12", "fr13", "fr14", "fr15",
   "fr16", "fr17", "fr18", "fr19", "fr20", "fr21", "fr22", "fr23",
   "fr24", "fr25", "fr26", "fr27", "fr28", "fr29", "fr30", "fr31"
   };
#endif	/* NeXT */

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));
#ifdef NeXT
static void fput_fp_reg PARAMS ((unsigned reg, FILE *stream));
static void fput_fp_reg_r PARAMS ((unsigned reg, FILE *stream));
#endif	/* NeXT */

/* Print one instruction from MEMADDR on STREAM.  */
int
print_insn_hppa (memaddr, info)
     CORE_ADDR memaddr;
     disassemble_info *info;
{
  long insn;
  unsigned int i, op;
  FILE *stream = info->stream;

  insn = read_memory_integer (memaddr, sizeof (insn));

  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>~nZFIMad|", 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_fp_reg_r (GET_FIELD (insn, 11, 15), stream);
		  else
		      fput_fp_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_fp_reg_r (GET_FIELD (insn, 6, 10), stream);
		  else
		      fput_fp_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_fp_reg_r (GET_FIELD (insn, 27, 31), stream);
		  else
		      fput_fp_reg (GET_FIELD (insn, 27, 31), stream);
		  break;
#ifdef NeXT
		case 'y':
		      fput_fp_reg (GET_FIELD (insn, 27, 31), stream);
		  break;
#endif	/* NeXT */
		case '4':
		  fput_fp_reg (GET_FIELD (insn, 6, 10), stream);
		  break;
		case '6':
		  fput_fp_reg (GET_FIELD (insn, 11, 15), stream);
		  break;
		case '7':
		  fput_fp_reg (GET_FIELD (insn, 27, 31), stream);
		  break;
		case '8':
		  fput_fp_reg (GET_FIELD (insn, 16, 20), stream);
		  break;
		case '9':
		  fput_fp_reg (GET_FIELD (insn, 21, 25), stream);
		  break;
		case '5':
		  fput_const (extract_5_load (insn), stream);
		  break;
		  /* case 's': */
#ifdef NeXT
		case 's':
		  fprintf_filtered (stream, "sr%d", GET_FIELD(insn, 16, 17));
		  break;
#endif	/* NeXT */
		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 '?':
#ifdef NeXT
		  fputs_filtered (compare_cond_names[GET_FIELD (insn, 16, 18)],
				  stream);
#else
		  fputs_filtered (compare_cond_names[GET_FIELD (insn, 16, 18) + 8],
				  stream);
#endif
		  break;
#ifdef NeXT
		case 'a':
		  fputs_filtered (compare_cond_names[GET_COND (insn)],
				  stream);
		  break;
		case 'd':
		  fputs_filtered (add_cond_names[GET_COND (insn)],
				  stream);
		  break;
#endif	/* NeXT */
		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;
#ifndef NeXT
		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;
#endif	/* NeXT */
		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;
#ifdef NeXT
		case '|':
#endif	/* NeXT */
		case '>':
		case '~':
		  fprintf_filtered (stream, "%s ",
				    shift_cond_names[GET_FIELD (insn, 16, 18)]);
#ifdef NeXT
		  if (s[1] != 'n')
		    fprintf_filtered (stream, " ");
#endif	/* NeXT */
		  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':
#ifndef NeXT	/* 4.8 */
		  op = GET_FIELD (insn, 0, 5);

		  if (op == 0x38 /* be */ || op == 0x39 /* ble */)
		    fput_const (extract_17 (insn), stream);
		  else
#endif	/* NeXT */
		    print_address (memaddr + 8 + extract_17 (insn), stream);

		  break;
#ifndef NeXT
		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;
		  }
#endif	/* NeXT */

#ifdef NeXT
		case 'z':
		  /* 17 bit displacement.  This is an offset from a register
		     so it gets disasssembled as just a number, not any sort
		     of address.  */
		  fput_const (extract_17 (insn), stream);
		  break;
#endif	/* NeXT */
		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':
#ifdef NeXT	  /* BTW, this is the only use of extract_5Q... */
		  fput_const (extract_5Q_store (insn), stream);
#else
		  fprintf_filtered (stream, "%d",
				    GET_FIELD (insn, 11, 15));
#endif	/* NeXT */
		  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 'M':
		  fputs_filtered (float_comp_names[GET_FIELD (insn, 27, 31)],
				  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_fp_reg_r (GET_FIELD (insn, 6, 10), stream);
                  else
                      fput_fp_reg (GET_FIELD (insn, 6, 10), stream);

                  break;
                case 'K':
                  if (GET_FIELD (insn, 19, 19))
                      fput_fp_reg_r (GET_FIELD (insn, 11, 15), stream);
                  else
                      fput_fp_reg (GET_FIELD (insn, 11, 15), stream);
                  break;
		default:
		  fprintf_filtered (stream, "%c", *s);
		  break;
		}
	    }
#ifndef NeXT
/* 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);
	    }
#endif	/* NeXT */
	  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);
}

static void
fput_fp_reg (reg, stream)
     unsigned reg;
     FILE *stream;
{
  if (reg)
    fputs_filtered (fp_reg_names[reg], stream);
  else
    fputs_filtered ("fr0", stream);
}

void
fput_fp_reg_r (reg, stream)
     unsigned reg;
     FILE *stream;
{
  if (reg < 4)
    fprintf_filtered (stream, "fpe%d", reg * 2 + 1);
  else
  {
    if (reg)
       fprintf_filtered (stream, "%s", fp_reg_names[reg]);
    else
       fprintf_filtered (stream, "%s", "fr0");
  }
  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);
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.