arc-opc.c

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

C
1,826
字号
    {      arc_insn myinsn;      myinsn = insert_reg (0, operand,mods, reg, value, errmsg) >> operand->shift;      insn |= B(myinsn);      ls_operand[LS_BASE] = OP_REG;    }  else if (ARC_SHIMM_CONST_P (value) && !cond_p)    {      if (shimm_p && value != shimm)	{	  /* convert the previous shimm operand to a limm.  */	  limm_p = 1;	  limm = shimm;	  insn &= ~C(-1); /* we know where the value is in insn.  */	  insn |= C(ARC_REG_LIMM);	  ls_operand[LS_VALUE] = OP_LIMM;	}      insn |= ARC_REG_SHIMM << operand->shift;      shimm_p = 1;      shimm = value;      ls_operand[LS_BASE] = OP_SHIMM;    }  else    {      if (limm_p && value != limm)	{	  *errmsg = "too many long constants";	  return insn;	}      limm_p = 1;      limm = value;      insn |= B(ARC_REG_LIMM);      ls_operand[LS_BASE] = OP_LIMM;    }  return insn;}/* Used in ld/st insns to handle the offset field. We don't try to   match operand syntax here. we catch bad combinations later.  */static arc_insninsert_offset (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;{  long minval, maxval;  if (reg != NULL)    {      arc_insn myinsn;      myinsn = insert_reg (0,operand,mods,reg,value,errmsg) >> operand->shift;      ls_operand[LS_OFFSET] = OP_REG;      if (operand->flags & ARC_OPERAND_LOAD) /* not if store, catch it later.  */	if ((insn & I(-1)) != I(1)) /* not if opcode == 1, catch it later.  */	  insn |= C(myinsn);    }  else    {      /* This is *way* more general than necessary, but maybe some day it'll	 be useful.  */      if (operand->flags & ARC_OPERAND_SIGNED)	{	  minval = -(1 << (operand->bits - 1));	  maxval = (1 << (operand->bits - 1)) - 1;	}      else	{	  minval = 0;	  maxval = (1 << operand->bits) - 1;	}      if ((cond_p && !limm_p) || (value < minval || value > maxval))	{	  if (limm_p && value != limm)	    {	      *errmsg = "too many long constants";	    }	  else	    {	      limm_p = 1;	      limm = value;	      if (operand->flags & ARC_OPERAND_STORE)		insn |= B(ARC_REG_LIMM);	      if (operand->flags & ARC_OPERAND_LOAD)		insn |= C(ARC_REG_LIMM);	      ls_operand[LS_OFFSET] = OP_LIMM;	    }	}      else	{	  if ((value < minval || value > maxval))	    *errmsg = "need too many limms";	  else if (shimm_p && value != shimm)	    {	      /* check for bad operand combinations before we lose info about them.  */	      if ((insn & I(-1)) == I(1))		{		  *errmsg = "to many shimms in load";		  goto out;		}	      if (limm_p && operand->flags & ARC_OPERAND_LOAD)		{		  *errmsg = "too many long constants";		  goto out;		}	      /* convert what we thought was a shimm to a limm.  */	      limm_p = 1;	      limm = shimm;	      if (ls_operand[LS_VALUE] == OP_SHIMM && operand->flags & ARC_OPERAND_STORE)		{		  insn &= ~C(-1);		  insn |= C(ARC_REG_LIMM);		  ls_operand[LS_VALUE] = OP_LIMM;		}	      if (ls_operand[LS_BASE] == OP_SHIMM && operand->flags & ARC_OPERAND_STORE)		{		  insn &= ~B(-1);		  insn |= B(ARC_REG_LIMM);		  ls_operand[LS_BASE] = OP_LIMM;		}	    }	  shimm = value;	  shimm_p = 1;	  ls_operand[LS_OFFSET] = OP_SHIMM;	}    } out:  return insn;}/* Used in st insns to do final disasemble syntax check.  */static longextract_st_syntax (insn, operand, mods, opval, invalid)     arc_insn *insn;     const struct arc_operand *operand ATTRIBUTE_UNUSED;     int mods ATTRIBUTE_UNUSED;     const struct arc_operand_value **opval ATTRIBUTE_UNUSED;     int *invalid;{#define ST_SYNTAX(V,B,O) \((ls_operand[LS_VALUE]  == (V) && \  ls_operand[LS_BASE]   == (B) && \  ls_operand[LS_OFFSET] == (O)))  if (!((ST_SYNTAX(OP_REG,OP_REG,OP_NONE) && (insn[0] & 511) == 0)	|| ST_SYNTAX(OP_REG,OP_LIMM,OP_NONE)	|| (ST_SYNTAX(OP_SHIMM,OP_REG,OP_NONE) && (insn[0] & 511) == 0)	|| (ST_SYNTAX(OP_SHIMM,OP_SHIMM,OP_NONE) && (insn[0] & 511) == 0)	|| ST_SYNTAX(OP_SHIMM,OP_LIMM,OP_NONE)	|| ST_SYNTAX(OP_SHIMM,OP_LIMM,OP_SHIMM)	|| ST_SYNTAX(OP_SHIMM,OP_SHIMM,OP_SHIMM)	|| (ST_SYNTAX(OP_LIMM,OP_REG,OP_NONE) && (insn[0] & 511) == 0)	|| ST_SYNTAX(OP_REG,OP_REG,OP_SHIMM)	|| ST_SYNTAX(OP_REG,OP_SHIMM,OP_SHIMM)	|| ST_SYNTAX(OP_SHIMM,OP_REG,OP_SHIMM)	|| ST_SYNTAX(OP_LIMM,OP_SHIMM,OP_SHIMM)	|| ST_SYNTAX(OP_LIMM,OP_SHIMM,OP_NONE)	|| ST_SYNTAX(OP_LIMM,OP_REG,OP_SHIMM)))    *invalid = 1;  return 0;}intarc_limm_fixup_adjust(insn)     arc_insn insn;{  int retval = 0;  /* check for st shimm,[limm].  */  if ((insn & (I(-1) | C(-1) | B(-1))) ==      (I(2) | C(ARC_REG_SHIMM) | B(ARC_REG_LIMM)))    {      retval = insn & 0x1ff;      if (retval & 0x100) /* sign extend 9 bit offset.  */	retval |= ~0x1ff;    }  return -retval; /* negate offset for return.  */}/* Used in st insns to do final syntax check.  */static arc_insninsert_st_syntax (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;{  if (ST_SYNTAX(OP_SHIMM,OP_REG,OP_NONE) && shimm != 0)    {      /* change an illegal insn into a legal one, it's easier to	 do it here than to try to handle it during operand scan.  */      limm_p = 1;      limm = shimm;      shimm_p = 0;      shimm = 0;      insn = insn & ~(C(-1) | 511);      insn |= ARC_REG_LIMM << ARC_SHIFT_REGC;      ls_operand[LS_VALUE] = OP_LIMM;    }  if (ST_SYNTAX(OP_REG,OP_SHIMM,OP_NONE) || ST_SYNTAX(OP_LIMM,OP_SHIMM,OP_NONE))    {      /* try to salvage this syntax.  */      if (shimm & 0x1) /* odd shimms won't work.  */	{	  if (limm_p) /* do we have a limm already?  */	    {	      *errmsg = "impossible store";	    }	  limm_p = 1;	  limm = shimm;	  shimm = 0;	  shimm_p = 0;	  insn = insn & ~(B(-1) | 511);	  insn |= B(ARC_REG_LIMM);	  ls_operand[LS_BASE] = OP_LIMM;	}      else	{	  shimm >>= 1;	  insn = insn & ~511;	  insn |= shimm;	  ls_operand[LS_OFFSET] = OP_SHIMM;	}    }  if (ST_SYNTAX(OP_SHIMM,OP_LIMM,OP_NONE))    {      limm += arc_limm_fixup_adjust(insn);    }  if (ST_SYNTAX(OP_LIMM,OP_SHIMM,OP_SHIMM) && (shimm * 2 == limm))    {      insn &= ~C(-1);      limm_p = 0;      limm = 0;      insn |= C(ARC_REG_SHIMM);      ls_operand[LS_VALUE] = OP_SHIMM;    }  if (!(ST_SYNTAX(OP_REG,OP_REG,OP_NONE)	|| ST_SYNTAX(OP_REG,OP_LIMM,OP_NONE)	|| ST_SYNTAX(OP_REG,OP_REG,OP_SHIMM)	|| ST_SYNTAX(OP_REG,OP_SHIMM,OP_SHIMM)	|| (ST_SYNTAX(OP_SHIMM,OP_SHIMM,OP_NONE) && (shimm == 0))	|| ST_SYNTAX(OP_SHIMM,OP_LIMM,OP_NONE)	|| ST_SYNTAX(OP_SHIMM,OP_REG,OP_NONE)	|| ST_SYNTAX(OP_SHIMM,OP_REG,OP_SHIMM)	|| ST_SYNTAX(OP_SHIMM,OP_SHIMM,OP_SHIMM)	|| ST_SYNTAX(OP_LIMM,OP_SHIMM,OP_SHIMM)	|| ST_SYNTAX(OP_LIMM,OP_REG,OP_NONE)	|| ST_SYNTAX(OP_LIMM,OP_REG,OP_SHIMM)))    *errmsg = "st operand error";  if (addrwb_p)    {      if (ls_operand[LS_BASE] != OP_REG)	*errmsg = "address writeback not allowed";      insn |= addrwb_p;    }  if (ST_SYNTAX(OP_SHIMM,OP_REG,OP_NONE) && shimm)    *errmsg = "store value must be zero";  return insn;}/* Used in ld insns to do final syntax check.  */static arc_insninsert_ld_syntax (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;{#define LD_SYNTAX(D,B,O) \((ls_operand[LS_DEST]  == (D) && \  ls_operand[LS_BASE]   == (B) && \  ls_operand[LS_OFFSET] == (O)))  int test = insn & I(-1);  if (!(test == I(1)))    {      if ((ls_operand[LS_DEST] == OP_SHIMM || ls_operand[LS_BASE] == OP_SHIMM	   || ls_operand[LS_OFFSET] == OP_SHIMM))	*errmsg = "invalid load/shimm insn";    }  if (!(LD_SYNTAX(OP_REG,OP_REG,OP_NONE)	|| LD_SYNTAX(OP_REG,OP_REG,OP_REG)	|| LD_SYNTAX(OP_REG,OP_REG,OP_SHIMM)	|| (LD_SYNTAX(OP_REG,OP_LIMM,OP_REG) && !(test == I(1)))	|| (LD_SYNTAX(OP_REG,OP_REG,OP_LIMM) && !(test == I(1)))	|| LD_SYNTAX(OP_REG,OP_SHIMM,OP_SHIMM)	|| (LD_SYNTAX(OP_REG,OP_LIMM,OP_NONE) && (test == I(1)))))    *errmsg = "ld operand error";  if (addrwb_p)    {      if (ls_operand[LS_BASE] != OP_REG)	*errmsg = "address writeback not allowed";      insn |= addrwb_p;    }  return insn;}/* Used in ld insns to do final syntax check.  */static longextract_ld_syntax (insn, operand, mods, opval, invalid)     arc_insn *insn;     const struct arc_operand *operand ATTRIBUTE_UNUSED;     int mods ATTRIBUTE_UNUSED;     const struct arc_operand_value **opval ATTRIBUTE_UNUSED;     int *invalid;{  int test = insn[0] & I(-1);  if (!(test == I(1)))    {      if ((ls_operand[LS_DEST] == OP_SHIMM || ls_operand[LS_BASE] == OP_SHIMM	   || ls_operand[LS_OFFSET] == OP_SHIMM))	*invalid = 1;    }  if (!((LD_SYNTAX(OP_REG,OP_REG,OP_NONE) && (test == I(1)))	|| LD_SYNTAX(OP_REG,OP_REG,OP_REG)	|| LD_SYNTAX(OP_REG,OP_REG,OP_SHIMM)	|| (LD_SYNTAX(OP_REG,OP_REG,OP_LIMM) && !(test == I(1)))	|| (LD_SYNTAX(OP_REG,OP_LIMM,OP_REG) && !(test == I(1)))	|| (LD_SYNTAX(OP_REG,OP_SHIMM,OP_NONE) && (shimm == 0))	|| LD_SYNTAX(OP_REG,OP_SHIMM,OP_SHIMM)	|| (LD_SYNTAX(OP_REG,OP_LIMM,OP_NONE) && (test == I(1)))))    *invalid = 1;  return 0;}/* Called at the end of processing normal insns (eg: add) to insert a shimm   value (if present) into the insn.  */static arc_insninsert_shimmfinish (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 (shimm_p)    insn |= (shimm & ((1 << operand->bits) - 1)) << operand->shift;  return insn;}/* Called at the end of processing normal insns (eg: add) to insert a limm   value (if present) into the insn.   Note that this function is only intended to handle instructions (with 4 byte   immediate operands).  It is not intended to handle data.  *//* ??? Actually, there's nothing for us to do as we can't call frag_more, the   caller must do that.  The extract fns take a pointer to two words.  The   insert fns could be converted and then we could do something useful, but   then the reloc handlers would have to know to work on the second word of   a 2 word quantity.  That's too much so we don't handle them.  */static arc_insninsert_limmfinish (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;{#if 0  if (limm_p)    ; /* nothing to do, gas does it.  */#endif  return insn;}static arc_insninsert_jumpflags (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;{  if (!flag_p)    {      *errmsg = "jump flags, but no .f seen";    }  if (!limm_p)    {      *errmsg = "jump flags, but no limm addr";    }  if (limm & 0xfc000000)    {      *errmsg = "flag bits of jump address limm lost";    }  if (limm & 0x03000000)    {      *errmsg = "attempt to set HR bits";    }  if ((value & ((1 << operand->bits) - 1)) != value)    {      *errmsg = "bad jump flags value";    }  jumpflags_p = 1;  limm = ((limm & ((1 << operand->shift) - 1))	  | ((value & ((1 << operand->bits) - 1)) << operand->shift));  return insn;}/* Called at the end of unary operand macros to copy the B field to C.  */static arc_insninsert_unopmacro (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;{  insn |= ((insn >> ARC_SHIFT_REGB) & ARC_MASK_REG) << operand->shift;  return insn;}/* Insert a relative address for a branch insn (b, bl, or lp).  */static arc_insninsert_reladdr (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;{  if (value & 3)    *errmsg = "branch address not on 4 byte boundary";  insn |= ((value >> 2) & ((1 << operand->bits) - 1)) << operand->shift;  return insn;}/* Insert a limm value as a 26 bit address right shifted 2 into the insn.   Note that this function is only intended to handle instructions (with 4 byte   immediate operands).  It is not intended to handle data.  */

⌨️ 快捷键说明

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