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

📄 tc-arc.c

📁 基于4个mips核的noc设计
💻 C
📖 第 1 页 / 共 4 页
字号:
/* tc-arc.c -- Assembler for the ARC   Copyright 1994, 1995, 1997, 1999, 2000, 2001   Free Software Foundation, Inc.   Contributed by Doug Evans (dje@cygnus.com).   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 <stdio.h>#include <ctype.h>#include "libiberty.h"#include "as.h"#include "subsegs.h"#include "opcode/arc.h"#include "../opcodes/arc-ext.h"#include "elf/arc.h"#include "dwarf2dbg.h"extern int arc_get_mach PARAMS ((char *));extern int arc_operand_type PARAMS ((int));extern int arc_insn_not_jl PARAMS ((arc_insn));extern int arc_limm_fixup_adjust PARAMS ((arc_insn));extern int arc_get_noshortcut_flag PARAMS ((void));extern int arc_set_ext_seg PARAMS ((void));extern void arc_code_symbol PARAMS ((expressionS *));static arc_insn arc_insert_operand PARAMS ((arc_insn,					    const struct arc_operand *, int,					    const struct arc_operand_value *,					    offsetT, char *, unsigned int));static void arc_common PARAMS ((int));static void arc_extinst PARAMS ((int));static void arc_extoper PARAMS ((int));static void arc_option PARAMS ((int));static int get_arc_exp_reloc_type PARAMS ((int, int, expressionS *,					   expressionS *));const struct suffix_classes {  char *name;  int  len;} suffixclass[] = {  { "SUFFIX_COND|SUFFIX_FLAG",23 },  { "SUFFIX_FLAG", 11 },  { "SUFFIX_COND", 11 },  { "SUFFIX_NONE", 11 }};#define MAXSUFFIXCLASS (sizeof (suffixclass) / sizeof (struct suffix_classes))const struct syntax_classes {  char *name;  int  len;  int  class;} syntaxclass[] = {  { "SYNTAX_3OP|OP1_MUST_BE_IMM", 26, SYNTAX_3OP|OP1_MUST_BE_IMM|SYNTAX_VALID },  { "OP1_MUST_BE_IMM|SYNTAX_3OP", 26, OP1_MUST_BE_IMM|SYNTAX_3OP|SYNTAX_VALID },  { "SYNTAX_2OP|OP1_IMM_IMPLIED", 26, SYNTAX_2OP|OP1_IMM_IMPLIED|SYNTAX_VALID },  { "OP1_IMM_IMPLIED|SYNTAX_2OP", 26, OP1_IMM_IMPLIED|SYNTAX_2OP|SYNTAX_VALID },  { "SYNTAX_3OP",                 10, SYNTAX_3OP|SYNTAX_VALID },  { "SYNTAX_2OP",                 10, SYNTAX_2OP|SYNTAX_VALID }};#define MAXSYNTAXCLASS (sizeof (syntaxclass) / sizeof (struct syntax_classes))const pseudo_typeS md_pseudo_table[] = {  { "align", s_align_bytes, 0 }, /* Defaulting is invalid (0).  */  { "comm", arc_common, 0 },  { "common", arc_common, 0 },  { "lcomm", arc_common, 1 },  { "lcommon", arc_common, 1 },  { "2byte", cons, 2 },  { "half", cons, 2 },  { "short", cons, 2 },  { "3byte", cons, 3 },  { "4byte", cons, 4 },  { "word", cons, 4 },  { "option", arc_option, 0 },  { "cpu", arc_option, 0 },  { "block", s_space, 0 },  { "file", dwarf2_directive_file, 0 },  { "loc", dwarf2_directive_loc, 0 },  { "extcondcode", arc_extoper, 0 },  { "extcoreregister", arc_extoper, 1 },  { "extauxregister", arc_extoper, 2 },  { "extinstruction", arc_extinst, 0 },  { NULL, 0, 0 },};/* This array holds the chars that always start a comment.  If the   pre-processor is disabled, these aren't very useful.  */const char comment_chars[] = "#;";/* This array holds the chars that only start a comment at the beginning of   a line.  If the line seems to have the form '# 123 filename'   .line and .file directives will appear in the pre-processed output *//* Note that input_file.c hand checks for '#' at the beginning of the   first line of the input file.  This is because the compiler outputs   #NO_APP at the beginning of its output.  *//* Also note that comments started like this one will always   work if '/' isn't otherwise defined.  */const char line_comment_chars[] = "#";const char line_separator_chars[] = "";/* Chars that can be used to separate mant from exp in floating point nums.  */const char EXP_CHARS[] = "eE";/* Chars that mean this number is a floating point constant   As in 0f12.456 or 0d1.2345e12.  */const char FLT_CHARS[] = "rRsSfFdD";/* Byte order.  */extern int target_big_endian;const char *arc_target_format = DEFAULT_TARGET_FORMAT;static int byte_order = DEFAULT_BYTE_ORDER;static segT arcext_section;/* One of bfd_mach_arc_n.  */static int arc_mach_type = bfd_mach_arc_6;/* Non-zero if the cpu type has been explicitly specified.  */static int mach_type_specified_p = 0;/* Non-zero if opcode tables have been initialized.   A .option command must appear before any instructions.  */static int cpu_tables_init_p = 0;static struct hash_control *arc_suffix_hash = NULL;const char *md_shortopts = "";struct option md_longopts[] = {#define OPTION_EB (OPTION_MD_BASE + 0)  { "EB", no_argument, NULL, OPTION_EB },#define OPTION_EL (OPTION_MD_BASE + 1)  { "EL", no_argument, NULL, OPTION_EL },#define OPTION_ARC5 (OPTION_MD_BASE + 2)  { "marc5", no_argument, NULL, OPTION_ARC5 },  { "pre-v6", no_argument, NULL, OPTION_ARC5 },#define OPTION_ARC6 (OPTION_MD_BASE + 3)  { "marc6", no_argument, NULL, OPTION_ARC6 },#define OPTION_ARC7 (OPTION_MD_BASE + 4)  { "marc7", no_argument, NULL, OPTION_ARC7 },#define OPTION_ARC8 (OPTION_MD_BASE + 5)  { "marc8", no_argument, NULL, OPTION_ARC8 },#define OPTION_ARC (OPTION_MD_BASE + 6)  { "marc", no_argument, NULL, OPTION_ARC },  { NULL, no_argument, NULL, 0 }};size_t md_longopts_size = sizeof (md_longopts);#define IS_SYMBOL_OPERAND(o) \ ((o) == 'b' || (o) == 'c' || (o) == 's' || (o) == 'o' || (o) == 'O')struct arc_operand_value *get_ext_suffix (char *s);/* Invocation line includes a switch not recognized by the base assembler.   See if it's a processor-specific option.  */intmd_parse_option (c, arg)     int c;     char *arg ATTRIBUTE_UNUSED;{  switch (c)    {    case OPTION_ARC5:      arc_mach_type = bfd_mach_arc_5;      break;    case OPTION_ARC:    case OPTION_ARC6:      arc_mach_type = bfd_mach_arc_6;      break;    case OPTION_ARC7:      arc_mach_type = bfd_mach_arc_7;      break;    case OPTION_ARC8:      arc_mach_type = bfd_mach_arc_8;      break;    case OPTION_EB:      byte_order = BIG_ENDIAN;      arc_target_format = "elf32-bigarc";      break;    case OPTION_EL:      byte_order = LITTLE_ENDIAN;      arc_target_format = "elf32-littlearc";      break;    default:      return 0;    }  return 1;}voidmd_show_usage (stream)     FILE *stream;{  fprintf (stream, "\ARC Options:\n\  -marc[5|6|7|8]          select processor variant (default arc%d)\n\  -EB                     assemble code for a big endian cpu\n\  -EL                     assemble code for a little endian cpu\n", arc_mach_type + 5);}/* This function is called once, at assembler startup time.  It should   set up all the tables, etc. that the MD part of the assembler will need.   Opcode selection is deferred until later because we might see a .option   command.  */voidmd_begin (){  /* The endianness can be chosen "at the factory".  */  target_big_endian = byte_order == BIG_ENDIAN;  if (!bfd_set_arch_mach (stdoutput, bfd_arch_arc, arc_mach_type))    as_warn ("could not set architecture and machine");  /* This call is necessary because we need to initialize `arc_operand_map'     which may be needed before we see the first insn.  */  arc_opcode_init_tables (arc_get_opcode_mach (arc_mach_type,					       target_big_endian));}/* Initialize the various opcode and operand tables.   MACH is one of bfd_mach_arc_xxx.  */static voidinit_opcode_tables (mach)     int mach;{  int i;  char *last;  if ((arc_suffix_hash = hash_new ()) == NULL)    as_fatal ("virtual memory exhausted");  if (!bfd_set_arch_mach (stdoutput, bfd_arch_arc, mach))    as_warn ("could not set architecture and machine");  /* This initializes a few things in arc-opc.c that we need.     This must be called before the various arc_xxx_supported fns.  */  arc_opcode_init_tables (arc_get_opcode_mach (mach, target_big_endian));  /* Only put the first entry of each equivalently named suffix in the     table.  */  last = "";  for (i = 0; i < arc_suffixes_count; i++)    {      if (strcmp (arc_suffixes[i].name, last) != 0)	hash_insert (arc_suffix_hash, arc_suffixes[i].name, (PTR) (arc_suffixes + i));      last = arc_suffixes[i].name;    }  /* Since registers don't have a prefix, we put them in the symbol table so     they can't be used as symbols.  This also simplifies argument parsing as     we can let gas parse registers for us.  The recorded register number is     the address of the register's entry in arc_reg_names.     If the register name is already in the table, then the existing     definition is assumed to be from an .ExtCoreRegister pseudo-op.  */  for (i = 0; i < arc_reg_names_count; i++)    {      if (symbol_find (arc_reg_names[i].name))	continue;      /* Use symbol_create here instead of symbol_new so we don't try to	 output registers into the object file's symbol table.  */      symbol_table_insert (symbol_create (arc_reg_names[i].name,					  reg_section,					  (int) &arc_reg_names[i],					  &zero_address_frag));    }  /* Tell `.option' it's too late.  */  cpu_tables_init_p = 1;}/* Insert an operand value into an instruction.   If REG is non-NULL, it is a register number and ignore VAL.  */static arc_insnarc_insert_operand (insn, operand, mods, reg, val, file, line)     arc_insn insn;     const struct arc_operand *operand;     int mods;     const struct arc_operand_value *reg;     offsetT val;     char *file;     unsigned int line;{  if (operand->bits != 32)    {      long min, max;      offsetT test;      if ((operand->flags & ARC_OPERAND_SIGNED) != 0)	{	  if ((operand->flags & ARC_OPERAND_SIGNOPT) != 0)	    max = (1 << operand->bits) - 1;	  else	    max = (1 << (operand->bits - 1)) - 1;	  min = - (1 << (operand->bits - 1));	}      else	{	  max = (1 << operand->bits) - 1;	  min = 0;	}      if ((operand->flags & ARC_OPERAND_NEGATIVE) != 0)	test = - val;      else	test = val;      if (test < (offsetT) min || test > (offsetT) max)	{	  const char *err =	    "operand out of range (%s not between %ld and %ld)";	  char buf[100];	  sprint_value (buf, test);	  if (file == (char *) NULL)	    as_warn (err, buf, min, max);	  else	    as_warn_where (file, line, err, buf, min, max);	}    }  if (operand->insert)    {      const char *errmsg;      errmsg = NULL;      insn = (*operand->insert) (insn, operand, mods, reg, (long) val, &errmsg);      if (errmsg != (const char *) NULL)	as_warn (errmsg);    }  else    insn |= (((long) val & ((1 << operand->bits) - 1))	     << operand->shift);  return insn;}/* 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 arc_fixup {  /* index into `arc_operands'  */  int opindex;  expressionS exp;};#define MAX_FIXUPS 5#define MAX_SUFFIXES 5/* This routine is called for each instruction to be assembled.  */voidmd_assemble (str)     char *str;{  const struct arc_opcode *opcode;  const struct arc_opcode *std_opcode;  struct arc_opcode *ext_opcode;  char *start;  const char *last_errmsg = 0;  arc_insn insn;  static int init_tables_p = 0;  /* Opcode table initialization is deferred until here because we have to     wait for a possible .option command.  */  if (!init_tables_p)    {      init_opcode_tables (arc_mach_type);      init_tables_p = 1;    }  /* Skip leading white space.  */  while (isspace (*str))    str++;  /* The instructions are stored in lists hashed by the first letter (though     we needn't care how they're hashed).  Get the first in the list.  */  ext_opcode = arc_ext_opcodes;  std_opcode = arc_opcode_lookup_asm (str);  /* Keep looking until we find a match.  */  start = str;  for (opcode = (ext_opcode ? ext_opcode : std_opcode);       opcode != NULL;       opcode = (ARC_OPCODE_NEXT_ASM (opcode)		 ? ARC_OPCODE_NEXT_ASM (opcode)		 : (ext_opcode ? ext_opcode = NULL, std_opcode : NULL)))    {      int past_opcode_p, fc, num_suffixes;      int fix_up_at = 0;      char *syn;      struct arc_fixup fixups[MAX_FIXUPS];      /* Used as a sanity check.  If we need a limm reloc, make sure we ask	 for an extra 4 bytes from frag_more.  */      int limm_reloc_p;      int ext_suffix_p;      const struct arc_operand_value *insn_suffixes[MAX_SUFFIXES];      /* Is this opcode supported by the selected cpu?  */      if (! arc_opcode_supported (opcode))	continue;      /* Scan the syntax string.  If it doesn't match, try the next one.  */      arc_opcode_init_insert ();      insn = opcode->value;      fc = 0;      past_opcode_p = 0;      num_suffixes = 0;      limm_reloc_p = 0;      ext_suffix_p = 0;      /* We don't check for (*str != '\0') here because we want to parse	 any trailing fake arguments in the syntax string.  */      for (str = start, syn = opcode->syntax; *syn != '\0';)	{	  int mods;	  const struct arc_operand *operand;	  /* Non operand chars must match exactly.  */	  if (*syn != '%' || *++syn == '%')	    {	      /* Handle '+' specially as we want to allow "ld r0,[sp-4]".  */	      /* ??? The syntax has changed to [sp,-4].  */	      if (0 && *syn == '+' && *str == '-')		{		  /* Skip over syn's +, but leave str's - alone.		     That makes the case identical to "ld r0,[sp+-4]".  */		  ++syn;		}	      else if (*str == *syn)		{		  if (*syn == ' ')		    past_opcode_p = 1;		  ++syn;		  ++str;		}	      else		break;	      continue;	    }	  /* We have an operand.  Pick out any modifiers.  */	  mods = 0;	  while (ARC_MOD_P (arc_operands[arc_operand_map[(int) *syn]].flags))	    {	      mods |= arc_operands[arc_operand_map[(int) *syn]].flags & ARC_MOD_BITS;	      ++syn;	    }	  operand = arc_operands + arc_operand_map[(int) *syn];	  if (operand->fmt == 0)	    as_fatal ("unknown syntax format character `%c'", *syn);	  if (operand->flags & ARC_OPERAND_FAKE)	    {	      const char *errmsg = NULL;	      if (operand->insert)		{		  insn = (*operand->insert) (insn, operand, mods, NULL, 0, &errmsg);		  if (errmsg != (const char *) NULL)		    {		      last_errmsg = errmsg;		      if (operand->flags & ARC_OPERAND_ERROR)			{			  as_bad (errmsg);			  return;			}		      else if (operand->flags & ARC_OPERAND_WARN)			as_warn (errmsg);		      break;		    }		  if (limm_reloc_p		      && (operand->flags && operand->flags & ARC_OPERAND_LIMM)		      && (operand->flags &			  (ARC_OPERAND_ABSOLUTE_BRANCH | ARC_OPERAND_ADDRESS)))		    {		      fixups[fix_up_at].opindex = arc_operand_map[operand->fmt];		    }		}	      ++syn;	    }	  /* Are we finished with suffixes?  */	  else if (!past_opcode_p)	    {	      int found;	      char c;	      char *s, *t;	      const struct arc_operand_value *suf, *suffix_end;	      const struct arc_operand_value *suffix = NULL;	      if (!(operand->flags & ARC_OPERAND_SUFFIX))		abort ();	      /* If we're at a space in the input string, we want to skip the		 remaining suffixes.  There may be some fake ones though, so

⌨️ 快捷键说明

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