aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans-Peter Nilsson <hp@axis.com>2004-11-04 15:00:37 +0000
committerHans-Peter Nilsson <hp@axis.com>2004-11-04 15:00:37 +0000
commitae57792d90d18306c9e470b9ecc245cdeef389f4 (patch)
treebd3957e95e9a8e9cf28eca84597470d3b127c1f8
parentbac23f82ae51ce67cf2d2e0ce4e2e222413efadc (diff)
downloadgdb-ae57792d90d18306c9e470b9ecc245cdeef389f4.zip
gdb-ae57792d90d18306c9e470b9ecc245cdeef389f4.tar.gz
gdb-ae57792d90d18306c9e470b9ecc245cdeef389f4.tar.bz2
* configure.in (crisv32): Recognize. AC_DEFINE_UNQUOTED
DEFAULT_CRIS_ARCH. Handle crisv32-*-linux-gnu* like cris-*-linux-gnu* and crisv32-*-* like cris-*-*. * configure: Regenerate. * config/tc-cris.c (enum cris_archs): New. (cris_mach, cris_arch_from_string, s_cris_arch, get_sup_reg) (cris_insn_ver_valid_for_arch): New functions. (DEFAULT_CRIS_ARCH): New macro, default to cris_any_v0_v10. (cris_arch): New variable. (md_pseudo_table): New pseudo .arch. (err_for_dangerous_mul_placement): Initialize according to DEFAULT_CRIS_ARCH. (STATE_COND_BRANCH): Renamed from STATE_CONDITIONAL_BRANCH. All users changed. (STATE_COND_BRANCH_V32, STATE_COND_BRANCH_COMMON) (STATE_ABS_BRANCH_V32, STATE_LAPC, BRANCH_BF_V32, BRANCH_BB_V32) (BRANCH_WF_V32, BRANCH_WB_V32): New. (BRANCH_BF, BRANCH_BB, BRANCH_WF, BRANCH_WB): Don't undef after use in md_cris_relax_table. (md_cris_relax_table): Add entries for STATE_COND_BRANCH_V32, STATE_COND_BRANCH_COMMON, STATE_ABS_BRANCH_V32, STATE_LAPC. Update and improve head comment. (OPTION_PIC): Define in terms of previous option, OPTION_US. (OPTION_MULBUG_ABORT_ON, OPTION_MULBUG_ABORT_OFF): Similar. (OPTION_ARCH): New. (md_longopts): New option --march=... (cris_any_v0_v10_long_jump_size, crisv32_long_jump_size): New macros. (md_long_jump_size): Initialize in terms of DEFAULT_CRIS_ARCH. (HANDLE_RELAXABLE): New macro. (md_estimate_size_before_relax): Use HANDLE_RELAXABLE for common cases. Check for weak symbols and assume not relaxable. Handle STATE_COND_BRANCH_V32, STATE_COND_BRANCH_COMMON, STATE_ABS_BRANCH_V32, STATE_LAPC. Use new variable symbolP, not fragP->fr_symbol. (md_convert_frag): Handle STATE_COND_BRANCH_V32, STATE_COND_BRANCH_COMMON, STATE_ABS_BRANCH_V32, STATE_LAPC. (cris_create_short_jump): Adjust for CRISv32. (md_create_long_jump): Ditto. Emit error for common_v10_v32. (md_begin): Define symbols "..asm.arch.cris.v32", "..asm.arch.cris.v10", "..asm.arch.cris.common_v10_v32" and "..asm.arch.cris.any_v0_v10". Use cris_insn_ver_valid_for_arch when entering opcode table entry points. (md_assemble): Adjust branch handling for CRISv32. Handle LAPC relaxation. In fix_new_exp call for main insn, pass 1 for pcrel parameter for 8, 16 and 32-bit pc-relative insns and LAPC. (cris_process_instruction): Initialize out_insnp->insn_type to CRIS_INSN_NONE, not CRIS_INSN_NORMAL. <case ']', '[', 'A', 'd', 'Q', 'N', 'n', 'Y', 'U', 'u', 'T'>: New cases. <case 'm'>: Check that modified_char == '.'. <invalid operands>: Consume the rest of the line. When operands don't match, skip over subsequent insns with non-matching version specifier but same mnemonic. <immediate constant, case SIZE_SPEC_REG>: Immediate operands for special registers in CRISv32 are always 32 bit long. <immediate constant, case SIZE_FIELD_SIGNED, SIZE_FIELD_UNSIGNED>: New cases. (get_gen_reg): Only recognize "PC" when followed by "+]" for v32 and compatible. Recognize "ACR" for v32, unless followed by "+". (get_spec_reg): Consider cris_arch when looking up register. (get_autoinc_prefix_or_indir_op): Don't recognize assignment for v32 or compatible. (get_3op_or_dip_prefix_op): Check for ']' after seeing '[rN+'. (cris_get_expression): Restore input_line_pointer if failing "early". (get_flags): Consider cris_arch and recognize flags accordingly. (branch_disp): Adjust for CRISv32. (gen_cond_branch_32): Similar. Emit error for common_v10_v32. (cris_number_to_imm): Use as_bad_where, not as_bad. Remove related FIXME. Don't insist on BFD_RELOC_32_PCREL fixup to be resolved. Don't enter zeros in object file for BFD_RELOC_32_PCREL. <case BFD_RELOC_CRIS_LAPCQ_OFFSET, BFD_RELOC_CRIS_SIGNED_16> <case BFD_RELOC_CRIS_SIGNED_8>: New case. (md_parse_option): Break out "return 1". <OPTION_ARCH> New case. (tc_gen_reloc): <case BFD_RELOC_CRIS_LAPCQ_OFFSET> <case BFD_RELOC_CRIS_SIGNED_16, BFD_RELOC_CRIS_SIGNED_8> <case BFD_RELOC_CRIS_UNSIGNED_8, BFD_RELOC_CRIS_UNSIGNED_16> <case BFD_RELOC_32_PCREL>: New cases. Addends for non-zero fx_pcrel are too in fx_offset. (md_show_usage): Show --march=<arch>. (md_apply_fix3): Adjust val for BFD_RELOC_CRIS_LAPCQ_OFFSET. (md_pcrel_from): BFD_RELOC_CRIS_LAPCQ_OFFSET is PC-relative too. (s_syntax) <struct syntaxes>: Properly constify member operand. * config/tc-cris.h (TARGET_MACH): Define. (cris_mach): Declare. * doc/as.texinfo (Overview) <CRIS>: Add --march=... * doc/c-cris.texi (CRIS-Symbols): New node for built-in symbols. (CRIS-Opts): Document --march=... (CRIS-Pseudos): Document .arch.
-rw-r--r--gas/ChangeLog94
-rw-r--r--gas/config/tc-cris.c1263
-rw-r--r--gas/config/tc-cris.h3
-rwxr-xr-xgas/configure12
-rw-r--r--gas/configure.in9
-rw-r--r--gas/doc/as.texinfo1
-rw-r--r--gas/doc/c-cris.texi102
7 files changed, 1333 insertions, 151 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 73398b3..d273789 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,97 @@
+2004-11-04 Hans-Peter Nilsson <hp@axis.com>
+
+ * configure.in (crisv32): Recognize. AC_DEFINE_UNQUOTED
+ DEFAULT_CRIS_ARCH. Handle crisv32-*-linux-gnu* like
+ cris-*-linux-gnu* and crisv32-*-* like cris-*-*.
+ * configure: Regenerate.
+ * config/tc-cris.c (enum cris_archs): New.
+ (cris_mach, cris_arch_from_string, s_cris_arch, get_sup_reg)
+ (cris_insn_ver_valid_for_arch): New functions.
+ (DEFAULT_CRIS_ARCH): New macro, default to cris_any_v0_v10.
+ (cris_arch): New variable.
+ (md_pseudo_table): New pseudo .arch.
+ (err_for_dangerous_mul_placement): Initialize according to
+ DEFAULT_CRIS_ARCH.
+ (STATE_COND_BRANCH): Renamed from STATE_CONDITIONAL_BRANCH.
+ All users changed.
+ (STATE_COND_BRANCH_V32, STATE_COND_BRANCH_COMMON)
+ (STATE_ABS_BRANCH_V32, STATE_LAPC, BRANCH_BF_V32, BRANCH_BB_V32)
+ (BRANCH_WF_V32, BRANCH_WB_V32): New.
+ (BRANCH_BF, BRANCH_BB, BRANCH_WF, BRANCH_WB): Don't undef after
+ use in md_cris_relax_table.
+ (md_cris_relax_table): Add entries for STATE_COND_BRANCH_V32,
+ STATE_COND_BRANCH_COMMON, STATE_ABS_BRANCH_V32, STATE_LAPC.
+ Update and improve head comment.
+ (OPTION_PIC): Define in terms of previous option, OPTION_US.
+ (OPTION_MULBUG_ABORT_ON, OPTION_MULBUG_ABORT_OFF): Similar.
+ (OPTION_ARCH): New.
+ (md_longopts): New option --march=...
+ (cris_any_v0_v10_long_jump_size, crisv32_long_jump_size): New
+ macros.
+ (md_long_jump_size): Initialize in terms of DEFAULT_CRIS_ARCH.
+ (HANDLE_RELAXABLE): New macro.
+ (md_estimate_size_before_relax): Use HANDLE_RELAXABLE for common
+ cases. Check for weak symbols and assume not relaxable. Handle
+ STATE_COND_BRANCH_V32, STATE_COND_BRANCH_COMMON,
+ STATE_ABS_BRANCH_V32, STATE_LAPC. Use new variable symbolP, not
+ fragP->fr_symbol.
+ (md_convert_frag): Handle STATE_COND_BRANCH_V32,
+ STATE_COND_BRANCH_COMMON, STATE_ABS_BRANCH_V32, STATE_LAPC.
+ (cris_create_short_jump): Adjust for CRISv32.
+ (md_create_long_jump): Ditto. Emit error for common_v10_v32.
+ (md_begin): Define symbols "..asm.arch.cris.v32",
+ "..asm.arch.cris.v10", "..asm.arch.cris.common_v10_v32" and
+ "..asm.arch.cris.any_v0_v10". Use cris_insn_ver_valid_for_arch
+ when entering opcode table entry points.
+ (md_assemble): Adjust branch handling for CRISv32. Handle LAPC
+ relaxation. In fix_new_exp call for main insn, pass 1 for pcrel
+ parameter for 8, 16 and 32-bit pc-relative insns and LAPC.
+ (cris_process_instruction): Initialize out_insnp->insn_type to
+ CRIS_INSN_NONE, not CRIS_INSN_NORMAL.
+ <case ']', '[', 'A', 'd', 'Q', 'N', 'n', 'Y', 'U', 'u', 'T'>: New
+ cases.
+ <case 'm'>: Check that modified_char == '.'.
+ <invalid operands>: Consume the rest of the line.
+ When operands don't match, skip over subsequent insns with
+ non-matching version specifier but same mnemonic.
+ <immediate constant, case SIZE_SPEC_REG>: Immediate operands for
+ special registers in CRISv32 are always 32 bit long.
+ <immediate constant, case SIZE_FIELD_SIGNED, SIZE_FIELD_UNSIGNED>:
+ New cases.
+ (get_gen_reg): Only recognize "PC" when followed by "+]" for v32
+ and compatible. Recognize "ACR" for v32, unless followed by "+".
+ (get_spec_reg): Consider cris_arch when looking up register.
+ (get_autoinc_prefix_or_indir_op): Don't recognize assignment for
+ v32 or compatible.
+ (get_3op_or_dip_prefix_op): Check for ']' after seeing '[rN+'.
+ (cris_get_expression): Restore input_line_pointer if failing "early".
+ (get_flags): Consider cris_arch and recognize flags accordingly.
+ (branch_disp): Adjust for CRISv32.
+ (gen_cond_branch_32): Similar. Emit error for common_v10_v32.
+ (cris_number_to_imm): Use as_bad_where, not as_bad. Remove
+ related FIXME. Don't insist on BFD_RELOC_32_PCREL fixup to be
+ resolved. Don't enter zeros in object file for
+ BFD_RELOC_32_PCREL.
+ <case BFD_RELOC_CRIS_LAPCQ_OFFSET, BFD_RELOC_CRIS_SIGNED_16>
+ <case BFD_RELOC_CRIS_SIGNED_8>: New case.
+ (md_parse_option): Break out "return 1".
+ <OPTION_ARCH> New case.
+ (tc_gen_reloc): <case BFD_RELOC_CRIS_LAPCQ_OFFSET>
+ <case BFD_RELOC_CRIS_SIGNED_16, BFD_RELOC_CRIS_SIGNED_8>
+ <case BFD_RELOC_CRIS_UNSIGNED_8, BFD_RELOC_CRIS_UNSIGNED_16>
+ <case BFD_RELOC_32_PCREL>: New cases.
+ Addends for non-zero fx_pcrel are too in fx_offset.
+ (md_show_usage): Show --march=<arch>.
+ (md_apply_fix3): Adjust val for BFD_RELOC_CRIS_LAPCQ_OFFSET.
+ (md_pcrel_from): BFD_RELOC_CRIS_LAPCQ_OFFSET is PC-relative too.
+ (s_syntax) <struct syntaxes>: Properly constify member operand.
+ * config/tc-cris.h (TARGET_MACH): Define.
+ (cris_mach): Declare.
+ * doc/as.texinfo (Overview) <CRIS>: Add --march=...
+ * doc/c-cris.texi (CRIS-Symbols): New node for built-in symbols.
+ (CRIS-Opts): Document --march=...
+ (CRIS-Pseudos): Document .arch.
+
2004-11-04 Jan Beulich <jbeulich@novell.com>
* config/tc-i386.c (set_intel_syntax): Allow % in symbol names when
diff --git a/gas/config/tc-cris.c b/gas/config/tc-cris.c
index 0f3d3c8..5e8d4bd 100644
--- a/gas/config/tc-cris.c
+++ b/gas/config/tc-cris.c
@@ -113,6 +113,17 @@ struct cris_instruction
int imm_oprnd_size;
};
+enum cris_archs
+{
+ arch_cris_unknown,
+ arch_crisv0, arch_crisv3, arch_crisv8, arch_crisv10,
+ arch_cris_any_v0_v10, arch_crisv32, arch_cris_common_v10_v32
+};
+
+static enum cris_archs cris_arch_from_string PARAMS ((char **));
+static int cris_insn_ver_valid_for_arch PARAMS ((enum cris_insn_version_usage,
+ enum cris_archs));
+
static void cris_process_instruction PARAMS ((char *,
struct cris_instruction *,
struct cris_prefix *));
@@ -121,6 +132,7 @@ static int get_bw_size_modifier PARAMS ((char **, int *));
static int get_gen_reg PARAMS ((char **, int *));
static int get_spec_reg PARAMS ((char **,
const struct cris_spec_reg **));
+static int get_sup_reg PARAMS ((char **, int *));
static int get_autoinc_prefix_or_indir_op PARAMS ((char **,
struct cris_prefix *,
int *, int *, int *,
@@ -139,6 +151,7 @@ static void cris_create_short_jump PARAMS ((char *, addressT, addressT,
static void s_syntax PARAMS ((int));
static void s_cris_file PARAMS ((int));
static void s_cris_loc PARAMS ((int));
+static void s_cris_arch PARAMS ((int));
/* Get ":GOT", ":GOTOFF", ":PLT" etc. suffixes. */
static void cris_get_pic_suffix PARAMS ((char **,
@@ -176,12 +189,22 @@ static bfd_boolean symbols_have_leading_underscore
/* Whether or not we allow PIC, and expand to PIC-friendly constructs. */
static bfd_boolean pic = FALSE;
+/* If we're configured for "cris", default to allow all v0..v10
+ instructions and register names. */
+#ifndef DEFAULT_CRIS_ARCH
+#define DEFAULT_CRIS_ARCH cris_any_v0_v10
+#endif
+
+/* No whitespace in the CONCAT2 parameter list. */
+static enum cris_archs cris_arch = XCONCAT2 (arch_,DEFAULT_CRIS_ARCH);
+
const pseudo_typeS md_pseudo_table[] =
{
{"dword", cons, 4},
{"syntax", s_syntax, 0},
{"file", s_cris_file, 0},
{"loc", s_cris_loc, 0},
+ {"arch", s_cris_arch, 0},
{NULL, 0, 0}
};
@@ -189,7 +212,8 @@ static int warn_for_branch_expansion = 0;
/* Whether to emit error when a MULS/MULU could be located last on a
cache-line. */
-static int err_for_dangerous_mul_placement = 1;
+static int err_for_dangerous_mul_placement
+ = (XCONCAT2 (arch_,DEFAULT_CRIS_ARCH) != arch_crisv32);
const char cris_comment_chars[] = ";";
@@ -214,12 +238,11 @@ const char FLT_CHARS[] = "";
---/ /--+-----------------+-----------------+-----------------+
The "how long" bits are 00 = byte, 01 = word, 10 = dword (long).
- This is a Un*x convention.
Not all lengths are legit for a given value of (what state).
Groups for CRIS address relaxing:
- 1. Bcc
+ 1. Bcc (pre-V32)
length: byte, word, 10-byte expansion
2. BDAP
@@ -228,11 +251,28 @@ const char FLT_CHARS[] = "";
3. MULS/MULU
Not really a relaxation (no infrastructure to get delay-slots
right), just an alignment and placement checker for the v10
- multiply/cache-bug. */
+ multiply/cache-bug.
+
+ 4. Bcc (V32 and later)
+ length: byte, word, 14-byte expansion
+
+ 5. Bcc (V10+V32)
+ length: byte, word, error
+
+ 6. BA (V32)
+ length: byte, word, dword
-#define STATE_CONDITIONAL_BRANCH (1)
+ 7. LAPC (V32)
+ length: byte, dword
+ */
+
+#define STATE_COND_BRANCH (1)
#define STATE_BASE_PLUS_DISP_PREFIX (2)
#define STATE_MUL (3)
+#define STATE_COND_BRANCH_V32 (4)
+#define STATE_COND_BRANCH_COMMON (5)
+#define STATE_ABS_BRANCH_V32 (6)
+#define STATE_LAPC (7)
#define STATE_LENGTH_MASK (3)
#define STATE_BYTE (0)
@@ -248,8 +288,12 @@ const char FLT_CHARS[] = "";
#define BRANCH_BF ( 254)
#define BRANCH_BB (-256)
+#define BRANCH_BF_V32 ( 252)
+#define BRANCH_BB_V32 (-258)
#define BRANCH_WF (2 + 32767)
#define BRANCH_WB (2 + -32768)
+#define BRANCH_WF_V32 (-2 + 32767)
+#define BRANCH_WB_V32 (-2 + -32768)
#define BDAP_BF ( 127)
#define BDAP_BB (-128)
@@ -295,39 +339,90 @@ const relax_typeS md_cris_relax_table[] =
{0, 0, 4, 0},
/* Unused (2, 3). */
- {0, 0, 0, 0},
+ {1, 1, 0, 0},
/* MULS/MULU (3, 0). Positions (3, 1..3) are unused. */
- {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}
+ {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0},
+
+ /* V32: Bcc o (4, 0). */
+ {BRANCH_BF_V32, BRANCH_BB_V32, 0, ENCODE_RELAX (4, 1)},
+
+ /* V32: Bcc [PC+] (4, 1). */
+ {BRANCH_WF_V32, BRANCH_WB_V32, 2, ENCODE_RELAX (4, 2)},
+
+ /* V32: BA .+12; NOP; BA32 target; NOP; Bcc .-6 (4, 2). */
+ {0, 0, 12, 0},
+
+ /* Unused (4, 3). */
+ {1, 1, 0, 0},
+
+ /* COMMON: Bcc o (5, 0). The offsets are calculated as for v32. Code
+ should contain two nop insns (or four if offset size is large or
+ unknown) after every label. */
+ {BRANCH_BF_V32, BRANCH_BB_V32, 0, ENCODE_RELAX (5, 1)},
+
+ /* COMMON: Bcc [PC+] (5, 1). */
+ {BRANCH_WF_V32, BRANCH_WB_V32, 2, ENCODE_RELAX (5, 2)},
+
+ /* COMMON: FIXME: ???. Treat as error currently. */
+ {0, 0, 12, 0},
+
+ /* Unused (5, 3). */
+ {1, 1, 0, 0},
+
+ /* V32: BA o (6, 0). */
+ {BRANCH_BF_V32, BRANCH_BB_V32, 0, ENCODE_RELAX (6, 1)},
+
+ /* V32: BA.W (6, 1). */
+ {BRANCH_WF_V32, BRANCH_WB_V32, 2, ENCODE_RELAX (6, 2)},
+
+ /* V32: BA.D (6, 2). */
+ {0, 0, 4, 0},
+
+ /* Unused (6, 3). */
+ {1, 1, 0, 0},
+
+ /* LAPC: LAPCQ .+0..15*2,Rn (7, 0). */
+ {14*2, -1*2, 0, ENCODE_RELAX (7, 2)},
+
+ /* Unused (7, 1).
+ While there's a shorter sequence, e.g. LAPCQ + an ADDQ or SUBQ,
+ that would affect flags, so we can't do that as it wouldn't be a
+ proper insn expansion of LAPCQ. This row is associated with a
+ 2-byte expansion, so it's unused rather than the next. */
+ {1, 1, 0, 0},
+
+ /* LAPC: LAPC.D (7, 2). */
+ {0, 0, 4, 0},
+
+ /* Unused (7, 3). */
+ {1, 1, 0, 0}
};
-#undef BRANCH_BF
-#undef BRANCH_BB
-#undef BRANCH_WF
-#undef BRANCH_WB
#undef BDAP_BF
#undef BDAP_BB
#undef BDAP_WF
#undef BDAP_WB
-/* Target-specific multicharacter options, not const-declared at usage
- in 2.9.1 and CVS of 2000-02-16. */
+/* Target-specific multicharacter options, not const-declared. */
struct option md_longopts[] =
{
#define OPTION_NO_US (OPTION_MD_BASE + 0)
{"no-underscore", no_argument, NULL, OPTION_NO_US},
#define OPTION_US (OPTION_MD_BASE + 1)
{"underscore", no_argument, NULL, OPTION_US},
-#define OPTION_PIC (OPTION_MD_BASE + 2)
+#define OPTION_PIC (OPTION_US + 1)
{"pic", no_argument, NULL, OPTION_PIC},
-#define OPTION_MULBUG_ABORT_ON (OPTION_MD_BASE + 3)
+#define OPTION_MULBUG_ABORT_ON (OPTION_PIC + 1)
{"mul-bug-abort", no_argument, NULL, OPTION_MULBUG_ABORT_ON},
-#define OPTION_MULBUG_ABORT_OFF (OPTION_MD_BASE + 4)
+#define OPTION_MULBUG_ABORT_OFF (OPTION_MULBUG_ABORT_ON + 1)
{"no-mul-bug-abort", no_argument, NULL, OPTION_MULBUG_ABORT_OFF},
+#define OPTION_ARCH (OPTION_MULBUG_ABORT_OFF + 1)
+ {"march", required_argument, NULL, OPTION_ARCH},
{NULL, no_argument, NULL, 0}
};
-/* Not const-declared at usage in 2.9.1. */
+/* Not const-declared. */
size_t md_longopts_size = sizeof (md_longopts);
const char *md_shortopts = "hHN";
@@ -342,7 +437,12 @@ const char *md_shortopts = "hHN";
numbers, and md_create_short_jump is called after relaxation. */
int md_short_jump_size = 6;
-int md_long_jump_size = 6;
+
+/* The v32 version has a delay-slot, hence two bytes longer. */
+#define cris_any_v0_v10_long_jump_size 6
+#define crisv32_long_jump_size 8
+
+int md_long_jump_size = XCONCAT2 (DEFAULT_CRIS_ARCH,_long_jump_size);
/* Report output format. Small changes in output format (like elf
variants below) can happen until all options are parsed, but after
@@ -367,6 +467,36 @@ cris_target_format ()
}
}
+/* Return a bfd_mach_cris... value corresponding to the value of
+ cris_arch. */
+
+unsigned int
+cris_mach ()
+{
+ unsigned int retval = 0;
+
+ switch (cris_arch)
+ {
+ case arch_cris_common_v10_v32:
+ retval = bfd_mach_cris_v10_v32;
+ break;
+
+ case arch_crisv32:
+ retval = bfd_mach_cris_v32;
+ break;
+
+ case arch_crisv10:
+ case arch_cris_any_v0_v10:
+ retval = bfd_mach_cris_v0_v10;
+ break;
+
+ default:
+ BAD_CASE (cris_arch);
+ }
+
+ return retval;
+}
+
/* We need a port-specific relaxation function to cope with sym2 - sym1
relative expressions with both symbols in the same segment (but not
necessarily in the same frag as this insn), for example:
@@ -394,7 +524,11 @@ cris_relax_frag (seg, fragP, stretch)
because of the different reasons that they aren't relaxable. */
switch (fragP->fr_subtype)
{
- case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_DWORD):
+ case ENCODE_RELAX (STATE_COND_BRANCH, STATE_DWORD):
+ case ENCODE_RELAX (STATE_COND_BRANCH_V32, STATE_DWORD):
+ case ENCODE_RELAX (STATE_COND_BRANCH_COMMON, STATE_DWORD):
+ case ENCODE_RELAX (STATE_ABS_BRANCH_V32, STATE_DWORD):
+ case ENCODE_RELAX (STATE_LAPC, STATE_DWORD):
case ENCODE_RELAX (STATE_BASE_PLUS_DISP_PREFIX, STATE_DWORD):
/* When we get to these states, the frag won't grow any more. */
return 0;
@@ -484,21 +618,63 @@ md_estimate_size_before_relax (fragP, segment_type)
segT segment_type;
{
int old_fr_fix;
+ symbolS *symbolP = fragP->fr_symbol;
+
+#define HANDLE_RELAXABLE(state) \
+ case ENCODE_RELAX (state, STATE_UNDF): \
+ if (symbolP != NULL \
+ && S_GET_SEGMENT (symbolP) == segment_type \
+ && !S_IS_WEAK (symbolP)) \
+ /* The symbol lies in the same segment - a relaxable \
+ case. */ \
+ fragP->fr_subtype \
+ = ENCODE_RELAX (state, STATE_BYTE); \
+ else \
+ /* Unknown or not the same segment, so not relaxable. */ \
+ fragP->fr_subtype \
+ = ENCODE_RELAX (state, STATE_DWORD); \
+ fragP->fr_var \
+ = md_cris_relax_table[fragP->fr_subtype].rlx_length; \
+ break
old_fr_fix = fragP->fr_fix;
switch (fragP->fr_subtype)
{
- case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_UNDF):
- if (S_GET_SEGMENT (fragP->fr_symbol) == segment_type)
- /* The symbol lies in the same segment - a relaxable case. */
- fragP->fr_subtype
- = ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_BYTE);
+ HANDLE_RELAXABLE (STATE_COND_BRANCH);
+ HANDLE_RELAXABLE (STATE_COND_BRANCH_V32);
+ HANDLE_RELAXABLE (STATE_COND_BRANCH_COMMON);
+ HANDLE_RELAXABLE (STATE_ABS_BRANCH_V32);
+
+ case ENCODE_RELAX (STATE_LAPC, STATE_UNDF):
+ if (symbolP != NULL
+ && S_GET_SEGMENT (symbolP) == segment_type
+ && !S_IS_WEAK (symbolP))
+ {
+ /* The symbol lies in the same segment - a relaxable case.
+ Check if we currently have an odd offset; we can't code
+ that into the instruction. Relaxing presumably only cause
+ multiple-of-two changes, so we should only need to adjust
+ for that here. */
+ bfd_vma target_address
+ = (symbolP
+ ? S_GET_VALUE (symbolP)
+ : 0) + fragP->fr_offset;
+ bfd_vma var_part_offset = fragP->fr_fix;
+ bfd_vma address_of_var_part = fragP->fr_address + var_part_offset;
+ long offset = target_address - (address_of_var_part - 2);
+
+ fragP->fr_subtype
+ = (offset & 1)
+ ? ENCODE_RELAX (STATE_LAPC, STATE_DWORD)
+ : ENCODE_RELAX (STATE_LAPC, STATE_BYTE);
+ }
else
/* Unknown or not the same segment, so not relaxable. */
fragP->fr_subtype
- = ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_DWORD);
- fragP->fr_var = md_cris_relax_table[fragP->fr_subtype].rlx_length;
+ = ENCODE_RELAX (STATE_LAPC, STATE_DWORD);
+ fragP->fr_var
+ = md_cris_relax_table[fragP->fr_subtype].rlx_length;
break;
case ENCODE_RELAX (STATE_BASE_PLUS_DISP_PREFIX, STATE_UNDF):
@@ -512,7 +688,7 @@ md_estimate_size_before_relax (fragP, segment_type)
would in general be no shorter or faster code, only more
complicated. */
- if (S_GET_SEGMENT (fragP->fr_symbol) != absolute_section)
+ if (S_GET_SEGMENT (symbolP) != absolute_section)
{
/* Go for dword if not absolute or same segment. */
fragP->fr_subtype
@@ -534,7 +710,8 @@ md_estimate_size_before_relax (fragP, segment_type)
{
/* Absolute expression. */
long int value;
- value = S_GET_VALUE (fragP->fr_symbol) + fragP->fr_offset;
+ value = (symbolP != NULL
+ ? S_GET_VALUE (symbolP) : 0) + fragP->fr_offset;
if (value >= -128 && value <= 127)
{
@@ -571,9 +748,20 @@ md_estimate_size_before_relax (fragP, segment_type)
}
break;
- case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_BYTE):
- case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_WORD):
- case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_DWORD):
+ case ENCODE_RELAX (STATE_COND_BRANCH, STATE_BYTE):
+ case ENCODE_RELAX (STATE_COND_BRANCH, STATE_WORD):
+ case ENCODE_RELAX (STATE_COND_BRANCH, STATE_DWORD):
+ case ENCODE_RELAX (STATE_COND_BRANCH_V32, STATE_BYTE):
+ case ENCODE_RELAX (STATE_COND_BRANCH_V32, STATE_WORD):
+ case ENCODE_RELAX (STATE_COND_BRANCH_V32, STATE_DWORD):
+ case ENCODE_RELAX (STATE_COND_BRANCH_COMMON, STATE_BYTE):
+ case ENCODE_RELAX (STATE_COND_BRANCH_COMMON, STATE_WORD):
+ case ENCODE_RELAX (STATE_COND_BRANCH_COMMON, STATE_DWORD):
+ case ENCODE_RELAX (STATE_ABS_BRANCH_V32, STATE_BYTE):
+ case ENCODE_RELAX (STATE_ABS_BRANCH_V32, STATE_WORD):
+ case ENCODE_RELAX (STATE_ABS_BRANCH_V32, STATE_DWORD):
+ case ENCODE_RELAX (STATE_LAPC, STATE_BYTE):
+ case ENCODE_RELAX (STATE_LAPC, STATE_DWORD):
case ENCODE_RELAX (STATE_BASE_PLUS_DISP_PREFIX, STATE_BYTE):
case ENCODE_RELAX (STATE_BASE_PLUS_DISP_PREFIX, STATE_WORD):
case ENCODE_RELAX (STATE_BASE_PLUS_DISP_PREFIX, STATE_DWORD):
@@ -648,24 +836,35 @@ md_convert_frag (abfd, sec, fragP)
switch (fragP->fr_subtype)
{
- case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_BYTE):
+ case ENCODE_RELAX (STATE_COND_BRANCH, STATE_BYTE):
+ case ENCODE_RELAX (STATE_COND_BRANCH_V32, STATE_BYTE):
+ case ENCODE_RELAX (STATE_COND_BRANCH_COMMON, STATE_BYTE):
+ case ENCODE_RELAX (STATE_ABS_BRANCH_V32, STATE_BYTE):
opcodep[0] = branch_disp ((target_address - address_of_var_part));
var_part_size = 0;
break;
- case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_WORD):
+ case ENCODE_RELAX (STATE_COND_BRANCH, STATE_WORD):
+ case ENCODE_RELAX (STATE_COND_BRANCH_V32, STATE_WORD):
+ case ENCODE_RELAX (STATE_COND_BRANCH_COMMON, STATE_WORD):
+ case ENCODE_RELAX (STATE_ABS_BRANCH_V32, STATE_WORD):
/* We had a quick immediate branch, now turn it into a word one i.e. a
PC autoincrement. */
opcodep[0] = BRANCH_PC_LOW;
opcodep[1] &= 0xF0;
opcodep[1] |= BRANCH_INCR_HIGH;
md_number_to_chars (var_partp,
- (long) (target_address - (address_of_var_part + 2)),
+ (long)
+ (target_address
+ - (address_of_var_part
+ + (cris_arch == arch_crisv32
+ || cris_arch == arch_cris_common_v10_v32
+ ? -2 : 2))),
2);
var_part_size = 2;
break;
- case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_DWORD):
+ case ENCODE_RELAX (STATE_COND_BRANCH, STATE_DWORD):
gen_cond_branch_32 (fragP->fr_opcode, var_partp, fragP,
fragP->fr_symbol, (symbolS *) NULL,
fragP->fr_offset);
@@ -673,6 +872,74 @@ md_convert_frag (abfd, sec, fragP)
var_part_size = 2 + 2 + 4 + 2;
break;
+ case ENCODE_RELAX (STATE_COND_BRANCH_V32, STATE_DWORD):
+ gen_cond_branch_32 (fragP->fr_opcode, var_partp, fragP,
+ fragP->fr_symbol, (symbolS *) NULL,
+ fragP->fr_offset);
+ /* Twelve bytes added: a branch, nop and another branch and nop. */
+ var_part_size = 2 + 2 + 2 + 4 + 2;
+ break;
+
+ case ENCODE_RELAX (STATE_COND_BRANCH_COMMON, STATE_DWORD):
+ as_bad_where (fragP->fr_file, fragP->fr_line,
+ _("Relaxation to long branches for .arch common_v10_v32\
+ not implemented"));
+ /* Pretend we have twelve bytes for sake of quelling further
+ errors. */
+ var_part_size = 2 + 2 + 2 + 4 + 2;
+ break;
+
+ case ENCODE_RELAX (STATE_ABS_BRANCH_V32, STATE_DWORD):
+ /* We had a quick immediate branch or a word immediate ba. Now
+ turn it into a dword one. */
+ opcodep[0] = BA_DWORD_OPCODE & 255;
+ opcodep[1] = (BA_DWORD_OPCODE >> 8) & 255;
+ fix_new (fragP, var_partp - fragP->fr_literal, 4, symbolP,
+ fragP->fr_offset + 6, 1, BFD_RELOC_32_PCREL);
+ var_part_size = 4;
+ break;
+
+ case ENCODE_RELAX (STATE_LAPC, STATE_BYTE):
+ {
+ long offset = target_address - (address_of_var_part - 2);
+
+ /* This is mostly a sanity check; useful occurrences (if there
+ really are any) should have been caught in
+ md_estimate_size_before_relax. We can (at least
+ theoretically) stumble over invalid code with odd sizes and
+ .p2aligns within the code, so emit an error if that happens.
+ (The generic relaxation machinery is not fit to check this.) */
+
+ if (offset & 1)
+ as_bad_where (fragP->fr_file, fragP->fr_line,
+ _("Complicated LAPC target operand is not\
+ a multiple of two. Use LAPC.D"));
+
+ /* FIXME: This *is* a sanity check. Remove when done with. */
+ if (offset > 15*2 || offset < 0)
+ as_fatal (_("Internal error found in md_convert_frag: offset %ld.\
+ Please report this."),
+ offset);
+
+ opcodep[0] |= (offset / 2) & 0xf;
+ var_part_size = 0;
+ }
+ break;
+
+ case ENCODE_RELAX (STATE_LAPC, STATE_DWORD):
+ {
+ md_number_to_chars (opcodep,
+ LAPC_DWORD_OPCODE + (opcodep[1] & 0xf0) * 256,
+ 2);
+ /* Remember that the reloc is against the position *after* the
+ relocated contents, so we need to adjust to the start of
+ the insn. */
+ fix_new (fragP, var_partp - fragP->fr_literal, 4, fragP->fr_symbol,
+ fragP->fr_offset + 6, 1, BFD_RELOC_32_PCREL);
+ var_part_size = 4;
+ }
+ break;
+
case ENCODE_RELAX (STATE_BASE_PLUS_DISP_PREFIX, STATE_BYTE):
if (symbolP == NULL)
as_fatal (_("internal inconsistency in %s: bdapq no symbol"),
@@ -737,9 +1004,8 @@ md_convert_frag (abfd, sec, fragP)
Used by md_create_long_jump.
This used to be md_create_short_jump, but is now called from
- md_create_long_jump instead, when sufficient.
- since the sizes of the jumps are the same. It used to be brittle,
- making possibilities for creating bad code. */
+ md_create_long_jump instead, when sufficient, since the sizes of the
+ jumps are the same for pre-v32. */
static void
cris_create_short_jump (storep, from_addr, to_addr, fragP, to_symbol)
@@ -751,20 +1017,39 @@ cris_create_short_jump (storep, from_addr, to_addr, fragP, to_symbol)
{
long int distance;
+ /* See md_create_long_jump about the comment on the "+ 2". */
+ long int max_minimal_minus_distance;
+ long int max_minimal_plus_distance;
+ int nop_opcode;
+
+ if (cris_arch == arch_crisv32)
+ {
+ max_minimal_minus_distance = BRANCH_BB_V32 + 2;
+ max_minimal_plus_distance = BRANCH_BF_V32 + 2;
+ nop_opcode = NOP_OPCODE_V32;
+ }
+ else
+ {
+ max_minimal_minus_distance = BRANCH_BB + 2;
+ max_minimal_plus_distance = BRANCH_BF + 2;
+ nop_opcode = NOP_OPCODE;
+ }
+
distance = to_addr - from_addr;
- if (-254 <= distance && distance <= 256)
+ if (max_minimal_minus_distance <= distance
+ && distance <= max_minimal_plus_distance)
{
/* Create a "short" short jump: "BA distance - 2". */
storep[0] = branch_disp (distance - 2);
storep[1] = BA_QUICK_HIGH;
/* A nop for the delay slot. */
- md_number_to_chars (storep + 2, NOP_OPCODE, 2);
+ md_number_to_chars (storep + 2, nop_opcode, 2);
/* The extra word should be filled with something sane too. Make it
a nop to keep disassembly sane. */
- md_number_to_chars (storep + 4, NOP_OPCODE, 2);
+ md_number_to_chars (storep + 4, nop_opcode, 2);
}
else
{
@@ -772,10 +1057,14 @@ cris_create_short_jump (storep, from_addr, to_addr, fragP, to_symbol)
md_number_to_chars (storep, BA_PC_INCR_OPCODE, 2);
/* ".WORD distance - 4". */
- md_number_to_chars (storep + 2, (long) (distance - 4), 2);
+ md_number_to_chars (storep + 2,
+ (long) (distance - 4
+ - (cris_arch == arch_crisv32
+ ? -4 : 0)),
+ 2);
/* A nop for the delay slot. */
- md_number_to_chars (storep + 4, NOP_OPCODE, 2);
+ md_number_to_chars (storep + 4, nop_opcode, 2);
}
}
@@ -798,24 +1087,50 @@ md_create_long_jump (storep, from_addr, to_addr, fragP, to_symbol)
{
long int distance;
+ /* FIXME: What's that "+ 3"? It comes from the magic numbers that
+ used to be here, it's just translated to the limit macros used in
+ the relax table. But why + 3? */
+ long int max_short_minus_distance
+ = cris_arch != arch_crisv32 ? BRANCH_WB + 3 : BRANCH_WB_V32 + 3;
+
+ long int max_short_plus_distance
+ = cris_arch != arch_crisv32 ? BRANCH_WF + 3 : BRANCH_WF_V32 + 3;
+
+ /* Bail out for compatibility mode. (It seems it can be implemented,
+ perhaps with a 10-byte sequence: "move.d NNNN,$pc/$acr", "jump
+ $acr", "nop"; but doesn't seem worth it at the moment.) */
+ if (cris_arch == arch_cris_common_v10_v32)
+ as_fatal (_("Out-of-range .word offset handling\
+ is not implemented for .arch common_v10_v32"));
+
distance = to_addr - from_addr;
- if (-32763 <= distance && distance <= 32772)
- {
- /* Then make it a "short" long jump. */
- cris_create_short_jump (storep, from_addr, to_addr, fragP,
- to_symbol);
- }
+ if (max_short_minus_distance <= distance
+ && distance <= max_short_plus_distance)
+ /* Then make it a "short" long jump. */
+ cris_create_short_jump (storep, from_addr, to_addr, fragP,
+ to_symbol);
else
{
- /* We have a "long" long jump: "JUMP [PC+]".
- Make it an "ADD [PC+],PC" if we're supposed to emit PIC code. */
+ /* We have a "long" long jump: "JUMP [PC+]". If CRISv32, always
+ make it a BA. Else make it an "ADD [PC+],PC" if we're supposed
+ to emit PIC code. */
md_number_to_chars (storep,
- pic ? ADD_PC_INCR_OPCODE : JUMP_PC_INCR_OPCODE, 2);
+ cris_arch == arch_crisv32
+ ? BA_DWORD_OPCODE
+ : (pic ? ADD_PC_INCR_OPCODE : JUMP_PC_INCR_OPCODE),
+ 2);
/* Follow with a ".DWORD to_addr", PC-relative for PIC. */
fix_new (fragP, storep + 2 - fragP->fr_literal, 4, to_symbol,
- 0, pic ? 1 : 0, pic ? BFD_RELOC_32_PCREL : BFD_RELOC_32);
+ cris_arch == arch_crisv32 ? 6 : 0,
+ cris_arch == arch_crisv32 || pic ? 1 : 0,
+ cris_arch == arch_crisv32 || pic
+ ? BFD_RELOC_32_PCREL : BFD_RELOC_32);
+
+ /* Follow it with a "NOP" for CRISv32. */
+ if (cris_arch == arch_crisv32)
+ md_number_to_chars (storep + 6, NOP_OPCODE_V32, 2);
}
}
@@ -852,9 +1167,34 @@ md_begin ()
if (op_hash == NULL)
as_fatal (_("Virtual memory exhausted"));
+ /* Enable use of ".if ..asm.arch.cris.v32"
+ and ".if ..asm.arch.cris.common_v10_v32" and a few others. */
+ symbol_table_insert (symbol_new ("..asm.arch.cris.v32", absolute_section,
+ (cris_arch == arch_crisv32),
+ &zero_address_frag));
+ symbol_table_insert (symbol_new ("..asm.arch.cris.v10", absolute_section,
+ (cris_arch == arch_crisv10),
+ &zero_address_frag));
+ symbol_table_insert (symbol_new ("..asm.arch.cris.common_v10_v32",
+ absolute_section,
+ (cris_arch == arch_cris_common_v10_v32),
+ &zero_address_frag));
+ symbol_table_insert (symbol_new ("..asm.arch.cris.any_v0_v10",
+ absolute_section,
+ (cris_arch == arch_cris_any_v0_v10),
+ &zero_address_frag));
+
while (cris_opcodes[i].name != NULL)
{
const char *name = cris_opcodes[i].name;
+
+ if (! cris_insn_ver_valid_for_arch (cris_opcodes[i].applicable_version,
+ cris_arch))
+ {
+ i++;
+ continue;
+ }
+
hashret = hash_insert (op_hash, name, (PTR) &cris_opcodes[i]);
if (hashret != NULL && *hashret != '\0')
@@ -980,7 +1320,12 @@ md_assemble (str)
is_undefined = 1;
}
- if (to_seg == now_seg || is_undefined)
+ if (to_seg == now_seg || is_undefined
+ /* In CRISv32, there *is* a 32-bit absolute branch, so don't
+ emit the 12-byte sequence for known symbols in other
+ segments. */
+ || (cris_arch == arch_crisv32
+ && output_instruction.opcode == BA_QUICK_OPCODE))
{
/* Handle complex expressions. */
valueT addvalue
@@ -992,12 +1337,24 @@ md_assemble (str)
? output_instruction.expr.X_add_symbol
: make_expr_symbol (&output_instruction.expr));
- /* If is_undefined, then the expression may BECOME now_seg. */
- length_code = is_undefined ? STATE_UNDF : STATE_BYTE;
-
- /* Make room for max ten bytes of variable length. */
- frag_var (rs_machine_dependent, 10, 0,
- ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, length_code),
+ /* If is_undefined, the expression may still become now_seg.
+ That case is handled by md_estimate_size_before_relax. */
+ length_code = to_seg == now_seg ? STATE_BYTE : STATE_UNDF;
+
+ /* Make room for max twelve bytes of variable length for v32 mode,
+ ten for v10 and older. */
+ frag_var (rs_machine_dependent,
+ (cris_arch == arch_crisv32
+ || cris_arch == arch_cris_common_v10_v32) ? 12 : 10, 0,
+ ENCODE_RELAX (cris_arch == arch_crisv32
+ ? (output_instruction.opcode
+ == BA_QUICK_OPCODE
+ ? STATE_ABS_BRANCH_V32
+ : STATE_COND_BRANCH_V32)
+ : (cris_arch == arch_cris_common_v10_v32
+ ? STATE_COND_BRANCH_COMMON
+ : STATE_COND_BRANCH),
+ length_code),
sym, addvalue, opcodep);
}
else
@@ -1005,7 +1362,10 @@ md_assemble (str)
/* We have: to_seg != now_seg && to_seg != undefined_section.
This means it is a branch to a known symbol in another
section, perhaps an absolute address. Emit a 32-bit branch. */
- char *cond_jump = frag_more (10);
+ char *cond_jump
+ = frag_more ((cris_arch == arch_crisv32
+ || cris_arch == arch_cris_common_v10_v32)
+ ? 12 : 10);
gen_cond_branch_32 (opcodep, cond_jump, frag_now,
output_instruction.expr.X_add_symbol,
@@ -1057,7 +1417,29 @@ md_assemble (str)
p = frag_more (output_instruction.imm_oprnd_size);
fix_new_exp (frag_now, (p - frag_now->fr_literal),
output_instruction.imm_oprnd_size,
- &output_instruction.expr, 0, reloc);
+ &output_instruction.expr,
+ reloc == BFD_RELOC_32_PCREL
+ || reloc == BFD_RELOC_16_PCREL
+ || reloc == BFD_RELOC_8_PCREL, reloc);
+ }
+ else if (output_instruction.reloc == BFD_RELOC_CRIS_LAPCQ_OFFSET
+ && output_instruction.expr.X_md != 0)
+ {
+ /* Handle complex expressions. */
+ valueT addvalue
+ = (output_instruction.expr.X_op_symbol != NULL
+ ? 0 : output_instruction.expr.X_add_number);
+ symbolS *sym
+ = (output_instruction.expr.X_op_symbol != NULL
+ ? make_expr_symbol (&output_instruction.expr)
+ : output_instruction.expr.X_add_symbol);
+
+ /* This is a relaxing construct, so we need a frag_var rather
+ than the fix_new_exp call below. */
+ frag_var (rs_machine_dependent,
+ 4, 0,
+ ENCODE_RELAX (STATE_LAPC, STATE_UNDF),
+ sym, addvalue, opcodep);
}
else if (output_instruction.reloc != BFD_RELOC_NONE)
{
@@ -1069,7 +1451,12 @@ md_assemble (str)
expressions" - where the expression contains a difference of
two symbols in the same segment. */
fix_new_exp (frag_now, (opcodep - frag_now->fr_literal), 2,
- &output_instruction.expr, 0,
+ &output_instruction.expr,
+ output_instruction.reloc == BFD_RELOC_32_PCREL
+ || output_instruction.reloc == BFD_RELOC_16_PCREL
+ || output_instruction.reloc == BFD_RELOC_8_PCREL
+ || (output_instruction.reloc
+ == BFD_RELOC_CRIS_LAPCQ_OFFSET),
output_instruction.reloc);
}
}
@@ -1097,7 +1484,7 @@ cris_process_instruction (insn_text, out_insnp, prefixp)
error. */
prefixp->kind = PREFIX_NONE;
prefixp->reloc = BFD_RELOC_NONE;
- out_insnp->insn_type = CRIS_INSN_NORMAL;
+ out_insnp->insn_type = CRIS_INSN_NONE;
out_insnp->imm_oprnd_size = 0;
/* Find the end of the opcode mnemonic. We assume (true in 2.9.1)
@@ -1183,6 +1570,8 @@ cris_process_instruction (insn_text, out_insnp, prefixp)
Ignore it here. */
continue;
+ case '[':
+ case ']':
case ',':
case ' ':
/* These must match exactly. */
@@ -1190,6 +1579,21 @@ cris_process_instruction (insn_text, out_insnp, prefixp)
continue;
break;
+ case 'A':
+ /* "ACR", case-insensitive.
+ Handle a sometimes-mandatory dollar sign as register
+ prefix. */
+ if (*s == REGISTER_PREFIX_CHAR)
+ s++;
+ else if (demand_register_prefix)
+ break;
+
+ if ((*s++ != 'a' && s[-1] != 'A')
+ || (*s++ != 'c' && s[-1] != 'C')
+ || (*s++ != 'r' && s[-1] != 'R'))
+ break;
+ continue;
+
case 'B':
/* This is not really an operand, but causes a "BDAP
-size,SP" prefix to be output, for PUSH instructions. */
@@ -1237,6 +1641,19 @@ cris_process_instruction (insn_text, out_insnp, prefixp)
continue;
}
+ /* For 'd', check for an optional ".d" or ".D" at the
+ start of the operands, followed by a space character. */
+ case 'd':
+ if (modified_char == '.' && *s == '.')
+ {
+ if ((s[1] != 'd' && s[1] == 'D')
+ || ! ISSPACE (s[2]))
+ break;
+ s += 2;
+ continue;
+ }
+ continue;
+
case 'D':
/* General register in bits <15:12> and <3:0>. */
if (! get_gen_reg (&s, &regno))
@@ -1317,7 +1734,8 @@ cris_process_instruction (insn_text, out_insnp, prefixp)
case 'm':
/* A size modifier, B, W or D, to be put in bits <5:4>. */
- if (! get_bwd_size_modifier (&s, &size_bits))
+ if (modified_char != '.'
+ || ! get_bwd_size_modifier (&s, &size_bits))
break;
else
{
@@ -1335,8 +1753,25 @@ cris_process_instruction (insn_text, out_insnp, prefixp)
continue;
}
+ case 'Q':
+ /* A 8-bit quick BDAP expression, "expr,R". */
+ if (! cris_get_expression (&s, &out_insnp->expr))
+ break;
+
+ if (*s != ',')
+ break;
+
+ s++;
+
+ if (!get_gen_reg (&s, &regno))
+ break;
+
+ out_insnp->opcode |= regno << 12;
+ out_insnp->reloc = BFD_RELOC_CRIS_SIGNED_8;
+ continue;
+
case 'O':
- /* A BDAP expression for any size, "expr,r". */
+ /* A BDAP expression for any size, "expr,R". */
if (! cris_get_expression (&s, &prefixp->expr))
break;
else
@@ -1420,7 +1855,7 @@ cris_process_instruction (insn_text, out_insnp, prefixp)
case 's':
/* Source operand in bits <10>, <3:0> and optionally a
prefix; i.e. an indirect operand or an side-effect
- prefix. */
+ prefix (where valid). */
if (! get_autoinc_prefix_or_indir_op (&s, prefixp, &mode,
&regno,
&imm_expr_found,
@@ -1452,6 +1887,71 @@ cris_process_instruction (insn_text, out_insnp, prefixp)
continue;
}
+ case 'N':
+ case 'Y':
+ /* Like 's', but immediate operand only. Also does not
+ modify insn. There are no insns where a PIC reloc
+ specifier makes sense. */
+ if (cris_get_expression (&s, &out_insnp->expr))
+ {
+ imm_expr_found = 1;
+ continue;
+ }
+ break;
+
+ case 'n':
+ /* Like 'N', but PC-relative to the start of the insn.
+ There might be a :PLT to request a PLT entry. */
+ if (cris_get_expression (&s, &out_insnp->expr))
+ {
+ imm_expr_found = 1;
+ out_insnp->reloc = BFD_RELOC_32_PCREL;
+
+ /* We have to adjust the expression, because that
+ relocation is to the location *after* the
+ relocation. So add 2 for the insn and 4 for the
+ relocation. */
+ out_insnp->expr.X_add_number += 6;
+
+ if (pic && *s == PIC_SUFFIX_CHAR)
+ cris_get_pic_suffix (&s, &out_insnp->reloc,
+ &out_insnp->expr);
+
+ continue;
+ }
+ break;
+
+ case 'U':
+ /* Maybe 'u', maybe 'n'. Only for LAPC/LAPCQ. */
+ if (cris_get_expression (&s, &out_insnp->expr))
+ {
+ out_insnp->reloc = BFD_RELOC_CRIS_LAPCQ_OFFSET;
+
+ /* Define 1 as relaxing. */
+ out_insnp->expr.X_md = 1;
+ continue;
+ }
+ break;
+
+ case 'u':
+ /* Four PC-relative bits in <3:0> representing <4:1>:0 of
+ an offset relative to the beginning of the current
+ insn. */
+ if (cris_get_expression (&s, &out_insnp->expr))
+ {
+ out_insnp->reloc = BFD_RELOC_CRIS_LAPCQ_OFFSET;
+
+ /* Define 0 as non-relaxing. */
+ out_insnp->expr.X_md = 0;
+
+ /* We have to adjust the expression, because that
+ relocation is to the location *after* the
+ insn. So add 2 for the insn. */
+ out_insnp->expr.X_add_number += 2;
+ continue;
+ }
+ break;
+
case 'x':
/* Rs.m in bits <15:12> and <5:4>. */
if (! get_gen_reg (&s, &regno)
@@ -1506,6 +2006,15 @@ cris_process_instruction (insn_text, out_insnp, prefixp)
continue;
}
+ case 'T':
+ if (cris_arch == arch_crisv32
+ && get_sup_reg (&s, &regno))
+ {
+ out_insnp->opcode |= regno << 12;
+ continue;
+ }
+ break;
+
default:
BAD_CASE (*args);
}
@@ -1520,9 +2029,19 @@ cris_process_instruction (insn_text, out_insnp, prefixp)
{
/* If it's just that the args don't match, maybe the next
item in the table is the same opcode but with
- matching operands. */
+ matching operands. First skip any invalid ones. */
+ while (instruction[1].name != NULL
+ && strcmp (instruction->name, instruction[1].name) == 0
+ && ! cris_insn_ver_valid_for_arch (instruction[1]
+ .applicable_version,
+ cris_arch))
+ ++instruction;
+
if (instruction[1].name != NULL
- && ! strcmp (instruction->name, instruction[1].name))
+ && strcmp (instruction->name, instruction[1].name) == 0
+ && cris_insn_ver_valid_for_arch (instruction[1]
+ .applicable_version,
+ cris_arch))
{
/* Yep. Restart and try that one instead. */
++instruction;
@@ -1534,6 +2053,11 @@ cris_process_instruction (insn_text, out_insnp, prefixp)
/* We've come to the end of instructions with this
opcode, so it must be an error. */
as_bad (_("Illegal operands"));
+
+ /* As discard_rest_of_line, but without continuing to the
+ next line. */
+ while (!is_end_of_line[(unsigned char) *input_line_pointer])
+ input_line_pointer++;
return;
}
}
@@ -1558,52 +2082,91 @@ cris_process_instruction (insn_text, out_insnp, prefixp)
break;
case SIZE_SPEC_REG:
- switch (out_insnp->spec_reg->reg_size)
- {
- case 1:
- if (out_insnp->expr.X_op == O_constant
- && (out_insnp->expr.X_add_number < -128
- || out_insnp->expr.X_add_number > 255))
- as_bad (_("Immediate value not in 8 bit range: %ld"),
- out_insnp->expr.X_add_number);
- /* Fall through. */
- case 2:
- /* FIXME: We need an indicator in the instruction
- table to pass on, to indicate if we need to check
- overflow for a signed or unsigned number. */
- if (out_insnp->expr.X_op == O_constant
- && (out_insnp->expr.X_add_number < -32768
- || out_insnp->expr.X_add_number > 65535))
- as_bad (_("Immediate value not in 16 bit range: %ld"),
- out_insnp->expr.X_add_number);
- out_insnp->imm_oprnd_size = 2;
- break;
-
- case 4:
- out_insnp->imm_oprnd_size = 4;
- break;
-
- default:
- BAD_CASE (out_insnp->spec_reg->reg_size);
- }
+ if (cris_arch == arch_crisv32)
+ /* All immediate loads of special registers are
+ 32-bit on CRISv32. */
+ out_insnp->imm_oprnd_size = 4;
+ else
+ switch (out_insnp->spec_reg->reg_size)
+ {
+ case 1:
+ if (out_insnp->expr.X_op == O_constant
+ && (out_insnp->expr.X_add_number < -128
+ || out_insnp->expr.X_add_number > 255))
+ as_bad (_("Immediate value not in 8 bit range: %ld"),
+ out_insnp->expr.X_add_number);
+ /* Fall through. */
+ case 2:
+ /* FIXME: We need an indicator in the instruction
+ table to pass on, to indicate if we need to check
+ overflow for a signed or unsigned number. */
+ if (out_insnp->expr.X_op == O_constant
+ && (out_insnp->expr.X_add_number < -32768
+ || out_insnp->expr.X_add_number > 65535))
+ as_bad (_("Immediate value not in 16 bit range: %ld"),
+ out_insnp->expr.X_add_number);
+ out_insnp->imm_oprnd_size = 2;
+ break;
+
+ case 4:
+ out_insnp->imm_oprnd_size = 4;
+ break;
+
+ default:
+ BAD_CASE (out_insnp->spec_reg->reg_size);
+ }
break;
case SIZE_FIELD:
+ case SIZE_FIELD_SIGNED:
+ case SIZE_FIELD_UNSIGNED:
switch (size_bits)
{
+ /* FIXME: Find way to pass un/signedness to
+ caller, and set reloc type instead, postponing
+ this check until cris_number_to_imm. That
+ necessarily corrects the reloc type for the
+ byte case, maybe requiring further changes. */
case 0:
- if (out_insnp->expr.X_op == O_constant
- && (out_insnp->expr.X_add_number < -128
- || out_insnp->expr.X_add_number > 255))
- as_bad (_("Immediate value not in 8 bit range: %ld"),
- out_insnp->expr.X_add_number);
+ if (out_insnp->expr.X_op == O_constant)
+ {
+ if (instruction->imm_oprnd_size == SIZE_FIELD
+ && (out_insnp->expr.X_add_number < -128
+ || out_insnp->expr.X_add_number > 255))
+ as_bad (_("Immediate value not in 8 bit range: %ld"),
+ out_insnp->expr.X_add_number);
+ else if (instruction->imm_oprnd_size == SIZE_FIELD_SIGNED
+ && (out_insnp->expr.X_add_number < -128
+ || out_insnp->expr.X_add_number > 127))
+ as_bad (_("Immediate value not in 8 bit signed range: %ld"),
+ out_insnp->expr.X_add_number);
+ else if (instruction->imm_oprnd_size == SIZE_FIELD_UNSIGNED
+ && (out_insnp->expr.X_add_number < 0
+ || out_insnp->expr.X_add_number > 255))
+ as_bad (_("Immediate value not in 8 bit unsigned range: %ld"),
+ out_insnp->expr.X_add_number);
+ }
+
/* Fall through. */
case 1:
- if (out_insnp->expr.X_op == O_constant
- && (out_insnp->expr.X_add_number < -32768
- || out_insnp->expr.X_add_number > 65535))
- as_bad (_("Immediate value not in 16 bit range: %ld"),
- out_insnp->expr.X_add_number);
+ if (out_insnp->expr.X_op == O_constant)
+ {
+ if (instruction->imm_oprnd_size == SIZE_FIELD
+ && (out_insnp->expr.X_add_number < -32768
+ || out_insnp->expr.X_add_number > 65535))
+ as_bad (_("Immediate value not in 16 bit range: %ld"),
+ out_insnp->expr.X_add_number);
+ else if (instruction->imm_oprnd_size == SIZE_FIELD_SIGNED
+ && (out_insnp->expr.X_add_number < -32768
+ || out_insnp->expr.X_add_number > 32767))
+ as_bad (_("Immediate value not in 16 bit signed range: %ld"),
+ out_insnp->expr.X_add_number);
+ else if (instruction->imm_oprnd_size == SIZE_FIELD_UNSIGNED
+ && (out_insnp->expr.X_add_number < 0
+ || out_insnp->expr.X_add_number > 65535))
+ as_bad (_("Immediate value not in 16 bit unsigned range: %ld"),
+ out_insnp->expr.X_add_number);
+ }
out_insnp->imm_oprnd_size = 2;
break;
@@ -1767,7 +2330,18 @@ get_gen_reg (cPP, regnop)
(*cPP)++;
if ((**cPP == 'C' || **cPP == 'c')
- && ! ISALNUM ((*cPP)[1]))
+ && ! ISALNUM ((*cPP)[1])
+ /* Here's a little twist: For v32 and the compatibility mode,
+ we only recognize PC as a register number if there's '+]'
+ after. We don't consume that, but the presence can only be
+ valid after a register in a post-increment context, which
+ is also the only valid context for PC as a register for
+ v32. Not that it's used very often, but saying "MOVE.D
+ [PC+],R5" should remain valid. It's not supported for
+ jump-type insns or other insns with no [Rn+] mode, though. */
+ && ((cris_arch != arch_crisv32
+ && cris_arch != arch_cris_common_v10_v32)
+ || ((*cPP)[1] == '+' && (*cPP)[2] == ']')))
{
/* It's "PC": consume the "c" and we're done. */
(*cPP)++;
@@ -1776,6 +2350,20 @@ get_gen_reg (cPP, regnop)
}
break;
+ /* Like with PC, we recognize ACR, but only if it's *not* followed
+ by '+', and only for v32. */
+ case 'A':
+ case 'a':
+ if (cris_arch != arch_crisv32
+ || ((*cPP)[1] != 'c' && (*cPP)[1] != 'C')
+ || ((*cPP)[2] != 'r' && (*cPP)[2] != 'R')
+ || ISALNUM ((*cPP)[3])
+ || (*cPP)[3] == '+')
+ break;
+ (*cPP) += 3;
+ *regnop = 15;
+ return 1;
+
case 'R':
case 'r':
/* Hopefully r[0-9] or r1[0-5]. Consume 'R' or 'r'. */
@@ -1878,7 +2466,9 @@ get_spec_reg (cPP, sregpp)
/* For a match, we must have consumed the name in the table, and we
must be outside what could be part of a name. Assume here that a
test for alphanumerics is sufficient for a name test. */
- if (*s2 == 0 && ! ISALNUM (*s1))
+ if (*s2 == 0 && ! ISALNUM (*s1)
+ && cris_insn_ver_valid_for_arch (sregp->applicable_version,
+ cris_arch))
{
/* We have a match. Update the pointer and be done. */
*cPP = s1;
@@ -1891,6 +2481,64 @@ get_spec_reg (cPP, sregpp)
return 0;
}
+/* Get a support register from the string pointed out by *cPP. The
+ variable *cPP is advanced to the character following the support-
+ register name if one is found, and retains its original position
+ otherwise.
+
+ cPP Pointer to pointer to string starting with a support-register
+ name.
+
+ sregpp Pointer to int containing the register number.
+
+ Return 1 iff a correct support-register name is found. */
+
+static int
+get_sup_reg (cPP, regnop)
+ char **cPP;
+ int *regnop;
+{
+ char *s1;
+ const char *s2;
+ char *name_begin = *cPP;
+
+ const struct cris_support_reg *sregp;
+
+ /* Handle a sometimes-mandatory dollar sign as register prefix. */
+ if (*name_begin == REGISTER_PREFIX_CHAR)
+ name_begin++;
+ else if (demand_register_prefix)
+ return 0;
+
+ /* Loop over all support-registers. */
+ for (sregp = cris_support_regs; sregp->name != NULL; sregp++)
+ {
+ /* Start over from beginning of the supposed name. */
+ s1 = name_begin;
+ s2 = sregp->name;
+
+ while (*s2 != '\0' && TOLOWER (*s1) == *s2)
+ {
+ s1++;
+ s2++;
+ }
+
+ /* For a match, we must have consumed the name in the table, and we
+ must be outside what could be part of a name. Assume here that a
+ test for alphanumerics is sufficient for a name test. */
+ if (*s2 == 0 && ! ISALNUM (*s1))
+ {
+ /* We have a match. Update the pointer and be done. */
+ *cPP = s1;
+ *regnop = sregp->number;
+ return 1;
+ }
+ }
+
+ /* If we got here, we did not find any name. */
+ return 0;
+}
+
/* Get an unprefixed or side-effect-prefix operand from the string pointed
out by *cPP. The pointer *cPP is advanced to the character following
the indirect operand if we have success, else it contains an undefined
@@ -1968,7 +2616,12 @@ get_autoinc_prefix_or_indir_op (cPP, prefixp, is_autoincp, src_regnop,
case '=':
/* This must be indexed with assign, or offset with assign
- to match. */
+ to match. Not supported for crisv32 or in
+ compatibility mode. */
+ if (cris_arch == arch_crisv32
+ || cris_arch == arch_cris_common_v10_v32)
+ return 0;
+
(*cPP)++;
/* Either way, the next thing must be a register. */
@@ -2297,8 +2950,14 @@ get_3op_or_dip_prefix_op (cPP, prefixp)
prefixp->opcode |= size_bits << 4;
}
/* Seen "[rN+", but not a '[' or a register, so then
- it must be a constant "I". */
- else if (cris_get_expression (cPP, &prefixp->expr))
+ it must be a constant "I".
+
+ As a quality of implementation improvement, we check for a
+ closing ']', like in an erroneous "[rN+]". If we don't,
+ the expression parser will emit a confusing "bad
+ expression" when it sees the ']', probably because it
+ doesn't like seeing no expression. */
+ else if (**cPP != ']' && cris_get_expression (cPP, &prefixp->expr))
{
/* Expression found, so fill in the bits of offset
mode and drop down to check the closing ']'. */
@@ -2419,6 +3078,17 @@ cris_get_expression (cPP, exprP)
saved_input_line_pointer = input_line_pointer;
input_line_pointer = *cPP;
+ /* Avoid a common error, confusing addressing modes. Beware that the
+ call to expression below does not signal that error; it treats []
+ as parentheses, unless #define NEED_INDEX_OPERATOR in which case it
+ gives them other confusing semantics rather than plain outlawing
+ them, which is what we want. */
+ if (*input_line_pointer == '[')
+ {
+ input_line_pointer = saved_input_line_pointer;
+ return 0;
+ }
+
exp = expression (exprP);
if (exprP->X_op == O_illegal || exprP->X_op == O_absent)
{
@@ -2454,15 +3124,49 @@ get_flags (cPP, flagsp)
{
case 'd':
case 'D':
+ if (! cris_insn_ver_valid_for_arch (cris_ver_v0_3,
+ cris_arch))
+ return 0;
+ *flagsp |= 0x80;
+ break;
+
case 'm':
case 'M':
+ if (! cris_insn_ver_valid_for_arch (cris_ver_v8_10,
+ cris_arch))
+ return 0;
*flagsp |= 0x80;
break;
case 'e':
case 'E':
+ if (! cris_insn_ver_valid_for_arch (cris_ver_v0_3,
+ cris_arch))
+ return 0;
+ *flagsp |= 0x40;
+ break;
+
case 'b':
case 'B':
+ if (! cris_insn_ver_valid_for_arch (cris_ver_v8_10,
+ cris_arch))
+ return 0;
+ *flagsp |= 0x40;
+ break;
+
+ case 'p':
+ case 'P':
+ if (! cris_insn_ver_valid_for_arch (cris_ver_v32p,
+ cris_arch))
+ return 0;
+ *flagsp |= 0x80;
+ break;
+
+ case 'u':
+ case 'U':
+ if (! cris_insn_ver_valid_for_arch (cris_ver_v32p,
+ cris_arch))
+ return 0;
*flagsp |= 0x40;
break;
@@ -2513,6 +3217,8 @@ get_flags (cPP, flagsp)
}
/* Generate code and fixes for a BDAP prefix.
+ For v32, this handles ADDOQ because thankfully the opcodes are the
+ same.
base_regno Int containing the base register number.
@@ -2591,6 +3297,10 @@ branch_disp (offset)
{
int disp;
+ /* Adjust all short branch offsets here. */
+ if (cris_arch == arch_crisv32 || cris_arch == arch_cris_common_v10_v32)
+ offset += 2;
+
disp = offset & 0xFE;
if (offset < 0)
@@ -2623,6 +3333,27 @@ gen_cond_branch_32 (opcodep, writep, fragP, add_symP, sub_symP, add_num)
symbolS *sub_symP;
long int add_num;
{
+ int nop_opcode;
+ int opc_offset;
+ int branch_offset;
+
+ if (cris_arch == arch_crisv32)
+ {
+ nop_opcode = NOP_OPCODE_V32;
+ opc_offset = 10;
+ branch_offset = -2 - 8;
+ }
+ else
+ {
+ nop_opcode = NOP_OPCODE;
+ opc_offset = 8;
+ branch_offset = -2 - 6;
+ }
+
+ /* We should never get here for compatibility mode. */
+ if (cris_arch == arch_cris_common_v10_v32)
+ as_fatal (_("Calling gen_cond_branch_32 for .arch common_v10_v32\n"));
+
if (warn_for_branch_expansion)
as_warn_where (fragP->fr_file, fragP->fr_line,
_("32-bit conditional branch generated"));
@@ -2638,8 +3369,8 @@ gen_cond_branch_32 (opcodep, writep, fragP, add_symP, sub_symP, add_num)
it's not the optimal extended construct, but we should get this
rarely enough that it shouldn't matter. */
- writep[8] = branch_disp (-2 - 6);
- writep[9] = opcodep[1];
+ writep[opc_offset] = branch_disp (branch_offset);
+ writep[opc_offset + 1] = opcodep[1];
/* Then, we change the branch to an unconditional branch over the
extended part, to the new location of the Bcc:
@@ -2649,8 +3380,9 @@ gen_cond_branch_32 (opcodep, writep, fragP, add_symP, sub_symP, add_num)
Note that these two writes are to currently different locations,
merged later. */
- md_number_to_chars (opcodep, BA_QUICK_OPCODE + 8, 2);
- md_number_to_chars (writep, NOP_OPCODE, 2);
+ md_number_to_chars (opcodep, BA_QUICK_OPCODE
+ + (cris_arch == arch_crisv32 ? 12 : 8), 2);
+ md_number_to_chars (writep, nop_opcode, 2);
/* Then the extended thing, the 32-bit jump insn.
opcodep+4: JUMP [PC+]
@@ -2658,7 +3390,9 @@ gen_cond_branch_32 (opcodep, writep, fragP, add_symP, sub_symP, add_num)
opcodep+4: ADD [PC+],PC. */
md_number_to_chars (writep + 2,
- pic ? ADD_PC_INCR_OPCODE : JUMP_PC_INCR_OPCODE, 2);
+ cris_arch == arch_crisv32
+ ? BA_DWORD_OPCODE
+ : (pic ? ADD_PC_INCR_OPCODE : JUMP_PC_INCR_OPCODE), 2);
/* We have to fill in the actual value too.
opcodep+6: .DWORD
@@ -2668,10 +3402,12 @@ gen_cond_branch_32 (opcodep, writep, fragP, add_symP, sub_symP, add_num)
if (add_symP == NULL && sub_symP == NULL)
{
/* An absolute address. */
- if (pic)
+ if (pic || cris_arch == arch_crisv32)
fix_new (fragP, writep + 4 - fragP->fr_literal, 4,
section_symbol (absolute_section),
- add_num, 1, BFD_RELOC_32_PCREL);
+ add_num
+ + (cris_arch == arch_crisv32 ? 6 : 0),
+ 1, BFD_RELOC_32_PCREL);
else
md_number_to_chars (writep + 4, add_num, 4);
}
@@ -2683,8 +3419,15 @@ gen_cond_branch_32 (opcodep, writep, fragP, add_symP, sub_symP, add_num)
/* Not absolute, we have to make it a frag for later evaluation. */
fix_new (fragP, writep + 4 - fragP->fr_literal, 4, add_symP,
- add_num, pic ? 1 : 0, pic ? BFD_RELOC_32_PCREL : BFD_RELOC_32);
+ add_num + (cris_arch == arch_crisv32 ? 6 : 0),
+ pic || cris_arch == arch_crisv32 ? 1 : 0,
+ pic || cris_arch == arch_crisv32
+ ? BFD_RELOC_32_PCREL : BFD_RELOC_32);
}
+
+ if (cris_arch == arch_crisv32)
+ /* Follow it with a "NOP" for CRISv32. */
+ md_number_to_chars (writep + 8, NOP_OPCODE_V32, 2);
}
/* Get the size of an immediate-reloc in bytes. Only valid for PIC
@@ -2772,7 +3515,7 @@ cris_get_pic_suffix (cPP, relocp, exprP)
syntax error. */
}
-/* This *could* be:
+/* This *could* have been:
Turn a string in input_line_pointer into a floating point constant
of type TYPE, and store the appropriate bytes in *LITP. The number
@@ -2843,15 +3586,19 @@ cris_number_to_imm (bufp, val, n, fixP, seg)
switch (fixP->fx_r_type)
{
/* These must be fully resolved when getting here. */
- case BFD_RELOC_32_PCREL:
case BFD_RELOC_16_PCREL:
case BFD_RELOC_8_PCREL:
- as_bad_where (fixP->fx_frag->fr_file, fixP->fx_frag->fr_line,
+ as_bad_where (fixP->fx_file, fixP->fx_line,
_("PC-relative relocation must be trivially resolved"));
default:
;
}
+ /* Only do this for old-arch binaries. */
+ if (cris_arch != arch_cris_any_v0_v10
+ && (fixP->fx_addsy != NULL || fixP->fx_pcrel))
+ return;
+
switch (fixP->fx_r_type)
{
/* Ditto here, we put the addend into the object code as
@@ -2870,8 +3617,14 @@ cris_number_to_imm (bufp, val, n, fixP, seg)
being relocated for these. */
break;
- case BFD_RELOC_32:
case BFD_RELOC_32_PCREL:
+ /* If this one isn't fully resolved, we don't want to put anything
+ in the object. */
+ if (fixP->fx_addsy != NULL || fixP->fx_pcrel)
+ break;
+
+ /* Fall through. */
+ case BFD_RELOC_32:
/* No use having warnings here, since most hosts have a 32-bit type
for "long" (which will probably change soon, now that I wrote
this). */
@@ -2883,14 +3636,24 @@ cris_number_to_imm (bufp, val, n, fixP, seg)
/* FIXME: The 16 and 8-bit cases should have a way to check
whether a signed or unsigned (or any signedness) number is
- accepted.
- FIXME: Does the as_bad calls find the line number by themselves,
- or should we change them into as_bad_where? */
+ accepted. */
case BFD_RELOC_16:
case BFD_RELOC_16_PCREL:
if (val > 0xffff || val < -32768)
- as_bad (_("Value not in 16 bit range: %ld"), val);
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("Value not in 16 bit range: %ld"), val);
+ if (! fixP->fx_addsy)
+ {
+ bufp[1] = (val >> 8) & 0xFF;
+ bufp[0] = val & 0xFF;
+ }
+ break;
+
+ case BFD_RELOC_CRIS_SIGNED_16:
+ if (val > 32767 || val < -32768)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("Value not in 16 bit signed range: %ld"), val);
if (! fixP->fx_addsy)
{
bufp[1] = (val >> 8) & 0xFF;
@@ -2901,35 +3664,50 @@ cris_number_to_imm (bufp, val, n, fixP, seg)
case BFD_RELOC_8:
case BFD_RELOC_8_PCREL:
if (val > 255 || val < -128)
- as_bad (_("Value not in 8 bit range: %ld"), val);
+ as_bad_where (fixP->fx_file, fixP->fx_line, _("Value not in 8 bit range: %ld"), val);
+ if (! fixP->fx_addsy)
+ bufp[0] = val & 0xFF;
+ break;
+
+ case BFD_RELOC_CRIS_SIGNED_8:
+ if (val > 127 || val < -128)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("Value not in 8 bit signed range: %ld"), val);
if (! fixP->fx_addsy)
bufp[0] = val & 0xFF;
break;
+ case BFD_RELOC_CRIS_LAPCQ_OFFSET:
+ /* FIXME: Test-cases for out-of-range values. Probably also need
+ to use as_bad_where. */
case BFD_RELOC_CRIS_UNSIGNED_4:
if (val > 15 || val < 0)
- as_bad (_("Value not in 4 bit unsigned range: %ld"), val);
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("Value not in 4 bit unsigned range: %ld"), val);
if (! fixP->fx_addsy)
bufp[0] |= val & 0x0F;
break;
case BFD_RELOC_CRIS_UNSIGNED_5:
if (val > 31 || val < 0)
- as_bad (_("Value not in 5 bit unsigned range: %ld"), val);
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("Value not in 5 bit unsigned range: %ld"), val);
if (! fixP->fx_addsy)
bufp[0] |= val & 0x1F;
break;
case BFD_RELOC_CRIS_SIGNED_6:
if (val > 31 || val < -32)
- as_bad (_("Value not in 6 bit range: %ld"), val);
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("Value not in 6 bit range: %ld"), val);
if (! fixP->fx_addsy)
bufp[0] |= val & 0x3F;
break;
case BFD_RELOC_CRIS_UNSIGNED_6:
if (val > 63 || val < 0)
- as_bad (_("Value not in 6 bit unsigned range: %ld"), val);
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("Value not in 6 bit unsigned range: %ld"), val);
if (! fixP->fx_addsy)
bufp[0] |= val & 0x3F;
break;
@@ -2983,7 +3761,7 @@ md_parse_option (arg, argp)
case 'N':
warn_for_branch_expansion = 1;
- return 1;
+ break;
case OPTION_NO_US:
demand_register_prefix = TRUE;
@@ -2992,28 +3770,50 @@ md_parse_option (arg, argp)
as_bad (_("--no-underscore is invalid with a.out format"));
else
symbols_have_leading_underscore = FALSE;
- return 1;
+ break;
case OPTION_US:
demand_register_prefix = FALSE;
symbols_have_leading_underscore = TRUE;
- return 1;
+ break;
case OPTION_PIC:
pic = TRUE;
- return 1;
+ break;
+
+ case OPTION_ARCH:
+ {
+ char *str = argp;
+ enum cris_archs argarch = cris_arch_from_string (&str);
+
+ if (argarch == arch_cris_unknown)
+ as_bad (_("invalid <arch> in --march=<arch>: %s"), argp);
+ else
+ cris_arch = argarch;
+
+ if (argarch == arch_crisv32)
+ {
+ err_for_dangerous_mul_placement = 0;
+ md_long_jump_size = crisv32_long_jump_size;
+ }
+ else
+ md_long_jump_size = cris_any_v0_v10_long_jump_size;
+ }
+ break;
case OPTION_MULBUG_ABORT_OFF:
err_for_dangerous_mul_placement = 0;
- return 1;
+ break;
case OPTION_MULBUG_ABORT_ON:
err_for_dangerous_mul_placement = 1;
- return 1;
+ break;
default:
return 0;
}
+
+ return 1;
}
/* Round up a section size to the appropriate boundary. */
@@ -3057,6 +3857,14 @@ tc_gen_reloc (section, fixP)
switch (fixP->fx_r_type)
{
+ case BFD_RELOC_CRIS_SIGNED_8:
+ code = BFD_RELOC_8;
+ break;
+
+ case BFD_RELOC_CRIS_SIGNED_16:
+ code = BFD_RELOC_16;
+ break;
+
case BFD_RELOC_CRIS_16_GOT:
case BFD_RELOC_CRIS_32_GOT:
case BFD_RELOC_CRIS_16_GOTPLT:
@@ -3065,10 +3873,14 @@ tc_gen_reloc (section, fixP)
case BFD_RELOC_CRIS_32_PLT_GOTREL:
case BFD_RELOC_CRIS_32_PLT_PCREL:
case BFD_RELOC_32:
+ case BFD_RELOC_32_PCREL:
case BFD_RELOC_16:
case BFD_RELOC_8:
case BFD_RELOC_VTABLE_INHERIT:
case BFD_RELOC_VTABLE_ENTRY:
+ case BFD_RELOC_CRIS_UNSIGNED_8:
+ case BFD_RELOC_CRIS_UNSIGNED_16:
+ case BFD_RELOC_CRIS_LAPCQ_OFFSET:
code = fixP->fx_r_type;
break;
default:
@@ -3083,10 +3895,7 @@ tc_gen_reloc (section, fixP)
*relP->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy);
relP->address = fixP->fx_frag->fr_address + fixP->fx_where;
- if (fixP->fx_pcrel)
- relP->addend = 0;
- else
- relP->addend = fixP->fx_offset;
+ relP->addend = fixP->fx_offset;
/* This is the standard place for KLUDGEs to work around bugs in
bfd_install_relocation (first such note in the documentation
@@ -3154,6 +3963,9 @@ md_show_usage (stream)
_(" Registers will require a `$'-prefix.\n"));
fprintf (stream, "%s",
_(" --pic Enable generation of position-independent code.\n"));
+ fprintf (stream, "%s",
+ _(" --march=<arch> Generate code for <arch>. Valid choices for <arch>\n\
+ are v0_v10, v10, v32 and common_v10_v32.\n"));
}
/* Apply a fixS (fixup of an instruction or data that we didn't have
@@ -3186,6 +3998,9 @@ md_apply_fix3 (fixP, valP, seg)
as_bad_where (fixP->fx_file, fixP->fx_line,
_("expression too complex"));
+ /* This operand-type is scaled. */
+ if (fixP->fx_r_type == BFD_RELOC_CRIS_LAPCQ_OFFSET)
+ val /= 2;
cris_number_to_imm (buf, val, fixP->fx_size, fixP, seg);
}
}
@@ -3208,7 +4023,8 @@ md_pcrel_from (fixP)
if (OUTPUT_FLAVOR != bfd_target_elf_flavour
|| (fixP->fx_r_type != BFD_RELOC_8_PCREL
&& fixP->fx_r_type != BFD_RELOC_16_PCREL
- && fixP->fx_r_type != BFD_RELOC_32_PCREL))
+ && fixP->fx_r_type != BFD_RELOC_32_PCREL
+ && fixP->fx_r_type != BFD_RELOC_CRIS_LAPCQ_OFFSET))
as_bad_where (fixP->fx_file, fixP->fx_line,
_("Invalid pc-relative relocation"));
return fixP->fx_size + addr;
@@ -3308,7 +4124,7 @@ s_syntax (ignore)
{
static const struct syntaxes
{
- const char *operand;
+ const char *const operand;
void (*fn) PARAMS ((void));
} syntax_table[] =
{{SYNTAX_ENFORCE_REG_PREFIX, cris_force_reg_prefix},
@@ -3362,6 +4178,163 @@ s_cris_loc (dummy)
dwarf2_directive_loc (dummy);
}
+/* 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 (str)
+ 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 (iver, 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 (dummy)
+ 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. */
+
+ 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 = str;
+ demand_empty_rest_of_line ();
+ return;
+}
+
/*
* Local variables:
* eval: (c-set-style "gnu")
diff --git a/gas/config/tc-cris.h b/gas/config/tc-cris.h
index 4621501..2f969c6 100644
--- a/gas/config/tc-cris.h
+++ b/gas/config/tc-cris.h
@@ -39,6 +39,9 @@ extern const char *cris_target_format PARAMS ((void));
#define TARGET_ARCH bfd_arch_cris
+extern unsigned int cris_mach PARAMS ((void));
+#define TARGET_MACH (cris_mach ())
+
#define TARGET_BYTES_BIG_ENDIAN 0
extern const char *md_shortopts;
diff --git a/gas/configure b/gas/configure
index 98ffaf1..4fbef39 100755
--- a/gas/configure
+++ b/gas/configure
@@ -4182,6 +4182,13 @@ for this_target in $target $canon_targets ; do
arm*b|xscale*b|strongarm*b) cpu_type=arm endian=big ;;
arm*|xscale*|strongarm*) cpu_type=arm endian=little ;;
c4x*) cpu_type=tic4x ;;
+ crisv32) cpu_type=cris arch=crisv32
+
+cat >>confdefs.h <<_ACEOF
+#define DEFAULT_CRIS_ARCH $arch
+_ACEOF
+
+ ;;
crx*) cpu_type=crx endian=little ;;
hppa*) cpu_type=hppa ;;
i[3-7]86) cpu_type=i386 arch=i386;;
@@ -4275,8 +4282,9 @@ for this_target in $target $canon_targets ; do
avr-*-*) fmt=elf ;;
- cris-*-linux-gnu*) fmt=multi bfd_gas=yes em=linux ;;
- cris-*-*) fmt=multi bfd_gas=yes ;;
+ cris-*-linux-gnu* | crisv32-*-linux-gnu*)
+ fmt=multi bfd_gas=yes em=linux ;;
+ cris-*-* | crisv32-*-*) fmt=multi bfd_gas=yes ;;
crx-*-elf*) fmt=elf ;;
diff --git a/gas/configure.in b/gas/configure.in
index e24d0e4..64469d5 100644
--- a/gas/configure.in
+++ b/gas/configure.in
@@ -129,6 +129,10 @@ changequote([,])dnl
arm*b|xscale*b|strongarm*b) cpu_type=arm endian=big ;;
arm*|xscale*|strongarm*) cpu_type=arm endian=little ;;
c4x*) cpu_type=tic4x ;;
+ crisv32) cpu_type=cris arch=crisv32
+ AC_DEFINE_UNQUOTED(DEFAULT_CRIS_ARCH, $arch,
+ [Default CRIS architecture.])
+ ;;
crx*) cpu_type=crx endian=little ;;
hppa*) cpu_type=hppa ;;
changequote(,)dnl
@@ -224,8 +228,9 @@ changequote([,])dnl
avr-*-*) fmt=elf ;;
- cris-*-linux-gnu*) fmt=multi bfd_gas=yes em=linux ;;
- cris-*-*) fmt=multi bfd_gas=yes ;;
+ cris-*-linux-gnu* | crisv32-*-linux-gnu*)
+ fmt=multi bfd_gas=yes em=linux ;;
+ cris-*-* | crisv32-*-*) fmt=multi bfd_gas=yes ;;
crx-*-elf*) fmt=elf ;;
diff --git a/gas/doc/as.texinfo b/gas/doc/as.texinfo
index 280fb32..26dd5e9 100644
--- a/gas/doc/as.texinfo
+++ b/gas/doc/as.texinfo
@@ -276,6 +276,7 @@ gcc(1), ld(1), and the Info entries for @file{binutils} and @file{ld}.
[@b{--underscore} | @b{--no-underscore}]
[@b{--pic}] [@b{-N}]
[@b{--emulation=criself} | @b{--emulation=crisaout}]
+ [@b{--march=v0_v10} | @b{--march=v10} | @b{--march=v32} | @b{--march=common_v10_v32}]
@c Deprecated -- deliberately not documented.
@c [@b{-h}] [@b{-H}]
@end ifset
diff --git a/gas/doc/c-cris.texi b/gas/doc/c-cris.texi
index e814767..e84952c 100644
--- a/gas/doc/c-cris.texi
+++ b/gas/doc/c-cris.texi
@@ -16,6 +16,7 @@
@menu
* CRIS-Opts:: Command-line Options
* CRIS-Expand:: Instruction expansion
+* CRIS-Symbols:: Symbols
* CRIS-Syntax:: Syntax
@end menu
@@ -68,6 +69,39 @@ affect expansion of instructions. The expansion with
@option{--pic} will use PC-relative rather than (slightly
faster) absolute addresses in those expansions.
+@cindex @option{--march=@var{architecture}} command line option, CRIS
+@cindex CRIS @option{--march=@var{architecture}} command line option
+@cindex Architecture variant option, CRIS
+@cindex CRIS architecture variant option
+The option @option{--march=@var{architecture}}
+@anchor{march-option}specifies the recognized instruction set
+and recognized register names. It also controls the
+architecture type of the object file. Valid values for
+@var{architecture} are:
+@table @code
+
+@item v0_v10
+All instructions and register names for any architecture variant
+in the set v0@dots{}v10 are recognized. This is the
+default if the target is configured as cris-*.
+
+@item v10
+Only instructions and register names for CRIS v10 (as found in
+ETRAX 100 LX) are recognized. This is the default if the target
+is configured as crisv10-*.
+
+@item v32
+Only instructions and register names for CRIS v32 (code name
+Guinness) are recognized. This is the default if the target is
+configured as crisv32-*. This value implies
+@option{--no-mul-bug-abort}. (A subsequent
+@option{--mul-bug-abort} will turn it back on.)
+
+@item common_v10_v32
+Only instructions with register names and addressing modes with
+opcodes common to the v10 and v32 are recognized.
+@end table
+
@cindex @option{-N} command line option, CRIS
@cindex CRIS @option{-N} command line option
When @option{-N} is specified, @code{@value{AS}} will emit a
@@ -113,6 +147,59 @@ full 32-bit address. Since this does not correspond to a single
instruction, such expansions can optionally be warned about.
@xref{CRIS-Opts}.
+If the operand is found to fit the range, a @code{lapc} mnemonic
+will translate to a @code{lapcq} instruction. Use @code{lapc.d}
+to force the 32-bit @code{lapc} instruction.
+
+Similarly, the @code{addo} mnemonic will translate to the
+shortest fitting instruction of @code{addoq}, @code{addo.w} and
+@code{addo.d}, when used with a operand that is a constant known
+at assembly time.
+
+@node CRIS-Symbols
+@section Symbols
+@cindex Symbols, built-in, CRIS
+@cindex Symbols, CRIS, built-in
+@cindex CRIS built-in symbols
+@cindex Built-in symbols, CRIS
+
+Some symbols are defined by the assembler. They're intended to
+be used in conditional assembly, for example:
+@smallexample
+ .if ..asm.arch.cris.v32
+ @var{code for CRIS v32}
+ .elseif ..asm.arch.cris.common_v10_v32
+ @var{code common to CRIS v32 and CRIS v10}
+ .elseif ..asm.arch.cris.v10 | ..asm.arch.cris.any_v0_v10
+ @var{code for v10}
+ .else
+ .error "Code needs to be added here."
+ .endif
+@end smallexample
+
+These symbols are defined in the assembler, reflecting
+command-line options, either when specified or the default.
+They are always defined, to 0 or 1.
+@table @code
+
+@item ..asm.arch.cris.any_v0_v10
+This symbol is non-zero when @option{--march=v0_v10} is specified
+or the default.
+
+@item ..asm.arch.cris.common_v10_v32
+Set according to the option @option{--march=common_v10_v32}.
+
+@item ..asm.arch.cris.v10
+Reflects the option @option{--march=v10}.
+
+@item ..asm.arch.cris.v32
+Corresponds to @option{--march=v10}.
+@end table
+
+Speaking of symbols, when a symbol is used in code, it can have
+a suffix modifying its value for use in position-independent
+code. @xref{CRIS-Pic}.
+
@node CRIS-Syntax
@section Syntax
@@ -147,7 +234,8 @@ separate instructions can be specified on a single line.
@cindex Position-independent code, symbols in, CRIS
When generating @anchor{crispic}position-independent code (SVR4
-PIC) for use in cris-axis-linux-gnu shared libraries, symbol
+PIC) for use in cris-axis-linux-gnu or crisv32-axis-linux-gnu
+shared libraries, symbol
suffixes are used to specify what kind of run-time symbol lookup
will be used, expressed in the object as different
@emph{relocation types}. Usually, all absolute symbol values
@@ -271,7 +359,7 @@ each expression, a 32-bit little-endian constant is emitted.
@cindex pseudo-op .syntax, CRIS
@cindex CRIS assembler directive .syntax
@cindex CRIS pseudo-op .syntax
-The @code{.syntax} directive takes as ARGUMENT one of the
+The @code{.syntax} directive takes as @var{ARGUMENT} one of the
following case-sensitive choices.
@table @code
@@ -305,6 +393,16 @@ directive and emits an error if the option @option{--underscore}
is in effect.
@end table
+@item .arch ARGUMENT
+@cindex assembler directive .arch, CRIS
+@cindex pseudo-op .arch, CRIS
+@cindex CRIS assembler directive .arch
+@cindex CRIS pseudo-op .arch
+This is an assertion directive, giving an error if the specified
+@var{ARGUMENT} is not the same as the specified or default value
+for the @option{--march=@var{architecture}} option
+(@pxref{march-option}).
+
@c If you compare with md_pseudo_table, you see that we don't
@c document ".file" and ".loc" here. This is because we're just
@c wrapping the corresponding ELF function and emitting an error for