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

📄 tc-i370.c

📁 基于4个mips核的noc设计
💻 C
📖 第 1 页 / 共 5 页
字号:
#endif /* LITERAL_POOL_SUPPORT *//* add support for the HLASM-like USING directive to indicate * the base register to use ...  we don't support the full * hlasm semantics for this ... we merely pluck a base address * and a register number out.  We print a warning if using is * called multiple times.  I suppose we should check to see * if the regno is valid ... */static voidi370_using (ignore)     int ignore;{  expressionS ex, baseaddr;  int iregno;  char *star;  /* if "*" appears in a using, it means "."  */  /* replace it with "." so that expr doesn't get confused.  */  star = strchr (input_line_pointer, '*');  if (star)    *star = '.';  /* the first arg to using will usually be ".", but it can   * be a more complex exprsssion too ...  */  expression (&baseaddr);  if (star)    *star = '*';  if (O_constant != baseaddr.X_op      && O_symbol != baseaddr.X_op      && O_uminus != baseaddr.X_op)  {    as_bad (".using: base address expression illegal or too complex");  }  if (*input_line_pointer != '\0') ++input_line_pointer;  /* the second arg to using had better be a register */  register_name (&ex);  demand_empty_rest_of_line ();  iregno = ex.X_add_number;  if (0 == strncmp (now_seg->name, ".text", 5))    {      i370_using_text_baseaddr = baseaddr;      i370_using_text_regno = iregno;    }  else    {      i370_using_other_baseaddr = baseaddr;      i370_using_other_regno = iregno;      i370_other_section = now_seg;    }}static voidi370_drop (ignore)     int ignore;{  expressionS ex;  int iregno;  register_name (&ex);  demand_empty_rest_of_line ();  iregno = ex.X_add_number;  if (0 == strncmp (now_seg->name, ".text", 5))    {      if (iregno != i370_using_text_regno)        {          as_bad ("droping register %d in section %s does not match using register %d",		  iregno, now_seg->name, i370_using_text_regno);        }      i370_using_text_regno = -1;      i370_using_text_baseaddr.X_op = O_absent;    }  else    {      if (iregno != i370_using_other_regno)        {          as_bad ("droping register %d in section %s does not match using register %d",		  iregno, now_seg->name, i370_using_other_regno);        }      if (i370_other_section != now_seg)        {          as_bad ("droping register %d in section %s previously used in section %s",		  iregno, now_seg->name, i370_other_section->name);        }      i370_using_other_regno = -1;      i370_using_other_baseaddr.X_op = O_absent;      i370_other_section = undefined_section;    }}/* Make the first argument an address-relative expression * by subtracting the second argument. */static voidi370_make_relative (expressionS *exx, expressionS *baseaddr){  if (O_constant == baseaddr->X_op)    {       exx->X_op = O_symbol;       exx->X_add_number -= baseaddr->X_add_number;    }  else if (O_symbol == baseaddr->X_op)    {       exx->X_op = O_subtract;       exx->X_op_symbol = baseaddr->X_add_symbol;       exx->X_add_number -= baseaddr->X_add_number;    }  else if (O_uminus == baseaddr->X_op)    {       exx->X_op = O_add;       exx->X_op_symbol = baseaddr->X_add_symbol;       exx->X_add_number += baseaddr->X_add_number;     }  else     {       as_bad ("Missing or bad .using directive");     }}/* We need to keep a list of fixups.  We can't simply generate them as   we go, because that would require us to first create the frag, and   that would screw up references to ``.''.  */struct i370_fixup{  expressionS exp;  int opindex;  bfd_reloc_code_real_type reloc;};#define MAX_INSN_FIXUPS (5)/* This routine is called for each instruction to be assembled.  */voidmd_assemble (str)     char *str;{  char *s, *opcode_str;  const struct i370_opcode *opcode;  i370_insn_t insn;  const unsigned char *opindex_ptr;  int have_optional_index, have_optional_basereg, have_optional_reg;  int skip_optional_index, skip_optional_basereg, skip_optional_reg;  int use_text=0, use_other=0;  int off_by_one;  struct i370_fixup fixups[MAX_INSN_FIXUPS];  int fc;  char *f;  int i;#ifdef OBJ_ELF  bfd_reloc_code_real_type reloc;#endif  /* Get the opcode.  */  for (s = str; *s != '\0' && ! isspace (*s); s++)    ;  if (*s != '\0')    *s++ = '\0';  opcode_str = str;  /* Look up the opcode in the hash table.  */  opcode = (const struct i370_opcode *) hash_find (i370_hash, str);  if (opcode == (const struct i370_opcode *) NULL)    {      const struct i370_macro *macro;      assert (i370_macro_hash);      macro = (const struct i370_macro *) hash_find (i370_macro_hash, str);      if (macro == (const struct i370_macro *) NULL)        as_bad ("Unrecognized opcode: `%s'", str);      else	i370_macro (s, macro);      return;    }  insn = opcode->opcode;  str = s;  while (isspace (*str))    ++str;  /* I370 operands are either expressions or address constants.     Many operand types are optional.  The optional operands     are always surrounded by parens, and are used to denote the base     register ... e.g. "A R1, D2" or "A R1, D2(,B2) as opposed to     the fully-formed "A R1, D2(X2,B2)".  Note also the = sign,     such as A R1,=A(i) where the address-of operator =A implies     use of both a base register, and a missing index register.     So, before we start seriously parsing the operands, we check     to see if we have an optional operand, and, if we do, we count     the number of commas to see which operand should be omitted.  */  have_optional_index = have_optional_basereg = have_optional_reg = 0;  for (opindex_ptr = opcode->operands; *opindex_ptr != 0; opindex_ptr++)    {      const struct i370_operand *operand;      operand = &i370_operands[*opindex_ptr];      if ((operand->flags & I370_OPERAND_INDEX) != 0)	have_optional_index = 1;      if ((operand->flags & I370_OPERAND_BASE) != 0)	have_optional_basereg = 1;      if ((operand->flags & I370_OPERAND_OPTIONAL) != 0)	have_optional_reg = 1;    }  skip_optional_index = skip_optional_basereg = skip_optional_reg = 0;  if (have_optional_index || have_optional_basereg)    {      unsigned int opcount, nwanted;      /* There is an optional operand.  Count the number of	 commas and open-parens in the input line.  */      if (*str == '\0')	opcount = 0;      else	{	  opcount = 1;	  s = str;	  while ((s = strpbrk (s, ",(=")) != (char *) NULL)	    {	      ++opcount;	      ++s;	      if (',' == *s) ++s;  /* avoid counting things like (, */	      if ('=' == *s) { ++s; --opcount; }	    }	}      /* If there are fewer operands in the line then are called	 for by the instruction, we want to skip the optional	 operand.  */      nwanted = strlen (opcode->operands);      if (have_optional_index)	{	  if (opcount < nwanted)	    skip_optional_index = 1;	  if (have_optional_basereg && ((opcount+1) < nwanted))	    skip_optional_basereg = 1;	  if (have_optional_reg && ((opcount+1) < nwanted))	    skip_optional_reg = 1;	}      else	{	  if (have_optional_basereg && (opcount < nwanted))	    skip_optional_basereg = 1;	  if (have_optional_reg && (opcount < nwanted))	    skip_optional_reg = 1;	}    }  /* Perform some off-by-one hacks on the length field of certain instructions.   * Its such a shame to have to do this, but the problem is that HLASM got   * defined so that the lengths differ by one from the actual machine instructions.   * this code should probably be moved to a special inster-operand routine.   * Sigh. Affected instructions are Compare Logical, Move and Exclusive OR   * hack alert -- aren't *all* SS instructions affected ??   */  off_by_one = 0;  if (0 == strcasecmp ("CLC", opcode->name)      || 0 == strcasecmp ("ED", opcode->name)      || 0 == strcasecmp ("EDMK", opcode->name)      || 0 == strcasecmp ("MVC", opcode->name)      || 0 == strcasecmp ("MVCIN", opcode->name)      || 0 == strcasecmp ("MVN", opcode->name)      || 0 == strcasecmp ("MVZ", opcode->name)      || 0 == strcasecmp ("NC", opcode->name)      || 0 == strcasecmp ("OC", opcode->name)      || 0 == strcasecmp ("XC", opcode->name))    off_by_one = 1;  /* Gather the operands.  */  fc = 0;  for (opindex_ptr = opcode->operands; *opindex_ptr != 0; opindex_ptr++)    {      const struct i370_operand *operand;      const char *errmsg;      char *hold;      expressionS ex;      operand = &i370_operands[*opindex_ptr];      errmsg = NULL;      /* If this is an index operand, and we are skipping it,	 just insert a zero.  */      if (skip_optional_index &&	  ((operand->flags & I370_OPERAND_INDEX) != 0))        {          insn = i370_insert_operand (insn, operand, 0);          continue;        }      /* If this is the base operand, and we are skipping it,	 just insert the current using basreg.  */      if (skip_optional_basereg &&          ((operand->flags & I370_OPERAND_BASE) != 0))        {          int basereg = -1;          if (use_text)            {              if (0 == strncmp (now_seg->name, ".text", 5)		  || 0 > i370_using_other_regno)                {                  basereg = i370_using_text_regno;                }              else                {                  basereg = i370_using_other_regno;                }            }          else if (use_other)            {              if (0 > i370_using_other_regno)                {                  basereg = i370_using_text_regno;                }              else                {                  basereg = i370_using_other_regno;                }            }          if (0 > basereg)            {              as_bad ("not using any base register");            }          insn = i370_insert_operand (insn, operand, basereg);          continue;        }      /* If this is an optional operand, and we are skipping it,	 Use zero (since a non-zero value would denote a register)  */      if (skip_optional_reg	  && ((operand->flags & I370_OPERAND_OPTIONAL) != 0))        {          insn = i370_insert_operand (insn, operand, 0);          continue;        }      /* Gather the operand.  */      hold = input_line_pointer;      input_line_pointer = str;      /* register names are only allowed where there are registers ...  */      if ((operand->flags & I370_OPERAND_GPR) != 0)        {          /* quickie hack to get past things like (,r13) */          if (skip_optional_index && (',' == *input_line_pointer))            {              *input_line_pointer = ' ';              input_line_pointer ++;            }          if (! register_name (&ex))            {              as_bad ("expecting a register for operand %d",		      opindex_ptr - opcode->operands + 1);            }        }      /* check for a address constant expression */      /* We will put PSW-relative addresses in the text section,       * and adress literals in the .data (or other) section.  */      else if (i370_addr_cons (&ex))	use_other=1;      else if (i370_addr_offset (&ex))	use_text=1;      else expression (&ex);      str = input_line_pointer;      input_line_pointer = hold;      /* perform some off-by-one hacks on the length field of certain instructions.       * Its such a shame to have to do this, but the problem is that HLASM got       * defined so that the programmer specifies a length that is one greater       * than what the machine instruction wants.       * Sigh.       */      if (off_by_one && (0 == strcasecmp ("SS L", operand->name)))	{	  ex.X_add_number --;	}      if (ex.X_op == O_illegal)        as_bad ("illegal operand");      else if (ex.X_op == O_absent)        as_bad ("missing operand");      else if (ex.X_op == O_register)        {          insn = i370_insert_operand (insn, operand, ex.X_add_number);        }      else if (ex.X_op == O_constant)        {#ifdef OBJ_ELF          /* Allow @HA, @L, @H on constants.           * Well actually, no we don't; there really don't make sense           * (at least not to me) for the i370.  However, this code is           * left here for any dubious future expansion reasons ...  */          char *orig_str = str;          if ((reloc = i370_elf_suffix (&str, &ex)) != BFD_RELOC_UNUSED)            switch (reloc)              {              default:        	str = orig_str;        	break;              case BFD_RELOC_LO16:        	/* X_unsigned is the default, so if the user has done                   something which cleared it, we always produce a                   signed value.  */		ex.X_add_number = (((ex.X_add_number & 0xffff)				    ^ 0x8000)				   - 0x8000);        	break;              case BFD_RELOC_HI16:        	ex.X_add_number = (ex.X_add_number >> 16) & 0xffff;        	break;              case BFD_RELOC_HI16_S:        	ex.X_add_number = (((ex.X_add_number >> 16) & 0xffff)        			   + ((ex.X_add_number >> 15) & 1));        	break;              }#endif          insn = i370_insert_operand (insn, operand, ex.X_add_number);        }#ifdef OBJ_ELF      else if ((reloc = i370_elf_suffix (&str, &ex)) != BFD_RELOC_UNUSED)        {          as_tsktsk ("md_assemble(): suffixed relocations not supported\n");          /* We need to generate a fixup for this expression.  */          if (fc >= MAX_INSN_FIXUPS)            as_fatal ("too many fixups");          fixups[fc].exp = ex;          fixups[fc].opindex = 0;          fixups[fc].reloc = reloc;          ++fc;        }#endif /* OBJ_ELF */      else        {          /* We need to generate a fixup for this expression.  */          /* Typically, the expression will just be a symbol ...           * printf ("insn %s needs fixup for %s \

⌨️ 快捷键说明

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