sparc-dis.c

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

C
983
字号
		      break;		    }		  case 'k':		    info->target = memaddr + SEX (X_DISP16 (insn), 16) * 4;		    (*info->print_address_func) (info->target, info);		    break;		  case 'G':		    info->target = memaddr + SEX (X_DISP19 (insn), 19) * 4;		    (*info->print_address_func) (info->target, info);		    break;		  case '6':		  case '7':		  case '8':		  case '9':		    (*info->fprintf_func) (stream, "%%fcc%c", *s - '6' + '0');		    break;		  case 'z':		    (*info->fprintf_func) (stream, "%%icc");		    break;		  case 'Z':		    (*info->fprintf_func) (stream, "%%xcc");		    break;		  case 'E':		    (*info->fprintf_func) (stream, "%%ccr");		    break;		  case 's':		    (*info->fprintf_func) (stream, "%%fprs");		    break;		  case 'o':		    (*info->fprintf_func) (stream, "%%asi");		    break;		    		  case 'W':		    (*info->fprintf_func) (stream, "%%tick");		    break;		  case 'P':		    (*info->fprintf_func) (stream, "%%pc");		    break;		  case '?':		    if (X_RS1 (insn) == 31)		      (*info->fprintf_func) (stream, "%%ver");		    else if ((unsigned) X_RS1 (insn) < 16)		      (*info->fprintf_func) (stream, "%%%s",					     v9_priv_reg_names[X_RS1 (insn)]);		    else		      (*info->fprintf_func) (stream, "%%reserved");		    break;		  case '!':		    if ((unsigned) X_RD (insn) < 15)		      (*info->fprintf_func) (stream, "%%%s",					     v9_priv_reg_names[X_RD (insn)]);		    else		      (*info->fprintf_func) (stream, "%%reserved");		    break;		  case '/':		    if (X_RS1 (insn) < 16 || X_RS1 (insn) > 25)		      (*info->fprintf_func) (stream, "%%reserved");		    else		      (*info->fprintf_func) (stream, "%%%s",					     v9a_asr_reg_names[X_RS1 (insn)-16]);		    break;		  case '_':		    if (X_RD (insn) < 16 || X_RD (insn) > 25)		      (*info->fprintf_func) (stream, "%%reserved");		    else		      (*info->fprintf_func) (stream, "%%%s",					     v9a_asr_reg_names[X_RD (insn)-16]);		    break;		  case '*':		    {		      const char *name = sparc_decode_prefetch (X_RD (insn));		      if (name)			(*info->fprintf_func) (stream, "%s", name);		      else			(*info->fprintf_func) (stream, "%d", X_RD (insn));		      break;		    }		    		  case 'M':		    (*info->fprintf_func) (stream, "%%asr%d", X_RS1 (insn));		    break;		    		  case 'm':		    (*info->fprintf_func) (stream, "%%asr%d", X_RD (insn));		    break;		    		  case 'L':		    info->target = memaddr + SEX (X_DISP30 (insn), 30) * 4;		    (*info->print_address_func) (info->target, info);		    break;		  case 'n':		    (*info->fprintf_func)		      (stream, "%#x", SEX (X_DISP22 (insn), 22));		    break;		  case 'l':		    info->target = memaddr + SEX (X_DISP22 (insn), 22) * 4;		    (*info->print_address_func) (info->target, info);		    break;		  case 'A':		    {		      const char *name = sparc_decode_asi (X_ASI (insn));		      if (name)			(*info->fprintf_func) (stream, "%s", name);		      else			(*info->fprintf_func) (stream, "(%d)", X_ASI (insn));		      break;		    }		  case 'C':		    (*info->fprintf_func) (stream, "%%csr");		    break;		  case 'F':		    (*info->fprintf_func) (stream, "%%fsr");		    break;		  case 'p':		    (*info->fprintf_func) (stream, "%%psr");		    break;		  case 'q':		    (*info->fprintf_func) (stream, "%%fq");		    break;		  case 'Q':		    (*info->fprintf_func) (stream, "%%cq");		    break;		  case 't':		    (*info->fprintf_func) (stream, "%%tbr");		    break;		  case 'w':		    (*info->fprintf_func) (stream, "%%wim");		    break;		  case 'x':		    (*info->fprintf_func) (stream, "%d",					   ((X_LDST_I (insn) << 8)					    + X_ASI (insn)));		    break;		  case 'y':		    (*info->fprintf_func) (stream, "%%y");		    break;		  case 'u':		  case 'U':		    {		      int val = *s == 'U' ? X_RS1 (insn) : X_RD (insn);		      const char *name = sparc_decode_sparclet_cpreg (val);		      if (name)			(*info->fprintf_func) (stream, "%s", name);		      else			(*info->fprintf_func) (stream, "%%cpreg(%d)", val);		      break;		    }		  }	      }	  }	  /* If we are adding or or'ing something to rs1, then	     check to see whether the previous instruction was	     a sethi to the same register as in the sethi.	     If so, attempt to print the result of the add or	     or (in this context add and or do the same thing)	     and its symbolic value.  */	  if (imm_ored_to_rs1 || imm_added_to_rs1)	    {	      unsigned long prev_insn;	      int errcode;	      errcode =		(*info->read_memory_func)		  (memaddr - 4, buffer, sizeof (buffer), info);	      prev_insn = getword (buffer);	      if (errcode == 0)		{		  /* If it is a delayed branch, we need to look at the		     instruction before the delayed branch.  This handles		     sequences such as		     sethi %o1, %hi(_foo), %o1		     call _printf		     or %o1, %lo(_foo), %o1		     */		  if (is_delayed_branch (prev_insn))		    {		      errcode = (*info->read_memory_func)			(memaddr - 8, buffer, sizeof (buffer), info);		      prev_insn = getword (buffer);		    }		}	      /* If there was a problem reading memory, then assume		 the previous instruction was not sethi.  */	      if (errcode == 0)		{		  /* Is it sethi to the same register?  */		  if ((prev_insn & 0xc1c00000) == 0x01000000		      && X_RD (prev_insn) == X_RS1 (insn))		    {		      (*info->fprintf_func) (stream, "\t! ");		      info->target = 			(0xFFFFFFFF & (int) X_IMM22 (prev_insn) << 10);		      if (imm_added_to_rs1)			info->target += X_SIMM (insn, 13);		      else			info->target |= X_SIMM (insn, 13);		      (*info->print_address_func) (info->target, info);		      info->insn_type = dis_dref;		      info->data_size = 4;  /* FIXME!!! */		    }		}	    }	  if (opcode->flags & (F_UNBR|F_CONDBR|F_JSR))	    {		/* FIXME -- check is_annulled flag */	      if (opcode->flags & F_UNBR)		info->insn_type = dis_branch;	      if (opcode->flags & F_CONDBR)		info->insn_type = dis_condbranch;	      if (opcode->flags & F_JSR)		info->insn_type = dis_jsr;	      if (opcode->flags & F_DELAYED)		info->branch_delay_insns = 1;	    }	  return sizeof (buffer);	}    }  info->insn_type = dis_noninsn;	/* Mark as non-valid instruction */  (*info->fprintf_func) (stream, _("unknown"));  return sizeof (buffer);}/* Given BFD mach number, return a mask of SPARC_OPCODE_ARCH_FOO values.  */static intcompute_arch_mask (mach)     unsigned long mach;{  switch (mach)    {    case 0 :    case bfd_mach_sparc :      return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V8);    case bfd_mach_sparc_sparclet :      return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLET);    case bfd_mach_sparc_sparclite :    case bfd_mach_sparc_sparclite_le :      /* sparclites insns are recognized by default (because that's how	 they've always been treated, for better or worse).  Kludge this by	 indicating generic v8 is also selected.  */      return (SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLITE)	      | SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V8));    case bfd_mach_sparc_v8plus :    case bfd_mach_sparc_v9 :      return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9);    case bfd_mach_sparc_v8plusa :    case bfd_mach_sparc_v9a :      return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9A);    case bfd_mach_sparc_v8plusb :    case bfd_mach_sparc_v9b :      return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9B);    }  abort ();}/* Compare opcodes A and B.  */static intcompare_opcodes (a, b)     const PTR a;     const PTR 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 one (and only one) insn isn't supported by the current architecture,     prefer the one that is.  If neither are supported, but they're both for     the same architecture, continue processing.  Otherwise (both unsupported     and for different architectures), prefer lower numbered arch's (fudged     by comparing the bitmasks).  */  if (op0->architecture & current_arch_mask)    {      if (! (op1->architecture & current_arch_mask))	return -1;    }  else    {      if (op1->architecture & current_arch_mask)	return 1;      else if (op0->architecture != op1->architecture)	return op0->architecture - op1->architecture;    }  /* If a bit is set in both match and lose, there is something     wrong with the opcode table.  */  if (match0 & lose0)    {      fprintf	(stderr,	 /* xgettext:c-format */	 _("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,	 /* xgettext:c-format */	 _("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,		 /* xgettext:c-format */		 _("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;      }  }  /* Put 1,i before i,1.  */  {    int i0 = strncmp (op0->args, "i,1", 3) == 0;    int i1 = strncmp (op1->args, "i,1", 3) == 0;    if (i0 ^ i1)      return i0 - i1;  }  /* 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.  */  /* ??? This is no longer true now that we sort a vector of pointers,     not the table itself.  */  return 0;}/* Build a hash table from the opcode table.   OPCODE_TABLE is a sorted list of pointers into the opcode table.  */static voidbuild_hash_table (opcode_table, hash_table, num_opcodes)     const struct sparc_opcode **opcode_table;     struct opcode_hash **hash_table;     int num_opcodes;{  register int i;  int hash_count[HASH_SIZE];  static struct opcode_hash *hash_buf = NULL;  /* Start at the end of the table and work backwards so that each     chain is sorted.  */  memset (hash_table, 0, HASH_SIZE * sizeof (hash_table[0]));  memset (hash_count, 0, HASH_SIZE * sizeof (hash_count[0]));  if (hash_buf != NULL)    free (hash_buf);  hash_buf = (struct opcode_hash *) xmalloc (sizeof (struct opcode_hash) * num_opcodes);  for (i = num_opcodes - 1; i >= 0; --i)    {      register int hash = HASH_INSN (opcode_table[i]->match);      register struct opcode_hash *h = &hash_buf[i];      h->next = hash_table[hash];      h->opcode = opcode_table[i];      hash_table[hash] = h;      ++hash_count[hash];    }#if 0 /* for debugging */  {    int min_count = num_opcodes, max_count = 0;    int total;    for (i = 0; i < HASH_SIZE; ++i)      {        if (hash_count[i] < min_count)	  min_count = hash_count[i];	if (hash_count[i] > max_count)	  max_count = hash_count[i];	total += hash_count[i];      }    printf ("Opcode hash table stats: min %d, max %d, ave %f\n",	    min_count, max_count, (double) total / HASH_SIZE);  }#endif}

⌨️ 快捷键说明

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