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

📄 tc-d30v.c

📁 基于4个mips核的noc设计
💻 C
📖 第 1 页 / 共 4 页
字号:
		  else if (flags & OPERAND_FLAG)		    used_reg[j][2] |= 1L << regno;		  else if (!(flags & OPERAND_CONTROL))		    {		      int r, z;		      /* Need to check if there are two source			 registers, for example st2w.  */		      if (flags & OPERAND_2REG)			z = 1;		      else			z = 0;		      for (r = regno; r <= regno + z; r++)			{			  if (r >= 32)			    used_reg[j][1] |= 1L << (r - 32);			  else			    used_reg[j][0] |= 1L << r;			}		    }		}	    }	}    }  flags_set1 = op1->op->flags_set;  flags_set2 = op2->op->flags_set;  flags_used1 = op1->op->flags_used;  flags_used2 = op2->op->flags_used;  /* Check for illegal combinations with ADDppp/SUBppp.  */  if (((flags_set1 & FLAG_NOT_WITH_ADDSUBppp) != 0       && (flags_used2 & FLAG_ADDSUBppp) != 0)      || ((flags_set2 & FLAG_NOT_WITH_ADDSUBppp) != 0	  && (flags_used1 & FLAG_ADDSUBppp) != 0))    return 0;  /* Load instruction combined with half-word multiply is illegal.  */  if (((flags_used1 & FLAG_MEM) != 0 && (flags_used2 & FLAG_MUL16))      || ((flags_used2 & FLAG_MEM) != 0 && (flags_used1 & FLAG_MUL16)))    return 0;  /* Specifically allow add || add by removing carry, overflow bits dependency.     This is safe, even if an addc follows since the IU takes the argument in     the right container, and it writes its results last.     However, don't paralellize add followed by addc or sub followed by     subb.  */  if (mod_reg[0][2] == FLAG_CVVA && mod_reg[1][2] == FLAG_CVVA      && (used_reg[0][2] & ~flag_reg[0]) == 0      && (used_reg[1][2] & ~flag_reg[1]) == 0      && op1->op->unit == EITHER && op2->op->unit == EITHER)    {      mod_reg[0][2] = mod_reg[1][2] = 0;    }  for (j = 0; j < 3; j++)    {      /* If the second instruction depends on the first, we obviously	 cannot parallelize.  Note, the mod flag implies use, so	 check that as well.  */      /* If flag_explicitly_parallel is set, then the case of the	 second instruction using a register the first instruction	 modifies is assumed to be okay; we trust the human.  We	 don't trust the human if both instructions modify the same	 register but we do trust the human if they modify the same	 flags.  */      /* We have now been requested not to trust the human if the	 instructions modify the same flag registers either.  */      if (flag_explicitly_parallel)	{	  if ((mod_reg[0][j] & mod_reg[1][j]) != 0)	    return 0;	}      else        if ((mod_reg[0][j] & (mod_reg[1][j] | used_reg[1][j])) != 0)	  return 0;    }  return 1;}/* 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 D30V, it   mostly handles the special VLIW parsing and packing and leaves the   difficult stuff to do_assemble ().  */static long long prev_insn = -1;static struct d30v_insn prev_opcode;static subsegT prev_subseg;static segT prev_seg = 0;voidmd_assemble (str)     char *str;{  struct d30v_insn opcode;  long long insn;  /* Execution type; parallel, etc.  */  exec_type_enum extype = EXEC_UNKNOWN;  /* Saved extype.  Used for multiline instructions.  */  static exec_type_enum etype = EXEC_UNKNOWN;  char *str2;  if ((prev_insn != -1) && prev_seg      && ((prev_seg != now_seg) || (prev_subseg != now_subseg)))    d30v_cleanup (false);  if (d30v_current_align < 3)    d30v_align (3, NULL, d30v_last_label);  else if (d30v_current_align > 3)    d30v_current_align = 3;  d30v_last_label = NULL;  flag_explicitly_parallel = 0;  flag_xp_state = 0;  if (etype == EXEC_UNKNOWN)    {      /* Look for the special multiple instruction separators.  */      str2 = strstr (str, "||");      if (str2)	{	  extype = EXEC_PARALLEL;	  flag_xp_state = 1;	}      else	{	  str2 = strstr (str, "->");	  if (str2)	    extype = EXEC_SEQ;	  else	    {	      str2 = strstr (str, "<-");	      if (str2)		extype = EXEC_REVSEQ;	    }	}      /* STR2 points to the separator, if one.  */      if (str2)	{	  *str2 = 0;	  /* If two instructions are present and we already have one saved,	     then first write it out.  */	  d30v_cleanup (false);	  /* Assemble first instruction and save it.  */	  prev_insn = do_assemble (str, &prev_opcode, 1, 0);	  if (prev_insn == -1)	    as_bad (_("Cannot assemble instruction"));	  if (prev_opcode.form != NULL && prev_opcode.form->form >= LONG)	    as_bad (_("First opcode is long.  Unable to mix instructions as specified."));	  fixups = fixups->next;	  str = str2 + 2;	  prev_seg = now_seg;	  prev_subseg = now_subseg;	}    }  insn = do_assemble (str, &opcode,		      (extype != EXEC_UNKNOWN || etype != EXEC_UNKNOWN),		      extype == EXEC_PARALLEL);  if (insn == -1)    {      if (extype != EXEC_UNKNOWN)	etype = extype;      as_bad (_("Cannot assemble instruction"));      return;    }  if (etype != EXEC_UNKNOWN)    {      extype = etype;      etype = EXEC_UNKNOWN;    }  /* Word multiply instructions must not be followed by either a load or a     16-bit multiply instruction in the next cycle.  */  if (   (extype != EXEC_REVSEQ)      && prev_mul32_p      && (opcode.op->flags_used & (FLAG_MEM | FLAG_MUL16)))    {      /* However, load and multiply should able to be combined in a parallel	 operation, so check for that first.  */      if (prev_insn != -1	  && (opcode.op->flags_used & FLAG_MEM)	  && opcode.form->form < LONG	  && (extype == EXEC_PARALLEL || (Optimizing && extype == EXEC_UNKNOWN))	  && parallel_ok (&prev_opcode, (long) prev_insn,			  &opcode, (long) insn, extype)	  && write_2_short (&prev_opcode, (long) prev_insn,			    &opcode, (long) insn, extype, fixups) == 0)	{	  /* No instructions saved.  */	  prev_insn = -1;	  return;	}      else	{	  /* Can't parallelize, flush previous instruction and emit a	     word of NOPS, unless the previous instruction is a NOP,	     in which case just flush it, as this will generate a word	     of NOPs for us.  */	  if (prev_insn != -1 && (strcmp (prev_opcode.op->name, "nop") == 0))	    d30v_cleanup (false);	  else	    {	      char *f;	      if (prev_insn != -1)		d30v_cleanup (true);	      else		{		  f = frag_more (8);		  d30v_number_to_chars (f, NOP2, 8);		  if (warn_nops == NOP_ALL || warn_nops == NOP_MULTIPLY)		    {		      if (opcode.op->flags_used & FLAG_MEM)			as_warn (_("word of NOPs added between word multiply and load"));		      else			as_warn (_("word of NOPs added between word multiply and 16-bit multiply"));		    }		}	    }	  extype = EXEC_UNKNOWN;	}    }  else if (   (extype == EXEC_REVSEQ)	   && cur_mul32_p	   && (prev_opcode.op->flags_used & (FLAG_MEM | FLAG_MUL16)))    {      /* Can't parallelize, flush current instruction and add a         sequential NOP.  */      write_1_short (&opcode, (long) insn, fixups->next->next, true);      /* Make the previous instruction the current one.  */      extype = EXEC_UNKNOWN;      insn = prev_insn;      now_seg = prev_seg;      now_subseg = prev_subseg;      prev_insn = -1;      cur_mul32_p = prev_mul32_p;      prev_mul32_p = 0;      memcpy (&opcode, &prev_opcode, sizeof (prev_opcode));    }  /* If this is a long instruction, write it and any previous short     instruction.  */  if (opcode.form->form >= LONG)    {      if (extype != EXEC_UNKNOWN)	as_bad (_("Instruction uses long version, so it cannot be mixed as specified"));      d30v_cleanup (false);      write_long (&opcode, insn, fixups);      prev_insn = -1;    }  else if ((prev_insn != -1)	   && (write_2_short	       (&prev_opcode, (long) prev_insn, &opcode,		(long) insn, extype, fixups) == 0))    {      /* No instructions saved.  */      prev_insn = -1;    }  else    {      if (extype != EXEC_UNKNOWN)	as_bad (_("Unable to mix instructions as specified"));      /* Save off last instruction so it may be packed on next pass.  */      memcpy (&prev_opcode, &opcode, sizeof (prev_opcode));      prev_insn = insn;      prev_seg = now_seg;      prev_subseg = now_subseg;      fixups = fixups->next;      prev_mul32_p = cur_mul32_p;    }}/* Assemble a single instruction and return an opcode.   Return -1 (an invalid opcode) on error.  */#define NAME_BUF_LEN	20static long longdo_assemble (str, opcode, shortp, is_parallel)     char *str;     struct d30v_insn *opcode;     int shortp;     int is_parallel;{  unsigned char *op_start;  unsigned char *save;  unsigned char *op_end;  char           name[NAME_BUF_LEN];  int            cmp_hack;  int            nlen = 0;  int            fsize = (shortp ? FORCE_SHORT : 0);  expressionS    myops[6];  long long      insn;  /* Drop leading whitespace.  */  while (*str == ' ')    str++;  /* Find the opcode end.  */  for (op_start = op_end = (unsigned char *) (str);       *op_end       && nlen < (NAME_BUF_LEN - 1)       && *op_end != '/'       && !is_end_of_line[*op_end] && *op_end != ' ';       op_end++)    {      name[nlen] = tolower (op_start[nlen]);      nlen++;    }  if (nlen == 0)    return -1;  name[nlen] = 0;  /* If there is an execution condition code, handle it.  */  if (*op_end == '/')    {      int i = 0;      while ((i < ECC_MAX) && strncasecmp (d30v_ecc_names[i], op_end + 1, 2))	i++;      if (i == ECC_MAX)	{	  char tmp[4];	  strncpy (tmp, op_end + 1, 2);	  tmp[2] = 0;	  as_bad (_("unknown condition code: %s"), tmp);	  return -1;	}#if 0      printf ("condition code=%d\n", i);#endif      opcode->ecc = i;      op_end += 3;    }  else    opcode->ecc = ECC_AL;  /* CMP and CMPU change their name based on condition codes.  */  if (!strncmp (name, "cmp", 3))    {      int p, i;      char **str = (char **) d30v_cc_names;      if (name[3] == 'u')	p = 4;      else	p = 3;      for (i = 1; *str && strncmp (*str, &name[p], 2); i++, str++)	;      /* cmpu only supports some condition codes.  */      if (p == 4)	{	  if (i < 3 || i > 6)	    {	      name[p + 2] = 0;	      as_bad (_("cmpu doesn't support condition code %s"), &name[p]);	    }	}      if (!*str)	{	  name[p + 2] = 0;	  as_bad (_("unknown condition code: %s"), &name[p]);	}      cmp_hack = i;      name[p] = 0;    }  else    cmp_hack = 0;#if 0  printf ("cmp_hack=%d\n", cmp_hack);#endif  /* Need to look for .s or .l.  */  if (name[nlen - 2] == '.')    {      switch (name[nlen - 1])	{	case 's':	  fsize = FORCE_SHORT;	  break;	case 'l':	  fsize = FORCE_LONG;	  break;	}      name[nlen - 2] = 0;    }  /* Find the first opcode with the proper name.  */  opcode->op = (struct d30v_opcode *) hash_find (d30v_hash, name);  if (opcode->op == NULL)    {      as_bad (_("unknown opcode: %s"), name);      return -1;    }  save = input_line_pointer;  input_line_pointer = op_end;  while (!(opcode->form = find_format (opcode->op, myops, fsize, cmp_hack)))    {      opcode->op++;      if (opcode->op->name == NULL || strcmp (opcode->op->name, name))	{	  as_bad (_("operands for opcode `%s' do not match any valid format"),		  name);	  return -1;	}    }  input_line_pointer = save;  insn = build_insn (opcode, myops);  /* Propigate multiply status.  */  if (insn != -1)    {      if (is_parallel && prev_mul32_p)	cur_mul32_p = 1;      else	{	  prev_mul32_p = cur_mul32_p;	  cur_mul32_p  = (opcode->op->flags_used & FLAG_MUL32) != 0;	}    }  /* Propagate left_kills_right status.  */  if (insn != -1)    {      prev_left_kills_right_p = cur_left_kills_right_p;      if (opcode->op->flags_set & FLAG_LKR)	{	  cur_left_kills_right_p = 1;	  if (strcmp (opcode->op->name, "mvtsys") == 0)	    {	      /* Left kills right for only mvtsys only for                 PSW/PSWH/PSWL/flags target.  */	      if ((myops[0].X_op == O_register) &&		  ((myops[0].X_add_number == OPERAND_CONTROL) || /* psw */		   (myops[0].X_add_number == OPERAND_CONTROL+MAX_CONTROL_REG+2) || /* pswh */		   (myops[0].X_add_number == OPERAND_CONTROL+MAX_CONTROL_REG+1) || /* pswl */		   (myops[0].X_add_number == OPERAND_FLAG+0) || /* f0 */		   (myops[0].X_add_number == OPERAND_FLAG+1) || /* f1 */		   (myops[0].X_add_number == OPERAND_FLAG+2) || /* f2 */		   (myops[0].X_add_number == OPERAND_FLAG+3) || /* f3 */		   (myops[0].X_add_number == OPERAND_FLAG+4) || /* f4 */		   (myops[0].X_add_number == OPERAND_FLAG+5) || /* f5 */		   (myops[0].X_add_number == OPERAND_FLAG+6) || /* f6 */		   (myops[0].X_add_number == OPERAND_FLAG+7))) /* f7 */		{		  cur_left_kills_right_p = 1;		}	      else		{		  /* Other mvtsys target registers don't kill right                     instruction.  */		  cur_left_kills_right_p = 0;		}	    } /* mvtsys */	}      else	cur_left_kills_right_p = 0;    }  return insn;}/* Get a pointer to an entry in the format table.   It must look at all formats for an opcode and use the operands   to choose the correct one.  Return NULL on error.  */static struct d30v_format *find_format (opcode, myops, fsize, cmp_hack)     struct d30v_opcode *opcode;     expressionS myops[];     int fsize;     int cmp_hack;{  int numops, match, index, i = 0, j, k;  struct d30v_format *fm;  if (opcode == NULL)    return NULL;  /* Get all the operands and save them as expressions.  */  numops = get_operands (myops, cmp_hack);  while ((index = opcode->format[i++]) != 0)    {      if (fsize == FORCE_SHORT && index >= LONG)	continue;      if (fsize == FORCE_LONG && index < LONG)	continue;      fm = (struct d30v_format *) &d30v_format_table[index];      k = index;      while (fm->form == index)	{	  match = 1;	  /* Now check the operands for compatibility.  */	  for (j = 0; match && fm->operands[j]; j++)	    {	      int flags = d30v_operand_table[fm->operands[j]].flags;	      int bits = d30v_operand_table[fm->operands[j]].bits;	      int X_op = myops[j].X_op;	      int num = myops[j].X_add_number;	      if (flags & OPERAND_SPECIAL)		break;	      else if (X_op == O_illegal)		match = 0;	      else if (flags & OPERAND_REG)		{		  if (X_op != O_register		      || ((flags & OPERAND_ACC) && !(num & OPERAND_ACC))		      || (!(flags & OPERAND_ACC) && (num & OPERAND_ACC))		      || ((flags & OPERAND_FLAG) && !(num & OPERAND_FLAG))		      || (!(flags & (OPERAND_FLAG | OPERAND_CONTROL)) && (num & OPERAND_FLAG))		      || ((flags & OPERAND_CONTROL)			  && !(num & (OPERAND_CONTROL | OPERAND_FLAG))))		    {		      match = 0;		    }		}	      else if (((flags & OPERAND_MINUS)			&& (X_op != O_absent || num != OPERAND_MINUS))		       || ((flags & OPERAND_PLUS)			   && (X_op != O_absent || num != OPERAND_PLUS))		       || ((flags & OPERAND_ATMINUS)			   && (X_op != O_absent || num != OPERAND_ATMINUS))		       || ((flags & OPERAND_ATPAR)			   && (X_op != O_absent || num != OPERAND_ATPAR))		       || ((flags & OPERAND_ATSIGN)			   && (X_op != O_absent || num != OPERAND_ATSIGN)))		{		  match = 0;		}	      else if (flags & OPERAND_NUM)		{		  /* A number can be a constant or symbol expression.  */		  /* If we have found a register name, but that name		     also matches a symbol, then re-parse the name as		     an expression.  */		  if (X_op == O_register		      && symbol_find ((char *) myops[j].X_op_symbol))		    {		      input_line_pointer = (char *) myops[j].X_op_symbol;		      expression (&myops[j]);		    }

⌨️ 快捷键说明

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