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

📄 tc-d10v.c

📁 基于4个mips核的noc设计
💻 C
📖 第 1 页 / 共 3 页
字号:
{  int i, bits, shift, flags, format;  unsigned long number;  /* The insn argument is only used for the DIVS kludge.  */  if (insn)    format = LONG_R;  else    {      insn = opcode->opcode;      format = opcode->format;    }  for (i = 0; opcode->operands[i]; i++)    {      flags = d10v_operands[opcode->operands[i]].flags;      bits = d10v_operands[opcode->operands[i]].bits;      shift = d10v_operands[opcode->operands[i]].shift;      number = opers[i].X_add_number;      if (flags & OPERAND_REG)	{	  number &= REGISTER_MASK;	  if (format == LONG_L)	    shift += 15;	}      if (opers[i].X_op != O_register && opers[i].X_op != O_constant)	{	  /* Now create a fixup.  */	  if (fixups->fc >= MAX_INSN_FIXUPS)	    as_fatal (_("too many fixups"));	  if (AT_WORD_P (&opers[i]))	    {	      /* Reconize XXX>>1+N aka XXX@word+N as special (AT_WORD).  */	      fixups->fix[fixups->fc].reloc = BFD_RELOC_D10V_18;	      opers[i].X_op = O_symbol;	      opers[i].X_op_symbol = NULL; /* Should free it.  */	      /* number is left shifted by AT_WORD_RIGHT_SHIFT so                 that, it is aligned with the symbol's value.  Later,                 BFD_RELOC_D10V_18 will right shift (symbol_value +                 X_add_number).  */	      number <<= AT_WORD_RIGHT_SHIFT;	      opers[i].X_add_number = number;	    }	  else	    fixups->fix[fixups->fc].reloc =	      get_reloc ((struct d10v_operand *) &d10v_operands[opcode->operands[i]]);	  if (fixups->fix[fixups->fc].reloc == BFD_RELOC_16 ||	      fixups->fix[fixups->fc].reloc == BFD_RELOC_D10V_18)	    fixups->fix[fixups->fc].size = 2;	  else	    fixups->fix[fixups->fc].size = 4;	  fixups->fix[fixups->fc].exp = opers[i];	  fixups->fix[fixups->fc].operand = opcode->operands[i];	  fixups->fix[fixups->fc].pcrel =	    (flags & OPERAND_ADDR) ? true : false;	  (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);      number &= 0x7FFFFFFF >> (31 - bits);      insn = insn | (number << shift);    }  /* kludge: for DIVS, we need to put the operands in twice  */  /* on the second pass, format is changed to LONG_R to force     the second set of operands to not be shifted over 15.  */  if ((opcode->opcode == OPCODE_DIVS) && (format == LONG_L))    insn = build_insn (opcode, opers, insn);  return insn;}/* Write out a long form instruction.  */static voidwrite_long (insn, fx)     unsigned long insn;     Fixups *fx;{  int i, where;  char *f = frag_more (4);  insn |= FM11;  number_to_chars_bigendian (f, insn, 4);  for (i = 0; i < fx->fc; i++)    {      if (fx->fix[i].reloc)	{	  where = f - frag_now->fr_literal;	  if (fx->fix[i].size == 2)	    where += 2;	  if (fx->fix[i].reloc == BFD_RELOC_D10V_18)	    fx->fix[i].operand |= 4096;	  fix_new_exp (frag_now,		       where,		       fx->fix[i].size,		       &(fx->fix[i].exp),		       fx->fix[i].pcrel,		       fx->fix[i].operand|2048);	}    }  fx->fc = 0;}/* Write out a short form instruction by itself.  */static voidwrite_1_short (opcode, insn, fx)     struct d10v_opcode *opcode;     unsigned long insn;     Fixups *fx;{  char *f = frag_more (4);  int i, where;  if (opcode->exec_type & PARONLY)    as_fatal (_("Instruction must be executed in parallel with another instruction."));  /* The other container needs to be NOP.  */  /* According to 4.3.1: for FM=00, sub-instructions performed only     by IU cannot be encoded in L-container.  */  if (opcode->unit == IU)    insn |= FM00 | (NOP << 15);		/* Right container.  */  else    insn = FM00 | (insn << 15) | NOP;	/* Left container.  */  number_to_chars_bigendian (f, insn, 4);  for (i = 0; i < fx->fc; i++)    {      if (fx->fix[i].reloc)	{	  where = f - frag_now->fr_literal;	  if (fx->fix[i].size == 2)	    where += 2;	  if (fx->fix[i].reloc == BFD_RELOC_D10V_18)	    fx->fix[i].operand |= 4096;	  /* If it's an R reloc, we may have to switch it to L.  */	  if ((fx->fix[i].reloc == BFD_RELOC_D10V_10_PCREL_R)	      && (opcode->unit != IU))	    fx->fix[i].operand |= 1024;	  fix_new_exp (frag_now,		       where,		       fx->fix[i].size,		       &(fx->fix[i].exp),		       fx->fix[i].pcrel,		       fx->fix[i].operand|2048);	}    }  fx->fc = 0;}/* Expects two short instructions.   If possible, writes out both as a single packed instruction.   Otherwise, writes out the first one, packed with a NOP.   Returns number of instructions not written out.  */static intwrite_2_short (opcode1, insn1, opcode2, insn2, exec_type, fx)     struct d10v_opcode *opcode1, *opcode2;     unsigned long insn1, insn2;     packing_type exec_type;     Fixups *fx;{  unsigned long insn;  char *f;  int i, j, where;  if ((exec_type != PACK_PARALLEL)      && ((opcode1->exec_type & PARONLY) || (opcode2->exec_type & PARONLY)))    as_fatal (_("Instruction must be executed in parallel"));  if ((opcode1->format & LONG_OPCODE) || (opcode2->format & LONG_OPCODE))    as_fatal (_("Long instructions may not be combined."));  switch (exec_type)    {    case PACK_UNSPEC:	/* Order not specified.  */      if (opcode1->exec_type & ALONE)	{	  /* Case of a short branch on a separate GAS line.	     Pack with NOP.  */	  write_1_short (opcode1, insn1, fx->next);	  return 1;	}      if (Optimizing	  && parallel_ok (opcode1, insn1, opcode2, insn2, exec_type))	{	  /* Parallel.  */	  if (opcode1->unit == IU)	    insn = FM00 | (insn2 << 15) | insn1;	  else if (opcode2->unit == MU)	    insn = FM00 | (insn2 << 15) | insn1;	  else	    {	      insn = FM00 | (insn1 << 15) | insn2;	      /* Advance over dummy fixup since packed insn1 in L.  */	      fx = fx->next;	    }	}      else if (opcode1->unit == IU)	/* Reverse sequential with IU opcode1 on right and done first.  */	insn = FM10 | (insn2 << 15) | insn1;      else	{	  /* Sequential with non-IU opcode1 on left and done first.  */	  insn = FM01 | (insn1 << 15) | insn2;	  /* Advance over dummy fixup since packed insn1 in L.  */	  fx = fx->next;	}      break;    case PACK_PARALLEL:      if (opcode1->exec_type & SEQ || opcode2->exec_type & SEQ)	as_fatal	  (_("One of these instructions may not be executed in parallel."));      if (opcode1->unit == IU)	{	  if (opcode2->unit == IU)	    as_fatal (_("Two IU instructions may not be executed in parallel"));	  if (!flag_warn_suppress_instructionswap)	    as_warn (_("Swapping instruction order"));	  insn = FM00 | (insn2 << 15) | insn1;	}      else if (opcode2->unit == MU)	{	  if (opcode1->unit == MU)	    as_fatal (_("Two MU instructions may not be executed in parallel"));	  if (!flag_warn_suppress_instructionswap)	    as_warn (_("Swapping instruction order"));	  insn = FM00 | (insn2 << 15) | insn1;	}      else	{	  insn = FM00 | (insn1 << 15) | insn2;	  /* Advance over dummy fixup since packed insn1 in L.  */	  fx = fx->next;	}      break;    case PACK_LEFT_RIGHT:      if (opcode1->unit != IU)	insn = FM01 | (insn1 << 15) | insn2;      else if (opcode2->unit == MU || opcode2->unit == EITHER)	{	  if (!flag_warn_suppress_instructionswap)	    as_warn (_("Swapping instruction order"));	  insn = FM10 | (insn2 << 15) | insn1;	}      else	as_fatal (_("IU instruction may not be in the left container"));      if (opcode1->exec_type & ALONE)	as_warn (_("Instruction in R container is squashed by flow control instruction in L container."));      /* Advance over dummy fixup.  */      fx = fx->next;      break;    case PACK_RIGHT_LEFT:      if (opcode2->unit != MU)	insn = FM10 | (insn1 << 15) | insn2;      else if (opcode1->unit == IU || opcode1->unit == EITHER)	{	  if (!flag_warn_suppress_instructionswap)	    as_warn (_("Swapping instruction order"));	  insn = FM01 | (insn2 << 15) | insn1;	}      else	as_fatal (_("MU instruction may not be in the right container"));      if (opcode2->exec_type & ALONE)	as_warn (_("Instruction in R container is squashed by flow control instruction in L container."));      /* Advance over dummy fixup.  */      fx = fx->next;      break;    default:      as_fatal (_("unknown execution type passed to write_2_short()"));    }  f = frag_more (4);  number_to_chars_bigendian (f, insn, 4);  /* Process fixup chains.     Note that the packing code above advanced fx conditionally.     dlindsay@cygnus.com:  There's something subtle going on here involving	_dummy_first_bfd_reloc_code_real.  This is related to the	difference between BFD_RELOC_D10V_10_PCREL_R and _L, ie whether	a fixup is done in the L or R container.  A bug in this code	can pass Plum Hall fine, yet still affect hand-written assembler.  */  for (j = 0; j < 2; j++)    {      for (i = 0; i < fx->fc; i++)	{	  if (fx->fix[i].reloc)	    {	      where = f - frag_now->fr_literal;	      if (fx->fix[i].size == 2)		where += 2;	      if ((fx->fix[i].reloc == BFD_RELOC_D10V_10_PCREL_R) && (j == 0))		fx->fix[i].operand |= 1024;	      if (fx->fix[i].reloc == BFD_RELOC_D10V_18)		fx->fix[i].operand |= 4096;	      fix_new_exp (frag_now,			   where,			   fx->fix[i].size,			   &(fx->fix[i].exp),			   fx->fix[i].pcrel,			   fx->fix[i].operand|2048);	    }	}      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 d10v_opcode *op1, *op2;     unsigned long insn1, insn2;     packing_type exec_type;{  int i, j, flags, mask, shift, regno;  unsigned long ins, mod[2], used[2];  struct d10v_opcode *op;  if ((op1->exec_type & SEQ) != 0 || (op2->exec_type & SEQ) != 0      || (op1->exec_type & PAR) == 0 || (op2->exec_type & PAR) == 0      || (op1->unit == BOTH) || (op2->unit == BOTH)      || (op1->unit == IU && op2->unit == IU)      || (op1->unit == MU && op2->unit == MU))    return 0;  /* If this is auto parallization, and either instruction is a branch,     don't parallel.  */  if (exec_type == PACK_UNSPEC      && (op1->exec_type & ALONE || op2->exec_type & ALONE))    return 0;  /* The idea here is to create two sets of bitmasks (mod and used)     which indicate which registers are modified or used by each     instruction.  The operation can only be done in parallel if     instruction 1 and instruction 2 modify different registers, and     the first instruction does not modify registers that the second     is using (The second instruction can modify registers that the     first is using as they are only written back after the first     instruction has completed).  Accesses to control registers, PSW,     and memory are treated as accesses to a single register.  So if     both instructions write memory or if the first instruction writes     memory and the second reads, then they cannot be done in     parallel.  Likewise, if the first instruction mucks with the psw     and the second reads the PSW (which includes C, F0, and F1), then     they cannot operate safely in parallel.  */  /* The bitmasks (mod and used) look like this (bit 31 = MSB).  */  /* r0-r15	  0-15   */  /* a0-a1	  16-17  */  /* cr (not psw) 18     */  /* psw	  19     */  /* mem	  20     */  for (j = 0; j < 2; j++)    {      if (j == 0)	{	  op = op1;	  ins = insn1;	}      else	{	  op = op2;	  ins = insn2;	}      mod[j] = used[j] = 0;      if (op->exec_type & BRANCH_LINK)	mod[j] |= 1 << 13;      for (i = 0; op->operands[i]; i++)	{	  flags = d10v_operands[op->operands[i]].flags;	  shift = d10v_operands[op->operands[i]].shift;	  mask = 0x7FFFFFFF >> (31 - d10v_operands[op->operands[i]].bits);	  if (flags & OPERAND_REG)	    {	      regno = (ins >> shift) & mask;	      if (flags & (OPERAND_ACC0 | OPERAND_ACC1))		regno += 16;	      else if (flags & OPERAND_CONTROL)	/* mvtc or mvfc.  */		{		  if (regno == 0)		    regno = 19;		  else		    regno = 18;		}	      else if (flags & (OPERAND_FFLAG | OPERAND_CFLAG))		regno = 19;	      if (flags & OPERAND_DEST)		{		  mod[j] |= 1 << regno;		  if (flags & OPERAND_EVEN)		    mod[j] |= 1 << (regno + 1);		}	      else		{		  used[j] |= 1 << regno;		  if (flags & OPERAND_EVEN)		    used[j] |= 1 << (regno + 1);		  /* Auto inc/dec also modifies the register.  */		  if (op->operands[i + 1] != 0		      && (d10v_operands[op->operands[i + 1]].flags			  & (OPERAND_PLUS | OPERAND_MINUS)) != 0)		    mod[j] |= 1 << regno;		}	    }	  else if (flags & OPERAND_ATMINUS)	    {	      /* SP implicitly used/modified.  */	      mod[j] |= 1 << 15;	      used[j] |= 1 << 15;	    }	}      if (op->exec_type & RMEM)	used[j] |= 1 << 20;      else if (op->exec_type & WMEM)	mod[j] |= 1 << 20;      else if (op->exec_type & RF0)	used[j] |= 1 << 19;      else if (op->exec_type & WF0)	mod[j] |= 1 << 19;      else if (op->exec_type & WCAR)	mod[j] |= 1 << 19;    }  if ((mod[0] & mod[1]) == 0 && (mod[0] & used[1]) == 0)    return 1;  return 0;}/* This is the main entry point for the machine-dependent assembler.   STR points to a machine-dependent instruction.  This function is   supposed to emit the frags/bytes it assembles to.  For the D10V, it   mostly handles the special VLIW parsing and packing and leaves the   difficult stuff to do_assemble().  */static unsigned long prev_insn;static struct d10v_opcode *prev_opcode = 0;static subsegT prev_subseg;static segT prev_seg = 0;;voidmd_assemble (str)     char *str;{  /* etype is saved extype.  For multi-line instructions.  */  packing_type extype = PACK_UNSPEC;		/* Parallel, etc.  */  struct d10v_opcode *opcode;  unsigned long insn;  char *str2;  if (etype == PACK_UNSPEC)    {      /* Look for the special multiple instruction separators.  */      str2 = strstr (str, "||");      if (str2)	extype = PACK_PARALLEL;      else	{	  str2 = strstr (str, "->");	  if (str2)	    extype = PACK_LEFT_RIGHT;	  else	    {	      str2 = strstr (str, "<-");	      if (str2)		extype = PACK_RIGHT_LEFT;	    }	}      /* STR2 points to the separator, if there is one.  */      if (str2)	{	  *str2 = 0;	  /* If two instructions are present and we already have one saved,	     then first write out the saved one.  */	  d10v_cleanup ();	  /* Assemble first instruction and save it.  */	  prev_insn = do_assemble (str, &prev_opcode);	  prev_seg = now_seg;	  prev_subseg = now_subseg;	  if (prev_insn == (unsigned long) -1)	    as_fatal (_("can't find opcode "));	  fixups = fixups->next;	  str = str2 + 2;	}    }  insn = do_assemble (str, &opcode);  if (insn == (unsigned long) -1)    {      if (extype != PACK_UNSPEC)	{	  etype = extype;	  return;	}      as_fatal (_("can't find opcode "));    }  if (etype != PACK_UNSPEC)    {      extype = etype;      etype = PACK_UNSPEC;    }  /* If this is a long instruction, write it and any previous short     instruction.  */  if (opcode->format & LONG_OPCODE)    {      if (extype != PACK_UNSPEC)	as_fatal (_("Unable to mix instructions as specified"));      d10v_cleanup ();      write_long (insn, fixups);      prev_opcode = NULL;      return;    }  if (prev_opcode      && prev_seg      && ((prev_seg != now_seg) || (prev_subseg != now_subseg)))    d10v_cleanup ();  if (prev_opcode      && (write_2_short (prev_opcode, prev_insn, opcode, insn, extype, fixups) == 0))    {      /* No instructions saved.  */      prev_opcode = NULL;    }  else    {      if (extype != PACK_UNSPEC)	as_fatal (_("Unable to mix instructions as specified"));      /* Save last instruction so it may be packed on next pass.  */      prev_opcode = opcode;      prev_insn = insn;      prev_seg = now_seg;      prev_subseg = now_subseg;      fixups = fixups->next;    }}/* Assemble a single instruction.   Return an opcode, or -1 (an invalid opcode) on error.  */static unsigned longdo_assemble (str, opcode)     char *str;     struct d10v_opcode **opcode;{  unsigned char *op_start, *save;  unsigned char *op_end;  char name[20];  int nlen = 0;  expressionS myops[6];  unsigned long insn;  /* Drop leading whitespace.  */  while (*str == ' ')

⌨️ 快捷键说明

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