aboutsummaryrefslogtreecommitdiff
path: root/gas
diff options
context:
space:
mode:
authorDavid Edelsohn <dje.gcc@gmail.com>1995-02-10 02:01:01 +0000
committerDavid Edelsohn <dje.gcc@gmail.com>1995-02-10 02:01:01 +0000
commit31add5f0c96ac11ac534dbb74abf9cd989270b8e (patch)
tree0aedb6fee43ee9fbf7c7343b94ced831d6f9448e /gas
parent2db01c3d5249a16d710acdc73412d4d4fd1a29c4 (diff)
downloadgdb-31add5f0c96ac11ac534dbb74abf9cd989270b8e.zip
gdb-31add5f0c96ac11ac534dbb74abf9cd989270b8e.tar.gz
gdb-31add5f0c96ac11ac534dbb74abf9cd989270b8e.tar.bz2
* config/tc-arc.c (md_pseudo_table): Add .cpu.
(comment_chars): Add ';'. (arc_mach_type, mach_type_specified, cpu_tables_init_p): New globals. (md_parse_option): Delete support for -mmult. Add -mcpu=xxx. (md_begin): Current ARCs are little endian. Call bfd_set_arch_mach to set the cpu type. (init_opcode_tables): New function. (md_begin): Ignore suffixes and registers not supported by cpu. (md_assemble): Initialize opcode tables here. Ignore opcodes not supported by selected cpu. Always ask for more memory in one piece. (arc_cpu): New function. (md_numbers_to_chars): Support both endians (will probably be needed eventually anyway). (md_apply_fix): Likewise.
Diffstat (limited to 'gas')
-rw-r--r--gas/config/tc-arc.c467
1 files changed, 230 insertions, 237 deletions
diff --git a/gas/config/tc-arc.c b/gas/config/tc-arc.c
index b229398..aa45592 100644
--- a/gas/config/tc-arc.c
+++ b/gas/config/tc-arc.c
@@ -1,5 +1,5 @@
/* tc-arc.c -- Assembler for the ARC
- Copyright (C) 1994 Free Software Foundation, Inc.
+ Copyright (C) 1994, 1995 Free Software Foundation, Inc.
Contributed by Doug Evans (dje@cygnus.com).
This file is part of GAS, the GNU Assembler.
@@ -23,8 +23,10 @@
#include "as.h"
#include "subsegs.h"
#include "opcode/arc.h"
+#include "elf/arc.h"
extern int target_big_endian;
+extern int arc_get_mach PARAMS ((char *));
static arc_insn arc_insert_operand PARAMS ((arc_insn insn,
const struct arc_operand *operand,
@@ -33,31 +35,22 @@ static arc_insn arc_insert_operand PARAMS ((arc_insn insn,
offsetT val,
char *file, unsigned int line));
-static void s_data1 PARAMS ((void));
-static void s_seg PARAMS ((int));
-static void s_proc PARAMS ((int));
-static void s_reserve PARAMS ((int));
-static void s_common PARAMS ((int));
+static void arc_common PARAMS ((int));
+static void arc_cpu PARAMS ((int));
+/*static void arc_rename PARAMS ((int));*/
+
+static int find_mach PARAMS ((char *));
const pseudo_typeS md_pseudo_table[] =
{
- {"align", s_align_bytes, 0}, /* Defaulting is invalid (0) */
- {"common", s_common, 0},
- {"global", s_globl, 0},
- {"half", cons, 2},
- {"optim", s_ignore, 0},
- {"proc", s_proc, 0},
- {"reserve", s_reserve, 0},
- {"seg", s_seg, 0},
- {"skip", s_space, 0},
- {"word", cons, 4},
- {"xword", cons, 8},
- {"pushsection", obj_elf_section, 0},
- {"popsection", obj_elf_previous, 0},
- {"uahalf", cons, 2},
- {"uaword", cons, 4},
- {"uaxword", cons, 8},
- {NULL, 0, 0},
+ { "align", s_align_bytes, 0 }, /* Defaulting is invalid (0) */
+ { "common", arc_common, 0 },
+/*{ "hword", cons, 2 }, - already exists */
+ { "word", cons, 4 },
+ { "xword", cons, 8 },
+ { "cpu", arc_cpu, 0 },
+/*{ "rename", arc_rename, 0 },*/
+ { NULL, 0, 0 },
};
const int md_short_jump_size = 4;
@@ -66,7 +59,7 @@ const int md_reloc_size = 12; /* Size of relocation record */
/* This array holds the chars that always start a comment. If the
pre-processor is disabled, these aren't very useful */
-const char comment_chars[] = "#";
+const char 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'
@@ -88,6 +81,16 @@ const char EXP_CHARS[] = "eE";
/* or 0d1.2345e12 */
const char FLT_CHARS[] = "rRsSfFdDxXpP";
+/* One of bfd_mach_arc_xxx. */
+static int arc_mach_type = bfd_mach_arc_base;
+
+/* Non-zero if the cpu type was specified on the command line. */
+static int mach_type_specified = 0;
+
+/* Non-zero if opcode tables have been initialized.
+ A .cpu command must appear before any instructions. */
+static int cpu_tables_init_p = 0;
+
static const char *arc_condition_codes[] =
{
"al", "eq", "ne", "p", "n", "c", "nc", "v",
@@ -99,13 +102,11 @@ static struct hash_control *arc_suffix_hash = NULL;
static struct hash_control *arc_reg_hash = NULL;
const char *md_shortopts = "m:";
-struct option md_longopts[] = {
- {NULL, no_argument, NULL, 0}
+struct option md_longopts[] =
+{
+ { NULL, no_argument, NULL, 0 }
};
-size_t md_longopts_size = sizeof(md_longopts);
-
-/* Non-zero if we accept the mul/mulu and variable shift insns. */
-static int have_mult = 0;
+size_t md_longopts_size = sizeof (md_longopts);
/*
* md_parse_option
@@ -122,14 +123,19 @@ md_parse_option (c, arg)
switch (c)
{
case 'm':
- if (strcmp (arg, "mult") == 0)
- have_mult = 1;
- else
+ if (strncmp (arg, "cpu=", 4) == 0)
{
- as_bad ("invalid architecture -m%s", arg);
- return 0;
+ int mach = arc_get_mach (arg + 4);
+
+ if (mach != -1)
+ {
+ arc_mach_type = mach;
+ mach_type_specified = 1;
+ break;
+ }
}
- break;
+ as_bad ("invalid architecture -m%s", arg);
+ return 0;
default:
return 0;
@@ -144,24 +150,55 @@ md_show_usage (stream)
{
fprintf (stream, "\
ARC options:\n\
--mmult recognize the mul/mulu and variable shift instructions\n");
+-mcpu={base,host,graphics,audio} select cpu type\n");
}
/* 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. */
+ set up all the tables, etc. that the MD part of the assembler will need.
+ Opcode selection is defered until later because we might see a .cpu
+ command. */
+
void
md_begin ()
{
- register unsigned int i = 0;
- char *last;
+ /* The endianness can be chosen "at the factory". One day we may have
+ to be bi-endian. */
+ target_big_endian = 0;
- target_big_endian = 1;
+ if (!bfd_set_arch_mach (stdoutput, bfd_arch_arc, arc_mach_type))
+ as_warn ("could not set architecture and machine");
+}
+
+/* Initialize the various opcode and operand tables.
+ MACH is one of bfd_mach_arc_xxx. */
+
+static void
+init_opcode_tables (mach)
+ int mach;
+{
+ register unsigned int i;
+ char *last;
+ /* Indexed by bfd_mach_arc_xxx. */
+ static int cpu_type_map[] =
+ {
+ ARC_CPU_BASE,
+ ARC_CPU_HOST,
+ ARC_CPU_GRAPHICS,
+ ARC_CPU_AUDIO,
+ };
if ((arc_ops_hash = hash_new ()) == NULL
|| (arc_suffix_hash = hash_new ()) == NULL
|| (arc_reg_hash = hash_new ()) == NULL)
as_fatal ("Virtual memory exhausted");
+ if (!bfd_set_arch_mach (stdoutput, bfd_arch_arc, mach))
+ as_warn ("could not set architecture and machine");
+
+ /* This initializes a few things in arc-opc.c that we need.
+ This must be called before the various arc_xxx_supported fns. */
+ arc_opcode_init_tables (cpu_type_map[mach]);
+
#if 0
for (i = 0; i < arc_opcodes_count; i++)
hash_insert (arc_ops_hash, arc_opcodes[i].name, (PTR) (arc_opcodes + i));
@@ -172,6 +209,8 @@ md_begin ()
last = "";
for (i = 0; i < arc_suffixes_count; i++)
{
+ if (! arc_opval_supported (&arc_suffixes[i]))
+ continue;
if (strcmp (arc_suffixes[i].name, last) != 0)
hash_insert (arc_suffix_hash, arc_suffixes[i].name, (PTR) (arc_suffixes + i));
last = arc_suffixes[i].name;
@@ -179,10 +218,14 @@ md_begin ()
/* ??? This is the simple version. See tc-arm.c for something snazzier. */
for (i = 0; i < arc_reg_names_count; i++)
- hash_insert (arc_reg_hash, arc_reg_names[i].name, (PTR) (arc_reg_names + i));
+ {
+ if (! arc_opval_supported (&arc_reg_names[i]))
+ continue;
+ hash_insert (arc_reg_hash, arc_reg_names[i].name, (PTR) (arc_reg_names + i));
+ }
- /* This initializes a few things in arc-opc.c that we need. */
- arc_opcode_init_tables (have_mult ? ARC_HAVE_MULT_SHIFT : 0);
+ /* Tell `s_cpu' it's too late. */
+ cpu_tables_init_p = 1;
}
/* Insert an operand value into an instruction.
@@ -275,6 +318,15 @@ md_assemble (str)
char *start;
arc_insn insn;
bfd_reloc_code_real_type reloc;
+ static int init_tables_p = 0;
+
+ /* Opcode table initialization is deferred until here because we have to
+ wait for a possible .cpu command. */
+ if (!init_tables_p)
+ {
+ init_opcode_tables (arc_mach_type);
+ init_tables_p = 1;
+ }
/* Skip leading white space. */
while (isspace (*str))
@@ -294,6 +346,7 @@ md_assemble (str)
/* Keep looking until we find a match. If we haven't found a match, and the
first character no longer matches, we needn't look any further. */
+
start = str;
for ( ; opcode < opcode_end && *opcode->syntax == *start; ++opcode)
{
@@ -302,6 +355,10 @@ md_assemble (str)
struct arc_fixup fixups[MAX_INSN_FIXUPS];
int fc,limm_reloc_p;
+ /* Is this opcode supported by the selected cpu? */
+ if (! arc_opcode_supported (opcode))
+ continue;
+
/* Scan the syntax string. If it doesn't match, try the next one. */
arc_opcode_init_insert ();
@@ -583,18 +640,26 @@ md_assemble (str)
if (*str != '\0')
as_bad ("junk at end of line: `%s'", str);
- /* Write out the instruction. */
- f = frag_more (4);
- md_number_to_chars (f, insn, 4);
-
+ /* Write out the instruction.
+ It is important to fetch enough space in one call to `frag_more'.
+ We use (f - frag_now->fr_literal) to compute where we are and we
+ don't want frag_now to change between calls. */
if (arc_opcode_limm_p (&limm))
{
- char *f2 = frag_more (4);
- md_number_to_chars (f2, limm, 4);
+ f = frag_more (8);
+ md_number_to_chars (f, insn, 4);
+ md_number_to_chars (f + 4, limm, 4);
}
else if (limm_reloc_p)
- /* Ahh! We need a limm reloc, but the tables think we don't. */
- abort ();
+ {
+ /* We need a limm reloc, but the tables think we don't. */
+ abort ();
+ }
+ else
+ {
+ f = frag_more (4);
+ md_number_to_chars (f, insn, 4);
+ }
/* Create any fixups. At this point we do not use a
bfd_reloc_code_real_type, but instead just use the operand index.
@@ -625,150 +690,8 @@ md_assemble (str)
as_bad ("bad instruction `%s'", start);
}
-/*
- * sort of like s_lcomm
- *
- */
-#ifndef OBJ_ELF
-static int max_alignment = 15;
-#endif
-
-static void
-s_reserve (ignore)
- int ignore;
-{
- char *name;
- char *p;
- char c;
- int align;
- int size;
- int temp;
- symbolS *symbolP;
-
- name = input_line_pointer;
- c = get_symbol_end ();
- p = input_line_pointer;
- *p = c;
- SKIP_WHITESPACE ();
-
- if (*input_line_pointer != ',')
- {
- as_bad ("Expected comma after name");
- ignore_rest_of_line ();
- return;
- }
-
- ++input_line_pointer;
-
- if ((size = get_absolute_expression ()) < 0)
- {
- as_bad ("BSS length (%d.) <0! Ignored.", size);
- ignore_rest_of_line ();
- return;
- } /* bad length */
-
- *p = 0;
- symbolP = symbol_find_or_make (name);
- *p = c;
-
- if (strncmp (input_line_pointer, ",\"bss\"", 6) != 0
- && strncmp (input_line_pointer, ",\".bss\"", 7) != 0)
- {
- as_bad ("bad .reserve segment -- expected BSS segment");
- return;
- }
-
- if (input_line_pointer[2] == '.')
- input_line_pointer += 7;
- else
- input_line_pointer += 6;
- SKIP_WHITESPACE ();
-
- if (*input_line_pointer == ',')
- {
- ++input_line_pointer;
-
- SKIP_WHITESPACE ();
- if (*input_line_pointer == '\n')
- {
- as_bad ("Missing alignment");
- return;
- }
-
- align = get_absolute_expression ();
-#ifndef OBJ_ELF
- if (align > max_alignment)
- {
- align = max_alignment;
- as_warn ("Alignment too large: %d. assumed.", align);
- }
-#endif
- if (align < 0)
- {
- align = 0;
- as_warn ("Alignment negative. 0 assumed.");
- }
-
- record_alignment (bss_section, align);
-
- /* convert to a power of 2 alignment */
- for (temp = 0; (align & 1) == 0; align >>= 1, ++temp);;
-
- if (align != 1)
- {
- as_bad ("Alignment not a power of 2");
- ignore_rest_of_line ();
- return;
- } /* not a power of two */
-
- align = temp;
- } /* if has optional alignment */
- else
- align = 0;
-
- if ((S_GET_SEGMENT (symbolP) == bss_section
- || !S_IS_DEFINED (symbolP))
-#ifdef OBJ_AOUT
- && S_GET_OTHER (symbolP) == 0
- && S_GET_DESC (symbolP) == 0
-#endif
- )
- {
- if (! need_pass_2)
- {
- char *pfrag;
- segT current_seg = now_seg;
- subsegT current_subseg = now_subseg;
-
- subseg_set (bss_section, 1); /* switch to bss */
-
- if (align)
- frag_align (align, 0); /* do alignment */
-
- /* detach from old frag */
- if (S_GET_SEGMENT(symbolP) == bss_section)
- symbolP->sy_frag->fr_symbol = NULL;
-
- symbolP->sy_frag = frag_now;
- pfrag = frag_var (rs_org, 1, 1, (relax_substateT)0, symbolP,
- size, (char *)0);
- *pfrag = 0;
-
- S_SET_SEGMENT (symbolP, bss_section);
-
- subseg_set (current_seg, current_subseg);
- }
- }
- else
- {
- as_warn("Ignoring attempt to re-define symbol %s.", name);
- } /* if not redefining */
-
- demand_empty_rest_of_line ();
-}
-
static void
-s_common (ignore)
+arc_common (ignore)
int ignore;
{
char *name;
@@ -785,7 +708,7 @@ s_common (ignore)
SKIP_WHITESPACE ();
if (*input_line_pointer != ',')
{
- as_bad ("Expected comma after symbol-name");
+ as_bad ("expected comma after symbol-name");
ignore_rest_of_line ();
return;
}
@@ -802,7 +725,7 @@ s_common (ignore)
*p = c;
if (S_IS_DEFINED (symbolP))
{
- as_bad ("Ignoring attempt to re-define symbol");
+ as_bad ("ignoring attempt to re-define symbol");
ignore_rest_of_line ();
return;
}
@@ -824,7 +747,7 @@ s_common (ignore)
assert (symbolP->sy_frag == &zero_address_frag);
if (*input_line_pointer != ',')
{
- as_bad ("Expected comma after common length");
+ as_bad ("expected comma after common length");
ignore_rest_of_line ();
return;
}
@@ -921,59 +844,105 @@ s_common (ignore)
}
}
+/* Select the cpu we're assembling for. */
+
static void
-s_seg (ignore)
+arc_cpu (ignore)
int ignore;
{
+ int mach;
+ char c;
+ char *cpu;
+ static int seen_p = 0;
- if (strncmp (input_line_pointer, "\"text\"", 6) == 0)
+ /* Allow only one .cpu. */
+ if (seen_p)
{
- input_line_pointer += 6;
- s_text (0);
- return;
- }
- if (strncmp (input_line_pointer, "\"data\"", 6) == 0)
- {
- input_line_pointer += 6;
- s_data (0);
+ as_bad ("only one .cpu command allowed");
+ ignore_rest_of_line ();
return;
}
- if (strncmp (input_line_pointer, "\"data1\"", 7) == 0)
+ seen_p = 1;
+
+ /* If an instruction has already been seen, it's too late. */
+ if (cpu_tables_init_p)
{
- input_line_pointer += 7;
- s_data1 ();
+ as_bad (".cpu command must appear before any instructions");
+ ignore_rest_of_line ();
return;
}
- if (strncmp (input_line_pointer, "\"bss\"", 5) == 0)
+
+ cpu = input_line_pointer;
+ c = get_symbol_end ();
+ mach = arc_get_mach (cpu);
+ *input_line_pointer = c;
+ if (mach == -1)
+ goto bad_cpu;
+
+ /* Kind of overkill but what the heck. */
+ demand_empty_rest_of_line ();
+
+ /* The cpu may have been selected on the command line.
+ The choices must match. */
+ if (mach_type_specified && mach != arc_mach_type)
+ as_bad (".cpu conflicts with -mcpu flag");
+ else
{
- input_line_pointer += 5;
- /* We only support 2 segments -- text and data -- for now, so
- things in the "bss segment" will have to go into data for now.
- You can still allocate SEG_BSS stuff with .lcomm or .reserve. */
- subseg_set (data_section, 255); /* FIXME-SOMEDAY */
- return;
+ arc_mach_type = mach;
+ if (!bfd_set_arch_mach (stdoutput, bfd_arch_arc, mach))
+ as_warn ("could not set architecture and machine");
}
- as_bad ("Unknown segment type");
- demand_empty_rest_of_line ();
-}
+ return;
-static void
-s_data1 ()
-{
- subseg_set (data_section, 1);
- demand_empty_rest_of_line ();
+ bad_cpu:
+ as_bad ("bad .cpu op");
+ ignore_rest_of_line ();
}
+#if 0
+/* The .rename pseudo-op. This is used by gcc to implement
+ -mmangle-cpu-libgcc. */
+
static void
-s_proc (ignore)
+arc_rename (ignore)
int ignore;
{
- while (!is_end_of_line[(unsigned char) *input_line_pointer])
+ char *name,*new;
+ char c;
+ symbolS *sym;
+ int len;
+
+ name = input_line_pointer;
+ c = get_symbol_end ();
+ sym = symbol_find_or_make (name);
+ *input_line_pointer = c;
+
+ if (*input_line_pointer != ',')
{
- ++input_line_pointer;
+ as_bad ("missing rename string");
+ ignore_rest_of_line ();
+ return;
}
++input_line_pointer;
+ SKIP_WHITESPACE ();
+
+ name = input_line_pointer;
+ c = get_symbol_end ();
+ if (*name == '\0')
+ {
+ *input_line_pointer = c;
+ as_bad ("invalid symbol to rename to");
+ ignore_rest_of_line ();
+ return;
+ }
+ new = (char *) xmalloc (strlen (name) + 1);
+ strcpy (new, name);
+ *input_line_pointer = c;
+ sym->sy_tc.real_name = new;
+
+ demand_empty_rest_of_line ();
}
+#endif
/* 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
@@ -1034,7 +1003,11 @@ md_number_to_chars (buf, val, n)
valueT val;
int n;
{
- number_to_chars_bigendian (buf, val, n);
+ /* The ARC isn't bi-endian. Yet. */
+ if (target_big_endian)
+ number_to_chars_bigendian (buf, val, n);
+ else
+ number_to_chars_littleendian (buf, val, n);
}
/* Round up a section size to the appropriate boundary. */
@@ -1106,11 +1079,8 @@ md_pcrel_from (fixP)
{
if (fixP->fx_addsy != (symbolS *) NULL
&& ! S_IS_DEFINED (fixP->fx_addsy))
- {
- /* This makes a branch to an undefined symbol be a branch to the
- current location. */
- return 4;
- }
+ /* Return offset from PC to delay slot. Offsets are from there. */
+ return 4;
/* Return the address of the delay slot. */
return fixP->fx_frag->fr_address + fixP->fx_where + fixP->fx_size;
@@ -1181,10 +1151,16 @@ md_apply_fix (fixP, valueP)
/* Fetch the instruction, insert the fully resolved operand
value, and stuff the instruction back again. */
where = fixP->fx_frag->fr_literal + fixP->fx_where;
- insn = bfd_getb32 ((unsigned char *) where);
+ if (target_big_endian)
+ insn = bfd_getb32 ((unsigned char *) where);
+ else
+ insn = bfd_getl32 ((unsigned char *) where);
insn = arc_insert_operand (insn, operand, -1, NULL, (offsetT) value,
fixP->fx_file, fixP->fx_line);
- bfd_putb32 ((bfd_vma) insn, (unsigned char *) where);
+ if (target_big_endian)
+ bfd_putb32 ((bfd_vma) insn, (unsigned char *) where);
+ else
+ bfd_putl32 ((bfd_vma) insn, (unsigned char *) where);
if (fixP->fx_done)
{
@@ -1270,3 +1246,20 @@ tc_gen_reloc (section, fixP)
return reloc;
}
+
+/* Frobbers. */
+
+#if 0
+/* Set the real name if the .rename pseudo-op was used.
+ Return 1 if the symbol should not be included in the symbol table. */
+
+int
+arc_frob_symbol (sym)
+ symbolS *sym;
+{
+ if (sym->sy_tc.real_name != (char *) NULL)
+ S_SET_NAME (sym, sym->sy_tc.real_name);
+
+ return 0;
+}
+#endif