+/* Make a leading REGISTER_PREFIX_CHAR mandatory for all registers. */
+
+static void
+cris_force_reg_prefix (void)
+{
+ demand_register_prefix = TRUE;
+}
+
+/* Do not demand a leading REGISTER_PREFIX_CHAR for all registers. */
+
+static void
+cris_relax_reg_prefix (void)
+{
+ demand_register_prefix = FALSE;
+}
+
+/* Adjust for having a leading '_' on all user symbols. */
+
+static void
+cris_sym_leading_underscore (void)
+{
+ /* We can't really do anything more than assert that what the program
+ thinks symbol starts with agrees with the command-line options, since
+ the bfd is already created. */
+
+ if (!symbols_have_leading_underscore)
+ as_bad (_(".syntax %s requires command-line option `--underscore'"),
+ SYNTAX_USER_SYM_LEADING_UNDERSCORE);
+}
+
+/* Adjust for not having any particular prefix on user symbols. */
+
+static void cris_sym_no_leading_underscore (void)
+{
+ if (symbols_have_leading_underscore)
+ as_bad (_(".syntax %s requires command-line option `--no-underscore'"),
+ SYNTAX_USER_SYM_NO_LEADING_UNDERSCORE);
+}
+
+/* Handle the .syntax pseudo, which takes an argument that decides what
+ syntax the assembly code has. */
+
+static void
+s_syntax (int ignore ATTRIBUTE_UNUSED)
+{
+ static const struct syntaxes
+ {
+ const char *const operand;
+ void (*fn) (void);
+ } syntax_table[] =
+ {{SYNTAX_ENFORCE_REG_PREFIX, cris_force_reg_prefix},
+ {SYNTAX_RELAX_REG_PREFIX, cris_relax_reg_prefix},
+ {SYNTAX_USER_SYM_LEADING_UNDERSCORE, cris_sym_leading_underscore},
+ {SYNTAX_USER_SYM_NO_LEADING_UNDERSCORE, cris_sym_no_leading_underscore}};
+
+ const struct syntaxes *sp;
+
+ for (sp = syntax_table;
+ sp < syntax_table + sizeof (syntax_table) / sizeof (syntax_table[0]);
+ sp++)
+ {
+ if (strncmp (input_line_pointer, sp->operand,
+ strlen (sp->operand)) == 0)
+ {
+ (sp->fn) ();
+
+ input_line_pointer += strlen (sp->operand);
+ demand_empty_rest_of_line ();
+ return;
+ }
+ }
+
+ as_bad (_("Unknown .syntax operand"));
+}
+
+/* Wrapper for dwarf2_directive_file to emit error if this is seen when
+ not emitting ELF. */
+
+static void
+s_cris_file (int dummy)
+{
+ if (OUTPUT_FLAVOR != bfd_target_elf_flavour)
+ as_bad (_("Pseudodirective .file is only valid when generating ELF"));
+ else
+ dwarf2_directive_file (dummy);
+}
+
+/* Wrapper for dwarf2_directive_loc to emit error if this is seen when not
+ emitting ELF. */
+
+static void
+s_cris_loc (int dummy)
+{
+ if (OUTPUT_FLAVOR != bfd_target_elf_flavour)
+ as_bad (_("Pseudodirective .loc is only valid when generating ELF"));
+ else
+ dwarf2_directive_loc (dummy);
+}
+
+/* Worker for .dtpoffd: generate a R_CRIS_32_DTPREL reloc, as for
+ expr:DTPREL but for use in debug info. */
+
+static void
+s_cris_dtpoff (int bytes)
+{
+ expressionS ex;
+ char *p;
+
+ if (bytes != 4)
+ as_fatal (_("internal inconsistency problem: %s called for %d bytes"),
+ __FUNCTION__, bytes);
+
+ expression (&ex);
+
+ p = frag_more (bytes);
+ md_number_to_chars (p, 0, bytes);
+ fix_new_exp (frag_now, p - frag_now->fr_literal, bytes, &ex, FALSE,
+ BFD_RELOC_CRIS_32_DTPREL);
+
+ demand_empty_rest_of_line ();
+}
+
+
+/* Translate a <arch> string (as common to --march=<arch> and .arch <arch>)
+ into an enum. If the string *STR is recognized, *STR is updated to point
+ to the end of the string. If the string is not recognized,
+ arch_cris_unknown is returned. */
+
+static enum cris_archs
+cris_arch_from_string (const char **str)
+{
+ static const struct cris_arch_struct
+ {
+ const char *const name;
+ enum cris_archs arch;
+ } arch_table[] =
+ /* Keep in order longest-first for choices where one is a prefix
+ of another. */
+ {{"v0_v10", arch_cris_any_v0_v10},
+ {"v10", arch_crisv10},
+ {"v32", arch_crisv32},
+ {"common_v10_v32", arch_cris_common_v10_v32}};
+
+ const struct cris_arch_struct *ap;
+
+ for (ap = arch_table;
+ ap < arch_table + sizeof (arch_table) / sizeof (arch_table[0]);
+ ap++)
+ {
+ int len = strlen (ap->name);
+
+ if (strncmp (*str, ap->name, len) == 0
+ && (str[0][len] == 0 || ISSPACE (str[0][len])))
+ {
+ *str += strlen (ap->name);
+ return ap->arch;
+ }
+ }
+
+ return arch_cris_unknown;
+}
+
+/* Return nonzero if architecture version ARCH matches version range in
+ IVER. */
+
+static int
+cris_insn_ver_valid_for_arch (enum cris_insn_version_usage iver,
+ enum cris_archs arch)
+{
+ switch (arch)
+ {
+ case arch_cris_any_v0_v10:
+ return
+ (iver == cris_ver_version_all
+ || iver == cris_ver_warning
+ || iver == cris_ver_v0_3
+ || iver == cris_ver_v3p
+ || iver == cris_ver_v0_10
+ || iver == cris_ver_sim_v0_10
+ || iver == cris_ver_v3_10
+ || iver == cris_ver_v8
+ || iver == cris_ver_v8p
+ || iver == cris_ver_v8_10
+ || iver == cris_ver_v10
+ || iver == cris_ver_v10p);
+
+ case arch_crisv32:
+ return
+ (iver == cris_ver_version_all
+ || iver == cris_ver_v3p
+ || iver == cris_ver_v8p
+ || iver == cris_ver_v10p
+ || iver == cris_ver_v32p);
+
+ case arch_cris_common_v10_v32:
+ return
+ (iver == cris_ver_version_all
+ || iver == cris_ver_v3p
+ || iver == cris_ver_v8p
+ || iver == cris_ver_v10p);
+
+ case arch_crisv0:
+ return
+ (iver == cris_ver_version_all
+ || iver == cris_ver_v0_3
+ || iver == cris_ver_v0_10
+ || iver == cris_ver_sim_v0_10);
+
+ case arch_crisv3:
+ return
+ (iver == cris_ver_version_all
+ || iver == cris_ver_v0_3
+ || iver == cris_ver_v3p
+ || iver == cris_ver_v0_10
+ || iver == cris_ver_sim_v0_10
+ || iver == cris_ver_v3_10);
+
+ case arch_crisv8:
+ return
+ (iver == cris_ver_version_all
+ || iver == cris_ver_v3p
+ || iver == cris_ver_v0_10
+ || iver == cris_ver_sim_v0_10
+ || iver == cris_ver_v3_10
+ || iver == cris_ver_v8
+ || iver == cris_ver_v8p
+ || iver == cris_ver_v8_10);
+
+ case arch_crisv10:
+ return
+ (iver == cris_ver_version_all
+ || iver == cris_ver_v3p
+ || iver == cris_ver_v0_10
+ || iver == cris_ver_sim_v0_10
+ || iver == cris_ver_v3_10
+ || iver == cris_ver_v8p
+ || iver == cris_ver_v8_10
+ || iver == cris_ver_v10
+ || iver == cris_ver_v10p);
+
+ default:
+ BAD_CASE (arch);
+ }
+}
+
+/* Assert that the .arch ARCHCHOICE1 is compatible with the specified or
+ default --march=<ARCHCHOICE2> option. */
+
+static void
+s_cris_arch (int dummy ATTRIBUTE_UNUSED)
+{
+ /* Right now we take the easy route and check for sameness. It's not
+ obvious that allowing e.g. --march=v32 and .arch common_v0_v32
+ would be more useful than confusing, implementation-wise and
+ user-wise. */
+
+ const char *str = input_line_pointer;
+ enum cris_archs arch = cris_arch_from_string (&str);
+
+ if (arch == arch_cris_unknown)
+ {
+ as_bad (_("unknown operand to .arch"));
+
+ /* For this one, str does not reflect the end of the operand,
+ since there was no matching arch. Skip it manually; skip
+ things that can be part of a word (a name). */
+ while (is_part_of_name (*str))
+ str++;
+ }
+ else if (arch != cris_arch)
+ as_bad (_(".arch <arch> requires a matching --march=... option"));
+
+ input_line_pointer = (char *) str;
+ demand_empty_rest_of_line ();
+ return;
+}