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

📄 tc-tic80.c

📁 基于4个mips核的noc设计
💻 C
📖 第 1 页 / 共 2 页
字号:
/* tc-tic80.c -- Assemble for the TI TMS320C80 (MV)   Copyright 1996, 1997, 2000 Free Software Foundation, Inc.   This file is part of GAS, the GNU Assembler.   GAS is free software; you can redistribute it and/or modify   it under the terms of the GNU General Public License as published by   the Free Software Foundation; either version 2, or (at your option)   any later version.   GAS is distributed in the hope that it will be useful,   but WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   GNU General Public License for more details.   You should have received a copy of the GNU General Public License   along with GAS; see the file COPYING.  If not, write to the Free   Software Foundation, 59 Temple Place - Suite 330, Boston, MA   02111-1307, USA.  */#include "as.h"#include "opcode/tic80.h"#define internal_error(what) \  as_fatal(_("internal error:%s:%d: %s\n"), __FILE__, __LINE__, what)#define internal_error_a(what,arg) \  as_fatal(_("internal error:%s:%d: %s %d\n"), __FILE__, __LINE__, what, arg)/* Generic assembler global variables which must be defined by all   targets.  *//* Characters which always start a comment.  */const char comment_chars[] = ";";/* Characters which start a comment at the beginning of a line.  */const char line_comment_chars[] = ";*#";/* Characters which may be used to separate multiple commands on a single   line. The semicolon is such a character by default and should not be   explicitly listed.  */const char line_separator_chars[] = "";/* Characters which are used to indicate an exponent in a floating   point number.  */const char EXP_CHARS[] = "eE";/* Characters which mean that a number is a floating point constant,   as in 0f1.0.  */const char FLT_CHARS[] = "fF";/* This table describes all the machine specific pseudo-ops the assembler   has to support.  The fields are:   pseudo-op name without dot   function to call to execute this pseudo-op   integer arg to pass to the function  */extern void obj_coff_section ();const pseudo_typeS md_pseudo_table[] = {  { "align",	s_align_bytes,		4 },	/* Do byte alignment, default is a 4 byte boundary  */  { "word",	cons,			4 },	/* FIXME: Should this be machine independent?  */  { "bss",	s_lcomm_bytes,		1 },  { "sect",	obj_coff_section,	0},	/* For compatibility with TI tools  */  { "section",	obj_coff_section,	0},	/* Standard COFF .section pseudo-op  */  { NULL,	NULL,			0 }};/* Opcode hash table.  */static struct hash_control *tic80_hash;static struct tic80_opcode * find_opcode PARAMS ((struct tic80_opcode *, expressionS []));static void build_insn PARAMS ((struct tic80_opcode *, expressionS *));static int get_operands PARAMS ((expressionS exp[]));static int const_overflow PARAMS ((unsigned long num, int bits, int flags));/* Replace short PC relative instructions with long form when   necessary.  Currently this is off by default or when given the   -no-relax option.  Turning it on by using the -relax option forces   all PC relative instructions to use the long form, which is why it   is currently not the default.  */static int tic80_relax = 0;intmd_estimate_size_before_relax (fragP, segment_type)     fragS *fragP;     segT segment_type;{  internal_error (_("Relaxation is a luxury we can't afford"));  return (-1);}/* We have no need to default values of symbols.  */symbolS *md_undefined_symbol (name)     char *name;{  return 0;}/* Turn a string in input_line_pointer into a floating point constant   of type TYPE, and store the appropriate bytes in *LITP.  The number   of LITTLENUMS emitted is stored in *SIZEP.  An error message is   returned, or NULL on OK.  */#define MAX_LITTLENUMS 4char *md_atof (type, litP, sizeP)     int type;     char *litP;     int *sizeP;{  int prec;  LITTLENUM_TYPE words[MAX_LITTLENUMS];  LITTLENUM_TYPE *wordP;  char *t;  char *atof_ieee ();  switch (type)    {    case 'f':    case 'F':    case 's':    case 'S':      prec = 2;      break;    case 'd':    case 'D':    case 'r':    case 'R':      prec = 4;      break;    default:      *sizeP = 0;      return _("bad call to md_atof ()");    }  t = atof_ieee (input_line_pointer, type, words);  if (t)    {      input_line_pointer = t;    }  *sizeP = prec * sizeof (LITTLENUM_TYPE);  for (wordP = words; prec--;)    {      md_number_to_chars (litP, (valueT) (*wordP++), sizeof (LITTLENUM_TYPE));      litP += sizeof (LITTLENUM_TYPE);    }  return (NULL);}/* Check to see if the constant value in NUM will fit in a field of   width BITS if it has flags FLAGS.  */static intconst_overflow (num, bits, flags)     unsigned long num;     int bits;     int flags;{  long min, max;  int retval = 0;  /* Only need to check fields less than 32 bits wide.  */  if (bits < 32)    if (flags & TIC80_OPERAND_SIGNED)      {	max = (1 << (bits - 1)) - 1;	min = - (1 << (bits - 1));	retval = ((long) num > max) || ((long) num < min);      }    else      {	max = (1 << bits) - 1;	min = 0;	retval = (num > max) || (num < min);      }  return (retval);}/* get_operands () parses a string of operands and fills in a passed   array of expressions in EXP.   Note that we use O_absent expressions to record additional information   about the previous non-O_absent expression, such as ":m" or ":s"   modifiers or register numbers enclosed in parens like "(r10)".   Returns the number of expressions that were placed in EXP.  */static intget_operands (exp)     expressionS exp[];{  char *p = input_line_pointer;  int numexp = 0;  int mflag = 0;  int sflag = 0;  int parens = 0;  while (*p)    {      /* Skip leading whitespace.  */      while (*p == ' ' || *p == '\t' || *p == ',')	p++;      /* Check to see if we have any operands left to parse.  */      if (*p == 0 || *p == '\n' || *p == '\r')	break;      /* Notice scaling or direct memory operand modifiers and save them in	 an O_absent expression after the expression that they modify.  */      if (*p == ':')	{	  p++;	  exp[numexp].X_op = O_absent;	  if (*p == 'm')	    {	      p++;	      /* This is a ":m" modifier.  */	      exp[numexp].X_add_number = TIC80_OPERAND_M_SI | TIC80_OPERAND_M_LI;	    }	  else if (*p == 's')	    {	      p++;	      /* This is a ":s" modifier.  */	      exp[numexp].X_add_number = TIC80_OPERAND_SCALED;	    }	  else	    {	      as_bad (_("':' not followed by 'm' or 's'"));	    }	  numexp++;	  continue;	}      /* Handle leading '(' on operands that use them, by recording that we	 have entered a paren nesting level and then continuing.  We complain	 about multiple nesting.  */      if (*p == '(')	{	  if (++parens != 1)	    as_bad (_("paren nesting"));	  p++;	  continue;	}      /* Handle trailing ')' on operands that use them, by reducing the	 nesting level and then continuing.  We complain if there were too	 many closures.  */      if (*p == ')')	{	  /* Record that we have left a paren group and continue.  */	  if (--parens < 0)	    as_bad (_("mismatched parenthesis"));	  p++;	  continue;	}      /* Begin operand parsing at the current scan point.  */      input_line_pointer = p;      expression (&exp[numexp]);      if (exp[numexp].X_op == O_illegal)	{	  as_bad (_("illegal operand"));	}      else if (exp[numexp].X_op == O_absent)	{	  as_bad (_("missing operand"));	}      numexp++;      p = input_line_pointer;    }  if (parens)    {      exp[numexp].X_op = O_absent;      exp[numexp++].X_add_number = TIC80_OPERAND_PARENS;    }  /* Mark the end of the valid operands with an illegal expression.  */  exp[numexp].X_op = O_illegal;  return (numexp);}/* find_opcode() gets a pointer to the entry in the opcode table that   matches the instruction being assembled, or returns NULL if no such match   is found.   First it parses all the operands and save them as expressions.  Note that   we use O_absent expressions to record additional information about the   previous non-O_absent expression, such as ":m" or ":s" modifiers or   register numbers enclosed in parens like "(r10)".   It then looks at all opcodes with the same name and uses the operands to   choose the correct opcode.  */static struct tic80_opcode *find_opcode (opcode, myops)     struct tic80_opcode *opcode;     expressionS myops[];{  int numexp;				/* Number of expressions from parsing operands */  int expi;				/* Index of current expression to match */  int opi;				/* Index of current operand to match */  int match = 0;			/* Set to 1 when an operand match is found */  struct tic80_opcode *opc = opcode;	/* Pointer to current opcode table entry */  const struct tic80_opcode *end;	/* Pointer to end of opcode table */  /* First parse all the operands so we only have to do it once.  There may     be more expressions generated than there are operands.  */  numexp = get_operands (myops);  /* For each opcode with the same name, try to match it against the parsed     operands.  */  end = tic80_opcodes + tic80_num_opcodes;  while (!match && (opc < end) && (strcmp (opc->name, opcode->name) == 0))    {      /* Start off assuming a match.  If we find a mismatch, then this is	 reset and the operand/expr matching loop terminates with match	 equal to zero, which allows us to try the next opcode.  */      match = 1;      /* For each expression, try to match it against the current operand	 for the current opcode.  Upon any mismatch, we abandon further	 matching for the current opcode table entry.  */      for (expi = 0, opi = -1; (expi < numexp) && match; expi++)	{	  int bits, flags, X_op, num;	  X_op = myops[expi].X_op;	  num = myops[expi].X_add_number;	  /* The O_absent expressions apply to the same operand as the most	     recent non O_absent expression.  So only increment the operand	     index when the current expression is not one of these special	     expressions.  */	  if (X_op != O_absent)	    {	      opi++;	    }	  flags = tic80_operands[opc->operands[opi]].flags;	  bits  = tic80_operands[opc->operands[opi]].bits;	  switch (X_op)	    {	    case O_register:	      /* Also check that registers that are supposed to be		 even actually are even.  */	      if (((flags & TIC80_OPERAND_GPR) != (num & TIC80_OPERAND_GPR)) ||		  ((flags & TIC80_OPERAND_FPA) != (num & TIC80_OPERAND_FPA)) ||		  ((flags & TIC80_OPERAND_CR) != (num & TIC80_OPERAND_CR)) ||		  ((flags & TIC80_OPERAND_EVEN) && (num & 1)) ||		  const_overflow (num & ~TIC80_OPERAND_MASK, bits, flags))		{		  match = 0;		}	      break;	    case O_constant:	      if ((flags & TIC80_OPERAND_ENDMASK) && (num == 32))		{		  /* Endmask values of 0 and 32 give identical                     results.  */		  num = 0;		}	      if ((flags & (TIC80_OPERAND_FPA | TIC80_OPERAND_GPR)) ||		  const_overflow (num, bits, flags))		{		  match = 0;		}	      break;	    case O_symbol:	      if ((bits < 32) && (flags & TIC80_OPERAND_PCREL)		  && !tic80_relax)		{		  /* The default is to prefer the short form of PC		     relative relocations.  This is the only form that		     the TI assembler supports.  If the -relax option		     is given, we never use the short forms.		     FIXME: Should be able to choose "best-fit".  */		}	      else if ((bits == 32)#if 0		       && (flags & TIC80_OPERAND_BASEREL)#endif		       )		{		  /* The default is to prefer the long form of base		     relative relocations.  This is the only form that		     the TI assembler supports.  If the -no-relax		     option is given, we always use the long form of		     PC relative relocations.		     FIXME: Should be able to choose "best-fit".  */		}	      else		{		  /* Symbols that don't match one of the above cases are		     rejected as an operand.  */		  match = 0;		}	      break;	    case O_absent:	      /* If this is an O_absent expression, then it may be an		 expression that supplies additional information about		 the operand, such as ":m" or ":s" modifiers. Check to		 see that the operand matches this requirement.  */	      if (!((num & TIC80_OPERAND_M_SI) && (flags & TIC80_OPERAND_M_SI)		    || (num & TIC80_OPERAND_M_LI) && (flags & TIC80_OPERAND_M_LI)		    || (num & TIC80_OPERAND_SCALED) && (flags & TIC80_OPERAND_SCALED)))		{		  match = 0;		}	      break;	    case O_big:	      if ((num > 0) || !(flags & TIC80_OPERAND_FLOAT))		{		  match = 0;		}	      break;	    case O_illegal:	    case O_symbol_rva:	    case O_uminus:	    case O_bit_not:	    case O_logical_not:	    case O_multiply:	    case O_divide:	    case O_modulus:	    case O_left_shift:	    case O_right_shift:	    case O_bit_inclusive_or:	    case O_bit_or_not:	    case O_bit_exclusive_or:	    case O_bit_and:	    case O_add:	    case O_subtract:	    case O_eq:	    case O_ne:	    case O_lt:	    case O_le:	    case O_ge:	    case O_gt:	    case O_logical_and:	    case O_logical_or:	    case O_max:	    default:	      internal_error_a (_("unhandled expression type"), X_op);	    }	}      if (!match)	opc++;    }  return (match ? opc : NULL);#if 0  /* Now search the opcode table table for one with operands that     matches what we've got.  */  while (!match)    {      match = 1;      for (i = 0; opcode->operands[i]; i++)	{	  int flags = tic80_operands[opcode->operands[i]].flags;	  int X_op = myops[i].X_op;	  int num = myops[i].X_add_number;	  if (X_op == 0)	    {	      match = 0;	      break;	    }	  if (flags	      & (TIC80_OPERAND_GPR | TIC80_OPERAND_FPA | TIC80_OPERAND_CR))	    {	      if ((X_op != O_register) ||		  ((flags & TIC80_OPERAND_GPR) != (num & TIC80_OPERAND_GPR)) ||		  ((flags & TIC80_OPERAND_FPA) != (num & TIC80_OPERAND_FPA)) ||		  ((flags & TIC80_OPERAND_CR) != (num & TIC80_OPERAND_CR)))		{		  match = 0;		  break;		}	    }	  if (((flags & TIC80_OPERAND_MINUS) && ((X_op != O_absent) || (num != TIC80_OPERAND_MINUS))) ||	      ((flags & TIC80_OPERAND_PLUS) && ((X_op != O_absent) || (num != TIC80_OPERAND_PLUS))) ||	      ((flags & TIC80_OPERAND_ATMINUS) && ((X_op != O_absent) || (num != TIC80_OPERAND_ATMINUS))) ||	      ((flags & TIC80_OPERAND_ATPAR) && ((X_op != O_absent) || (num != TIC80_OPERAND_ATPAR))) ||	      ((flags & TIC80_OPERAND_ATSIGN) && ((X_op != O_absent) || (num != TIC80_OPERAND_ATSIGN))))	    {	      match = 0;	      break;	    }	}      /* We're only done if the operands matched so far AND there	 are no more to check.  */      if (match && myops[i].X_op == 0)	break;      else	match = 0;      next_opcode = opcode + 1;      if (next_opcode->opcode == 0)	break;      if (strcmp (next_opcode->name, opcode->name))

⌨️ 快捷键说明

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