arc-opc.c

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

C
1,826
字号
  { "hi", 13, COND, 0 },  { "ls", 14, COND, 0 },  { "pnz", 15, COND, 0 },  /* Condition codes 16-31 reserved for extensions.  */  { "f", 1, FLAG, 0 },  { "nd", ARC_DELAY_NONE, DELAY, 0 },  { "d", ARC_DELAY_NORMAL, DELAY, 0 },  { "jd", ARC_DELAY_JUMP, DELAY, 0 },  { "b", 1, SIZE1, 0 },  { "b", 1, SIZE10, 0 },  { "b", 1, SIZE22, 0 },  { "w", 2, SIZE1, 0 },  { "w", 2, SIZE10, 0 },  { "w", 2, SIZE22, 0 },  { "x", 1, SIGN0, 0 },  { "x", 1, SIGN9, 0 },  { "a", 1, ADDRESS3, 0 },  { "a", 1, ADDRESS12, 0 },  { "a", 1, ADDRESS24, 0 },  { "di", 1, CACHEBYPASS5, 0 },  { "di", 1, CACHEBYPASS14, 0 },  { "di", 1, CACHEBYPASS26, 0 },};const int arc_suffixes_count =  sizeof (arc_suffixes) / sizeof (arc_suffixes[0]);/* Indexed by first letter of opcode.  Points to chain of opcodes with same   first letter.  */static struct arc_opcode *opcode_map[26 + 1];/* Indexed by insn code.  Points to chain of opcodes with same insn code.  */static struct arc_opcode *icode_map[32];/* Configuration flags.  *//* Various ARC_HAVE_XXX bits.  */static int cpu_type;/* Translate a bfd_mach_arc_xxx value to a ARC_MACH_XXX value.  */intarc_get_opcode_mach (bfd_mach, big_p)     int bfd_mach, big_p;{  static int mach_type_map[] =  {    ARC_MACH_5,    ARC_MACH_6,    ARC_MACH_7,    ARC_MACH_8  };  return mach_type_map[bfd_mach] | (big_p ? ARC_MACH_BIG : 0);}/* Initialize any tables that need it.   Must be called once at start up (or when first needed).   FLAGS is a set of bits that say what version of the cpu we have,   and in particular at least (one of) ARC_MACH_XXX.  */voidarc_opcode_init_tables (flags)     int flags;{  static int init_p = 0;  cpu_type = flags;  /* We may be intentionally called more than once (for example gdb will call     us each time the user switches cpu).  These tables only need to be init'd     once though.  */  if (!init_p)    {      register int i,n;      memset (arc_operand_map, 0, sizeof (arc_operand_map));      n = sizeof (arc_operands) / sizeof (arc_operands[0]);      for (i = 0; i < n; ++i)	arc_operand_map[arc_operands[i].fmt] = i;      memset (opcode_map, 0, sizeof (opcode_map));      memset (icode_map, 0, sizeof (icode_map));      /* Scan the table backwards so macros appear at the front.  */      for (i = arc_opcodes_count - 1; i >= 0; --i)	{	  int opcode_hash = ARC_HASH_OPCODE (arc_opcodes[i].syntax);	  int icode_hash = ARC_HASH_ICODE (arc_opcodes[i].value);	  arc_opcodes[i].next_asm = opcode_map[opcode_hash];	  opcode_map[opcode_hash] = &arc_opcodes[i];	  arc_opcodes[i].next_dis = icode_map[icode_hash];	  icode_map[icode_hash] = &arc_opcodes[i];	}      init_p = 1;    }}/* Return non-zero if OPCODE is supported on the specified cpu.   Cpu selection is made when calling `arc_opcode_init_tables'.  */intarc_opcode_supported (opcode)     const struct arc_opcode *opcode;{  if (ARC_OPCODE_CPU (opcode->flags) <= cpu_type)    return 1;  return 0;}/* Return the first insn in the chain for assembling INSN.  */const struct arc_opcode *arc_opcode_lookup_asm (insn)     const char *insn;{  return opcode_map[ARC_HASH_OPCODE (insn)];}/* Return the first insn in the chain for disassembling INSN.  */const struct arc_opcode *arc_opcode_lookup_dis (insn)     unsigned int insn;{  return icode_map[ARC_HASH_ICODE (insn)];}/* Nonzero if we've seen an 'f' suffix (in certain insns).  */static int flag_p;/* Nonzero if we've finished processing the 'f' suffix.  */static int flagshimm_handled_p;/* Nonzero if we've seen a 'a' suffix (address writeback).  */static int addrwb_p;/* Nonzero if we've seen a 'q' suffix (condition code).  */static int cond_p;/* Nonzero if we've inserted a nullify condition.  */static int nullify_p;/* The value of the a nullify condition we inserted.  */static int nullify;/* Nonzero if we've inserted jumpflags.  */static int jumpflags_p;/* Nonzero if we've inserted a shimm.  */static int shimm_p;/* The value of the shimm we inserted (each insn only gets one but it can   appear multiple times).  */static int shimm;/* Nonzero if we've inserted a limm (during assembly) or seen a limm   (during disassembly).  */static int limm_p;/* The value of the limm we inserted.  Each insn only gets one but it can   appear multiple times.  */static long limm;/* Insertion functions.  *//* Called by the assembler before parsing an instruction.  */voidarc_opcode_init_insert (){  int i;  for(i = 0; i < OPERANDS; i++)    ls_operand[i] = OP_NONE;  flag_p = 0;  flagshimm_handled_p = 0;  cond_p = 0;  addrwb_p = 0;  shimm_p = 0;  limm_p = 0;  jumpflags_p = 0;  nullify_p = 0;  nullify = 0; /* the default is important.  */}/* Called by the assembler to see if the insn has a limm operand.   Also called by the disassembler to see if the insn contains a limm.  */intarc_opcode_limm_p (limmp)     long *limmp;{  if (limmp)    *limmp = limm;  return limm_p;}/* Insert a value into a register field.   If REG is NULL, then this is actually a constant.   We must also handle auxiliary registers for lr/sr insns.  */static arc_insninsert_reg (insn, operand, mods, reg, value, errmsg)     arc_insn insn;     const struct arc_operand *operand;     int mods;     const struct arc_operand_value *reg;     long value;     const char **errmsg;{  static char buf[100];  enum operand op_type = OP_NONE;  if (reg == NULL)    {      /* We have a constant that also requires a value stored in a register	 field.  Handle these by updating the register field and saving the	 value for later handling by either %S (shimm) or %L (limm).  */      /* Try to use a shimm value before a limm one.  */      if (ARC_SHIMM_CONST_P (value)	  /* If we've seen a conditional suffix we have to use a limm.  */	  && !cond_p	  /* If we already have a shimm value that is different than ours	     we have to use a limm.  */	  && (!shimm_p || shimm == value))	{	  int marker;	  op_type = OP_SHIMM;	  /* forget about shimm as dest mlm.  */	  if ('a' != operand->fmt)	    {	      shimm_p = 1;	      shimm = value;	      flagshimm_handled_p = 1;	      marker = flag_p ? ARC_REG_SHIMM_UPDATE : ARC_REG_SHIMM;	    }	  else	    {	      /* don't request flag setting on shimm as dest.  */	      marker = ARC_REG_SHIMM;	    }	  insn |= marker << operand->shift;	  /* insn |= value & 511; - done later.  */	}      /* We have to use a limm.  If we've already seen one they must match.  */      else if (!limm_p || limm == value)	{	  op_type = OP_LIMM;	  limm_p = 1;	  limm = value;	  insn |= ARC_REG_LIMM << operand->shift;	  /* The constant is stored later.  */	}      else	{	  *errmsg = "unable to fit different valued constants into instruction";	}    }  else    {      /* We have to handle both normal and auxiliary registers.  */      if (reg->type == AUXREG)	{	  if (!(mods & ARC_MOD_AUXREG))	    *errmsg = "auxiliary register not allowed here";	  else	    {	      if ((insn & I(-1)) == I(2)) /* check for use validity.  */		{		  if (reg->flags & ARC_REGISTER_READONLY)		    *errmsg = "attempt to set readonly register";		}	      else		{		  if (reg->flags & ARC_REGISTER_WRITEONLY)		    *errmsg = "attempt to read writeonly register";		}	      insn |= ARC_REG_SHIMM << operand->shift;	      insn |= reg->value << arc_operands[reg->type].shift;	    }	}      else	{	  /* check for use validity.  */	  if ('a' == operand->fmt || ((insn & I(-1)) < I(2)))	    {	      if (reg->flags & ARC_REGISTER_READONLY)		*errmsg = "attempt to set readonly register";	    }	  if ('a' != operand->fmt)	    {	      if (reg->flags & ARC_REGISTER_WRITEONLY)		*errmsg = "attempt to read writeonly register";	    }	  /* We should never get an invalid register number here.  */	  if ((unsigned int) reg->value > 60)	    {	      sprintf (buf, "invalid register number `%d'", reg->value);	      *errmsg = buf;	    }	  insn |= reg->value << operand->shift;	  op_type = OP_REG;	}    }  switch (operand->fmt)    {    case 'a':      ls_operand[LS_DEST] = op_type;      break;    case 's':      ls_operand[LS_BASE] = op_type;      break;    case 'c':      if ((insn & I(-1)) == I(2))	ls_operand[LS_VALUE] = op_type;      else	ls_operand[LS_OFFSET] = op_type;      break;    case 'o': case 'O':      ls_operand[LS_OFFSET] = op_type;      break;    }  return insn;}/* Called when we see an 'f' flag.  */static arc_insninsert_flag (insn, operand, mods, reg, value, errmsg)     arc_insn insn;     const struct arc_operand *operand ATTRIBUTE_UNUSED;     int mods ATTRIBUTE_UNUSED;     const struct arc_operand_value *reg ATTRIBUTE_UNUSED;     long value ATTRIBUTE_UNUSED;     const char **errmsg ATTRIBUTE_UNUSED;{  /* We can't store anything in the insn until we've parsed the registers.     Just record the fact that we've got this flag.  `insert_reg' will use it     to store the correct value (ARC_REG_SHIMM_UPDATE or bit 0x100).  */  flag_p = 1;  return insn;}/* Called when we see an nullify condition.  */static arc_insninsert_nullify (insn, operand, mods, reg, value, errmsg)     arc_insn insn;     const struct arc_operand *operand;     int mods ATTRIBUTE_UNUSED;     const struct arc_operand_value *reg ATTRIBUTE_UNUSED;     long value;     const char **errmsg ATTRIBUTE_UNUSED;{  nullify_p = 1;  insn |= (value & ((1 << operand->bits) - 1)) << operand->shift;  nullify = value;  return insn;}/* Called after completely building an insn to ensure the 'f' flag gets set   properly.  This is needed because we don't know how to set this flag until   we've parsed the registers.  */static arc_insninsert_flagfinish (insn, operand, mods, reg, value, errmsg)     arc_insn insn;     const struct arc_operand *operand;     int mods ATTRIBUTE_UNUSED;     const struct arc_operand_value *reg ATTRIBUTE_UNUSED;     long value ATTRIBUTE_UNUSED;     const char **errmsg ATTRIBUTE_UNUSED;{  if (flag_p && !flagshimm_handled_p)    {      if (shimm_p)	abort ();      flagshimm_handled_p = 1;      insn |= (1 << operand->shift);    }  return insn;}/* Called when we see a conditional flag (eg: .eq).  */static arc_insninsert_cond (insn, operand, mods, reg, value, errmsg)     arc_insn insn;     const struct arc_operand *operand;     int mods ATTRIBUTE_UNUSED;     const struct arc_operand_value *reg ATTRIBUTE_UNUSED;     long value;     const char **errmsg ATTRIBUTE_UNUSED;{  cond_p = 1;  insn |= (value & ((1 << operand->bits) - 1)) << operand->shift;  return insn;}/* Used in the "j" instruction to prevent constants from being interpreted as   shimm values (which the jump insn doesn't accept).  This can also be used   to force the use of limm values in other situations (eg: ld r0,[foo] uses   this).   ??? The mechanism is sound.  Access to it is a bit klunky right now.  */static arc_insninsert_forcelimm (insn, operand, mods, reg, value, errmsg)     arc_insn insn;     const struct arc_operand *operand ATTRIBUTE_UNUSED;     int mods ATTRIBUTE_UNUSED;     const struct arc_operand_value *reg ATTRIBUTE_UNUSED;     long value ATTRIBUTE_UNUSED;     const char **errmsg ATTRIBUTE_UNUSED;{  cond_p = 1;  return insn;}static arc_insninsert_addr_wb (insn, operand, mods, reg, value, errmsg)     arc_insn insn;     const struct arc_operand *operand;     int mods ATTRIBUTE_UNUSED;     const struct arc_operand_value *reg ATTRIBUTE_UNUSED;     long value ATTRIBUTE_UNUSED;     const char **errmsg ATTRIBUTE_UNUSED;{  addrwb_p = 1 << operand->shift;  return insn;}static arc_insninsert_base (insn, operand, mods, reg, value, errmsg)     arc_insn insn;     const struct arc_operand *operand;     int mods;     const struct arc_operand_value *reg;     long value;     const char **errmsg;{  if (reg != NULL)

⌨️ 快捷键说明

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