/* tc-a29k.c -- Assemble for the AMD 29000.
- Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+ Copyright (C) 1989, 90, 91, 92, 93, 94, 95, 1998
+ Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
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. */
+ 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. */
/* John Gilmore has reorganized this module somewhat, to make it easier
to convert it to new machines' assemblers as desired. There was too
much bloody rewriting required before. There still probably is. */
-#include "ctype.h"
+#include <ctype.h>
#include "as.h"
#include "opcode/a29k.h"
#define machine_ip a29k_ip
#define machine_it a29k_it
-const relax_typeS md_relax_table[] =
-{
- { 0, 0, 0, 0 }
-};
-
#define IMMEDIATE_BIT 0x01000000 /* Turns RB into Immediate */
#define ABSOLUTE_BIT 0x01000000 /* Turns PC-relative to Absolute */
#define CE_BIT 0x00800000 /* Coprocessor enable in LOAD */
{NULL, 0, 0},
};
-int md_short_jump_size = 4;
-int md_long_jump_size = 4;
#if defined(BFD_HEADERS)
#ifdef RELSZ
const int md_reloc_size = RELSZ; /* Coff headers */
changed in read.c. Ideally it shouldn't have to know about it at
all, but nothing is ideal around here. */
-static unsigned char octal[256];
-#define isoctal(c) octal[c]
-static unsigned char toHex[256];
-
/*
* anull bit - causes the branch delay slot instructions to not be executed
*/
return;
}
- as_bad ("Unknown segment type");
+ as_bad (_("Unknown segment type"));
demand_empty_rest_of_line ();
- return;
}
static void
{
subseg_set (SEG_DATA, 1);
demand_empty_rest_of_line ();
- return;
}
#endif /* OBJ_COFF */
insert_sreg ("iba1", SREG + 25);
insert_sreg ("ibc1", SREG + 26);
+ /* Additional registers for the 29040. */
+ insert_sreg ("dba", SREG + 27);
+ insert_sreg ("dbc", SREG + 28);
+ insert_sreg ("cir", SREG + 29);
+ insert_sreg ("cdr", SREG + 30);
+
/* Unprotected special-purpose register names */
insert_sreg ("ipc", SREG + 128);
insert_sreg ("ipa", SREG + 129);
}
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';
+ as_fatal (_("Broken assembler. No assembly attempted."));
define_some_regs ();
}
-void
-md_end ()
-{
- return;
-}
-
/* Assemble a single instruction. Its label has already been handled
by the generic front end. We just parse opcode and operands, and
produce the bytes of data and relocation. */
}
char *
-parse_operand (s, operandp)
+parse_operand (s, operandp, opt)
char *s;
expressionS *operandp;
+ int opt;
{
char *save = input_line_pointer;
char *new;
input_line_pointer = s;
expression (operandp);
- if (operandp->X_op == O_absent)
- as_bad ("missing operand");
+ if (operandp->X_op == O_absent && ! opt)
+ as_bad (_("missing operand"));
new = input_line_pointer;
input_line_pointer = save;
return new;
break;
default:
- as_bad ("Unknown opcode: `%s'", str);
+ as_bad (_("Unknown opcode: `%s'"), str);
return;
}
if ((insn = (struct machine_opcode *) hash_find (op_hash, str)) == NULL)
{
- as_bad ("Unknown opcode `%s'.", str);
+ as_bad (_("Unknown opcode `%s'."), str);
return;
}
argsStart = s;
and do a "continue". If an operand fails to match, we "break". */
if (insn->args[0] != '\0')
- s = parse_operand (s, operand); /* Prime the pump */
+ {
+ /* Prime the pump. */
+ s = parse_operand (s, operand, insn->args[0] == 'I');
+ }
for (args = insn->args;; ++args)
{
the_insn.opcode = opcode;
return;
}
- as_bad ("Too many operands: %s", s);
+ as_bad (_("Too many operands: %s"), s);
break;
case ',': /* Must match a comma */
if (*s++ == ',')
{
- s = parse_operand (s, operand); /* Parse next opnd */
+ /* Parse next operand. */
+ s = parse_operand (s, operand, args[1] == 'I');
continue;
}
break;
}
else
{
- as_bad ("Immediate value of %ld is too large",
+ as_bad (_("Immediate value of %ld is too large"),
(long) operand->X_add_number);
continue;
}
}
else
{
- as_bad ("Immediate value of %ld is too large",
+ as_bad (_("Immediate value of %ld is too large"),
(long) operand->X_add_number);
continue;
}
opcode |= reg << 16;
continue;
}
- as_fatal ("failed sanity check.");
+ as_fatal (_("failed sanity check."));
break;
case 'x': /* 16 bit constant, zero-extended */
/* Make sure the 'A' case really exists. */
if ((insn->opcode | ABSOLUTE_BIT) != (insn + 1)->opcode)
break;
+ {
+ bfd_vma v, mask;
+ mask = 0x1ffff;
+ v = operand->X_add_number & ~ mask;
+ if (v)
+ as_bad ("call/jmp target out of range");
+ }
opcode |= ABSOLUTE_BIT |
(operand->X_add_number & 0x0003FC00) << 6 |
((operand->X_add_number & 0x000003FC) >> 2);
}
break;
+ case 'I': /* ID bits of INV and IRETINV. */
+ /* This operand is optional. */
+ if (operand->X_op == O_absent)
+ continue;
+ else if (operand->X_op == O_constant
+ && operand->X_add_number < 4)
+ {
+ opcode |= operand->X_add_number << 16;
+ continue;
+ }
+ break;
+
case 'd': /* FD bits of CONVERT */
if (operand->X_op == O_constant &&
operand->X_add_number < 4)
valueT val;
int n;
{
-
- switch (n)
- {
-
- case 4:
- *buf++ = val >> 24;
- *buf++ = val >> 16;
- case 2:
- *buf++ = val >> 8;
- case 1:
- *buf = val;
- break;
-
- default:
- as_fatal ("failed sanity check.");
- }
- return;
+ number_to_chars_bigendian (buf, val, n);
}
void
buf[3] = val;
break;
-#if 0
- case RELOC_PC10:
- case RELOC_PC22:
- case RELOC_JMP_TBL:
- case RELOC_SEGOFF16:
- case RELOC_GLOB_DAT:
- case RELOC_JMP_SLOT:
- case RELOC_RELATIVE:
-#endif
case RELOC_JUMPTARG: /* 00XX00XX pattern in a word */
+ if (!fixP->fx_done)
+ {
+ /* The linker tries to support both AMD and old GNU style
+ R_IREL relocs. That means that if the addend is exactly
+ the negative of the address within the section, the
+ linker will not handle it correctly. */
+ if (fixP->fx_pcrel
+ && val != 0
+ && val == - (fixP->fx_frag->fr_address + fixP->fx_where))
+ as_bad_where
+ (fixP->fx_file, fixP->fx_line,
+ "the linker will not handle this relocation correctly");
+ }
+ else if (fixP->fx_pcrel)
+ {
+ long v = val >> 17;
+ if (v != 0 && v != -1)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ "call/jmp target out of range");
+ }
+ else
+ /* this case was supposed to be handled in machine_ip */
+ abort ();
buf[1] = val >> 10; /* Holds bits 0003FFFC of address */
buf[3] = val >> 2;
break;
case NO_RELOC:
default:
- as_bad ("bad relocation type: 0x%02x", fixP->fx_r_type);
+ as_bad (_("bad relocation type: 0x%02x"), fixP->fx_r_type);
break;
}
- return;
}
#ifdef OBJ_COFF
case RELOC_JUMPTARG:
return (R_IREL);
default:
- printf ("need %o3\n", fixP->fx_r_type);
+ printf (_("need %o3\n"), fixP->fx_r_type);
abort ();
} /* switch on type */
/* should never be called for 29k */
void
-md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol)
- char *ptr;
- addressT from_addr, to_addr;
- fragS *frag;
- symbolS *to_symbol;
-{
- as_fatal ("a29k_create_short_jmp\n");
-}
-
-/* should never be called for 29k */
-void
-md_convert_frag (headers, fragP)
+md_convert_frag (headers, seg, fragP)
object_headers *headers;
+ segT seg;
register fragS *fragP;
{
- as_fatal ("a29k_convert_frag\n");
-}
-
-/* should never be called for 29k */
-void
-md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol)
- char *ptr;
- addressT from_addr;
- addressT to_addr;
- fragS *frag;
- symbolS *to_symbol;
-{
- as_fatal ("a29k_create_long_jump\n");
+ as_fatal (_("a29k_convert_frag\n"));
}
/* should never be called for a29k */
register fragS *fragP;
segT segtype;
{
- as_fatal ("a29k_estimate_size_before_relax\n");
+ as_fatal (_("a29k_estimate_size_before_relax\n"));
return 0;
}
fprintf (stderr, "\t\tX_add_number = %d\n",
insn->exp.X_add_number);
fprintf (stderr, "}\n");
- return;
}
#endif
}
#endif /* OBJ_AOUT */
+\f
+CONST char *md_shortopts = "";
+struct option md_longopts[] = {
+ {NULL, no_argument, NULL, 0}
+};
+size_t md_longopts_size = sizeof(md_longopts);
int
-md_parse_option (argP, cntP, vecP)
- char **argP;
- int *cntP;
- char ***vecP;
+md_parse_option (c, arg)
+ int c;
+ char *arg;
{
return 0;
}
+void
+md_show_usage (stream)
+ FILE *stream;
+{
+}
+\f
+/* This is called when a line is unrecognized. This is used to handle
+ definitions of a29k style local labels. */
+
+int
+a29k_unrecognized_line (c)
+ int c;
+{
+ int lab;
+ char *s;
+
+ if (c != '$'
+ || ! isdigit ((unsigned char) input_line_pointer[0]))
+ return 0;
+
+ s = input_line_pointer;
+
+ lab = 0;
+ while (isdigit ((unsigned char) *s))
+ {
+ lab = lab * 10 + *s - '0';
+ ++s;
+ }
+
+ if (*s != ':')
+ {
+ /* Not a label definition. */
+ return 0;
+ }
+
+ if (dollar_label_defined (lab))
+ {
+ as_bad (_("label \"$%d\" redefined"), lab);
+ return 0;
+ }
+
+ define_dollar_label (lab);
+ colon (dollar_label_name (lab, 0));
+ input_line_pointer = s + 1;
+
+ return 1;
+}
/* Default the values of symbols known that should be "predefined". We
don't bother to predefine them unless you actually use one, since there
long regnum;
char testbuf[5 + /*SLOP*/ 5];
- if (name[0] == 'g' || name[0] == 'G' || name[0] == 'l' || name[0] == 'L')
+ if (name[0] == 'g' || name[0] == 'G'
+ || name[0] == 'l' || name[0] == 'L'
+ || name[0] == 's' || name[0] == 'S')
{
/* Perhaps a global or local register name */
if (name[1] == 'r' || name[1] == 'R')
{
- /* Parse the number, make sure it has no extra zeroes or trailing
- chars */
+ long maxreg;
+
+ /* Parse the number, make sure it has no extra zeroes or
+ trailing chars. */
regnum = atol (&name[2]);
- if (regnum > 127)
- return 0;
+
+ if (name[0] == 's' || name[0] == 'S')
+ maxreg = 255;
+ else
+ maxreg = 127;
+ if (regnum > maxreg)
+ return NULL;
+
sprintf (testbuf, "%ld", regnum);
if (strcmp (testbuf, &name[2]) != 0)
- return 0; /* gr007 or lr7foo or whatever */
+ return NULL; /* gr007 or lr7foo or whatever */
/* We have a wiener! Define and return a new symbol for it. */
if (name[0] == 'l' || name[0] == 'L')
regnum += 128;
+ else if (name[0] == 's' || name[0] == 'S')
+ regnum += SREG;
return (symbol_new (name, SEG_REGISTER, (valueT) regnum,
&zero_address_frag));
}
}
- return 0;
+ return NULL;
}
/* Parse an operand that is machine-specific. */
(void) expression (expressionP);
if (expressionP->X_op != O_constant
|| expressionP->X_add_number > 255)
- as_bad ("Invalid expression after %%%%\n");
+ as_bad (_("Invalid expression after %%%%\n"));
expressionP->X_op = O_register;
}
else if (input_line_pointer[0] == '&')
input_line_pointer++; /* Skip & */
(void) expression (expressionP);
if (expressionP->X_op != O_register)
- as_bad ("Invalid register in & expression");
+ as_bad (_("Invalid register in & expression"));
else
expressionP->X_op = O_constant;
}
+ else if (input_line_pointer[0] == '$'
+ && isdigit ((unsigned char) input_line_pointer[1]))
+ {
+ long lab;
+ char *name;
+ symbolS *sym;
+
+ /* This is a local label. */
+ ++input_line_pointer;
+ lab = (long) get_absolute_expression ();
+ if (dollar_label_defined (lab))
+ {
+ name = dollar_label_name (lab, 0);
+ sym = symbol_find (name);
+ }
+ else
+ {
+ name = dollar_label_name (lab, 1);
+ sym = symbol_find_or_make (name);
+ }
+
+ expressionP->X_op = O_symbol;
+ expressionP->X_add_symbol = sym;
+ expressionP->X_add_number = 0;
+ }
+ else if (input_line_pointer[0] == '$')
+ {
+ char *s;
+ char type;
+ int fieldnum, fieldlimit;
+ LITTLENUM_TYPE floatbuf[8];
+
+ /* $float(), $doubleN(), or $extendN() convert floating values
+ to integers. */
+
+ s = input_line_pointer;
+
+ ++s;
+
+ fieldnum = 0;
+ if (strncmp (s, "double", sizeof "double" - 1) == 0)
+ {
+ s += sizeof "double" - 1;
+ type = 'd';
+ fieldlimit = 2;
+ }
+ else if (strncmp (s, "float", sizeof "float" - 1) == 0)
+ {
+ s += sizeof "float" - 1;
+ type = 'f';
+ fieldlimit = 1;
+ }
+ else if (strncmp (s, "extend", sizeof "extend" - 1) == 0)
+ {
+ s += sizeof "extend" - 1;
+ type = 'x';
+ fieldlimit = 4;
+ }
+ else
+ {
+ return;
+ }
+
+ if (isdigit (*s))
+ {
+ fieldnum = *s - '0';
+ ++s;
+ }
+ if (fieldnum >= fieldlimit)
+ return;
+
+ SKIP_WHITESPACE ();
+ if (*s != '(')
+ return;
+ ++s;
+ SKIP_WHITESPACE ();
+
+ s = atof_ieee (s, type, floatbuf);
+ if (s == NULL)
+ return;
+ s = s;
+
+ SKIP_WHITESPACE ();
+ if (*s != ')')
+ return;
+ ++s;
+ SKIP_WHITESPACE ();
+
+ input_line_pointer = s;
+ expressionP->X_op = O_constant;
+ expressionP->X_unsigned = 1;
+ expressionP->X_add_number = ((floatbuf[fieldnum * 2]
+ << LITTLENUM_NUMBER_OF_BITS)
+ + floatbuf[fieldnum * 2 + 1]);
+ }
}
/* Round up a section size to the appropriate boundary. */