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

📄 i860.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/* i860.c -- Assemble for the I860   Copyright (C) 1989 Free Software Foundation, Inc.This file is part of GAS, the GNU Assembler.GAS is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 1, 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 ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GAS; see the file COPYING.  If not, write tothe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */#include <stdio.h>#include <ctype.h>#include "i860-opcode.h"#include "as.h"#include "frags.h"#include "struc-symbol.h"#include "flonum.h"#include "expr.h"#include "hash.h"#include "md.h"#include "i860.h"	/* position dependent redefine */#include "write.h"#include "read.h"#include "symbols.h"void md_begin();void md_end();void md_number_to_chars();void md_assemble();char *md_atof();void md_convert_frag();void md_create_short_jump();void md_create_long_jump();int  md_estimate_size_before_relax();void md_number_to_imm();void md_number_to_disp();void md_number_to_field();void md_ri_to_chars();static void i860_ip();void emit_relocations();const relax_typeS md_relax_table[] = { 0 };/* handle of the OPCODE hash table */static struct hash_control *op_hash = NULL;static void s_dual(), s_enddual();static void s_atmp();const pseudo_typeSmd_pseudo_table[] = {    { "dual",       s_dual,     4 },    { "enddual",    s_enddual,  4 },    { "atmp",	    s_atmp,	4 },    { NULL,         0,          0 },};int md_short_jump_size = 4;int md_long_jump_size = 4;int omagic  =  OMAGIC;  /* Magic number for header *//* This array holds the chars that always start a comment.  If the    pre-processor is disabled, these aren't very useful */char comment_chars[] = "!/";	/* JF removed '|' from 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 '/*' will always start a comment */char line_comment_chars[] = "#/";/* Chars that can be used to separate mant from exp in floating point nums */char EXP_CHARS[] = "eE";/* Chars that mean this number is a floating point constant *//* As in 0f12.456 *//* or    0d1.2345e12 */char FLT_CHARS[] = "rRsSfFdDxXpP";/* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be   changed in read.c .  Ideally it shouldn't have to know about it at all,   but nothing is ideal around here. */int size_reloc_info = sizeof(struct relocation_info);static unsigned char octal[256];#define isoctal(c)  octal[c]static unsigned char toHex[256];struct i860_it {    char    *error;    unsigned long opcode;    struct nlist *nlistp;    expressionS exp;    int pcrel;    enum expand_type expand;    enum highlow_type highlow;    enum reloc_type reloc;} the_insn;#ifdef __STDC__static void print_insn(struct i860_it *insn);static int getExpression(char *str);#elsestatic void print_insn();static int getExpression();#endifstatic char *expr_end;static char last_expand;	/* error if expansion after branch */enum dual{    DUAL_OFF = 0, DUAL_ON, DUAL_DDOT, DUAL_ONDDOT,};static enum dual dual_mode = DUAL_OFF;	/* dual-instruction mode */static voids_dual()	/* floating point instructions have dual set */{    dual_mode = DUAL_ON;}static voids_enddual()	/* floating point instructions have dual set */{    dual_mode = DUAL_OFF;}static int atmp = 31; /* temporary register for pseudo's */static voids_atmp(){    register int temp;    if (strncmp(input_line_pointer, "sp", 2) == 0) {      input_line_pointer += 2;      atmp = 2;    }    else if (strncmp(input_line_pointer, "fp", 2) == 0) {      input_line_pointer += 2;      atmp = 3;    }    else if (strncmp(input_line_pointer, "r", 1) == 0) {      input_line_pointer += 1;      temp = get_absolute_expression();      if (temp >= 0 && temp <= 31)          atmp = temp;        else            as_warn("Unknown temporary pseudo register");    }    else {        as_warn("Unknown temporary pseudo register");    }    demand_empty_rest_of_line();    return;}/* 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.  */voidmd_begin(){  register char *retval = NULL;  int lose = 0;  register unsigned int i = 0;  op_hash = hash_new();  if (op_hash == NULL)    as_fatal("Virtual memory exhausted");  while (i < NUMOPCODES)    {      const char *name = i860_opcodes[i].name;      retval = hash_insert(op_hash, name, &i860_opcodes[i]);      if(retval != NULL && *retval != '\0')	{	  fprintf (stderr, "internal error: can't hash `%s': %s\n",		   i860_opcodes[i].name, retval);	  lose = 1;	}      do	{	  if (i860_opcodes[i].match & i860_opcodes[i].lose)	    {	      fprintf (stderr, "internal error: losing opcode: `%s' \"%s\"\n",		       i860_opcodes[i].name, i860_opcodes[i].args);	      lose = 1;	    }	  ++i;	} while (i < NUMOPCODES		 && !strcmp(i860_opcodes[i].name, name));    }  if (lose)    as_fatal ("Broken assembler.  No assembly attempted.");  for (i = '0'; i < '8'; ++i)    octal[i] = 1;  for (i = '0'; i <= '9'; ++i)    toHex[i] = i - '0';  for (i = 'a'; i <= 'f'; ++i)    toHex[i] = i + 10 - 'a';  for (i = 'A'; i <= 'F'; ++i)    toHex[i] = i + 10 - 'A';}voidmd_end(){    return;}voidmd_assemble(str)    char *str;{    char *toP;    int rsd;    int no_opcodes = 1;    int i;    struct i860_it pseudo[3];    assert(str);    i860_ip(str);    /* check for expandable flag to produce pseudo-instructions */    if (the_insn.expand != 0 && the_insn.highlow == NO_SPEC) {	for (i = 0; i < 3; i++)	    pseudo[i] = the_insn;	switch (the_insn.expand) {	case E_DELAY:		no_opcodes = 1;		break;	case E_MOV:	    if (the_insn.exp.X_add_symbol == NULL &&	        the_insn.exp.X_subtract_symbol == NULL &&		(the_insn.exp.X_add_number < (1 << 15) &&		 the_insn.exp.X_add_number >= -(1 << 15)))		break;	    /* or l%const,r0,ireg_dest */	    pseudo[0].opcode = (the_insn.opcode & 0x001f0000) | 0xe4000000;	    pseudo[0].highlow = PAIR;	    /* orh h%const,ireg_dest,ireg_dest */	    pseudo[1].opcode = (the_insn.opcode & 0x03ffffff) | 0xec000000 |		((the_insn.opcode & 0x001f0000) << 5);	    pseudo[1].highlow = HIGH;	    no_opcodes = 2;	    break;	case E_ADDR:	    if (the_insn.exp.X_add_symbol == NULL &&	        the_insn.exp.X_subtract_symbol == NULL)		break;	    /* orh ha%addr_expr,r0,r31 */	    pseudo[0].opcode = 0xec000000 | (atmp<<16);	    pseudo[0].highlow = HIGHADJ;	    pseudo[0].reloc = LOW0;	/* must overwrite */	    /* l%addr_expr(r31),ireg_dest */	    pseudo[1].opcode = (the_insn.opcode & ~0x003e0000) | (atmp << 21);	    pseudo[1].highlow = PAIR;	    no_opcodes = 2;	    break;	case E_U32:	/* 2nd version emulates Intel as, not doc. */	    if (the_insn.exp.X_add_symbol == NULL &&	        the_insn.exp.X_subtract_symbol == NULL &&		(the_insn.exp.X_add_number < (1 << 16) &&		 the_insn.exp.X_add_number >= 0))		break;	    /* $(opcode)h h%const,ireg_src2,ireg_dest	    pseudo[0].opcode = (the_insn.opcode & 0xf3ffffff) | 0x0c000000; */	    /* $(opcode)h h%const,ireg_src2,r31 */	    pseudo[0].opcode = (the_insn.opcode & 0xf3e0ffff) | 0x0c000000 |		(atmp << 16);	    pseudo[0].highlow = HIGH;	    /* $(opcode) l%const,ireg_dest,ireg_dest	    pseudo[1].opcode = (the_insn.opcode & 0xf01f0000) | 0x04000000 |		((the_insn.opcode & 0x001f0000) << 5); */	    /* $(opcode) l%const,r31,ireg_dest */	    pseudo[1].opcode = (the_insn.opcode & 0xf01f0000) | 0x04000000 |		(atmp << 21);	    pseudo[1].highlow = PAIR;	    no_opcodes = 2;	    break;	case E_AND:	/* 2nd version emulates Intel as, not doc. */	    if (the_insn.exp.X_add_symbol == NULL &&	        the_insn.exp.X_subtract_symbol == NULL &&		(the_insn.exp.X_add_number < (1 << 16) &&		 the_insn.exp.X_add_number >= 0))		break;	    /* andnot h%const,ireg_src2,ireg_dest	    pseudo[0].opcode = (the_insn.opcode & 0x03ffffff) | 0xd4000000; */	    /* andnot h%const,ireg_src2,r31 */	    pseudo[0].opcode = (the_insn.opcode & 0x03e0ffff) | 0xd4000000 |		(atmp << 16);	    pseudo[0].highlow = HIGH;	    pseudo[0].exp.X_add_number = -1 - the_insn.exp.X_add_number;	    /* andnot l%const,ireg_dest,ireg_dest	    pseudo[1].opcode = (the_insn.opcode & 0x001f0000) | 0xd4000000 |		((the_insn.opcode & 0x001f0000) << 5); */	    /* andnot l%const,r31,ireg_dest */	    pseudo[1].opcode = (the_insn.opcode & 0x001f0000) | 0xd4000000 |		(atmp << 21);	    pseudo[1].highlow = PAIR;	    pseudo[1].exp.X_add_number = -1 - the_insn.exp.X_add_number;	    no_opcodes = 2;	    break;	case E_S32:	    if (the_insn.exp.X_add_symbol == NULL &&	        the_insn.exp.X_subtract_symbol == NULL &&		(the_insn.exp.X_add_number < (1 << 15) &&		 the_insn.exp.X_add_number >= -(1 << 15)))		break;	    /* orh h%const,r0,r31 */	    pseudo[0].opcode = 0xec000000 | (atmp << 16);	    pseudo[0].highlow = HIGH;	    /* or l%const,r31,r31 */	    pseudo[1].opcode = 0xe4000000 | (atmp << 21) | (atmp << 16);	    pseudo[1].highlow = PAIR;	    /* r31,ireg_src2,ireg_dest */	    pseudo[2].opcode = (the_insn.opcode & ~0x0400ffff) | (atmp << 11);	    pseudo[2].reloc = NO_RELOC;	    no_opcodes = 3;	    break;    	default:	    abort();	}        the_insn = pseudo[0];	/* check for expanded opcode after branch or in dual */	if (no_opcodes > 1 && last_expand == TRUE)	    as_warn("Expanded opcode after delayed branch: `%s'", str);	if (no_opcodes > 1 && dual_mode != DUAL_OFF)	    as_warn("Expanded opcode in dual mode: `%s'", str);    }    i = 0;    do {	/* always produce at least one opcode */        toP = frag_more(4);        /* put out the opcode */        md_number_to_chars(toP, the_insn.opcode, 4);	/* check for expanded opcode after branch or in dual */	last_expand = the_insn.pcrel;        /* put out the symbol-dependent stuff */        if (the_insn.reloc != NO_RELOC) {	    fix_new(	        frag_now,                           /* which frag */	        (toP - frag_now->fr_literal), /* where */	        4,                                  /* size */	        the_insn.exp.X_add_symbol,	        the_insn.exp.X_subtract_symbol,	        the_insn.exp.X_add_number,	        the_insn.pcrel,		/* merge bit fields into one argument */		(int)(((the_insn.highlow & 0x3) << 4) | (the_insn.reloc & 0xf))	    );        }        the_insn = pseudo[++i];    } while (--no_opcodes > 0);}static voidi860_ip(str)    char *str;{    char *s;    const char *args;    char c;    unsigned long i;    struct i860_opcode *insn;    char *argsStart;    unsigned long   opcode;    unsigned int mask;    int match = FALSE;    int comma = 0;    for (s = str; islower(*s) || *s == '.' || *s == '3'; ++s)	;    switch (*s) {    case '\0':	break;    case ',':	comma = 1;	/*FALLTHROUGH*/    case ' ':	*s++ = '\0';	break;    default:	    as_warn("Unknown opcode: `%s'", str);	    exit(1);    }    if (strncmp(str, "d.", 2) == 0) {	/* check for d. opcode prefix */	if (dual_mode == DUAL_ON)	    dual_mode = DUAL_ONDDOT;	else	    dual_mode = DUAL_DDOT;	str += 2;    }    if ((insn = (struct i860_opcode *) hash_find(op_hash, str)) == NULL) {	if (dual_mode == DUAL_DDOT || dual_mode == DUAL_ONDDOT)	    str -= 2;	as_warn("Unknown opcode: `%s'", str);	return;    }    if (comma) {	*--s = ',';    }    argsStart = s;    for (;;) {	opcode = insn->match;	bzero(&the_insn, sizeof(the_insn));	the_insn.reloc = NO_RELOC;	/*	 * Build the opcode, checking as we go to make	 * sure that the operands match	 */	for (args = insn->args; ; ++args) {	    switch (*args) {	    case '\0':  /* end of args */		if (*s == '\0') {		    match = TRUE;		}		break;	    case '+':	    case '(':   /* these must match exactly */	    case ')':	    case ',':	    case ' ':		if (*s++ == *args)		    continue;		break;	    case '#':   /* must be at least one digit */		if (isdigit(*s++)) {		    while (isdigit(*s)) {			++s;		    }		    continue;		}		break;	    case '1':   /* next operand must be a register */	    case '2':	    case 'd':		switch (*s) {		case 'f':   /* frame pointer */		    s++;		    if (*s++ == 'p') {			mask = 0x3;			break;		    }		    goto error;		case 's':   /* stack pointer */		    s++;		    if (*s++ == 'p') {			mask= 0x2;			break;		    }		    goto error;		case 'r': /* any register */		    s++;		    if (!isdigit(c = *s++)) {			goto error;		    }		    if (isdigit(*s)) {		        if ((c = 10 * (c - '0') + (*s++ - '0')) >= 32) {			    goto error;			}		    } else {			c -= '0';		    }		    mask= c;		    break;		default:	/* not this opcode */		    goto error;		}		/*		 * Got the register, now figure out where		 * it goes in the opcode.		 */		switch (*args) {		case '1':		    opcode |= mask << 11;		    continue;		case '2':		    opcode |= mask << 21;		    continue;		case 'd':		    opcode |= mask << 16;		    continue;		}		break;	    case 'e':    /* next operand is a floating point register */	    case 'f':	    case 'g':	        if (*s++ == 'f' && isdigit(*s)) {		    mask = *s++;		    if (isdigit(*s)) {			mask = 10 * (mask - '0') + (*s++ - '0');			if (mask >= 32) {			    break;			}		    } else {			mask -= '0';		    }		    switch (*args) {		    case 'e':			opcode |= mask << 11;			continue;		    case 'f':			opcode |= mask << 21;			continue;		    case 'g':			opcode |= mask << 16;			if (dual_mode != DUAL_OFF)			    opcode |= (1 << 9);	/* dual mode instruction */			if (dual_mode == DUAL_DDOT)			    dual_mode = DUAL_OFF;			if (dual_mode == DUAL_ONDDOT)			    dual_mode = DUAL_ON;			if ((opcode & (1 << 10)) && (mask == ((opcode >> 11) & 0x1f)))			    as_warn("Fsr1 equals fdest with Pipelining");			continue;		    }		}		break;

⌨️ 快捷键说明

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