sparc-dis.c

来自「基于4个mips核的noc设计」· C语言 代码 · 共 983 行 · 第 1/2 页

C
983
字号
/* Print SPARC instructions.   Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,   2000 Free Software Foundation, Inc.This program is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe 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 ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with this program; if not, write to the Free SoftwareFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */#include <stdio.h>#include "sysdep.h"#include "opcode/sparc.h"#include "dis-asm.h"#include "libiberty.h"#include "opintl.h"/* Bitmask of v9 architectures.  */#define MASK_V9 ((1 << SPARC_OPCODE_ARCH_V9) \		 | (1 << SPARC_OPCODE_ARCH_V9A) \		 | (1 << SPARC_OPCODE_ARCH_V9B))/* 1 if INSN is for v9 only.  */#define V9_ONLY_P(insn) (! ((insn)->architecture & ~MASK_V9))/* 1 if INSN is for v9.  */#define V9_P(insn) (((insn)->architecture & MASK_V9) != 0)/* The sorted opcode table.  */static const struct sparc_opcode **sorted_opcodes;/* For faster lookup, after insns are sorted they are hashed.  *//* ??? I think there is room for even more improvement.  */#define HASH_SIZE 256/* It is important that we only look at insn code bits as that is how the   opcode table is hashed.  OPCODE_BITS is a table of valid bits for each   of the main types (0,1,2,3).  */static int opcode_bits[4] = { 0x01c00000, 0x0, 0x01f80000, 0x01f80000 };#define HASH_INSN(INSN) \  ((((INSN) >> 24) & 0xc0) | (((INSN) & opcode_bits[((INSN) >> 30) & 3]) >> 19))struct opcode_hash {  struct opcode_hash *next;  const struct sparc_opcode *opcode;};static struct opcode_hash *opcode_hash_table[HASH_SIZE];static void build_hash_table  PARAMS ((const struct sparc_opcode **, struct opcode_hash **, int));static int is_delayed_branch PARAMS ((unsigned long));static int compare_opcodes PARAMS ((const PTR, const PTR));static int compute_arch_mask PARAMS ((unsigned long));/* Sign-extend a value which is N bits long.  */#define	SEX(value, bits) \	((((int)(value)) << ((8 * sizeof (int)) - bits))	\			 >> ((8 * sizeof (int)) - bits) )static  char *reg_names[] ={ "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",	  "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",	  "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",	  "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7",	  "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",	  "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",	  "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",  "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",  "f32", "f33", "f34", "f35", "f36", "f37", "f38", "f39",	  "f40", "f41", "f42", "f43", "f44", "f45", "f46", "f47",	  "f48", "f49", "f50", "f51", "f52", "f53", "f54", "f55",  "f56", "f57", "f58", "f59", "f60", "f61", "f62", "f63",/* psr, wim, tbr, fpsr, cpsr are v8 only.  */  "y", "psr", "wim", "tbr", "pc", "npc", "fpsr", "cpsr"};#define	freg_names	(&reg_names[4 * 8])/* These are ordered according to there register number in   rdpr and wrpr insns.  */static char *v9_priv_reg_names[] ={  "tpc", "tnpc", "tstate", "tt", "tick", "tba", "pstate", "tl",  "pil", "cwp", "cansave", "canrestore", "cleanwin", "otherwin",  "wstate", "fq"  /* "ver" - special cased */};/* These are ordered according to there register number in   rd and wr insns (-16).  */static char *v9a_asr_reg_names[] ={  "pcr", "pic", "dcr", "gsr", "set_softint", "clear_softint",  "softint", "tick_cmpr", "sys_tick", "sys_tick_cmpr"};/* Macros used to extract instruction fields.  Not all fields have   macros defined here, only those which are actually used.  */#define X_RD(i) (((i) >> 25) & 0x1f)#define X_RS1(i) (((i) >> 14) & 0x1f)#define X_LDST_I(i) (((i) >> 13) & 1)#define X_ASI(i) (((i) >> 5) & 0xff)#define X_RS2(i) (((i) >> 0) & 0x1f)#define X_IMM(i,n) (((i) >> 0) & ((1 << (n)) - 1))#define X_SIMM(i,n) SEX (X_IMM ((i), (n)), (n))#define X_DISP22(i) (((i) >> 0) & 0x3fffff)#define X_IMM22(i) X_DISP22 (i)#define X_DISP30(i) (((i) >> 0) & 0x3fffffff)/* These are for v9.  */#define X_DISP16(i) (((((i) >> 20) & 3) << 14) | (((i) >> 0) & 0x3fff))#define X_DISP19(i) (((i) >> 0) & 0x7ffff)#define X_MEMBAR(i) ((i) & 0x7f)/* Here is the union which was used to extract instruction fields   before the shift and mask macros were written.   union sparc_insn     {       unsigned long int code;       struct	 {	   unsigned int anop:2;	   #define	op	ldst.anop	   unsigned int anrd:5;	   #define	rd	ldst.anrd	   unsigned int op3:6;	   unsigned int anrs1:5;	   #define	rs1	ldst.anrs1	   unsigned int i:1;	   unsigned int anasi:8;	   #define	asi	ldst.anasi	   unsigned int anrs2:5;	   #define	rs2	ldst.anrs2	   #define	shcnt	rs2	 } ldst;       struct	 {	   unsigned int anop:2, anrd:5, op3:6, anrs1:5, i:1;	   unsigned int IMM13:13;	   #define	imm13	IMM13.IMM13	 } IMM13;       struct	 {	   unsigned int anop:2;	   unsigned int a:1;	   unsigned int cond:4;	   unsigned int op2:3;	   unsigned int DISP22:22;	   #define	disp22	branch.DISP22	   #define	imm22	disp22	 } branch;       struct	 {	   unsigned int anop:2;	   unsigned int a:1;	   unsigned int z:1;	   unsigned int rcond:3;	   unsigned int op2:3;	   unsigned int DISP16HI:2;	   unsigned int p:1;	   unsigned int _rs1:5;	   unsigned int DISP16LO:14;	 } branch16;       struct	 {	   unsigned int anop:2;	   unsigned int adisp30:30;	   #define	disp30	call.adisp30	 } call;     };   *//* Nonzero if INSN is the opcode for a delayed branch.  */static intis_delayed_branch (insn)     unsigned long insn;{  struct opcode_hash *op;  for (op = opcode_hash_table[HASH_INSN (insn)]; op; op = op->next)    {      CONST struct sparc_opcode *opcode = op->opcode;      if ((opcode->match & insn) == opcode->match	  && (opcode->lose & insn) == 0)	return (opcode->flags & F_DELAYED);    }  return 0;}/* extern void qsort (); *//* Records current mask of SPARC_OPCODE_ARCH_FOO values, used to pass value   to compare_opcodes.  */static unsigned int current_arch_mask;/* Print one instruction from MEMADDR on INFO->STREAM.   We suffix the instruction with a comment that gives the absolute   address involved, as well as its symbolic form, if the instruction   is preceded by a findable `sethi' and it either adds an immediate   displacement to that register, or it is an `add' or `or' instruction   on that register.  */intprint_insn_sparc (memaddr, info)     bfd_vma memaddr;     disassemble_info *info;{  FILE *stream = info->stream;  bfd_byte buffer[4];  unsigned long insn;  register struct opcode_hash *op;  /* Nonzero of opcode table has been initialized.  */  static int opcodes_initialized = 0;  /* bfd mach number of last call.  */  static unsigned long current_mach = 0;  bfd_vma (*getword) PARAMS ((const unsigned char *));  if (!opcodes_initialized      || info->mach != current_mach)    {      int i;      current_arch_mask = compute_arch_mask (info->mach);      if (!opcodes_initialized)	sorted_opcodes = (const struct sparc_opcode **)	  xmalloc (sparc_num_opcodes * sizeof (struct sparc_opcode *));      /* Reset the sorted table so we can resort it.  */      for (i = 0; i < sparc_num_opcodes; ++i)	sorted_opcodes[i] = &sparc_opcodes[i];      qsort ((char *) sorted_opcodes, sparc_num_opcodes,	     sizeof (sorted_opcodes[0]), compare_opcodes);      build_hash_table (sorted_opcodes, opcode_hash_table, sparc_num_opcodes);      current_mach = info->mach;      opcodes_initialized = 1;    }  {    int status =      (*info->read_memory_func) (memaddr, buffer, sizeof (buffer), info);    if (status != 0)      {	(*info->memory_error_func) (status, memaddr, info);	return -1;      }  }  /* On SPARClite variants such as DANlite (sparc86x), instructions     are always big-endian even when the machine is in little-endian mode. */  if (info->endian == BFD_ENDIAN_BIG || info->mach == bfd_mach_sparc_sparclite)    getword = bfd_getb32;  else    getword = bfd_getl32;  insn = getword (buffer);  info->insn_info_valid = 1;			/* We do return this info */  info->insn_type = dis_nonbranch;		/* Assume non branch insn */  info->branch_delay_insns = 0;			/* Assume no delay */  info->target = 0;				/* Assume no target known */  for (op = opcode_hash_table[HASH_INSN (insn)]; op; op = op->next)    {      CONST struct sparc_opcode *opcode = op->opcode;      /* If the insn isn't supported by the current architecture, skip it.  */      if (! (opcode->architecture & current_arch_mask))	continue;      if ((opcode->match & insn) == opcode->match	  && (opcode->lose & insn) == 0)	{	  /* Nonzero means that we have found an instruction which has	     the effect of adding or or'ing the imm13 field to rs1.  */	  int imm_added_to_rs1 = 0;	  int imm_ored_to_rs1 = 0;	  /* Nonzero means that we have found a plus sign in the args	     field of the opcode table.  */	  int found_plus = 0;	  	  /* Nonzero means we have an annulled branch.  */	  int is_annulled = 0;	  /* Do we have an `add' or `or' instruction combining an             immediate with rs1?  */	  if (opcode->match == 0x80102000) /* or */	    imm_ored_to_rs1 = 1;	  if (opcode->match == 0x80002000) /* add */	    imm_added_to_rs1 = 1;	  if (X_RS1 (insn) != X_RD (insn)	      && strchr (opcode->args, 'r') != 0)	      /* Can't do simple format if source and dest are different.  */	      continue;	  if (X_RS2 (insn) != X_RD (insn)	      && strchr (opcode->args, 'O') != 0)	      /* Can't do simple format if source and dest are different.  */	      continue;	  (*info->fprintf_func) (stream, opcode->name);	  {	    register CONST char *s;	    if (opcode->args[0] != ',')	      (*info->fprintf_func) (stream, " ");	    for (s = opcode->args; *s != '\0'; ++s)	      {		while (*s == ',')		  {		    (*info->fprintf_func) (stream, ",");		    ++s;		    switch (*s) {		    case 'a':		      (*info->fprintf_func) (stream, "a");		      is_annulled = 1;		      ++s;		      continue;		    case 'N':		      (*info->fprintf_func) (stream, "pn");		      ++s;		      continue;		    case 'T':		      (*info->fprintf_func) (stream, "pt");		      ++s;		      continue;		    default:		      break;		    }		/* switch on arg */		  }		/* while there are comma started args */		(*info->fprintf_func) (stream, " ");					switch (*s)		  {		  case '+':		    found_plus = 1;		    /* note fall-through */		  default:		    (*info->fprintf_func) (stream, "%c", *s);		    break;		  case '#':		    (*info->fprintf_func) (stream, "0");		    break;#define	reg(n)	(*info->fprintf_func) (stream, "%%%s", reg_names[n])		  case '1':		  case 'r':		    reg (X_RS1 (insn));		    break;		  case '2':		  case 'O':		    reg (X_RS2 (insn));		    break;		  case 'd':		    reg (X_RD (insn));		    break;#undef	reg#define	freg(n)		(*info->fprintf_func) (stream, "%%%s", freg_names[n])#define	fregx(n)	(*info->fprintf_func) (stream, "%%%s", freg_names[((n) & ~1) | (((n) & 1) << 5)])		  case 'e':		    freg (X_RS1 (insn));		    break;		  case 'v':	/* double/even */		  case 'V':	/* quad/multiple of 4 */		    fregx (X_RS1 (insn));		    break;		  case 'f':		    freg (X_RS2 (insn));		    break;		  case 'B':	/* double/even */		  case 'R':	/* quad/multiple of 4 */		    fregx (X_RS2 (insn));		    break;		  case 'g':		    freg (X_RD (insn));		    break;		  case 'H':	/* double/even */		  case 'J':	/* quad/multiple of 4 */		    fregx (X_RD (insn));		    break;#undef	freg#undef	fregx#define	creg(n)	(*info->fprintf_func) (stream, "%%c%u", (unsigned int) (n))		  case 'b':		    creg (X_RS1 (insn));		    break;		  case 'c':		    creg (X_RS2 (insn));		    break;		  case 'D':		    creg (X_RD (insn));		    break;#undef	creg		  case 'h':		    (*info->fprintf_func) (stream, "%%hi(%#x)",					   (0xFFFFFFFF					    & ((int) X_IMM22 (insn) << 10)));		    break;		  case 'i':	/* 13 bit immediate */		  case 'I':	/* 11 bit immediate */		  case 'j':	/* 10 bit immediate */		    {		      int imm;		      if (*s == 'i')		        imm = X_SIMM (insn, 13);		      else if (*s == 'I')			imm = X_SIMM (insn, 11);		      else			imm = X_SIMM (insn, 10);		      /* Check to see whether we have a 1+i, and take			 note of that fact.			 Note: because of the way we sort the table,			 we will be matching 1+i rather than i+1,			 so it is OK to assume that i is after +,			 not before it.  */		      if (found_plus)			imm_added_to_rs1 = 1;		      		      if (imm <= 9)			(*info->fprintf_func) (stream, "%d", imm);		      else			(*info->fprintf_func) (stream, "%#x", imm);		    }		    break;		  case 'X':	/* 5 bit unsigned immediate */		  case 'Y':	/* 6 bit unsigned immediate */		    {		      int imm = X_IMM (insn, *s == 'X' ? 5 : 6);		      if (imm <= 9)			(info->fprintf_func) (stream, "%d", imm);		      else			(info->fprintf_func) (stream, "%#x", (unsigned) imm);		    }		    break;		  case '3':		    (info->fprintf_func) (stream, "%d", X_IMM (insn, 3));		    break;		  case 'K':		    {		      int mask = X_MEMBAR (insn);		      int bit = 0x40, printed_one = 0;		      const char *name;		      if (mask == 0)			(info->fprintf_func) (stream, "0");		      else			while (bit)			  {			    if (mask & bit)			      {				if (printed_one)				  (info->fprintf_func) (stream, "|");				name = sparc_decode_membar (bit);				(info->fprintf_func) (stream, "%s", name);				printed_one = 1;			      }			    bit >>= 1;			  }

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?