};
/* Information about the cpu/variant we're assembling for. */
-static struct cpu_type selected_cpu;
+static struct cpu_type selected_cpu = { 0, 0, 0, 0, 0 };
+
+/* A table with options. */
+static const struct feature_type
+{
+ unsigned feature;
+ unsigned cpus;
+ const char *name;
+}
+ feature_list[] =
+{
+ { ARC_CD, ARC_OPCODE_ARCV2, "code-density" },
+ { ARC_NPS400, ARC_OPCODE_ARC700, "nps400" },
+ { ARC_SPFP, ARC_OPCODE_ARCFPX, "single-precision FPX" },
+ { ARC_DPFP, ARC_OPCODE_ARCFPX, "double-precision FPX" },
+ { ARC_FPUDA, ARC_OPCODE_ARCv2EM, "double assist FP" }
+};
/* Used by the arc_reloc_op table. Order is important. */
#define O_gotoff O_md1 /* @gotoff relocation. */
}
}
+/* Check if a feature is allowed for a specific CPU. */
+
+static void
+arc_check_feature (void)
+{
+ unsigned i;
+
+ if (!selected_cpu.features
+ || !selected_cpu.name)
+ return;
+ for (i = 0; (i < ARRAY_SIZE (feature_list)); i++)
+ {
+ if ((selected_cpu.features & feature_list[i].feature)
+ && !(selected_cpu.flags & feature_list[i].cpus))
+ {
+ as_bad (_("invalid %s option for %s cpu"), feature_list[i].name,
+ selected_cpu.name);
+ }
+ }
+}
+
/* Select an appropriate entry from CPU_TYPES based on ARG and initialise
the relevant static global variables. Parameter SEL describes where
this selection originated from. */
gas_assert (sel != MACH_SELECTION_FROM_DEFAULT
|| mach_selection_mode == MACH_SELECTION_NONE);
+ if ((mach_selection_mode == MACH_SELECTION_FROM_CPU_DIRECTIVE)
+ && (sel == MACH_SELECTION_FROM_CPU_DIRECTIVE))
+ as_bad (_("Multiple .cpu directives found"));
+
/* Look for a matching entry in CPU_TYPES array. */
for (i = 0; cpu_types[i].name; ++i)
{
&& selected_cpu.mach != cpu_types[i].mach)
{
as_warn (_("Command-line value overrides \".cpu\" directive"));
- return;
}
+ return;
}
- /* Initialise static global data about selected machine type. */
- selected_cpu.flags = cpu_types[i].flags;
- selected_cpu.name = cpu_types[i].name;
- selected_cpu.features = cpu_types[i].features;
- selected_cpu.mach = cpu_types[i].mach;
- cpu_flags = cpu_types[i].eflags;
+ /* Initialise static global data about selected machine type. */
+ selected_cpu.flags = cpu_types[i].flags;
+ selected_cpu.name = cpu_types[i].name;
+ selected_cpu.features |= cpu_types[i].features;
+ selected_cpu.mach = cpu_types[i].mach;
+ cpu_flags = cpu_types[i].eflags;
break;
}
}
if (!cpu_types[i].name)
as_fatal (_("unknown architecture: %s\n"), arg);
+
+ /* Check if set features are compatible with the chosen CPU. */
+ arc_check_feature ();
gas_assert (cpu_flags != 0);
selected_cpu.eflags = (arc_initial_eflag & ~EF_ARC_MACH_MSK) | cpu_flags;
mach_selection_mode = sel;
int *pntok,
struct arc_flags *first_pflag,
int nflgs,
- int *pcpumatch)
+ int *pcpumatch,
+ const char **errmsg)
{
const struct arc_opcode *opcode;
struct arc_opcode_hash_entry_iterator iter;
switch (operand->flags & ARC_OPERAND_TYPECHECK_MASK)
{
case ARC_OPERAND_ADDRTYPE:
- /* Check to be an address type. */
- if (tok[tokidx].X_op != O_addrtype)
- goto match_failed;
+ {
+ *errmsg = NULL;
+
+ /* Check to be an address type. */
+ if (tok[tokidx].X_op != O_addrtype)
+ goto match_failed;
+
+ /* All address type operands need to have an insert
+ method in order to check that we have the correct
+ address type. */
+ gas_assert (operand->insert != NULL);
+ (*operand->insert) (0, tok[tokidx].X_add_number,
+ errmsg);
+ if (*errmsg != NULL)
+ goto match_failed;
+ }
break;
case ARC_OPERAND_IR:
/* Special handling? */
if (operand->insert)
{
- const char *errmsg = NULL;
+ *errmsg = NULL;
(*operand->insert)(0,
regno (tok[tokidx].X_add_number),
- &errmsg);
- if (errmsg)
+ errmsg);
+ if (*errmsg)
{
if (operand->flags & ARC_OPERAND_IGNORE)
{
{
if (operand->insert)
{
- const char *errmsg = NULL;
+ *errmsg = NULL;
(*operand->insert)(0,
tok[tokidx].X_add_number,
- &errmsg);
- if (errmsg)
+ errmsg);
+ if (*errmsg)
goto match_failed;
}
else if (!(operand->flags & ARC_OPERAND_IGNORE))
regs |= get_register (tok[tokidx].X_op_symbol);
if (operand->insert)
{
- const char *errmsg = NULL;
+ *errmsg = NULL;
(*operand->insert)(0,
regs,
- &errmsg);
- if (errmsg)
+ errmsg);
+ if (*errmsg)
goto match_failed;
}
else
bfd_boolean found_something = FALSE;
const struct arc_opcode_hash_entry *entry;
int cpumatch = 1;
+ const char *errmsg = NULL;
/* Search opcodes. */
entry = arc_find_opcode (opname);
frag_now->fr_file, frag_now->fr_line, opname);
found_something = TRUE;
opcode = find_opcode_match (entry, tok, &ntok, pflags,
- nflgs, &cpumatch);
+ nflgs, &cpumatch, &errmsg);
if (opcode != NULL)
{
struct arc_insn insn;
if (found_something)
{
if (cpumatch)
- as_bad (_("inappropriate arguments for opcode '%s'"), opname);
+ if (errmsg)
+ as_bad (_("%s for instruction '%s'"), errmsg, opname);
+ else
+ as_bad (_("inappropriate arguments for opcode '%s'"), opname);
else
as_bad (_("opcode '%s' not supported for target %s"), opname,
selected_cpu.name);
/* The hardware calculates relative to the start of the
insn, but this relocation is relative to location of the
LIMM, compensate. The base always needs to be
- substracted by 4 as we do not support this type of PCrel
+ subtracted by 4 as we do not support this type of PCrel
relocation for short instructions. */
base -= 4;
/* Fall through. */
break;
case OPTION_CD:
- /* This option has an effect only on ARC EM. */
- if (selected_cpu.flags & ARC_OPCODE_ARCv2EM)
- selected_cpu.features |= ARC_CD;
- else
- as_warn (_("Code density option invalid for selected CPU"));
+ selected_cpu.features |= ARC_CD;
+ arc_check_feature ();
break;
case OPTION_RELAX:
case OPTION_NPS400:
selected_cpu.features |= ARC_NPS400;
+ arc_check_feature ();
break;
case OPTION_SPFP:
selected_cpu.features |= ARC_SPFP;
+ arc_check_feature ();
break;
case OPTION_DPFP:
selected_cpu.features |= ARC_DPFP;
+ arc_check_feature ();
break;
case OPTION_FPUDA:
- /* This option has an effect only on ARC EM. */
- if (selected_cpu.flags & ARC_OPCODE_ARCv2EM)
- selected_cpu.features |= ARC_FPUDA;
- else
- as_warn (_("FPUDA invalid for selected CPU"));
+ selected_cpu.features |= ARC_FPUDA;
+ arc_check_feature ();
break;
/* Dummy options are accepted but have no effect. */