⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tc-d30v.c

📁 基于4个mips核的noc设计
💻 C
📖 第 1 页 / 共 4 页
字号:
      post = 0;    }  exp[numops].X_op = 0;  return numops;}/* Generate the instruction.   It does everything but write the FM bits.  */static long longbuild_insn (opcode, opers)     struct d30v_insn *opcode;     expressionS *opers;{  int i, length, bits, shift, flags;  unsigned long number, id = 0;  long long insn;  struct d30v_opcode *op = opcode->op;  struct d30v_format *form = opcode->form;  insn =    opcode->ecc << 28 | op->op1 << 25 | op->op2 << 20 | form->modifier << 18;  for (i = 0; form->operands[i]; i++)    {      flags = d30v_operand_table[form->operands[i]].flags;      /* Must be a register or number.  */      if (!(flags & OPERAND_REG) && !(flags & OPERAND_NUM)	  && !(flags & OPERAND_NAME) && !(flags & OPERAND_SPECIAL))	continue;      bits = d30v_operand_table[form->operands[i]].bits;      if (flags & OPERAND_SHIFT)	bits += 3;      length = d30v_operand_table[form->operands[i]].length;      shift = 12 - d30v_operand_table[form->operands[i]].position;      if (opers[i].X_op != O_symbol)	number = opers[i].X_add_number;      else	number = 0;      if (flags & OPERAND_REG)	{	  /* Check for mvfsys or mvtsys control registers.  */	  if (flags & OPERAND_CONTROL && (number & 0x7f) > MAX_CONTROL_REG)	    {	      /* PSWL or PSWH.  */	      id = (number & 0x7f) - MAX_CONTROL_REG;	      number = 0;	    }	  else if (number & OPERAND_FLAG)	    {	      /* NUMBER is a flag register.  */	      id = 3;	    }	  number &= 0x7F;	}      else if (flags & OPERAND_SPECIAL)	{	  number = id;	}      if (opers[i].X_op != O_register && opers[i].X_op != O_constant	  && !(flags & OPERAND_NAME))	{	  /* Now create a fixup.  */	  if (fixups->fc >= MAX_INSN_FIXUPS)	    as_fatal (_("too many fixups"));	  fixups->fix[fixups->fc].reloc =	    get_reloc ((struct d30v_operand *) &d30v_operand_table[form->operands[i]], op->reloc_flag);	  fixups->fix[fixups->fc].size = 4;	  fixups->fix[fixups->fc].exp = opers[i];	  fixups->fix[fixups->fc].operand = form->operands[i];	  if (fixups->fix[fixups->fc].reloc == BFD_RELOC_D30V_9_PCREL)	    fixups->fix[fixups->fc].pcrel = RELOC_PCREL;	  else	    fixups->fix[fixups->fc].pcrel = op->reloc_flag;	  (fixups->fc)++;	}      /* Truncate to the proper number of bits.  */      if ((opers[i].X_op == O_constant) && check_range (number, bits, flags))	as_bad (_("operand out of range: %d"), number);      if (bits < 31)	number &= 0x7FFFFFFF >> (31 - bits);      if (flags & OPERAND_SHIFT)	number >>= 3;      if (bits == 32)	{	  /* It's a LONG instruction.  */	  insn |= ((number & 0xffffffff) >> 26);	/* top 6 bits */	  insn <<= 32;			/* shift the first word over */	  insn |= ((number & 0x03FC0000) << 2);		/* next 8 bits */	  insn |= number & 0x0003FFFF;			/* bottom 18 bits */	}      else	insn |= number << shift;    }  return insn;}/* Write out a long form instruction.  */static voidwrite_long (opcode, insn, fx)     struct d30v_insn *opcode;     long long insn;     Fixups *fx;{  int i, where;  char *f = frag_more (8);  insn |= FM11;  d30v_number_to_chars (f, insn, 8);  for (i = 0; i < fx->fc; i++)    {      if (fx->fix[i].reloc)	{	  where = f - frag_now->fr_literal;	  fix_new_exp (frag_now,		       where,		       fx->fix[i].size,		       &(fx->fix[i].exp),		       fx->fix[i].pcrel,		       fx->fix[i].reloc);	}    }  fx->fc = 0;}/* Write out a short form instruction by itself.  */static voidwrite_1_short (opcode, insn, fx, use_sequential)     struct d30v_insn *opcode;     long long insn;     Fixups *fx;     int use_sequential;{  char *f = frag_more (8);  int i, where;  if (warn_nops == NOP_ALL)    as_warn (_("%s NOP inserted"), use_sequential ?	     _("sequential") : _("parallel"));  /* The other container needs to be NOP.  */  if (use_sequential)    {      /* Use a sequential NOP rather than a parallel one,	 as the current instruction is a FLAG_MUL32 type one	 and the next instruction is a load.  */      /* According to 4.3.1: for FM=01, sub-instructions performed	 only by IU cannot be encoded in L-container.  */      if (opcode->op->unit == IU)	/* Right then left.  */	insn |= FM10 | NOP_LEFT;      else	/* Left then right.  */	insn = FM01 | (insn << 32) | NOP_RIGHT;    }  else    {      /* According to 4.3.1: for FM=00, sub-instructions performed	 only by IU cannot be encoded in L-container.  */      if (opcode->op->unit == IU)	/* Right container.  */	insn |= FM00 | NOP_LEFT;      else	/* Left container.  */	insn = FM00 | (insn << 32) | NOP_RIGHT;    }  d30v_number_to_chars (f, insn, 8);  for (i = 0; i < fx->fc; i++)    {      if (fx->fix[i].reloc)	{	  where = f - frag_now->fr_literal;	  fix_new_exp (frag_now,		       where,		       fx->fix[i].size,		       &(fx->fix[i].exp),		       fx->fix[i].pcrel,		       fx->fix[i].reloc);	}    }  fx->fc = 0;}/* Write out a short form instruction if possible.   Return number of instructions not written out.  */static intwrite_2_short (opcode1, insn1, opcode2, insn2, exec_type, fx)     struct d30v_insn *opcode1, *opcode2;     long long insn1, insn2;     exec_type_enum exec_type;     Fixups *fx;{  long long insn = NOP2;  char *f;  int i, j, where;  if (exec_type == EXEC_SEQ      && (opcode1->op->flags_used & (FLAG_JMP | FLAG_JSR))      && ((opcode1->op->flags_used & FLAG_DELAY) == 0)      && ((opcode1->ecc == ECC_AL) || ! Optimizing))    {      /* Unconditional, non-delayed branches kill instructions in	 the right bin.  Conditional branches don't always but if	 we are not optimizing, then we have been asked to produce	 an error about such constructs.  For the purposes of this	 test, subroutine calls are considered to be branches.  */      write_1_short (opcode1, insn1, fx->next, false);      return 1;    }  /* Note: we do not have to worry about subroutine calls occuring     in the right hand container.  The return address is always     aligned to the next 64 bit boundary, be that 64 or 32 bit away.  */  switch (exec_type)    {    case EXEC_UNKNOWN:	/* Order not specified.  */      if (Optimizing	  && parallel_ok (opcode1, insn1, opcode2, insn2, exec_type)	  && ! (   (opcode1->op->unit == EITHER_BUT_PREFER_MU		 || opcode1->op->unit == MU)		&&		(   opcode2->op->unit == EITHER_BUT_PREFER_MU		 || opcode2->op->unit == MU)))	{	  /* Parallel.  */	  exec_type = EXEC_PARALLEL;	  if (opcode1->op->unit == IU	      || opcode2->op->unit == MU	      || opcode2->op->unit == EITHER_BUT_PREFER_MU)	    insn = FM00 | (insn2 << 32) | insn1;	  else	    {	      insn = FM00 | (insn1 << 32) | insn2;	      fx = fx->next;	    }	}      else if ((opcode1->op->flags_used & (FLAG_JMP | FLAG_JSR)		&& ((opcode1->op->flags_used & FLAG_DELAY) == 0))	       || opcode1->op->flags_used & FLAG_RP)	{	  /* We must emit (non-delayed) branch type instructions	     on their own with nothing in the right container.  */	  /* We must treat repeat instructions likewise, since the	     following instruction has to be separate from the repeat	     in order to be repeated.  */	  write_1_short (opcode1, insn1, fx->next, false);	  return 1;	}      else if (prev_left_kills_right_p)	{	  /* The left instruction kils the right slot, so we	     must leave it empty.  */	  write_1_short (opcode1, insn1, fx->next, false);	  return 1;	}      else if (opcode1->op->unit == IU)	{	  if (opcode2->op->unit == EITHER_BUT_PREFER_MU)	    {	      /* Case 103810 is a request from Mitsubishi that opcodes		 with EITHER_BUT_PREFER_MU should not be executed in		 reverse sequential order.  */	      write_1_short (opcode1, insn1, fx->next, false);	      return 1;	    }	  /* Reverse sequential.  */	  insn = FM10 | (insn2 << 32) | insn1;	  exec_type = EXEC_REVSEQ;	}      else	{	  /* Sequential.  */	  insn = FM01 | (insn1 << 32) | insn2;	  fx = fx->next;	  exec_type = EXEC_SEQ;	}      break;    case EXEC_PARALLEL:	/* Parallel.  */      flag_explicitly_parallel = flag_xp_state;      if (! parallel_ok (opcode1, insn1, opcode2, insn2, exec_type))	as_bad (_("Instructions may not be executed in parallel"));      else if (opcode1->op->unit == IU)	{	  if (opcode2->op->unit == IU)	    as_bad (_("Two IU instructions may not be executed in parallel"));	  as_warn (_("Swapping instruction order"));	  insn = FM00 | (insn2 << 32) | insn1;	}      else if (opcode2->op->unit == MU)	{	  if (opcode1->op->unit == MU)	    as_bad (_("Two MU instructions may not be executed in parallel"));	  else if (opcode1->op->unit == EITHER_BUT_PREFER_MU)	    as_warn (_("Executing %s in IU may not work"), opcode1->op->name);	  as_warn (_("Swapping instruction order"));	  insn = FM00 | (insn2 << 32) | insn1;	}      else	{	  if (opcode2->op->unit == EITHER_BUT_PREFER_MU)	    as_warn (_("Executing %s in IU may not work in parallel execution"),		     opcode2->op->name);	  insn = FM00 | (insn1 << 32) | insn2;	  fx = fx->next;	}      flag_explicitly_parallel = 0;      break;    case EXEC_SEQ:	/* Sequential.  */      if (opcode1->op->unit == IU)	as_bad (_("IU instruction may not be in the left container"));      if (prev_left_kills_right_p)	as_bad (_("special left instruction `%s' kills instruction "		  "`%s' in right container"),		opcode1->op->name, opcode2->op->name);      insn = FM01 | (insn1 << 32) | insn2;      fx = fx->next;      break;    case EXEC_REVSEQ:	/* Reverse sequential.  */      if (opcode2->op->unit == MU)	as_bad (_("MU instruction may not be in the right container"));      if (opcode1->op->unit == EITHER_BUT_PREFER_MU)	as_warn (_("Executing %s in reverse serial with %s may not work"),		 opcode1->op->name, opcode2->op->name);      else if (opcode2->op->unit == EITHER_BUT_PREFER_MU)	as_warn (_("Executing %s in IU in reverse serial may not work"),		 opcode2->op->name);      insn = FM10 | (insn1 << 32) | insn2;      fx = fx->next;      break;    default:      as_fatal (_("unknown execution type passed to write_2_short()"));    }#if 0  printf ("writing out %llx\n", insn);#endif  f = frag_more (8);  d30v_number_to_chars (f, insn, 8);  /* If the previous instruction was a 32-bit multiply but it is put into a     parallel container, mark the current instruction as being a 32-bit     multiply.  */  if (prev_mul32_p && exec_type == EXEC_PARALLEL)    cur_mul32_p = 1;  for (j = 0; j < 2; j++)    {      for (i = 0; i < fx->fc; i++)	{	  if (fx->fix[i].reloc)	    {	      where = (f - frag_now->fr_literal) + 4 * j;	      fix_new_exp (frag_now,			   where,			   fx->fix[i].size,			   &(fx->fix[i].exp),			   fx->fix[i].pcrel,			   fx->fix[i].reloc);	    }	}      fx->fc = 0;      fx = fx->next;    }  return 0;}/* Check 2 instructions and determine if they can be safely   executed in parallel.  Return 1 if they can be.  */static intparallel_ok (op1, insn1, op2, insn2, exec_type)     struct d30v_insn *op1, *op2;     unsigned long insn1, insn2;     exec_type_enum exec_type;{  int i, j, shift, regno, bits, ecc;  unsigned long flags, mask, flags_set1, flags_set2, flags_used1, flags_used2;  unsigned long ins, mod_reg[2][3], used_reg[2][3], flag_reg[2];  struct d30v_format *f;  struct d30v_opcode *op;  /* Section 4.3: Both instructions must not be IU or MU only.  */  if ((op1->op->unit == IU && op2->op->unit == IU)      || (op1->op->unit == MU && op2->op->unit == MU))    return 0;  /* First instruction must not be a jump to safely optimize, unless this     is an explicit parallel operation.  */  if (exec_type != EXEC_PARALLEL      && (op1->op->flags_used & (FLAG_JMP | FLAG_JSR)))    return 0;  /* If one instruction is /TX or /XT and the other is /FX or /XF respectively,     then it is safe to allow the two to be done as parallel ops, since only     one will ever be executed at a time.  */  if ((op1->ecc == ECC_TX && op2->ecc == ECC_FX)      || (op1->ecc == ECC_FX && op2->ecc == ECC_TX)      || (op1->ecc == ECC_XT && op2->ecc == ECC_XF)      || (op1->ecc == ECC_XF && op2->ecc == ECC_XT))    return 1;  /* [0] r0-r31     [1] r32-r63     [2] a0, a1, flag registers.  */  for (j = 0; j < 2; j++)    {      if (j == 0)	{	  f = op1->form;	  op = op1->op;	  ecc = op1->ecc;	  ins = insn1;	}      else	{	  f = op2->form;	  op = op2->op;	  ecc = op2->ecc;	  ins = insn2;	}      flag_reg[j] = 0;      mod_reg[j][0] = mod_reg[j][1] = 0;      used_reg[j][0] = used_reg[j][1] = 0;      if (flag_explicitly_parallel)	{	  /* For human specified parallel instructions we have been asked	     to ignore the possibility that both instructions could modify	     bits in the PSW, so we initialise the mod & used arrays to 0.	     We have been asked, however, to refuse to allow parallel	     instructions which explicitly set the same flag register,	     eg "cmpne f0,r1,0x10 || cmpeq f0, r5, 0x2", so further on we test	     for the use of a flag register and set a bit in the mod or used	     array appropriately.  */	  mod_reg[j][2]  = 0;	  used_reg[j][2] = 0;	}      else	{	  mod_reg[j][2] = (op->flags_set & FLAG_ALL);	  used_reg[j][2] = (op->flags_used & FLAG_ALL);	}      /* BSR/JSR always sets R62.  */      if (op->flags_used & FLAG_JSR)	mod_reg[j][1] = (1L << (62 - 32));      /* Conditional execution affects the flags_used.  */      switch (ecc)	{	case ECC_TX:	case ECC_FX:	  used_reg[j][2] |= flag_reg[j] = FLAG_0;	  break;	case ECC_XT:	case ECC_XF:	  used_reg[j][2] |= flag_reg[j] = FLAG_1;	  break;	case ECC_TT:	case ECC_TF:	  used_reg[j][2] |= flag_reg[j] = (FLAG_0 | FLAG_1);	  break;	}      for (i = 0; f->operands[i]; i++)	{	  flags = d30v_operand_table[f->operands[i]].flags;	  shift = 12 - d30v_operand_table[f->operands[i]].position;	  bits = d30v_operand_table[f->operands[i]].bits;	  if (bits == 32)	    mask = 0xffffffff;	  else	    mask = 0x7FFFFFFF >> (31 - bits);	  if ((flags & OPERAND_PLUS) || (flags & OPERAND_MINUS))	    {	      /* This is a post-increment or post-decrement.		 The previous register needs to be marked as modified.  */	      shift = 12 - d30v_operand_table[f->operands[i - 1]].position;	      regno = (ins >> shift) & 0x3f;	      if (regno >= 32)		mod_reg[j][1] |= 1L << (regno - 32);	      else		mod_reg[j][0] |= 1L << regno;	    }	  else if (flags & OPERAND_REG)	    {	      regno = (ins >> shift) & mask;	      /* The memory write functions don't have a destination                 register.  */	      if ((flags & OPERAND_DEST) && !(op->flags_set & FLAG_MEM))		{		  /* MODIFIED registers and flags.  */		  if (flags & OPERAND_ACC)		    {		      if (regno == 0)			mod_reg[j][2] |= FLAG_A0;		      else if (regno == 1)			mod_reg[j][2] |= FLAG_A1;		      else			abort ();		    }		  else if (flags & OPERAND_FLAG)		    mod_reg[j][2] |= 1L << regno;		  else if (!(flags & OPERAND_CONTROL))		    {		      int r, z;		      /* Need to check if there are two destination			 registers, for example ld2w.  */		      if (flags & OPERAND_2REG)			z = 1;		      else			z = 0;		      for (r = regno; r <= regno + z; r++)			{			  if (r >= 32)			    mod_reg[j][1] |= 1L << (r - 32);			  else			    mod_reg[j][0] |= 1L << r;			}		    }		}	      else		{		  /* USED, but not modified registers and flags.  */		  if (flags & OPERAND_ACC)		    {		      if (regno == 0)			used_reg[j][2] |= FLAG_A0;		      else if (regno == 1)			used_reg[j][2] |= FLAG_A1;		      else			abort ();		    }

⌨️ 快捷键说明

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