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

📄 tc-sh.c

📁 基于4个mips核的noc设计
💻 C
📖 第 1 页 / 共 5 页
字号:
  name[nlen] = 0;  *str_p = op_end;  if (nlen == 0)    as_bad (_("can't find opcode "));  return (sh_opcode_info *) hash_find (opcode_hash_control, name);}/* Assemble a parallel processing insn.  */#define DDT_BASE 0xf000 /* Base value for double data transfer insns */static unsigned intassemble_ppi (op_end, opcode)     char *op_end;     sh_opcode_info *opcode;{  int movx = 0;  int movy = 0;  int cond = 0;  int field_b = 0;  char *output;  int move_code;  unsigned int size;  /* Some insn ignore one or more register fields, e.g. psts machl,a0.     Make sure we encode a defined insn pattern.  */  reg_x = 0;  reg_y = 0;  for (;;)    {      sh_operand_info operand[3];      if (opcode->arg[0] != A_END)	op_end = get_operands (opcode, op_end, operand);      opcode = get_specific (opcode, operand);      if (opcode == 0)	{	  /* Couldn't find an opcode which matched the operands.  */	  char *where = frag_more (2);	  size = 2;	  where[0] = 0x0;	  where[1] = 0x0;	  as_bad (_("invalid operands for opcode"));	  return size;	}      if (opcode->nibbles[0] != PPI)	as_bad (_("insn can't be combined with parallel processing insn"));      switch (opcode->nibbles[1])	{	case NOPX:	  if (movx)	    as_bad (_("multiple movx specifications"));	  movx = DDT_BASE;	  break;	case NOPY:	  if (movy)	    as_bad (_("multiple movy specifications"));	  movy = DDT_BASE;	  break;	case MOVX:	  if (movx)	    as_bad (_("multiple movx specifications"));	  if (reg_n < 4 || reg_n > 5)	    as_bad (_("invalid movx address register"));	  if (opcode->nibbles[2] & 8)	    {	      if (reg_m == A_A1_NUM)		movx = 1 << 7;	      else if (reg_m != A_A0_NUM)		as_bad (_("invalid movx dsp register"));	    }	  else	    {	      if (reg_x > 1)		as_bad (_("invalid movx dsp register"));	      movx = reg_x << 7;	    }	  movx += ((reg_n - 4) << 9) + (opcode->nibbles[2] << 2) + DDT_BASE;	  break;	case MOVY:	  if (movy)	    as_bad (_("multiple movy specifications"));	  if (opcode->nibbles[2] & 8)	    {	      /* Bit 3 in nibbles[2] is intended for bit 4 of the opcode,		 so add 8 more.  */	      movy = 8;	      if (reg_m == A_A1_NUM)		movy += 1 << 6;	      else if (reg_m != A_A0_NUM)		as_bad (_("invalid movy dsp register"));	    }	  else	    {	      if (reg_y > 1)		as_bad (_("invalid movy dsp register"));	      movy = reg_y << 6;	    }	  if (reg_n < 6 || reg_n > 7)	    as_bad (_("invalid movy address register"));	  movy += ((reg_n - 6) << 8) + opcode->nibbles[2] + DDT_BASE;	  break;	case PSH:	  if (operand[0].immediate.X_op != O_constant)	    as_bad (_("dsp immediate shift value not constant"));	  field_b = ((opcode->nibbles[2] << 12)		     | (operand[0].immediate.X_add_number & 127) << 4		     | reg_n);	  break;	case PPI3:	  if (field_b)	    as_bad (_("multiple parallel processing specifications"));	  field_b = ((opcode->nibbles[2] << 12) + (opcode->nibbles[3] << 8)		     + (reg_x << 6) + (reg_y << 4) + reg_n);	  break;	case PDC:	  if (cond)	    as_bad (_("multiple condition specifications"));	  cond = opcode->nibbles[2] << 8;	  if (*op_end)	    goto skip_cond_check;	  break;	case PPIC:	  if (field_b)	    as_bad (_("multiple parallel processing specifications"));	  field_b = ((opcode->nibbles[2] << 12) + (opcode->nibbles[3] << 8)		     + cond + (reg_x << 6) + (reg_y << 4) + reg_n);	  cond = 0;	  break;	case PMUL:	  if (field_b)	    {	      if ((field_b & 0xef00) != 0xa100)		as_bad (_("insn cannot be combined with pmuls"));	      field_b -= 0x8100;	      switch (field_b & 0xf)		{		case A_X0_NUM:		  field_b += 0 - A_X0_NUM;		  break;		case A_Y0_NUM:		  field_b += 1 - A_Y0_NUM;		  break;		case A_A0_NUM:		  field_b += 2 - A_A0_NUM;		  break;		case A_A1_NUM:		  field_b += 3 - A_A1_NUM;		  break;		default:		  as_bad (_("bad padd / psub pmuls output operand"));		}	    }	  field_b += 0x4000 + reg_efg;	  break;	default:	  abort ();	}      if (cond)	{	  as_bad (_("condition not followed by conditionalizable insn"));	  cond = 0;	}      if (! *op_end)	break;    skip_cond_check:      opcode = find_cooked_opcode (&op_end);      if (opcode == NULL)	{	  (as_bad	   (_("unrecognized characters at end of parallel processing insn")));	  break;	}    }  move_code = movx | movy;  if (field_b)    {      /* Parallel processing insn.  */      unsigned long ppi_code = (movx | movy | 0xf800) << 16 | field_b;      output = frag_more (4);      size = 4;      if (! target_big_endian)	{	  output[3] = ppi_code >> 8;	  output[2] = ppi_code;	}      else	{	  output[2] = ppi_code >> 8;	  output[3] = ppi_code;	}      move_code |= 0xf800;    }  else    {      /* Just a double data transfer.  */      output = frag_more (2);      size = 2;    }  if (! target_big_endian)    {      output[1] = move_code >> 8;      output[0] = move_code;    }  else    {      output[0] = move_code >> 8;      output[1] = move_code;    }  return size;}/* This is the guts of the machine-dependent assembler.  STR points to a   machine dependent instruction.  This function is supposed to emit   the frags/bytes it assembles to.  */voidmd_assemble (str)     char *str;{  unsigned char *op_end;  sh_operand_info operand[3];  sh_opcode_info *opcode;  unsigned int size = 0;  opcode = find_cooked_opcode (&str);  op_end = str;  if (opcode == NULL)    {      as_bad (_("unknown opcode"));      return;    }  if (sh_relax      && ! seg_info (now_seg)->tc_segment_info_data.in_code)    {      /* Output a CODE reloc to tell the linker that the following         bytes are instructions, not data.  */      fix_new (frag_now, frag_now_fix (), 2, &abs_symbol, 0, 0,	       BFD_RELOC_SH_CODE);      seg_info (now_seg)->tc_segment_info_data.in_code = 1;    }  if (opcode->nibbles[0] == PPI)    {      size = assemble_ppi (op_end, opcode);    }  else    {      if (opcode->arg[0] == A_BDISP12	  || opcode->arg[0] == A_BDISP8)	{	  parse_exp (op_end + 1, &operand[0]);	  build_relax (opcode, &operand[0]);	}      else	{	  if (opcode->arg[0] == A_END)	    {	      /* Ignore trailing whitespace.  If there is any, it has already		 been compressed to a single space.  */	      if (*op_end == ' ')		op_end++;	    }	  else	    {	      op_end = get_operands (opcode, op_end, operand);	    }	  opcode = get_specific (opcode, operand);	  if (opcode == 0)	    {	      /* Couldn't find an opcode which matched the operands.  */	      char *where = frag_more (2);	      size = 2;	      where[0] = 0x0;	      where[1] = 0x0;	      as_bad (_("invalid operands for opcode"));	    }	  else	    {	      if (*op_end)		as_bad (_("excess operands: '%s'"), op_end);	      size = build_Mytes (opcode, operand);	    }	}    }#ifdef BFD_ASSEMBLER  dwarf2_emit_insn (size);#endif}/* This routine is called each time a label definition is seen.  It   emits a BFD_RELOC_SH_LABEL reloc if necessary.  */voidsh_frob_label (){  static fragS *last_label_frag;  static int last_label_offset;  if (sh_relax      && seg_info (now_seg)->tc_segment_info_data.in_code)    {      int offset;      offset = frag_now_fix ();      if (frag_now != last_label_frag	  || offset != last_label_offset)	{	  fix_new (frag_now, offset, 2, &abs_symbol, 0, 0, BFD_RELOC_SH_LABEL);	  last_label_frag = frag_now;	  last_label_offset = offset;	}    }}/* This routine is called when the assembler is about to output some   data.  It emits a BFD_RELOC_SH_DATA reloc if necessary.  */voidsh_flush_pending_output (){  if (sh_relax      && seg_info (now_seg)->tc_segment_info_data.in_code)    {      fix_new (frag_now, frag_now_fix (), 2, &abs_symbol, 0, 0,	       BFD_RELOC_SH_DATA);      seg_info (now_seg)->tc_segment_info_data.in_code = 0;    }}symbolS *md_undefined_symbol (name)     char *name;{#ifdef OBJ_ELF  /* Under ELF we need to default _GLOBAL_OFFSET_TABLE.  Otherwise we     have no need to default values of symbols.  */  if (strcmp (name, GLOBAL_OFFSET_TABLE_NAME) == 0)    {      if (!GOT_symbol)	{	  if (symbol_find (name))	    as_bad ("GOT already in the symbol table");	  GOT_symbol = symbol_new (name, undefined_section,				   (valueT)0, & zero_address_frag);	}      return GOT_symbol;    }#endif /* OBJ_ELF */  return 0;}#ifdef OBJ_COFF#ifndef BFD_ASSEMBLERvoidtc_crawl_symbol_chain (headers)     object_headers *headers;{  printf (_("call to tc_crawl_symbol_chain \n"));}voidtc_headers_hook (headers)     object_headers *headers;{  printf (_("call to tc_headers_hook \n"));}#endif#endif/* Various routines to kill one day.  *//* Equal to MAX_PRECISION in atof-ieee.c.  */#define MAX_LITTLENUMS 6/* 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.  */char *md_atof (type, litP, sizeP)     int type;     char *litP;     int *sizeP;{  int prec;  LITTLENUM_TYPE words[4];  char *t;  int i;  switch (type)    {    case 'f':      prec = 2;      break;    case 'd':      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 * 2;  if (! target_big_endian)    {      for (i = prec - 1; i >= 0; i--)	{	  md_number_to_chars (litP, (valueT) words[i], 2);	  litP += 2;	}    }  else    {      for (i = 0; i < prec; i++)	{	  md_number_to_chars (litP, (valueT) words[i], 2);	  litP += 2;	}    }  return NULL;}/* Handle the .uses pseudo-op.  This pseudo-op is used just before a   call instruction.  It refers to a label of the instruction which   loads the register which the call uses.  We use it to generate a   special reloc for the linker.  */static voids_uses (ignore)     int ignore ATTRIBUTE_UNUSED;{  expressionS ex;  if (! sh_relax)    as_warn (_(".uses pseudo-op seen when not relaxing"));  expression (&ex);  if (ex.X_op != O_symbol || ex.X_add_number != 0)    {      as_bad (_("bad .uses format"));      ignore_rest_of_line ();      return;    }  fix_new_exp (frag_now, frag_now_fix (), 2, &ex, 1, BFD_RELOC_SH_USES);  demand_empty_rest_of_line ();}CONST char *md_shortopts = "";struct option md_longopts[] ={#define OPTION_RELAX  (OPTION_MD_BASE)#define OPTION_LITTLE (OPTION_MD_BASE + 1)#define OPTION_SMALL (OPTION_LITTLE + 1)#define OPTION_DSP (OPTION_SMALL + 1)  {"relax", no_argument, NULL, OPTION_RELAX},  {"little", no_argument, NULL, OPTION_LITTLE},  {"small", no_argument, NULL, OPTION_SMALL},  {"dsp", no_argument, NULL, OPTION_DSP},  {NULL, no_argument, NULL, 0}};size_t md_longopts_size = sizeof (md_longopts);intmd_parse_option (c, arg)     int c;     char *arg ATTRIBUTE_UNUSED;{  switch (c)    {    case OPTION_RELAX:      sh_relax = 1;      break;    case OPTION_LITTLE:      shl = 1;      target_big_endian = 0;      break;    case OPTION_SMALL:      sh_small = 1;      break;    case OPTION_DSP:      sh_dsp = 1;      break;    default:      return 0;    }  return 1;}voidmd_show_usage (stream)     FILE *stream;{  fprintf (stream, _("\SH options:\n\-little			generate little endian code\n\-relax			alter jump instructions for long displacements\n\-small			align sections to 4 byte boundaries, not 16\n\-dsp			enable sh-dsp insns, and disable sh3e / sh4 insns.\n"));}voidtc_Nout_fix_to_chars (){  printf (_("call to tc_Nout_fix_to_chars \n"));  abort ();}/* This struct is used to pass arguments to sh_count_relocs through   bfd_map_over_sections.  */

⌨️ 快捷键说明

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