static void arc_option (int);
static void arc_extra_reloc (int);
static void arc_extinsn (int);
+static void arc_extcorereg (int);
const pseudo_typeS md_pseudo_table[] =
{
{ "lcommon", arc_lcomm, 0 },
{ "cpu", arc_option, 0 },
- { "extinstruction", arc_extinsn, 0 },
+ { "extinstruction", arc_extinsn, 0 },
+ { "extcoreregister", arc_extcorereg, EXT_CORE_REGISTER },
+ { "extauxregister", arc_extcorereg, EXT_AUX_REGISTER },
+ { "extcondcode", arc_extcorereg, EXT_COND_CODE },
{ "tls_gd_ld", arc_extra_reloc, BFD_RELOC_ARC_TLS_GD_LD },
{ "tls_gd_call", arc_extra_reloc, BFD_RELOC_ARC_TLS_GD_CALL },
static const attributes_t syntaxclass[] =
{
{ "SYNTAX_3OP", 10, ARC_SYNTAX_3OP },
- { "SYNTAX_2OP", 10, ARC_SYNTAX_2OP }
+ { "SYNTAX_2OP", 10, ARC_SYNTAX_2OP },
+ { "SYNTAX_1OP", 10, ARC_SYNTAX_1OP },
+ { "SYNTAX_NOP", 10, ARC_SYNTAX_NOP }
};
/* Extension instruction syntax classes modifiers. */
{ "OP1_MUST_BE_IMM" , 15, ARC_OP1_MUST_BE_IMM }
};
+/* Extension register type. */
+typedef struct
+{
+ char *name;
+ int number;
+ int imode;
+} extRegister_t;
+
+/* A structure to hold the additional conditional codes. */
+static struct
+{
+ struct arc_flag_operand *arc_ext_condcode;
+ int size;
+} ext_condcode = { NULL, 0 };
+
/* Structure to hold an entry in ARC_OPCODE_HASH. */
struct arc_opcode_hash_entry
{
/* The default architecture. */
static int arc_mach_type;
-/* Non-zero if the cpu type has been explicitly specified. */
-static int mach_type_specified_p = 0;
+/* TRUE if the cpu type has been explicitly specified. */
+static bfd_boolean mach_type_specified_p = FALSE;
/* The hash table of instruction opcodes. */
static struct hash_control *arc_opcode_hash;
/* The hash table of register symbols. */
static struct hash_control *arc_reg_hash;
+/* The hash table of aux register symbols. */
+static struct hash_control *arc_aux_hash;
+
/* A table of CPU names and opcode sets. */
static const struct cpu_type
{
entry = hash_find (arc_opcode_hash, name);
if (entry == NULL)
{
- entry = xmalloc (sizeof (*entry));
+ entry = XNEW (struct arc_opcode_hash_entry);
entry->count = 0;
entry->opcode = NULL;
name, retval);
}
- entry->opcode = xrealloc (entry->opcode,
- sizeof (const struct arc_opcode *)
- * (entry->count + 1));
+ entry->opcode = XRESIZEVEC (const struct arc_opcode *, entry->opcode,
+ entry->count + 1);
if (entry->opcode == NULL)
as_fatal (_("Virtual memory exhausted"));
{
md_parse_option (OPTION_MCPU, "archs");
}
+ else if (!strcmp ("NPS400", cpu))
+ {
+ md_parse_option (OPTION_MCPU, "nps400");
+ }
else
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"));
+
+ /* Set elf header flags. */
+ bfd_set_private_flags (stdoutput, arc_eflag);
}
else
if (arc_mach_type != mach)
case O_symbol:
{
const char *p;
- size_t len;
const struct arc_aux_reg *auxr;
- unsigned j;
if (opcode->class != AUXREG)
goto de_fault;
p = S_GET_NAME (tok[tokidx].X_add_symbol);
- len = strlen (p);
-
- auxr = &arc_aux_regs[0];
- for (j = 0; j < arc_num_aux_regs; j++, auxr++)
- if (len == auxr->length
- && strcasecmp (auxr->name, p) == 0
- && ((auxr->subclass == NONE)
- || check_cpu_feature (auxr->subclass)))
- {
- /* We modify the token array here, safe in the
- knowledge, that if this was the wrong choice
- then the original contents will be restored
- from BKTOK. */
- tok[tokidx].X_op = O_constant;
- tok[tokidx].X_add_number = auxr->address;
- ARC_SET_FLAG (tok[tokidx].X_add_symbol, ARC_FLAG_AUX);
- break;
- }
+
+ auxr = hash_find (arc_aux_hash, p);
+ if (auxr)
+ {
+ /* We modify the token array here, safe in the
+ knowledge, that if this was the wrong
+ choice then the original contents will be
+ restored from BKTOK. */
+ tok[tokidx].X_op = O_constant;
+ tok[tokidx].X_add_number = auxr->address;
+ ARC_SET_FLAG (tok[tokidx].X_add_symbol, ARC_FLAG_AUX);
+ }
if (tok[tokidx].X_op != O_constant)
goto de_fault;
/* Setup ready for flag parsing. */
lnflg = nflgs;
for (i = 0; i < nflgs; i++)
- first_pflag [i].code = 0;
+ first_pflag[i].flgp = NULL;
/* Check the flags. Iterate over the valid flag classes. */
for (flgidx = opcode->flags; *flgidx; ++flgidx)
const struct arc_flag_class *cl_flags = &arc_flag_classes[*flgidx];
const unsigned *flgopridx;
int cl_matches = 0;
+ struct arc_flags *pflag = NULL;
+
+ /* Check for extension conditional codes. */
+ if (ext_condcode.arc_ext_condcode
+ && cl_flags->class & F_CLASS_EXTEND)
+ {
+ struct arc_flag_operand *pf = ext_condcode.arc_ext_condcode;
+ while (pf->name)
+ {
+ pflag = first_pflag;
+ for (i = 0; i < nflgs; i++, pflag++)
+ {
+ if (!strcmp (pf->name, pflag->name))
+ {
+ if (pflag->flgp != NULL)
+ goto match_failed;
+ /* Found it. */
+ cl_matches++;
+ pflag->flgp = pf;
+ lnflg--;
+ break;
+ }
+ }
+ pf++;
+ }
+ }
for (flgopridx = cl_flags->flags; *flgopridx; ++flgopridx)
{
const struct arc_flag_operand *flg_operand;
- struct arc_flags *pflag = first_pflag;
+ pflag = first_pflag;
flg_operand = &arc_flag_operands[*flgopridx];
for (i = 0; i < nflgs; i++, pflag++)
{
/* Match against the parsed flags. */
if (!strcmp (flg_operand->name, pflag->name))
{
- if (pflag->code != 0)
+ if (pflag->flgp != NULL)
goto match_failed;
cl_matches++;
- pflag->code = *flgopridx;
+ pflag->flgp = (struct arc_flag_operand *) flg_operand;
lnflg--;
break; /* goto next flag class and parsed flag. */
}
}
}
- if (cl_flags->class == F_CLASS_REQUIRED && cl_matches == 0)
+ if ((cl_flags->class & F_CLASS_REQUIRED) && cl_matches == 0)
goto match_failed;
- if (cl_flags->class == F_CLASS_OPTIONAL && cl_matches > 1)
+ if ((cl_flags->class & F_CLASS_OPTIONAL) && cl_matches > 1)
goto match_failed;
}
/* Did I check all the parsed flags? */
/* Split off the opcode. */
opnamelen = strspn (str, "abcdefghijklmnopqrstuvwxyz_0123468");
- opname = xmalloc (opnamelen + 1);
- memcpy (opname, str, opnamelen);
- opname[opnamelen] = '\0';
+ opname = xmemdup0 (str, opnamelen);
/* Signalize we are assmbling the instructions. */
assembling_insn = TRUE;
/* Initialize the last instructions. */
memset (&arc_last_insns[0], 0, sizeof (arc_last_insns));
+
+ /* Aux register declaration. */
+ arc_aux_hash = hash_new ();
+ if (arc_aux_hash == NULL)
+ as_fatal (_("Virtual memory exhausted"));
+
+ const struct arc_aux_reg *auxr = &arc_aux_regs[0];
+ unsigned int i;
+ for (i = 0; i < arc_num_aux_regs; i++, auxr++)
+ {
+ const char *retval;
+
+ if (!(auxr->cpu & arc_target))
+ continue;
+
+ if ((auxr->subclass != NONE)
+ && !check_cpu_feature (auxr->subclass))
+ continue;
+
+ retval = hash_insert (arc_aux_hash, auxr->name, (void *) auxr);
+ if (retval)
+ as_fatal (_("internal error: can't hash aux register '%s': %s"),
+ auxr->name, retval);
+ }
}
/* Write a value out to the object file, using the appropriate
arelent *reloc;
bfd_reloc_code_real_type code;
- reloc = (arelent *) xmalloc (sizeof (* reloc));
- reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+ reloc = XNEW (arelent);
+ reloc->sym_ptr_ptr = XNEW (asymbol *);
*reloc->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy);
reloc->address = fixP->fx_frag->fr_address + fixP->fx_where;
case OPTION_MCPU:
{
arc_select_cpu (arg);
- mach_type_specified_p = 1;
+ mach_type_specified_p = TRUE;
break;
}
/* Handle flags. */
for (i = 0; i < nflg; i++)
{
- const struct arc_flag_operand *flg_operand =
- &arc_flag_operands[pflags[i].code];
+ const struct arc_flag_operand *flg_operand = pflags[i].flgp;
/* Check if the instruction has a delay slot. */
if (!strcmp (flg_operand->name, "d"))
&& (einsn.major != 5) && (einsn.major != 9))
as_fatal (_("minor opcode not in range [0x00 - 0x3f]"));
- switch (einsn.syntax & (ARC_SYNTAX_3OP | ARC_SYNTAX_2OP))
+ switch (einsn.syntax & ARC_SYNTAX_MASK)
{
case ARC_SYNTAX_3OP:
if (einsn.modsyn & ARC_OP1_IMM_IMPLIED)
as_fatal (_("Improper use of OP1_IMM_IMPLIED"));
break;
case ARC_SYNTAX_2OP:
+ case ARC_SYNTAX_1OP:
+ case ARC_SYNTAX_NOP:
if (einsn.modsyn & ARC_OP1_MUST_BE_IMM)
as_fatal (_("Improper use of OP1_MUST_BE_IMM"));
break;
create_extinst_section (&einsn);
}
+static void
+tokenize_extregister (extRegister_t *ereg, int opertype)
+{
+ char *name;
+ char *mode;
+ char c;
+ char *p;
+ int number, imode = 0;
+ bfd_boolean isCore_p = (opertype == EXT_CORE_REGISTER) ? TRUE : FALSE;
+ bfd_boolean isReg_p = (opertype == EXT_CORE_REGISTER
+ || opertype == EXT_AUX_REGISTER) ? TRUE : FALSE;
+
+ /* 1st: get register name. */
+ SKIP_WHITESPACE ();
+ p = input_line_pointer;
+ c = get_symbol_name (&p);
+
+ name = xstrdup (p);
+ restore_line_pointer (c);
+
+ /* 2nd: get register number. */
+ SKIP_WHITESPACE ();
+
+ if (*input_line_pointer != ',')
+ {
+ as_bad (_("expected comma after register name"));
+ ignore_rest_of_line ();
+ free (name);
+ return;
+ }
+ input_line_pointer++;
+ number = get_absolute_expression ();
+
+ if (number < 0)
+ {
+ as_bad (_("negative operand number %d"), number);
+ ignore_rest_of_line ();
+ free (name);
+ return;
+ }
+
+ if (isReg_p)
+ {
+ /* 3rd: get register mode. */
+ SKIP_WHITESPACE ();
+
+ if (*input_line_pointer != ',')
+ {
+ as_bad (_("expected comma after register number"));
+ ignore_rest_of_line ();
+ free (name);
+ return;
+ }
+
+ input_line_pointer++;
+ mode = input_line_pointer;
+
+ if (!strncmp (mode, "r|w", 3))
+ {
+ imode = 0;
+ input_line_pointer += 3;
+ }
+ else if (!strncmp (mode, "r", 1))
+ {
+ imode = ARC_REGISTER_READONLY;
+ input_line_pointer += 1;
+ }
+ else if (strncmp (mode, "w", 1))
+ {
+ as_bad (_("invalid mode"));
+ ignore_rest_of_line ();
+ free (name);
+ return;
+ }
+ else
+ {
+ imode = ARC_REGISTER_WRITEONLY;
+ input_line_pointer += 1;
+ }
+ }
+
+ if (isCore_p)
+ {
+ /* 4th: get core register shortcut. */
+ SKIP_WHITESPACE ();
+ if (*input_line_pointer != ',')
+ {
+ as_bad (_("expected comma after register mode"));
+ ignore_rest_of_line ();
+ free (name);
+ return;
+ }
+
+ input_line_pointer++;
+
+ if (!strncmp (input_line_pointer, "cannot_shortcut", 15))
+ {
+ imode |= ARC_REGISTER_NOSHORT_CUT;
+ input_line_pointer += 15;
+ }
+ else if (strncmp (input_line_pointer, "can_shortcut", 12))
+ {
+ as_bad (_("shortcut designator invalid"));
+ ignore_rest_of_line ();
+ free (name);
+ return;
+ }
+ else
+ {
+ input_line_pointer += 12;
+ }
+ }
+ demand_empty_rest_of_line ();
+
+ ereg->name = name;
+ ereg->number = number;
+ ereg->imode = imode;
+}
+
+/* Create an extension register/condition description in the arc
+ extension section of the output file.
+
+ The structure for an instruction is like this:
+ [0]: Length of the record.
+ [1]: Type of the record.
+
+ For core regs and condition codes:
+ [2]: Value.
+ [3]+ Name.
+
+ For auxilirary registers:
+ [2..5]: Value.
+ [6]+ Name
+
+ The sequence is terminated by an empty entry. */
+
+static void
+create_extcore_section (extRegister_t *ereg, int opertype)
+{
+ segT old_sec = now_seg;
+ int old_subsec = now_subseg;
+ char *p;
+ int name_len = strlen (ereg->name);
+
+ arc_set_ext_seg ();
+
+ switch (opertype)
+ {
+ case EXT_COND_CODE:
+ case EXT_CORE_REGISTER:
+ p = frag_more (1);
+ *p = 3 + name_len + 1;
+ p = frag_more (1);
+ *p = opertype;
+ p = frag_more (1);
+ *p = ereg->number;
+ break;
+ case EXT_AUX_REGISTER:
+ p = frag_more (1);
+ *p = 6 + name_len + 1;
+ p = frag_more (1);
+ *p = EXT_AUX_REGISTER;
+ p = frag_more (1);
+ *p = (ereg->number >> 24) & 0xff;
+ p = frag_more (1);
+ *p = (ereg->number >> 16) & 0xff;
+ p = frag_more (1);
+ *p = (ereg->number >> 8) & 0xff;
+ p = frag_more (1);
+ *p = (ereg->number) & 0xff;
+ break;
+ default:
+ break;
+ }
+
+ p = frag_more (name_len + 1);
+ strcpy (p, ereg->name);
+
+ subseg_set (old_sec, old_subsec);
+}
+
+/* Handler .extCoreRegister pseudo-op. */
+
+static void
+arc_extcorereg (int opertype)
+{
+ extRegister_t ereg;
+ struct arc_aux_reg *auxr;
+ const char *retval;
+ struct arc_flag_operand *ccode;
+
+ memset (&ereg, 0, sizeof (ereg));
+ tokenize_extregister (&ereg, opertype);
+
+ switch (opertype)
+ {
+ case EXT_CORE_REGISTER:
+ /* Core register. */
+ if (ereg.number > 60)
+ as_bad (_("core register %s value (%d) too large"), ereg.name,
+ ereg.number);
+ declare_register (ereg.name, ereg.number);
+ break;
+ case EXT_AUX_REGISTER:
+ /* Auxiliary register. */
+ auxr = XNEW (struct arc_aux_reg);
+ auxr->name = ereg.name;
+ auxr->cpu = arc_target;
+ auxr->subclass = NONE;
+ auxr->address = ereg.number;
+ retval = hash_insert (arc_aux_hash, auxr->name, (void *) auxr);
+ if (retval)
+ as_fatal (_("internal error: can't hash aux register '%s': %s"),
+ auxr->name, retval);
+ break;
+ case EXT_COND_CODE:
+ /* Condition code. */
+ if (ereg.number > 31)
+ as_bad (_("condition code %s value (%d) too large"), ereg.name,
+ ereg.number);
+ ext_condcode.size ++;
+ ext_condcode.arc_ext_condcode =
+ XRESIZEVEC (struct arc_flag_operand, ext_condcode.arc_ext_condcode,
+ ext_condcode.size + 1);
+ if (ext_condcode.arc_ext_condcode == NULL)
+ as_fatal (_("Virtual memory exhausted"));
+
+ ccode = ext_condcode.arc_ext_condcode + ext_condcode.size - 1;
+ ccode->name = ereg.name;
+ ccode->code = ereg.number;
+ ccode->bits = 5;
+ ccode->shift = 0;
+ ccode->favail = 0; /* not used. */
+ ccode++;
+ memset (ccode, 0, sizeof (struct arc_flag_operand));
+ break;
+ default:
+ as_bad (_("Unknown extension"));
+ break;
+ }
+ create_extcore_section (&ereg, opertype);
+}
+
/* Local variables:
eval: (c-set-style "gnu")
indent-tabs-mode: t