tc-ns32k.c

来自「基于4个mips核的noc设计」· C语言 代码 · 共 2,407 行 · 第 1/4 页

C
2,407
字号
/* ns32k.c  -- Assemble on the National Semiconductor 32k series   Copyright 1987, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,   2001   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.  *//*#define SHOW_NUM 1*//* Uncomment for debugging.  */#include <stdio.h>#include <ctype.h>#include "as.h"#include "opcode/ns32k.h"#include "obstack.h"/* Macros.  */#define IIF_ENTRIES 13		/* Number of entries in iif.  */#define PRIVATE_SIZE 256	/* Size of my garbage memory.  */#define MAX_ARGS 4#define DEFAULT	-1		/* addr_mode returns this value when                                   plain constant or label is                                   encountered.  */#define IIF(ptr,a1,c1,e1,g1,i1,k1,m1,o1,q1,s1,u1)	\    iif.iifP[ptr].type= a1;				\    iif.iifP[ptr].size= c1;				\    iif.iifP[ptr].object= e1;				\    iif.iifP[ptr].object_adjust= g1;			\    iif.iifP[ptr].pcrel= i1;				\    iif.iifP[ptr].pcrel_adjust= k1;			\    iif.iifP[ptr].im_disp= m1;				\    iif.iifP[ptr].relax_substate= o1;			\    iif.iifP[ptr].bit_fixP= q1;				\    iif.iifP[ptr].addr_mode= s1;			\    iif.iifP[ptr].bsr= u1;#ifdef SEQUENT_COMPATABILITY#define LINE_COMMENT_CHARS "|"#define ABSOLUTE_PREFIX '@'#define IMMEDIATE_PREFIX '#'#endif#ifndef LINE_COMMENT_CHARS#define LINE_COMMENT_CHARS "#"#endifconst char comment_chars[] = "#";const char line_comment_chars[] = LINE_COMMENT_CHARS;const char line_separator_chars[] = ";";#if !defined(ABSOLUTE_PREFIX) && !defined(IMMEDIATE_PREFIX)#define ABSOLUTE_PREFIX '@'	/* One or the other MUST be defined */#endifstruct addr_mode  {    char mode;			/* addressing mode of operand (0-31) */    char scaled_mode;		/* mode combined with scaled mode */    char scaled_reg;		/* register used in scaled+1 (1-8) */    char float_flag;		/* set if R0..R7 was F0..F7 ie a				   floating-point-register */    char am_size;		/* estimated max size of general addr-mode				   parts */    char im_disp;		/* if im_disp==1 we have a displacement */    char pcrel;			/* 1 if pcrel, this is really redundant info */    char disp_suffix[2];	/* length of displacement(s), 0=undefined */    char *disp[2];		/* pointer(s) at displacement(s)				   or immediates(s)     (ascii) */    char index_byte;		/* index byte */  };typedef struct addr_mode addr_modeS;char *freeptr, *freeptr_static;	/* Points at some number of free bytes.  */struct hash_control *inst_hash_handle;struct ns32k_opcode *desc;	/* Pointer at description of instruction.  */addr_modeS addr_modeP;const char EXP_CHARS[] = "eE";const char FLT_CHARS[] = "fd";	/* We don't want to support lowercase,                                   do we?  *//* UPPERCASE denotes live names when an instruction is built, IIF is * used as an intermediate form to store the actual parts of the * instruction. A ns32k machine instruction can be divided into a * couple of sub PARTs. When an instruction is assembled the * appropriate PART get an assignment. When an IIF has been completed * it is converted to a FRAGment as specified in AS.H.  *//* Internal structs.  */struct ns32k_option{  char *pattern;  unsigned long or;  unsigned long and;};typedef struct  {    int type;			/* how to interpret object */    int size;			/* Estimated max size of object */    unsigned long object;	/* binary data */    int object_adjust;		/* number added to object */    int pcrel;			/* True if object is pcrel */    int pcrel_adjust;		/* length in bytes from the					   instruction start to the					   displacement */    int im_disp;		/* True if the object is a displacement */    relax_substateT relax_substate;	/* Initial relaxsubstate */    bit_fixS *bit_fixP;		/* Pointer at bit_fix struct */    int addr_mode;		/* What addrmode do we associate with this				   iif-entry */    char bsr;			/* Sequent hack */  } iif_entryT;			/* Internal Instruction Format */struct int_ins_form  {    int instr_size;		/* Max size of instruction in bytes.  */    iif_entryT iifP[IIF_ENTRIES + 1];  };struct int_ins_form iif;expressionS exprP;char *input_line_pointer;/* Description of the PARTs in IIF  object[n]:   0	total length in bytes of entries in iif   1	opcode   2	index_byte_a   3	index_byte_b   4	disp_a_1   5	disp_a_2   6	disp_b_1   7	disp_b_2   8	imm_a   9	imm_b   10	implied1   11	implied2   For every entry there is a datalength in bytes. This is stored in size[n].  	 0,	the objectlength is not explicitly given by the instruction  		and the operand is undefined. This is a case for relaxation.  		Reserve 4 bytes for the final object.  	 1,	the entry contains one byte  	 2,	the entry contains two bytes  	 3,	the entry contains three bytes  	 4,	the entry contains four bytes  	etc   Furthermore, every entry has a data type identifier in type[n].   	 0,	the entry is void, ignore it.   	 1,	the entry is a binary number.  	 2,	the entry is a pointer at an expression.  		Where expression may be as simple as a single '1',  		and as complicated as  foo-bar+12,   		foo and bar may be undefined but suffixed by :{b|w|d} to  		control the length of the object.  	 3,	the entry is a pointer at a bignum struct   The low-order-byte coresponds to low physical memory.   Obviously a FRAGment must be created for each valid disp in PART whose   datalength is undefined (to bad) .   The case where just the expression is undefined is less severe and is   handled by fix. Here the number of bytes in the objectfile is known.   With this representation we simplify the assembly and separates the   machine dependent/independent parts in a more clean way (said OE).  */struct ns32k_option opt1[] =		/* restore, exit */{  {"r0", 0x80, 0xff},  {"r1", 0x40, 0xff},  {"r2", 0x20, 0xff},  {"r3", 0x10, 0xff},  {"r4", 0x08, 0xff},  {"r5", 0x04, 0xff},  {"r6", 0x02, 0xff},  {"r7", 0x01, 0xff},  {0, 0x00, 0xff}};struct ns32k_option opt2[] =		/* save, enter */{  {"r0", 0x01, 0xff},  {"r1", 0x02, 0xff},  {"r2", 0x04, 0xff},  {"r3", 0x08, 0xff},  {"r4", 0x10, 0xff},  {"r5", 0x20, 0xff},  {"r6", 0x40, 0xff},  {"r7", 0x80, 0xff},  {0, 0x00, 0xff}};struct ns32k_option opt3[] =		/* setcfg */{  {"c", 0x8, 0xff},  {"m", 0x4, 0xff},  {"f", 0x2, 0xff},  {"i", 0x1, 0xff},  {0, 0x0, 0xff}};struct ns32k_option opt4[] =		/* cinv */{  {"a", 0x4, 0xff},  {"i", 0x2, 0xff},  {"d", 0x1, 0xff},  {0, 0x0, 0xff}};struct ns32k_option opt5[] =		/* string inst */{  {"b", 0x2, 0xff},  {"u", 0xc, 0xff},  {"w", 0x4, 0xff},  {0, 0x0, 0xff}};struct ns32k_option opt6[] =		/* plain reg ext,cvtp etc */{  {"r0", 0x00, 0xff},  {"r1", 0x01, 0xff},  {"r2", 0x02, 0xff},  {"r3", 0x03, 0xff},  {"r4", 0x04, 0xff},  {"r5", 0x05, 0xff},  {"r6", 0x06, 0xff},  {"r7", 0x07, 0xff},  {0, 0x00, 0xff}};#if !defined(NS32032) && !defined(NS32532)#define NS32532#endifstruct ns32k_option cpureg_532[] =	/* lpr spr */{  {"us", 0x0, 0xff},  {"dcr", 0x1, 0xff},  {"bpc", 0x2, 0xff},  {"dsr", 0x3, 0xff},  {"car", 0x4, 0xff},  {"fp", 0x8, 0xff},  {"sp", 0x9, 0xff},  {"sb", 0xa, 0xff},  {"usp", 0xb, 0xff},  {"cfg", 0xc, 0xff},  {"psr", 0xd, 0xff},  {"intbase", 0xe, 0xff},  {"mod", 0xf, 0xff},  {0, 0x00, 0xff}};struct ns32k_option mmureg_532[] =	/* lmr smr */{  {"mcr", 0x9, 0xff},  {"msr", 0xa, 0xff},  {"tear", 0xb, 0xff},  {"ptb0", 0xc, 0xff},  {"ptb1", 0xd, 0xff},  {"ivar0", 0xe, 0xff},  {"ivar1", 0xf, 0xff},  {0, 0x0, 0xff}};struct ns32k_option cpureg_032[] =	/* lpr spr */{  {"upsr", 0x0, 0xff},  {"fp", 0x8, 0xff},  {"sp", 0x9, 0xff},  {"sb", 0xa, 0xff},  {"psr", 0xd, 0xff},  {"intbase", 0xe, 0xff},  {"mod", 0xf, 0xff},  {0, 0x0, 0xff}};struct ns32k_option mmureg_032[] =	/* lmr smr */{  {"bpr0", 0x0, 0xff},  {"bpr1", 0x1, 0xff},  {"pf0", 0x4, 0xff},  {"pf1", 0x5, 0xff},  {"sc", 0x8, 0xff},  {"msr", 0xa, 0xff},  {"bcnt", 0xb, 0xff},  {"ptb0", 0xc, 0xff},  {"ptb1", 0xd, 0xff},  {"eia", 0xf, 0xff},  {0, 0x0, 0xff}};#if defined(NS32532)struct ns32k_option *cpureg = cpureg_532;struct ns32k_option *mmureg = mmureg_532;#elsestruct ns32k_option *cpureg = cpureg_032;struct ns32k_option *mmureg = mmureg_032;#endifconst pseudo_typeS md_pseudo_table[] ={					/* So far empty.  */  {0, 0, 0}};#define IND(x,y)	(((x)<<2)+(y))/* Those are index's to relax groups in md_relax_table ie it must be   multiplied by 4 to point at a group start. Viz IND(x,y) Se function   relax_segment in write.c for more info.  */#define BRANCH		1#define PCREL		2/* Those are index's to entries in a relax group.  */#define BYTE		0#define WORD		1#define DOUBLE		2#define UNDEF           3/* Those limits are calculated from the displacement start in memory.   The ns32k uses the begining of the instruction as displacement   base.  This type of displacements could be handled here by moving   the limit window up or down. I choose to use an internal   displacement base-adjust as there are other routines that must   consider this. Also, as we have two various offset-adjusts in the   ns32k (acb versus br/brs/jsr/bcond), two set of limits would have   had to be used.  Now we dont have to think about that.  */const relax_typeS md_relax_table[] ={  {1, 1, 0, 0},  {1, 1, 0, 0},  {1, 1, 0, 0},  {1, 1, 0, 0},  {(63), (-64), 1, IND (BRANCH, WORD)},  {(8192), (-8192), 2, IND (BRANCH, DOUBLE)},  {0, 0, 4, 0},  {1, 1, 0, 0}};/* Array used to test if mode contains displacements.   Value is true if mode contains displacement.  */char disp_test[] ={0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1};/* Array used to calculate max size of displacements.  */char disp_size[] ={4, 1, 2, 0, 4};static void evaluate_expr PARAMS ((expressionS * resultP, char *ptr));static void md_number_to_disp PARAMS ((char *buf, long val, int n));static void md_number_to_imm PARAMS ((char *buf, long val, int n));/* Parse a general operand into an addressingmode struct   In:  pointer at operand in ascii form        pointer at addr_mode struct for result        the level of recursion. (always 0 or 1)   Out: data in addr_mode struct.  */intaddr_mode (operand, addr_modeP, recursive_level)     char *operand;     register addr_modeS *addr_modeP;     int recursive_level;{  register char *str;  register int i;  register int strl;  register int mode;  int j;  mode = DEFAULT;		/* default */  addr_modeP->scaled_mode = 0;	/* why not */  addr_modeP->scaled_reg = 0;	/* if 0, not scaled index */  addr_modeP->float_flag = 0;  addr_modeP->am_size = 0;  addr_modeP->im_disp = 0;  addr_modeP->pcrel = 0;	/* not set in this function */  addr_modeP->disp_suffix[0] = 0;  addr_modeP->disp_suffix[1] = 0;  addr_modeP->disp[0] = NULL;  addr_modeP->disp[1] = NULL;  str = operand;  if (str[0] == 0)    return 0;  strl = strlen (str);  switch (str[0])    {      /* The following three case statements controls the mode-chars	 this is the place to ed if you want to change them.  */#ifdef ABSOLUTE_PREFIX    case ABSOLUTE_PREFIX:      if (str[strl - 1] == ']')	break;      addr_modeP->mode = 21;	/* absolute */      addr_modeP->disp[0] = str + 1;      return -1;#endif#ifdef IMMEDIATE_PREFIX    case IMMEDIATE_PREFIX:      if (str[strl - 1] == ']')	break;      addr_modeP->mode = 20;	/* immediate */      addr_modeP->disp[0] = str + 1;      return -1;#endif    case '.':      if (str[strl - 1] != ']')	{	  switch (str[1])	    {	    case '-':	    case '+':	      if (str[2] != '\000')		{		  addr_modeP->mode = 27;	/* pc-relativ */		  addr_modeP->disp[0] = str + 2;		  return -1;		}	    default:	      as_warn (_("Invalid syntax in PC-relative addressing mode"));	      return 0;	    }	}      break;    case 'e':      if (str[strl - 1] != ']')	{	  if ((!strncmp (str, "ext(", 4)) && strl > 7)	    {				/* external */	      addr_modeP->disp[0] = str + 4;	      i = 0;	      j = 2;	      do		{			/* disp[0]'s termination point */		  j += 1;		  if (str[j] == '(')		    i++;		  if (str[j] == ')')		    i--;		}	      while (j < strl && i != 0);	      if (i != 0 || !(str[j + 1] == '-' || str[j + 1] == '+'))		{		  as_warn (_("Invalid syntax in External addressing mode"));		  return (0);		}	      str[j] = '\000';		/* null terminate disp[0] */	      addr_modeP->disp[1] = str + j + 2;	      addr_modeP->mode = 22;	      return -1;	    }	}      break;    default:      ;    }  strl = strlen (str);  switch (strl)    {    case 2:      switch (str[0])	{	case 'f':	  addr_modeP->float_flag = 1;	  /* Drop through.  */	case 'r':	  if (str[1] >= '0' && str[1] < '8')	    {	      addr_modeP->mode = str[1] - '0';	      return -1;	    }	  break;	default:	  break;	}      /* Drop through.  */    case 3:      if (!strncmp (str, "tos", 3))	{	  addr_modeP->mode = 23;	/* TopOfStack */	  return -1;	}      break;    default:      break;    }  if (strl > 4)    {      if (str[strl - 1] == ')')	{	  if (str[strl - 2] == ')')	    {	      if (!strncmp (&str[strl - 5], "(fp", 3))		mode = 16;		/* Memory Relative.  */	      else if (!strncmp (&str[strl - 5], "(sp", 3))		mode = 17;	      else if (!strncmp (&str[strl - 5], "(sb", 3))		mode = 18;	      if (mode != DEFAULT)		{			/* Memory relative.  */		  addr_modeP->mode = mode;		  j = strl - 5;		/* Temp for end of disp[0].  */		  i = 0;		  do		    {		      strl -= 1;		      if (str[strl] == ')')			i++;		      if (str[strl] == '(')			i--;		    }		  while (strl > -1 && i != 0);		  if (i != 0)		    {		      as_warn (_("Invalid syntax in Memory Relative addressing mode"));		      return (0);		    }		  addr_modeP->disp[1] = str;		  addr_modeP->disp[0] = str + strl + 1;		  str[j] = '\000';	/* Null terminate disp[0] .  */		  str[strl] = '\000';	/* Null terminate disp[1].  */		  return -1;		}	    }	  switch (str[strl - 3])	    {	    case 'r':	    case 'R':	      if (str[strl - 2] >= '0'		  && str[strl - 2] < '8'		  && str[strl - 4] == '(')		{		  addr_modeP->mode = str[strl - 2] - '0' + 8;		  addr_modeP->disp[0] = str;		  str[strl - 4] = 0;		  return -1;		/* reg rel */		}	      /* Drop through.  */	    default:	      if (!strncmp (&str[strl - 4], "(fp", 3))		mode = 24;	      else if (!strncmp (&str[strl - 4], "(sp", 3))		mode = 25;	      else if (!strncmp (&str[strl - 4], "(sb", 3))		mode = 26;	      else if (!strncmp (&str[strl - 4], "(pc", 3))		mode = 27;	      if (mode != DEFAULT)		{		  addr_modeP->mode = mode;		  addr_modeP->disp[0] = str;		  str[strl - 4] = '\0';		  return -1;		/* Memory space.  */		}	    }	}      /* No trailing ')' do we have a ']' ?  */      if (str[strl - 1] == ']')	{

⌨️ 快捷键说明

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