cris-dis.c

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

C
1,405
字号
	retval = (((insn >> 12) & 15) == (insn & 15));	if (!retval)	  return -1;	else	  retval += 4;	break;      case 'P':	{	  const struct cris_spec_reg *sregp	    = spec_reg_info ((insn >> 12) & 15);	  /* Since we match four bits, we will give a value of 4-1 = 3	     in a match.  If there is a corresponding exact match of a	     special register in another pattern, it will get a value of	     4, which will be higher.  This should be correct in that an	     exact pattern would match better than a general pattern.	     Note that there is a reason for not returning zero; the	     pattern for "clear" is partly  matched in the bit-pattern	     (the two lower bits must be zero), while the bit-pattern	     for a move from a special register is matched in the	     register constraint.  */	  if (sregp != NULL)	    {	      retval += 3;	      break;	    }	  else	    return -1;	}      }  if (prefix_insn != NO_CRIS_PREFIX && ! prefix_ok)    return -1;  return retval;}/* Return the length of an instruction.  */static unsignedbytes_to_skip (insn, matchedp)     unsigned int insn;     const struct cris_opcode *matchedp;{  /* Each insn is a word plus "immediate" operands.  */  unsigned to_skip = 2;  const char *template = matchedp->args;  const char *s;  for (s = template; *s; s++)    if (*s == 's' && (insn & 0x400) && (insn & 15) == 15)      {	/* Immediate via [pc+], so we have to check the size of the	   operand.  */	int mode_size = 1 << ((insn >> 4) & (*template == 'z' ? 1 : 3));	if (matchedp->imm_oprnd_size == SIZE_FIX_32)	  to_skip += 4;	else if (matchedp->imm_oprnd_size == SIZE_SPEC_REG)	  {	    const struct cris_spec_reg *sregp	      = spec_reg_info ((insn >> 12) & 15);	    /* FIXME: Improve error handling; should have been caught	       earlier.  */	    if (sregp == NULL)	      return 2;	    /* PC is incremented by two, not one, for a byte.  */	    to_skip += (sregp->reg_size + 1) & ~1;	  }	else	  to_skip += (mode_size + 1) & ~1;      }    else if (*s == 'b')      to_skip += 2;  return to_skip;}/* Print condition code flags.  */static char *print_flags (insn, cp)     unsigned int insn;     char *cp;{  /* Use the v8 (Etrax 100) flag definitions for disassembly.     The differences with v0 (Etrax 1..4) vs. Svinto are:     v0 'd' <=> v8 'm'     v0 'e' <=> v8 'b'.  */  static const char fnames[] = "cvznxibm";  unsigned char flagbits = (((insn >> 8) & 0xf0) | (insn & 15));  int i;  for (i = 0; i < 8; i++)    if (flagbits & (1 << i))      *cp++ = fnames[i];  return cp;}/* Print out an insn with its operands, and update the info->insn_type   fields.  The prefix_opcodep and the rest hold a prefix insn that is   supposed to be output as an address mode.  */static voidprint_with_operands (opcodep, insn, buffer, addr, info, prefix_opcodep,		     prefix_insn, prefix_buffer, with_reg_prefix)     const struct cris_opcode *opcodep;     unsigned int insn;     unsigned char *buffer;     bfd_vma addr;     disassemble_info *info;     /* If a prefix insn was before this insn (and is supposed to be	output as an address), here is a description of it.  */     const struct cris_opcode *prefix_opcodep;     unsigned int prefix_insn;     unsigned char *prefix_buffer;     boolean with_reg_prefix;{  /* Get a buffer of somewhat reasonable size where we store     intermediate parts of the insn.  */  char temp[sizeof (".d [$r13=$r12-2147483648],$r10") * 2];  char *tp = temp;  static const char mode_char[] = "bwd?";  const char *s;  const char *cs;  /* Print out the name first thing we do.  */  (*info->fprintf_func) (info->stream, "%s", opcodep->name);  cs = opcodep->args;  s = cs;  /* Ignore any prefix indicator.  */  if (*s == 'p')    s++;  if (*s == 'm' || *s == 'M' || *s == 'z')    {      *tp++ = '.';      /* Get the size-letter.  */      *tp++ = *s == 'M'	? (insn & 0x8000 ? 'd'	   : insn & 0x4000 ? 'w' : 'b')	: mode_char[(insn >> 4) & (*s == 'z' ? 1 : 3)];      /* Ignore the size and the space character that follows.  */      s += 2;    }  /* Add a space if this isn't a long-branch, because for those will add     the condition part of the name later.  */  if (opcodep->match != (BRANCH_PC_LOW + BRANCH_INCR_HIGH * 256))    *tp++ = ' ';  /* Fill in the insn-type if deducible from the name (and there's no     better way).  */  if (opcodep->name[0] == 'j')    {      if (strncmp (opcodep->name, "jsr", 3) == 0)	/* It's "jsr" or "jsrc".  */	info->insn_type = dis_jsr;      else	/* Any other jump-type insn is considered a branch.  */	info->insn_type = dis_branch;    }  /* We might know some more fields right now.  */  info->branch_delay_insns = opcodep->delayed;  /* Handle operands.  */  for (; *s; s++)    {    switch (*s)      {      case ',':	*tp++ = *s;	break;      case '!':	/* Ignore at this point; used at earlier stages to avoid recognition	   if there's a prefixes at something that in other ways looks like	   a "pop".  */	break;      case 'B':	/* This was the prefix that made this a "push".  We've already	   handled it by recognizing it, so signal that the prefix is	   handled by setting it to NULL.  */	prefix_opcodep = NULL;	break;      case 'D':      case 'r':	tp = format_reg (insn & 15, tp, with_reg_prefix);	break;      case 'R':	tp = format_reg ((insn >> 12) & 15, tp, with_reg_prefix);	break;      case 'y':      case 'S':      case 's':	/* Any "normal" memory operand.  */	if ((insn & 0x400) && (insn & 15) == 15)	  {	    /* We're looking at [pc+], i.e. we need to output an immediate	       number, where the size can depend on different things.  */	    long number;	    int signedp	      = ((*cs == 'z' && (insn & 0x20))		 || opcodep->match == BDAP_QUICK_OPCODE);	    int nbytes;	    if (opcodep->imm_oprnd_size == SIZE_FIX_32)	      nbytes = 4;	    else if (opcodep->imm_oprnd_size == SIZE_SPEC_REG)	      {		const struct cris_spec_reg *sregp		  = spec_reg_info ((insn >> 12) & 15);		/* A NULL return should have been as a non-match earlier,		   so catch it as an internal error in the error-case		   below.  */		if (sregp == NULL)		  /* Whatever non-valid size.  */		  nbytes = 42;		else		  /* PC is always incremented by a multiple of two.  */		  nbytes = (sregp->reg_size + 1) & ~1;	      }	    else	      {		int mode_size = 1 << ((insn >> 4) & (*cs == 'z' ? 1 : 3));		if (mode_size == 1)		  nbytes = 2;		else		  nbytes = mode_size;	      }	    switch (nbytes)	      {	      case 1:		number = buffer[2];		if (signedp && number > 127)		  number -= 256;		break;	      case 2:		number = buffer[2] + buffer[3] * 256;		if (signedp && number > 32767)		  number -= 65536;		break;	      case 4:		number		  = buffer[2] + buffer[3] * 256 + buffer[4] * 65536		  + buffer[5] * 0x1000000;		break;	      default:		strcpy (tp, "bug");		tp += 3;		number = 42;	      }	    if ((*cs == 'z' && (insn & 0x20))		|| (opcodep->match == BDAP_QUICK_OPCODE		    && (nbytes <= 2 || buffer[1 + nbytes] == 0)))	      tp = format_dec (number, tp, signedp);	    else	      {		unsigned int highbyte = (number >> 24) & 0xff;		/* Either output this as an address or as a number.  If it's		   a dword with the same high-byte as the address of the		   insn, assume it's an address, and also if it's a non-zero		   non-0xff high-byte.  If this is a jsr or a jump, then		   it's definitely an address.  */		if (nbytes == 4		    && (highbyte == ((addr >> 24) & 0xff)			|| (highbyte != 0 && highbyte != 0xff)			|| info->insn_type == dis_branch			|| info->insn_type == dis_jsr))		  {		    /* Finish off and output previous formatted bytes.  */		    *tp = 0;		    tp = temp;		    if (temp[0])		      (*info->fprintf_func) (info->stream, "%s", temp);		    (*info->print_address_func) ((bfd_vma) number, info);		    info->target = number;		  }		else		  tp = format_hex (number, tp);	      }	  }	else	  {	    /* Not an immediate number.  Then this is a (possibly	       prefixed) memory operand.  */	    if (info->insn_type != dis_nonbranch)	      {		int mode_size		  = 1 << ((insn >> 4)			  & (opcodep->args[0] == 'z' ? 1 : 3));		int size;		info->insn_type = dis_dref;		info->flags |= CRIS_DIS_FLAG_MEMREF;		if (opcodep->imm_oprnd_size == SIZE_FIX_32)		  size = 4;		else if (opcodep->imm_oprnd_size == SIZE_SPEC_REG)		  {		    const struct cris_spec_reg *sregp		      = spec_reg_info ((insn >> 12) & 15);		    /* FIXME: Improve error handling; should have been caught		       earlier.  */		    if (sregp == NULL)		      size = 4;		    else		      size = sregp->reg_size;		  }		else		  size = mode_size;		info->data_size = size;	      }	    *tp++ = '[';	    if (prefix_opcodep		/* We don't match dip with a postincremented field		   as a side-effect address mode.  */		&& ((insn & 0x400) == 0		    || prefix_opcodep->match != DIP_OPCODE))	      {		if (insn & 0x400)		  {		    tp = format_reg (insn & 15, tp, with_reg_prefix);		    *tp++ = '=';		  }		/* We mainly ignore the prefix format string when the		   address-mode syntax is output.  */		switch (prefix_opcodep->match)		  {		  case DIP_OPCODE:		    /* It's [r], [r+] or [pc+].  */		    if ((prefix_insn & 0x400) && (prefix_insn & 15) == 15)		      {			/* It's [pc+].  This cannot possibly be anything			   but an address.  */			unsigned long number			  = prefix_buffer[2] + prefix_buffer[3] * 256			  + prefix_buffer[4] * 65536			  + prefix_buffer[5] * 0x1000000;			info->target = (bfd_vma) number;			/* Finish off and output previous formatted			   data.  */			*tp = 0;			tp = temp;			if (temp[0])			  (*info->fprintf_func) (info->stream, "%s", temp);			(*info->print_address_func) ((bfd_vma) number, info);		      }		    else		      {			/* For a memref in an address, we use target2.			   In this case, target is zero.  */			info->flags			  |= (CRIS_DIS_FLAG_MEM_TARGET2_IS_REG			      | CRIS_DIS_FLAG_MEM_TARGET2_MEM);			info->target2 = prefix_insn & 15;			*tp++ = '[';			tp = format_reg (prefix_insn & 15, tp,					 with_reg_prefix);			if (prefix_insn & 0x400)			  *tp++ = '+';			*tp++ = ']';		      }		    break;		  case BDAP_QUICK_OPCODE:		    {		      int number;		      number = prefix_buffer[0];		      if (number > 127)			number -= 256;		      /* Output "reg+num" or, if num < 0, "reg-num".  */		      tp = format_reg ((prefix_insn >> 12) & 15, tp,				       with_reg_prefix);		      if (number >= 0)			*tp++ = '+';		      tp = format_dec (number, tp, 1);		      info->flags |= CRIS_DIS_FLAG_MEM_TARGET_IS_REG;		      info->target = (prefix_insn >> 12) & 15;		      info->target2 = (bfd_vma) number;		      break;		    }		  case BIAP_OPCODE:		    /* Output "r+R.m".  */		    tp = format_reg (prefix_insn & 15, tp, with_reg_prefix);		    *tp++ = '+';		    tp = format_reg ((prefix_insn >> 12) & 15, tp,				     with_reg_prefix);		    *tp++ = '.';		    *tp++ = mode_char[(prefix_insn >> 4) & 3];		    info->flags		      |= (CRIS_DIS_FLAG_MEM_TARGET2_IS_REG			  | CRIS_DIS_FLAG_MEM_TARGET_IS_REG			  | ((prefix_insn & 0x8000)			     ? CRIS_DIS_FLAG_MEM_TARGET2_MULT4			     : ((prefix_insn & 0x8000)				? CRIS_DIS_FLAG_MEM_TARGET2_MULT2 : 0)));		    /* Is it the casejump?  It's a "adds.w [pc+r%d.w],pc".  */		    if (insn == 0xf83f && (prefix_insn & ~0xf000) == 0x55f)		      /* Then start interpreting data as offsets.  */		      case_offset_counter = no_of_case_offsets;		    break;		  case BDAP_INDIR_OPCODE:		    /* Output "r+s.m", or, if "s" is [pc+], "r+s" or		       "r-s".  */		    tp = format_reg ((prefix_insn >> 12) & 15, tp,				     with_reg_prefix);		    if ((prefix_insn & 0x400) && (prefix_insn & 15) == 15)		      {			long number;			unsigned int nbytes;			/* It's a value.  Get its size.  */			int mode_size = 1 << ((prefix_insn >> 4) & 3);			if (mode_size == 1)			  nbytes = 2;			else			  nbytes = mode_size;			switch (nbytes)			  {			  case 1:

⌨️ 快捷键说明

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