home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 5
/
FreshFish_July-August1994.bin
/
bbs
/
gnu
/
gas-1.38-src.lha
/
src
/
amiga
/
gas-1.38
/
i860.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-09-22
|
28KB
|
1,143 lines
/* 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 modify
it under the terms of the GNU General Public License as published by
the 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 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, 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_typeS
md_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);
#else
static void print_insn();
static int getExpression();
#endif
static 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 void
s_dual() /* floating point instructions have dual set */
{
dual_mode = DUAL_ON;
}
static void
s_enddual() /* floating point instructions have dual set */
{
dual_mode = DUAL_OFF;
}
static int atmp = 31; /* temporary register for pseudo's */
static void
s_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. */
void
md_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';
}
void
md_end()
{
return;
}
void
md_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].opcod