bfd_boolean has_delay_slot;
} arc_last_insns[2];
+/* Structure to hold an entry in ARC_OPCODE_HASH. */
+struct arc_opcode_hash_entry
+{
+ /* The number of pointers in the OPCODE list. */
+ size_t count;
+
+ /* Points to a list of opcode pointers. */
+ const struct arc_opcode **opcode;
+};
+
+/* Structure used for iterating through an arc_opcode_hash_entry. */
+struct arc_opcode_hash_entry_iterator
+{
+ /* Index into the OPCODE element of the arc_opcode_hash_entry. */
+ size_t index;
+
+ /* The specific ARC_OPCODE from the ARC_OPCODES table that was last
+ returned by this iterator. */
+ const struct arc_opcode *opcode;
+};
+
/* Forward declaration. */
static void assemble_insn
(const struct arc_opcode *, const expressionS *, int,
/* Functions implementation. */
+/* Return a pointer to ARC_OPCODE_HASH_ENTRY that identifies all
+ ARC_OPCODE entries in ARC_OPCODE_HASH that match NAME, or NULL if there
+ are no matching entries in ARC_OPCODE_HASH. */
+
+static const struct arc_opcode_hash_entry *
+arc_find_opcode (const char *name)
+{
+ const struct arc_opcode_hash_entry *entry;
+
+ entry = hash_find (arc_opcode_hash, name);
+ return entry;
+}
+
+/* Initialise the iterator ITER. */
+
+static void
+arc_opcode_hash_entry_iterator_init (struct arc_opcode_hash_entry_iterator *iter)
+{
+ iter->index = 0;
+ iter->opcode = NULL;
+}
+
+/* Return the next ARC_OPCODE from ENTRY, using ITER to hold state between
+ calls to this function. Return NULL when all ARC_OPCODE entries have
+ been returned. */
+
+static const struct arc_opcode *
+arc_opcode_hash_entry_iterator_next (const struct arc_opcode_hash_entry *entry,
+ struct arc_opcode_hash_entry_iterator *iter)
+{
+ if (iter->opcode == NULL && iter->index == 0)
+ {
+ gas_assert (entry->count > 0);
+ iter->opcode = entry->opcode[iter->index];
+ }
+ else if (iter->opcode != NULL)
+ {
+ const char *old_name = iter->opcode->name;
+
+ iter->opcode++;
+ if ((iter->opcode - arc_opcodes >= (int) arc_num_opcodes)
+ || (strcmp (old_name, iter->opcode->name) != 0))
+ {
+ iter->index++;
+ if (iter->index == entry->count)
+ iter->opcode = NULL;
+ else
+ iter->opcode = entry->opcode[iter->index];
+ }
+ }
+
+ return iter->opcode;
+}
+
/* Like md_number_to_chars but used for limms. The 4-byte limm value,
is encoded as 'middle-endian' for a little-endian target. FIXME!
this function is used for regular 4 byte instructions as well. */
md_parse_option (OPTION_MCPU, "archs");
}
else
- as_fatal ("could not find the architecture");
+ as_fatal (_("could not find the architecture"));
if (!bfd_set_arch_mach (stdoutput, bfd_arch_arc, mach))
- as_fatal ("could not set architecture and machine");
+ as_fatal (_("could not set architecture and machine"));
}
else
if (arc_mach_type != mach)
- as_warn ("Command-line value overrides \".cpu\" directive");
+ as_warn (_("Command-line value overrides \".cpu\" directive"));
restore_line_pointer (c);
demand_empty_rest_of_line ();
bad_cpu:
restore_line_pointer (c);
- as_bad ("invalid identifier for \".cpu\"");
+ as_bad (_("invalid identifier for \".cpu\""));
ignore_rest_of_line ();
}
if (num_flags >= nflg)
goto err;
- flgnamelen = strspn (input_line_pointer, "abcdefghilmnopqrstvwxz");
+ flgnamelen = strspn (input_line_pointer,
+ "abcdefghijklmnopqrstuvwxyz0123456789");
if (flgnamelen > MAX_FLAG_NAME_LENGTH)
goto err;
syntax match. */
static const struct arc_opcode *
-find_opcode_match (const struct arc_opcode *first_opcode,
+find_opcode_match (const struct arc_opcode_hash_entry *entry,
expressionS *tok,
int *pntok,
struct arc_flags *first_pflag,
int nflgs,
int *pcpumatch)
{
- const struct arc_opcode *opcode = first_opcode;
+ const struct arc_opcode *opcode;
+ struct arc_opcode_hash_entry_iterator iter;
int ntok = *pntok;
int got_cpu_match = 0;
expressionS bktok[MAX_INSN_ARGS];
int bkntok;
expressionS emptyE;
+ arc_opcode_hash_entry_iterator_init (&iter);
memset (&emptyE, 0, sizeof (emptyE));
memcpy (bktok, tok, MAX_INSN_ARGS * sizeof (*tok));
bkntok = ntok;
- do
+ for (opcode = arc_opcode_hash_entry_iterator_next (entry, &iter);
+ opcode != NULL;
+ opcode = arc_opcode_hash_entry_iterator_next (entry, &iter))
{
const unsigned char *opidx;
const unsigned char *flgidx;
from BKTOK. */
tok[tokidx].X_op = O_constant;
tok[tokidx].X_add_number = auxr->address;
+ ARC_SET_FLAG (tok[i].X_add_symbol, ARC_FLAG_AUX);
break;
}
memcpy (tok, bktok, MAX_INSN_ARGS * sizeof (*tok));
ntok = bkntok;
}
- while (++opcode - arc_opcodes < (int) arc_num_opcodes
- && !strcmp (opcode->name, first_opcode->name));
if (*pcpumatch)
*pcpumatch = got_cpu_match;
/* Assumes the expressionS *tok is of sufficient size. */
-static const struct arc_opcode *
+static const struct arc_opcode_hash_entry *
find_special_case_pseudo (const char *opname,
int *ntok,
expressionS *tok,
break;
}
- return (const struct arc_opcode *)
- hash_find (arc_opcode_hash, pseudo_insn->mnemonic_r);
+ return arc_find_opcode (pseudo_insn->mnemonic_r);
}
-static const struct arc_opcode *
+static const struct arc_opcode_hash_entry *
find_special_case_flag (const char *opname,
int *nflgs,
struct arc_flags *pflags)
unsigned flag_idx, flag_arr_idx;
size_t flaglen, oplen;
const struct arc_flag_special *arc_flag_special_opcode;
- const struct arc_opcode *opcode;
+ const struct arc_opcode_hash_entry *entry;
/* Search for special case instruction. */
for (i = 0; i < arc_num_flag_special; i++)
flaglen = strlen (flagnm);
if (strcmp (opname + oplen, flagnm) == 0)
{
- opcode = (const struct arc_opcode *)
- hash_find (arc_opcode_hash,
- arc_flag_special_opcode->name);
+ entry = arc_find_opcode (arc_flag_special_opcode->name);
if (*nflgs + 1 > MAX_INSN_FLGS)
break;
memcpy (pflags[*nflgs].name, flagnm, flaglen);
pflags[*nflgs].name[flaglen] = '\0';
(*nflgs)++;
- return opcode;
+ return entry;
}
}
}
/* Used to find special case opcode. */
-static const struct arc_opcode *
+static const struct arc_opcode_hash_entry *
find_special_case (const char *opname,
int *nflgs,
struct arc_flags *pflags,
expressionS *tok,
int *ntok)
{
- const struct arc_opcode *opcode;
+ const struct arc_opcode_hash_entry *entry;
- opcode = find_special_case_pseudo (opname, ntok, tok, nflgs, pflags);
+ entry = find_special_case_pseudo (opname, ntok, tok, nflgs, pflags);
- if (opcode == NULL)
- opcode = find_special_case_flag (opname, nflgs, pflags);
+ if (entry == NULL)
+ entry = find_special_case_flag (opname, nflgs, pflags);
- return opcode;
+ return entry;
}
/* Given an opcode name, pre-tockenized set of argumenst and the
int nflgs)
{
bfd_boolean found_something = FALSE;
- const struct arc_opcode *opcode;
+ const struct arc_opcode_hash_entry *entry;
int cpumatch = 1;
/* Search opcodes. */
- opcode = (const struct arc_opcode *) hash_find (arc_opcode_hash, opname);
+ entry = arc_find_opcode (opname);
/* Couldn't find opcode conventional way, try special cases. */
- if (!opcode)
- opcode = find_special_case (opname, &nflgs, pflags, tok, &ntok);
+ if (entry == NULL)
+ entry = find_special_case (opname, &nflgs, pflags, tok, &ntok);
- if (opcode)
+ if (entry != NULL)
{
- pr_debug ("%s:%d: assemble_tokens: %s trying opcode 0x%08X\n",
- frag_now->fr_file, frag_now->fr_line, opcode->name,
- opcode->opcode);
+ const struct arc_opcode *opcode;
+ pr_debug ("%s:%d: assemble_tokens: %s\n",
+ frag_now->fr_file, frag_now->fr_line, opname);
found_something = TRUE;
- opcode = find_opcode_match (opcode, tok, &ntok, pflags, nflgs, &cpumatch);
- if (opcode)
+ opcode = find_opcode_match (entry, tok, &ntok, pflags,
+ nflgs, &cpumatch);
+ if (opcode != NULL)
{
struct arc_insn insn;
+
assemble_insn (opcode, tok, ntok, pflags, nflgs, &insn);
emit_insn (&insn);
return;
err = hash_insert (arc_reg_hash, S_GET_NAME (regS), (void *) regS);
if (err)
- as_fatal ("Inserting \"%s\" into register table failed: %s",
+ as_fatal (_("Inserting \"%s\" into register table failed: %s"),
name, err);
}
for (i = 0; i < arc_num_opcodes;)
{
const char *name, *retval;
+ struct arc_opcode_hash_entry *entry;
name = arc_opcodes[i].name;
- retval = hash_insert (arc_opcode_hash, name, (void *) &arc_opcodes[i]);
- if (retval)
- as_fatal (_("internal error: can't hash opcode '%s': %s"),
- name, retval);
+
+ entry = hash_find (arc_opcode_hash, name);
+ if (entry == NULL)
+ {
+ entry = xmalloc (sizeof (*entry));
+ entry->count = 0;
+ entry->opcode = NULL;
+
+ retval = hash_insert (arc_opcode_hash, name, (void *) entry);
+ if (retval)
+ as_fatal (_("internal error: can't hash opcode '%s': %s"),
+ name, retval);
+ }
+
+ entry->opcode = xrealloc (entry->opcode,
+ sizeof (const struct arc_opcode *)
+ * entry->count + 1);
+ entry->opcode [entry->count] = &arc_opcodes[i];
+ entry->count++;
while (++i < arc_num_opcodes
&& (arc_opcodes[i].name == name
return -1;
}
+
+/* Adjust the symbol table. Delete found AUX register symbols. */
+
+void
+arc_adjust_symtab (void)
+{
+ symbolS * sym;
+
+ for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym))
+ {
+ /* I've created a symbol during parsing process. Now, remove
+ the symbol as it is found to be an AUX register. */
+ if (ARC_GET_FLAG (sym) & ARC_FLAG_AUX)
+ symbol_remove (sym, &symbol_rootP, &symbol_lastP);
+ }
+
+ /* Now do generic ELF adjustments. */
+ elf_adjust_symtab ();
+}