* config/tc-mips.c (append_insn): Add jump address range overflow
[deliverable/binutils-gdb.git] / gas / config / tc-arm.c
index 514dba7598cfd8bccd203399c4e3c600547c1243..62c4bceeb8749e93c31c6a400f36a39a29cf200b 100644 (file)
@@ -1,8 +1,9 @@
 /* tc-arm.c -- Assemble for the ARM
-   Copyright (C) 1994, 95, 96, 97, 98, 1999, 2000
+   Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
    Free Software Foundation, Inc.
    Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org)
        Modified by David Taylor (dtaylor@armltd.co.uk)
+       Cirrus coprocessor mods by Aldy Hernandez (aldyh@redhat.com)
 
    This file is part of GAS, the GNU Assembler.
 
    Software Foundation, 59 Temple Place - Suite 330, Boston, MA
    02111-1307, USA.  */
 
-#include <ctype.h>
 #include <string.h>
 #define  NO_RELOC 0
 #include "as.h"
+#include "safe-ctype.h"
 
 /* Need TARGET_CPU.  */
 #include "config.h"
 #include "dwarf2dbg.h"
 #endif
 
-/* Types of processor to assemble for.  */
-#define ARM_1          0x00000001
-#define ARM_2          0x00000002
-#define ARM_3          0x00000004
-#define ARM_250                ARM_3
-#define ARM_6          0x00000008
-#define ARM_7          ARM_6           /* Same core instruction set.  */
-#define ARM_8          ARM_6           /* Same core instruction set.  */
-#define ARM_9          ARM_6           /* Same core instruction set.  */
-#define ARM_CPU_MASK   0x0000000f
-
-/* The following bitmasks control CPU extensions (ARM7 onwards):   */
-#define ARM_EXT_LONGMUL        0x00000010      /* Allow long multiplies.  */
-#define ARM_EXT_HALFWORD 0x00000020    /* Allow half word loads.  */
-#define ARM_EXT_THUMB  0x00000040      /* Allow BX instruction.   */
-#define ARM_EXT_V5     0x00000080      /* Allow CLZ, etc.         */
-#define ARM_EXT_V5E    0x00000100      /* "El Segundo".           */
-#define ARM_EXT_XSCALE 0x00000200      /* Allow MIA etc.          */
-
-/* Architectures are the sum of the base and extensions.  */
-#define ARM_ARCH_V3M     ARM_EXT_LONGMUL
-#define ARM_ARCH_V4     (ARM_ARCH_V3M | ARM_EXT_HALFWORD)
-#define ARM_ARCH_V4T   (ARM_ARCH_V4 | ARM_EXT_THUMB)
-#define ARM_ARCH_V5    (ARM_ARCH_V4 | ARM_EXT_V5)
-#define ARM_ARCH_V5T   (ARM_ARCH_V5 | ARM_EXT_THUMB)
-#define ARM_ARCH_V5TE  (ARM_ARCH_V5T | ARM_EXT_V5E)
-#define ARM_ARCH_XSCALE (ARM_ARCH_V5TE | ARM_EXT_XSCALE)
+/* The following bitmasks control CPU extensions:  */
+#define ARM_EXT_V1      0x00000001     /* All processors (core set).  */
+#define ARM_EXT_V2      0x00000002     /* Multiply instructions.  */
+#define ARM_EXT_V2S     0x00000004     /* SWP instructions.       */
+#define ARM_EXT_V3      0x00000008     /* MSR MRS.                */
+#define ARM_EXT_V3M     0x00000010     /* Allow long multiplies.  */
+#define ARM_EXT_V4      0x00000020     /* Allow half word loads.  */
+#define ARM_EXT_V4T     0x00000040     /* Thumb v1.               */
+#define ARM_EXT_V5      0x00000080     /* Allow CLZ, etc.         */
+#define ARM_EXT_V5T     0x00000100     /* Thumb v2.               */
+#define ARM_EXT_V5ExP   0x00000200     /* DSP core set.           */
+#define ARM_EXT_V5E     0x00000400     /* DSP Double transfers.   */
+/* Processor specific extensions.  */
+#define ARM_EXT_XSCALE  0x00000800     /* Allow MIA etc.          */
+#define ARM_EXT_MAVERICK 0x00001000    /* Use Cirrus/DSP coprocessor.  */
+
+/* Architectures are the sum of the base and extensions.  The ARM ARM (rev E)
+   defines the following: ARMv3, ARMv3M, ARMv4xM, ARMv4, ARMv4TxM, ARMv4T,
+   ARMv5xM, ARMv5, ARMv5TxM, ARMv5T, ARMv5TExP, ARMv5TE.  To these we add
+   three more to cover cores prior to ARM6.  Finally, there are cores which
+   implement further extensions in the co-processor space.  */
+#define ARM_ARCH_V1                      ARM_EXT_V1
+#define ARM_ARCH_V2    (ARM_ARCH_V1    | ARM_EXT_V2)
+#define ARM_ARCH_V2S   (ARM_ARCH_V2    | ARM_EXT_V2S)
+#define ARM_ARCH_V3    (ARM_ARCH_V2S   | ARM_EXT_V3)
+#define ARM_ARCH_V3M   (ARM_ARCH_V3    | ARM_EXT_V3M)
+#define ARM_ARCH_V4xM  (ARM_ARCH_V3    | ARM_EXT_V4)
+#define ARM_ARCH_V4    (ARM_ARCH_V3M   | ARM_EXT_V4)
+#define ARM_ARCH_V4TxM (ARM_ARCH_V4xM  | ARM_EXT_V4T)
+#define ARM_ARCH_V4T   (ARM_ARCH_V4    | ARM_EXT_V4T)
+#define ARM_ARCH_V5xM  (ARM_ARCH_V4xM  | ARM_EXT_V5)
+#define ARM_ARCH_V5    (ARM_ARCH_V4    | ARM_EXT_V5)
+#define ARM_ARCH_V5TxM (ARM_ARCH_V5xM  | ARM_EXT_V4T | ARM_EXT_V5T)
+#define ARM_ARCH_V5T   (ARM_ARCH_V5    | ARM_EXT_V4T | ARM_EXT_V5T)
+#define ARM_ARCH_V5TExP        (ARM_ARCH_V5T   | ARM_EXT_V5ExP)
+#define ARM_ARCH_V5TE  (ARM_ARCH_V5TExP | ARM_EXT_V5E)
+/* Processors with specific extensions in the co-processor space.  */
+#define ARM_ARCH_XSCALE        (ARM_ARCH_V5TE  | ARM_EXT_XSCALE)
 
 /* Some useful combinations:  */
 #define ARM_ANY                0x00ffffff
 #define ARM_2UP                (ARM_ANY - ARM_1)
-#define ARM_ALL                ARM_2UP         /* Not arm1 only.  */
-#define ARM_3UP                0x00fffffc
-#define ARM_6UP                0x00fffff8      /* Includes ARM7.  */
+#define ARM_ALL                ARM_ANY
 
-#define FPU_CORE       0x80000000
-#define FPU_FPA10      0x40000000
-#define FPU_FPA11      0x40000000
+#define FPU_FPA_EXT_V1 0x80000000      /* Base FPA instruction set.  */
+#define FPU_FPA_EXT_V2 0x40000000      /* LFM/SFM.                   */
 #define FPU_NONE       0
 
+#define FPU_ARCH_FPE    FPU_FPA_EXT_V1
+#define FPU_ARCH_FPA   (FPU_ARCH_FPE | FPU_FPA_EXT_V2)
+
 /* Some useful combinations.  */
-#define FPU_ALL                0xff000000      /* Note this is ~ARM_ANY.  */
-#define FPU_MEMMULTI   0x7f000000      /* Not fpu_core.  */
+#define FPU_ANY                0xff000000      /* Note this is ~ARM_ANY.  */
+
+/* Types of processor to assemble for.  */
+#define ARM_1          ARM_ARCH_V1
+#define ARM_2          ARM_ARCH_V2
+#define ARM_3          ARM_ARCH_V2S
+#define ARM_250                ARM_ARCH_V2S
+#define ARM_6          ARM_ARCH_V3
+#define ARM_7          ARM_ARCH_V3
+#define ARM_8          ARM_ARCH_V4
+#define ARM_9          ARM_ARCH_V4T
+#define ARM_STRONG     ARM_ARCH_V4
+#define ARM_CPU_MASK   0x0000000f              /* XXX? */
 
 #ifndef CPU_DEFAULT
 #if defined __XSCALE__
-#define CPU_DEFAULT    (ARM_9 | ARM_ARCH_XSCALE)
+#define CPU_DEFAULT    (ARM_ARCH_XSCALE)
 #else
 #if defined __thumb__
-#define CPU_DEFAULT    (ARM_7 | ARM_ARCH_V4T)
+#define CPU_DEFAULT    (ARM_ARCH_V5T)
 #else
 #define CPU_DEFAULT    ARM_ALL
 #endif
 #endif
 
 #ifndef FPU_DEFAULT
-#define FPU_DEFAULT FPU_ALL
+#define FPU_DEFAULT FPU_ARCH_FPA
 #endif
 
 #define streq(a, b)           (strcmp (a, b) == 0)
@@ -115,7 +138,7 @@ static boolean pic_code          = false;
 
 /* This array holds the chars that always start a comment.  If the
    pre-processor is disabled, these aren't very useful.  */
-CONST char comment_chars[] = "@";
+const char comment_chars[] = "@";
 
 /* This array holds the chars that only start a comment at the beginning of
    a line.  If the line seems to have the form '# 123 filename'
@@ -124,19 +147,19 @@ CONST char comment_chars[] = "@";
    first line of the input file.  This is because the compiler outputs
    #NO_APP at the beginning of its output.  */
 /* Also note that comments like this one will always work.  */
-CONST char line_comment_chars[] = "#";
+const char line_comment_chars[] = "#";
 
-CONST char line_separator_chars[] = ";";
+const char line_separator_chars[] = ";";
 
 /* Chars that can be used to separate mant
    from exp in floating point numbers.  */
-CONST char EXP_CHARS[] = "eE";
+const char EXP_CHARS[] = "eE";
 
 /* Chars that mean this number is a floating point constant.  */
 /* As in 0f12.456  */
 /* or    0d1.2345e12  */
 
-CONST char FLT_CHARS[] = "rRsSfFdDxXeEpP";
+const char FLT_CHARS[] = "rRsSfFdDxXeEpP";
 
 /* Prefix characters that indicate the start of an immediate
    value.  */
@@ -148,7 +171,7 @@ symbolS * GOT_symbol;
 #endif
 
 /* Size of relocation record.  */
-CONST int md_reloc_size = 8;
+const int md_reloc_size = 8;
 
 /* 0: assemble for ARM,
    1: assemble for Thumb,
@@ -163,7 +186,7 @@ typedef struct arm_fix
 
 struct arm_it
 {
-  CONST char *  error;
+  const char *  error;
   unsigned long instruction;
   int           suffix;
   int           size;
@@ -230,7 +253,7 @@ static const struct asm_shift_name shift_names [] =
 
 #define NUM_FLOAT_VALS 8
 
-CONST char * fp_const[] =
+const char * fp_const[] =
 {
   "0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "0.5", "10.0", 0
 };
@@ -262,14 +285,14 @@ LITTLENUM_TYPE fp_values[NUM_FLOAT_VALS][MAX_LITTLENUMS];
 
 struct asm_cond
 {
-  CONST char *  template;
+  const char *  template;
   unsigned long value;
 };
 
 /* This is to save a hash look-up in the common case.  */
 #define COND_ALWAYS 0xe0000000
 
-static CONST struct asm_cond conds[] =
+static const struct asm_cond conds[] =
 {
   {"eq", 0x00000000},
   {"ne", 0x10000000},
@@ -294,17 +317,17 @@ static CONST struct asm_cond conds[] =
    the set_bits:  */
 struct asm_flg
 {
-  CONST char *  template;      /* Basic flag string.  */
+  const char *  template;      /* Basic flag string.  */
   unsigned long set_bits;      /* Bits to set.  */
 };
 
-static CONST struct asm_flg s_flag[] =
+static const struct asm_flg s_flag[] =
 {
   {"s", CONDS_BIT},
   {NULL, 0}
 };
 
-static CONST struct asm_flg ldr_flags[] =
+static const struct asm_flg ldr_flags[] =
 {
   {"d",  DOUBLE_LOAD_FLAG},
   {"b",  0x00400000},
@@ -316,7 +339,7 @@ static CONST struct asm_flg ldr_flags[] =
   {NULL, 0}
 };
 
-static CONST struct asm_flg str_flags[] =
+static const struct asm_flg str_flags[] =
 {
   {"d",  DOUBLE_LOAD_FLAG},
   {"b",  0x00400000},
@@ -326,20 +349,20 @@ static CONST struct asm_flg str_flags[] =
   {NULL, 0}
 };
 
-static CONST struct asm_flg byte_flag[] =
+static const struct asm_flg byte_flag[] =
 {
   {"b", 0x00400000},
   {NULL, 0}
 };
 
-static CONST struct asm_flg cmp_flags[] =
+static const struct asm_flg cmp_flags[] =
 {
   {"s", CONDS_BIT},
   {"p", 0x0010f000},
   {NULL, 0}
 };
 
-static CONST struct asm_flg ldm_flags[] =
+static const struct asm_flg ldm_flags[] =
 {
   {"ed", 0x01800000},
   {"fd", 0x00800000},
@@ -352,7 +375,7 @@ static CONST struct asm_flg ldm_flags[] =
   {NULL, 0}
 };
 
-static CONST struct asm_flg stm_flags[] =
+static const struct asm_flg stm_flags[] =
 {
   {"ed", 0x00000000},
   {"fd", 0x01000000},
@@ -365,21 +388,21 @@ static CONST struct asm_flg stm_flags[] =
   {NULL, 0}
 };
 
-static CONST struct asm_flg lfm_flags[] =
+static const struct asm_flg lfm_flags[] =
 {
   {"fd", 0x00800000},
   {"ea", 0x01000000},
   {NULL, 0}
 };
 
-static CONST struct asm_flg sfm_flags[] =
+static const struct asm_flg sfm_flags[] =
 {
   {"fd", 0x01000000},
   {"ea", 0x00800000},
   {NULL, 0}
 };
 
-static CONST struct asm_flg round_flags[] =
+static const struct asm_flg round_flags[] =
 {
   {"p", 0x00000020},
   {"m", 0x00000040},
@@ -391,7 +414,7 @@ static CONST struct asm_flg round_flags[] =
    in that it accepts a precision specifier as well as a rounding specifier,
    despite the fact that this is meaningless.  To be more compatible, we
    accept it as well, though of course it does not set any bits.  */
-static CONST struct asm_flg fix_flags[] =
+static const struct asm_flg fix_flags[] =
 {
   {"p", 0x00000020},
   {"m", 0x00000040},
@@ -408,13 +431,13 @@ static CONST struct asm_flg fix_flags[] =
   {NULL, 0}
 };
 
-static CONST struct asm_flg except_flag[] =
+static const struct asm_flg except_flag[] =
 {
   {"e", 0x00400000},
   {NULL, 0}
 };
 
-static CONST struct asm_flg cplong_flag[] =
+static const struct asm_flg long_flag[] =
 {
   {"l", 0x00400000},
   {NULL, 0}
@@ -422,7 +445,7 @@ static CONST struct asm_flg cplong_flag[] =
 
 struct asm_psr
 {
-  CONST char *  template;
+  const char *  template;
   boolean       cpsr;
   unsigned long field;
 };
@@ -438,7 +461,7 @@ struct asm_psr
 #define PSR_s   (1 << 2)
 #define PSR_f   (1 << 3)
 
-static CONST struct asm_psr psrs[] =
+static const struct asm_psr psrs[] =
 {
   {"CPSR",     true,  PSR_c | PSR_f},
   {"CPSR_all", true,  PSR_c | PSR_f},
@@ -579,6 +602,17 @@ static CONST struct asm_psr psrs[] =
   {"SPSR_cxsf",        false, PSR_c | PSR_x | PSR_s | PSR_f},
 };
 
+enum cirrus_regtype
+  {
+    CIRRUS_REGTYPE_MVF   = 1,
+    CIRRUS_REGTYPE_MVFX  = 2,
+    CIRRUS_REGTYPE_MVD   = 3,
+    CIRRUS_REGTYPE_MVDX  = 4,
+    CIRRUS_REGTYPE_MVAX  = 5,
+    CIRRUS_REGTYPE_DSPSC = 6,
+    CIRRUS_REGTYPE_ANY   = 7
+  };
+
 /* Functions called by parser.  */
 /* ARM instructions.  */
 static void do_arit            PARAMS ((char *, unsigned long));
@@ -588,31 +622,29 @@ static void do_ldst               PARAMS ((char *, unsigned long));
 static void do_ldmstm          PARAMS ((char *, unsigned long));
 static void do_branch          PARAMS ((char *, unsigned long));
 static void do_swi             PARAMS ((char *, unsigned long));
+
 /* Pseudo Op codes.  */
 static void do_adr             PARAMS ((char *, unsigned long));
-static void do_adrl            PARAMS ((char *, unsigned long));
 static void do_nop             PARAMS ((char *, unsigned long));
-/* ARM 2.  */
+
+/* ARM v2.  */
 static void do_mul             PARAMS ((char *, unsigned long));
 static void do_mla             PARAMS ((char *, unsigned long));
-/* ARM 3.  */
+
+/* ARM v2S.  */
 static void do_swap            PARAMS ((char *, unsigned long));
-/* ARM 6.  */
+
+/* ARM v3.  */
 static void do_msr             PARAMS ((char *, unsigned long));
 static void do_mrs             PARAMS ((char *, unsigned long));
-/* ARM 7M.  */
+
+/* ARM v3M.  */
 static void do_mull            PARAMS ((char *, unsigned long));
-/* ARM THUMB.  */
-static void do_bx               PARAMS ((char *, unsigned long));
 
-/* ARM_EXT_XScale.  */
-static void do_mia             PARAMS ((char *, unsigned long));
-static void do_mar             PARAMS ((char *, unsigned long));
-static void do_mra             PARAMS ((char *, unsigned long));
-static void do_pld             PARAMS ((char *, unsigned long));
-static void do_ldrd            PARAMS ((char *, unsigned long));
+/* ARM v4T.  */
+static void do_bx               PARAMS ((char *, unsigned long));
 
-/* ARM_EXT_V5.  */
+/* ARM_v5.  */
 static void do_blx             PARAMS ((char *, unsigned long));
 static void do_bkpt            PARAMS ((char *, unsigned long));
 static void do_clz             PARAMS ((char *, unsigned long));
@@ -620,33 +652,66 @@ static void do_lstc2              PARAMS ((char *, unsigned long));
 static void do_cdp2            PARAMS ((char *, unsigned long));
 static void do_co_reg2         PARAMS ((char *, unsigned long));
 
-static void do_t_blx           PARAMS ((char *));
-static void do_t_bkpt          PARAMS ((char *));
-
-/* ARM_EXT_V5E.  */
+/* ARM v5ExP.  */
 static void do_smla            PARAMS ((char *, unsigned long));
 static void do_smlal           PARAMS ((char *, unsigned long));
 static void do_smul            PARAMS ((char *, unsigned long));
 static void do_qadd            PARAMS ((char *, unsigned long));
+
+/* ARM v5E.  */
+static void do_pld             PARAMS ((char *, unsigned long));
+static void do_ldrd            PARAMS ((char *, unsigned long));
 static void do_co_reg2c                PARAMS ((char *, unsigned long));
 
 /* Coprocessor Instructions.  */
 static void do_cdp             PARAMS ((char *, unsigned long));
 static void do_lstc            PARAMS ((char *, unsigned long));
 static void do_co_reg          PARAMS ((char *, unsigned long));
-static void do_fp_ctrl         PARAMS ((char *, unsigned long));
-static void do_fp_ldst         PARAMS ((char *, unsigned long));
-static void do_fp_ldmstm       PARAMS ((char *, unsigned long));
-static void do_fp_dyadic       PARAMS ((char *, unsigned long));
-static void do_fp_monadic      PARAMS ((char *, unsigned long));
-static void do_fp_cmp          PARAMS ((char *, unsigned long));
-static void do_fp_from_reg     PARAMS ((char *, unsigned long));
-static void do_fp_to_reg       PARAMS ((char *, unsigned long));
+
+/* FPA instructions.  */
+static void do_fpa_ctrl                PARAMS ((char *, unsigned long));
+static void do_fpa_ldst                PARAMS ((char *, unsigned long));
+static void do_fpa_ldmstm      PARAMS ((char *, unsigned long));
+static void do_fpa_dyadic      PARAMS ((char *, unsigned long));
+static void do_fpa_monadic     PARAMS ((char *, unsigned long));
+static void do_fpa_cmp         PARAMS ((char *, unsigned long));
+static void do_fpa_from_reg    PARAMS ((char *, unsigned long));
+static void do_fpa_to_reg      PARAMS ((char *, unsigned long));
+
+/* XScale.  */
+static void do_mia             PARAMS ((char *, unsigned long));
+static void do_mar             PARAMS ((char *, unsigned long));
+static void do_mra             PARAMS ((char *, unsigned long));
+
+/* ARM_EXT_MAVERICK.  */
+static void do_c_binops                PARAMS ((char *, unsigned long, int));
+static void do_c_binops_1      PARAMS ((char *, unsigned long));
+static void do_c_binops_2      PARAMS ((char *, unsigned long));
+static void do_c_binops_3      PARAMS ((char *, unsigned long));
+static void do_c_triple                PARAMS ((char *, unsigned long, int));
+static void do_c_triple_4      PARAMS ((char *, unsigned long));
+static void do_c_triple_5      PARAMS ((char *, unsigned long));
+static void do_c_quad          PARAMS ((char *, unsigned long, int));
+static void do_c_quad_6                PARAMS ((char *, unsigned long));
+static void do_c_dspsc         PARAMS ((char *, unsigned long, int));
+static void do_c_dspsc_1       PARAMS ((char *, unsigned long));
+static void do_c_dspsc_2       PARAMS ((char *, unsigned long));
+static void do_c_shift         PARAMS ((char *, unsigned long, int));
+static void do_c_shift_1       PARAMS ((char *, unsigned long));
+static void do_c_shift_2       PARAMS ((char *, unsigned long));
+static void do_c_ldst          PARAMS ((char *, unsigned long, int));
+static void do_c_ldst_1                PARAMS ((char *, unsigned long));
+static void do_c_ldst_2                PARAMS ((char *, unsigned long));
+static void do_c_ldst_3                PARAMS ((char *, unsigned long));
+static void do_c_ldst_4                PARAMS ((char *, unsigned long));
+static int cirrus_reg_required_here    PARAMS ((char **, int, enum cirrus_regtype));
+static int cirrus_valid_reg    PARAMS ((int, enum cirrus_regtype));
+static int cirrus_parse_offset PARAMS ((char **, int *));
 
 static void fix_new_arm                PARAMS ((fragS *, int, short, expressionS *, int, int));
 static int arm_reg_parse       PARAMS ((char **));
-static CONST struct asm_psr * arm_psr_parse PARAMS ((char **));
-static void symbol_locate      PARAMS ((symbolS *, CONST char *, segT, valueT, fragS *));
+static const struct asm_psr * arm_psr_parse PARAMS ((char **));
+static void symbol_locate      PARAMS ((symbolS *, const char *, segT, valueT, fragS *));
 static int add_to_lit_pool     PARAMS ((void));
 static unsigned validate_immediate PARAMS ((unsigned));
 static unsigned validate_immediate_twopart PARAMS ((unsigned int, unsigned int *));
@@ -679,6 +744,10 @@ static void set_constant_flonums   PARAMS ((void));
 static valueT md_chars_to_number       PARAMS ((char *, int));
 static void insert_reg_alias   PARAMS ((char *, int));
 static void output_inst                PARAMS ((void));
+static int accum0_required_here PARAMS ((char **));
+static int ld_mode_required_here PARAMS ((char **));
+static void do_branch25         PARAMS ((char *, unsigned long));
+static symbolS * find_real_start PARAMS ((symbolS *));
 #ifdef OBJ_ELF
 static bfd_reloc_code_real_type        arm_parse_reloc PARAMS ((void));
 #endif
@@ -690,22 +759,40 @@ static bfd_reloc_code_real_type   arm_parse_reloc PARAMS ((void));
 /* LONGEST_INST is the longest basic instruction name without
    conditions or flags.  ARM7M has 4 of length 5.  El Segundo
    has one basic instruction name of length 7 (SMLALxy).  */
-#define LONGEST_INST 7
+#define LONGEST_INST 10
+
+/* "INSN<cond> X,Y" where X:bit12, Y:bit16.  */
+#define CIRRUS_MODE1   0x100c
+
+/* "INSN<cond> X,Y" where X:bit16, Y:bit12.  */
+#define CIRRUS_MODE2   0x0c10
+
+/* "INSN<cond> X,Y" where X:0, Y:bit16.  */
+#define CIRRUS_MODE3   0x1000
+
+/* "INSN<cond> X,Y,Z" where X:16, Y:0, Z:12.  */
+#define CIRRUS_MODE4   0x0c0010
+
+/* "INSN<cond> X,Y,Z" where X:12, Y:16, Z:0.  */
+#define CIRRUS_MODE5   0x00100c
+
+/* "INSN<cond> W,X,Y,Z" where W:5, X:12, Y:16, Z:0.  */
+#define CIRRUS_MODE6   0x00100c05
 
 struct asm_opcode
 {
   /* Basic string to match.  */
-  CONST char * template;
+  const char * template;
 
   /* Basic instruction code.  */
   unsigned long value;
 
   /* Compulsory suffix that must follow conds.  If "", then the
      instruction is not conditional and must have no suffix.  */
-  CONST char * comp_suffix;
+  const char * comp_suffix;
 
   /* Bits to toggle if flag 'n' set.  */
-  CONST struct asm_flg * flags;
+  const struct asm_flg * flags;
 
   /* Which CPU variants this exists for.  */
   unsigned long variants;
@@ -714,175 +801,262 @@ struct asm_opcode
   void (* parms) PARAMS ((char *, unsigned long));
 };
 
-static CONST struct asm_opcode insns[] =
-{
-/* Intel XScale extensions to ARM V5 ISA.  */
-  {"mia",   0x0e200010, NULL,   NULL,        ARM_EXT_XSCALE, do_mia},
-  {"miaph", 0x0e280010, NULL,   NULL,        ARM_EXT_XSCALE, do_mia},
-  {"miabb", 0x0e2c0010, NULL,   NULL,        ARM_EXT_XSCALE, do_mia},
-  {"miabt", 0x0e2d0010, NULL,   NULL,        ARM_EXT_XSCALE, do_mia},
-  {"miatb", 0x0e2e0010, NULL,   NULL,        ARM_EXT_XSCALE, do_mia},
-  {"miatt", 0x0e2f0010, NULL,   NULL,        ARM_EXT_XSCALE, do_mia},
-  {"mar",   0x0c400000, NULL,   NULL,        ARM_EXT_XSCALE, do_mar},
-  {"mra",   0x0c500000, NULL,   NULL,        ARM_EXT_XSCALE, do_mra},
-  {"pld",   0xf450f000, "",     NULL,        ARM_EXT_XSCALE, do_pld},
-  {"ldr",   0x000000d0, NULL,   ldr_flags,   ARM_ANY,        do_ldrd},
-  {"str",   0x000000f0, NULL,   str_flags,   ARM_ANY,        do_ldrd},
-
-/* ARM Instructions.  */
-  {"and",   0x00000000, NULL,   s_flag,      ARM_ANY,      do_arit},
-  {"eor",   0x00200000, NULL,   s_flag,      ARM_ANY,      do_arit},
-  {"sub",   0x00400000, NULL,   s_flag,      ARM_ANY,      do_arit},
-  {"rsb",   0x00600000, NULL,   s_flag,      ARM_ANY,      do_arit},
-  {"add",   0x00800000, NULL,   s_flag,      ARM_ANY,      do_arit},
-  {"adc",   0x00a00000, NULL,   s_flag,      ARM_ANY,      do_arit},
-  {"sbc",   0x00c00000, NULL,   s_flag,      ARM_ANY,      do_arit},
-  {"rsc",   0x00e00000, NULL,   s_flag,      ARM_ANY,      do_arit},
-  {"orr",   0x01800000, NULL,   s_flag,      ARM_ANY,      do_arit},
-  {"bic",   0x01c00000, NULL,   s_flag,      ARM_ANY,      do_arit},
-  {"tst",   0x01000000, NULL,   cmp_flags,   ARM_ANY,      do_cmp},
-  {"teq",   0x01200000, NULL,   cmp_flags,   ARM_ANY,      do_cmp},
-  {"cmp",   0x01400000, NULL,   cmp_flags,   ARM_ANY,      do_cmp},
-  {"cmn",   0x01600000, NULL,   cmp_flags,   ARM_ANY,      do_cmp},
-  {"mov",   0x01a00000, NULL,   s_flag,      ARM_ANY,      do_mov},
-  {"mvn",   0x01e00000, NULL,   s_flag,      ARM_ANY,      do_mov},
-  {"str",   0x04000000, NULL,   str_flags,   ARM_ANY,      do_ldst},
-  {"ldr",   0x04100000, NULL,   ldr_flags,   ARM_ANY,      do_ldst},
-  {"stm",   0x08000000, NULL,   stm_flags,   ARM_ANY,      do_ldmstm},
-  {"ldm",   0x08100000, NULL,   ldm_flags,   ARM_ANY,      do_ldmstm},
-  {"swi",   0x0f000000, NULL,   NULL,        ARM_ANY,      do_swi},
+static const struct asm_opcode insns[] =
+{
+  /* XXX Temporary hack.  Override the normal load/store entry points.  */
+  {"ldr",   0x000000d0, NULL,   ldr_flags,   ARM_EXT_V1,        do_ldrd},
+  {"str",   0x000000f0, NULL,   str_flags,   ARM_EXT_V1,        do_ldrd},
+
+  /* Core ARM Instructions.  */
+  {"and",   0x00000000, NULL,   s_flag,      ARM_EXT_V1,      do_arit},
+  {"eor",   0x00200000, NULL,   s_flag,      ARM_EXT_V1,      do_arit},
+  {"sub",   0x00400000, NULL,   s_flag,      ARM_EXT_V1,      do_arit},
+  {"rsb",   0x00600000, NULL,   s_flag,      ARM_EXT_V1,      do_arit},
+  {"add",   0x00800000, NULL,   s_flag,      ARM_EXT_V1,      do_arit},
+  {"adc",   0x00a00000, NULL,   s_flag,      ARM_EXT_V1,      do_arit},
+  {"sbc",   0x00c00000, NULL,   s_flag,      ARM_EXT_V1,      do_arit},
+  {"rsc",   0x00e00000, NULL,   s_flag,      ARM_EXT_V1,      do_arit},
+  {"orr",   0x01800000, NULL,   s_flag,      ARM_EXT_V1,      do_arit},
+  {"bic",   0x01c00000, NULL,   s_flag,      ARM_EXT_V1,      do_arit},
+  {"tst",   0x01000000, NULL,   cmp_flags,   ARM_EXT_V1,      do_cmp},
+  {"teq",   0x01200000, NULL,   cmp_flags,   ARM_EXT_V1,      do_cmp},
+  {"cmp",   0x01400000, NULL,   cmp_flags,   ARM_EXT_V1,      do_cmp},
+  {"cmn",   0x01600000, NULL,   cmp_flags,   ARM_EXT_V1,      do_cmp},
+  {"mov",   0x01a00000, NULL,   s_flag,      ARM_EXT_V1,      do_mov},
+  {"mvn",   0x01e00000, NULL,   s_flag,      ARM_EXT_V1,      do_mov},
+  {"str",   0x04000000, NULL,   str_flags,   ARM_EXT_V1,      do_ldst},
+  {"ldr",   0x04100000, NULL,   ldr_flags,   ARM_EXT_V1,      do_ldst},
+  {"stm",   0x08000000, NULL,   stm_flags,   ARM_EXT_V1,      do_ldmstm},
+  {"ldm",   0x08100000, NULL,   ldm_flags,   ARM_EXT_V1,      do_ldmstm},
+  {"swi",   0x0f000000, NULL,   NULL,        ARM_EXT_V1,      do_swi},
 #ifdef TE_WINCE
-  {"bl",    0x0b000000, NULL,   NULL,        ARM_ANY,      do_branch},
-  {"b",     0x0a000000, NULL,   NULL,        ARM_ANY,      do_branch},
+  /* XXX This is the wrong place to do this.  Think multi-arch.  */
+  {"bl",    0x0b000000, NULL,   NULL,        ARM_EXT_V1,      do_branch},
+  {"b",     0x0a000000, NULL,   NULL,        ARM_EXT_V1,      do_branch},
 #else
-  {"bl",    0x0bfffffe, NULL,   NULL,        ARM_ANY,      do_branch},
-  {"b",     0x0afffffe, NULL,   NULL,        ARM_ANY,      do_branch},
+  {"bl",    0x0bfffffe, NULL,   NULL,        ARM_EXT_V1,      do_branch},
+  {"b",     0x0afffffe, NULL,   NULL,        ARM_EXT_V1,      do_branch},
 #endif
 
-/* Pseudo ops.  */
-  {"adr",   0x028f0000, NULL,   NULL,        ARM_ANY,      do_adr},
-  {"adrl",  0x028f0000, NULL,   NULL,        ARM_ANY,      do_adrl},
-  {"nop",   0x01a00000, NULL,   NULL,        ARM_ANY,      do_nop},
-
-/* ARM 2 multiplies.  */
-  {"mul",   0x00000090, NULL,   s_flag,      ARM_2UP,      do_mul},
-  {"mla",   0x00200090, NULL,   s_flag,      ARM_2UP,      do_mla},
-
-/* ARM 3 - swp instructions.  */
-  {"swp",   0x01000090, NULL,   byte_flag,   ARM_3UP,      do_swap},
-
-/* ARM 6 Coprocessor instructions.  */
-  {"mrs",   0x010f0000, NULL,   NULL,        ARM_6UP,      do_mrs},
-  {"msr",   0x0120f000, NULL,   NULL,        ARM_6UP,      do_msr},
-/* ScottB: our code uses 0x0128f000 for msr.
-   NickC:  but this is wrong because the bits 16 through 19 are
-           handled by the PSR_xxx defines above.  */
-
-/* ARM 7M long multiplies - need signed/unsigned flags!  */
-  {"smull", 0x00c00090, NULL,   s_flag,      ARM_EXT_LONGMUL,  do_mull},
-  {"umull", 0x00800090, NULL,   s_flag,      ARM_EXT_LONGMUL,  do_mull},
-  {"smlal", 0x00e00090, NULL,   s_flag,      ARM_EXT_LONGMUL,  do_mull},
-  {"umlal", 0x00a00090, NULL,   s_flag,      ARM_EXT_LONGMUL,  do_mull},
-
-/* ARM THUMB interworking.  */
-  {"bx",    0x012fff10, NULL,   NULL,        ARM_EXT_THUMB,    do_bx},
-
-/* Floating point instructions.  */
-  {"wfs",   0x0e200110, NULL,   NULL,        FPU_ALL,      do_fp_ctrl},
-  {"rfs",   0x0e300110, NULL,   NULL,        FPU_ALL,      do_fp_ctrl},
-  {"wfc",   0x0e400110, NULL,   NULL,        FPU_ALL,      do_fp_ctrl},
-  {"rfc",   0x0e500110, NULL,   NULL,        FPU_ALL,      do_fp_ctrl},
-  {"ldf",   0x0c100100, "sdep", NULL,        FPU_ALL,      do_fp_ldst},
-  {"stf",   0x0c000100, "sdep", NULL,        FPU_ALL,      do_fp_ldst},
-  {"lfm",   0x0c100200, NULL,   lfm_flags,   FPU_MEMMULTI, do_fp_ldmstm},
-  {"sfm",   0x0c000200, NULL,   sfm_flags,   FPU_MEMMULTI, do_fp_ldmstm},
-  {"mvf",   0x0e008100, "sde",  round_flags, FPU_ALL,      do_fp_monadic},
-  {"mnf",   0x0e108100, "sde",  round_flags, FPU_ALL,      do_fp_monadic},
-  {"abs",   0x0e208100, "sde",  round_flags, FPU_ALL,      do_fp_monadic},
-  {"rnd",   0x0e308100, "sde",  round_flags, FPU_ALL,      do_fp_monadic},
-  {"sqt",   0x0e408100, "sde",  round_flags, FPU_ALL,      do_fp_monadic},
-  {"log",   0x0e508100, "sde",  round_flags, FPU_ALL,      do_fp_monadic},
-  {"lgn",   0x0e608100, "sde",  round_flags, FPU_ALL,      do_fp_monadic},
-  {"exp",   0x0e708100, "sde",  round_flags, FPU_ALL,      do_fp_monadic},
-  {"sin",   0x0e808100, "sde",  round_flags, FPU_ALL,      do_fp_monadic},
-  {"cos",   0x0e908100, "sde",  round_flags, FPU_ALL,      do_fp_monadic},
-  {"tan",   0x0ea08100, "sde",  round_flags, FPU_ALL,      do_fp_monadic},
-  {"asn",   0x0eb08100, "sde",  round_flags, FPU_ALL,      do_fp_monadic},
-  {"acs",   0x0ec08100, "sde",  round_flags, FPU_ALL,      do_fp_monadic},
-  {"atn",   0x0ed08100, "sde",  round_flags, FPU_ALL,      do_fp_monadic},
-  {"urd",   0x0ee08100, "sde",  round_flags, FPU_ALL,      do_fp_monadic},
-  {"nrm",   0x0ef08100, "sde",  round_flags, FPU_ALL,      do_fp_monadic},
-  {"adf",   0x0e000100, "sde",  round_flags, FPU_ALL,      do_fp_dyadic},
-  {"suf",   0x0e200100, "sde",  round_flags, FPU_ALL,      do_fp_dyadic},
-  {"rsf",   0x0e300100, "sde",  round_flags, FPU_ALL,      do_fp_dyadic},
-  {"muf",   0x0e100100, "sde",  round_flags, FPU_ALL,      do_fp_dyadic},
-  {"dvf",   0x0e400100, "sde",  round_flags, FPU_ALL,      do_fp_dyadic},
-  {"rdf",   0x0e500100, "sde",  round_flags, FPU_ALL,      do_fp_dyadic},
-  {"pow",   0x0e600100, "sde",  round_flags, FPU_ALL,      do_fp_dyadic},
-  {"rpw",   0x0e700100, "sde",  round_flags, FPU_ALL,      do_fp_dyadic},
-  {"rmf",   0x0e800100, "sde",  round_flags, FPU_ALL,      do_fp_dyadic},
-  {"fml",   0x0e900100, "sde",  round_flags, FPU_ALL,      do_fp_dyadic},
-  {"fdv",   0x0ea00100, "sde",  round_flags, FPU_ALL,      do_fp_dyadic},
-  {"frd",   0x0eb00100, "sde",  round_flags, FPU_ALL,      do_fp_dyadic},
-  {"pol",   0x0ec00100, "sde",  round_flags, FPU_ALL,      do_fp_dyadic},
-  {"cmf",   0x0e90f110, NULL,   except_flag, FPU_ALL,      do_fp_cmp},
-  {"cnf",   0x0eb0f110, NULL,   except_flag, FPU_ALL,      do_fp_cmp},
-/* The FPA10 data sheet suggests that the 'E' of cmfe/cnfe should not
-   be an optional suffix, but part of the instruction.  To be compatible,
-   we accept either.  */
-  {"cmfe",  0x0ed0f110, NULL,   NULL,        FPU_ALL,      do_fp_cmp},
-  {"cnfe",  0x0ef0f110, NULL,   NULL,        FPU_ALL,      do_fp_cmp},
-  {"flt",   0x0e000110, "sde",  round_flags, FPU_ALL,      do_fp_from_reg},
-  {"fix",   0x0e100110, NULL,   fix_flags,   FPU_ALL,      do_fp_to_reg},
-
-/* Generic copressor instructions.  */
-  {"cdp",   0x0e000000, NULL,  NULL,         ARM_2UP,      do_cdp},
-  {"ldc",   0x0c100000, NULL,  cplong_flag,  ARM_2UP,      do_lstc},
-  {"stc",   0x0c000000, NULL,  cplong_flag,  ARM_2UP,      do_lstc},
-  {"mcr",   0x0e000010, NULL,  NULL,         ARM_2UP,      do_co_reg},
-  {"mrc",   0x0e100010, NULL,  NULL,         ARM_2UP,      do_co_reg},
-
-/*  ARM ISA extension 5.  */
-/* Note: blx is actually 2 opcodes, so the .value is set dynamically.
-   And it's sometimes conditional and sometimes not.  */
+  /* Pseudo ops.  */
+  {"adr",   0x028f0000, NULL,   long_flag,   ARM_EXT_V1,      do_adr},
+  {"nop",   0x01a00000, NULL,   NULL,        ARM_EXT_V1,      do_nop},
+
+  /* ARM 2 multiplies.  */
+  {"mul",   0x00000090, NULL,   s_flag,      ARM_EXT_V2,      do_mul},
+  {"mla",   0x00200090, NULL,   s_flag,      ARM_EXT_V2,      do_mla},
+
+  /* Generic copressor instructions.  */
+  {"cdp",   0x0e000000, NULL,  NULL,         ARM_EXT_V2,      do_cdp},
+  {"ldc",   0x0c100000, NULL,  long_flag,    ARM_EXT_V2,      do_lstc},
+  {"stc",   0x0c000000, NULL,  long_flag,    ARM_EXT_V2,      do_lstc},
+  {"mcr",   0x0e000010, NULL,  NULL,         ARM_EXT_V2,      do_co_reg},
+  {"mrc",   0x0e100010, NULL,  NULL,         ARM_EXT_V2,      do_co_reg},
+
+  /* ARM 3 - swp instructions.  */
+  {"swp",   0x01000090, NULL,   byte_flag,   ARM_EXT_V2S,      do_swap},
+
+  /* ARM 6 Status register instructions.  */
+  {"mrs",   0x010f0000, NULL,   NULL,        ARM_EXT_V3,      do_mrs},
+  {"msr",   0x0120f000, NULL,   NULL,        ARM_EXT_V3,      do_msr},
+  /* ScottB: our code uses 0x0128f000 for msr.
+     NickC:  but this is wrong because the bits 16 through 19 are
+            handled by the PSR_xxx defines above.  */
+
+  /* ARM 7M long multiplies - need signed/unsigned flags!  */
+  {"smull", 0x00c00090, NULL,   s_flag,      ARM_EXT_V3M,  do_mull},
+  {"umull", 0x00800090, NULL,   s_flag,      ARM_EXT_V3M,  do_mull},
+  {"smlal", 0x00e00090, NULL,   s_flag,      ARM_EXT_V3M,  do_mull},
+  {"umlal", 0x00a00090, NULL,   s_flag,      ARM_EXT_V3M,  do_mull},
+
+  /* ARM Architecture 4T.  */
+  /* Note: bx (and blx) are required on V5, even if the processor does
+     not support Thumb.   */
+  {"bx",    0x012fff10, NULL,   NULL,        ARM_EXT_V4T | ARM_EXT_V5, do_bx},
+
+  /*  ARM ISA extension 5.  */
+  /* Note: blx is actually 2 opcodes, so the .value is set dynamically.
+     And it's sometimes conditional and sometimes not.  */
   {"blx",            0, NULL,   NULL,        ARM_EXT_V5, do_blx},
   {"clz",   0x016f0f10, NULL,   NULL,        ARM_EXT_V5, do_clz},
   {"bkpt",  0xe1200070, "",    NULL,        ARM_EXT_V5, do_bkpt},
-  {"ldc2",  0xfc100000, "",    cplong_flag, ARM_EXT_V5, do_lstc2},
-  {"stc2",  0xfc000000, "",    cplong_flag, ARM_EXT_V5, do_lstc2},
+  {"ldc2",  0xfc100000, "",    long_flag,   ARM_EXT_V5, do_lstc2},
+  {"stc2",  0xfc000000, "",    long_flag,   ARM_EXT_V5, do_lstc2},
   {"cdp2",  0xfe000000, "",    NULL,        ARM_EXT_V5, do_cdp2},
   {"mcr2",  0xfe000010, "",    NULL,        ARM_EXT_V5, do_co_reg2},
   {"mrc2",  0xfe100010, "",    NULL,        ARM_EXT_V5, do_co_reg2},
 
-/*  ARM ISA extension 5E, El Segundo.  */
-  {"smlabb", 0x01000080, NULL,   NULL,        ARM_EXT_V5E, do_smla},
-  {"smlatb", 0x010000a0, NULL,   NULL,        ARM_EXT_V5E, do_smla},
-  {"smlabt", 0x010000c0, NULL,   NULL,        ARM_EXT_V5E, do_smla},
-  {"smlatt", 0x010000e0, NULL,   NULL,        ARM_EXT_V5E, do_smla},
-
-  {"smlawb", 0x01200080, NULL,   NULL,        ARM_EXT_V5E, do_smla},
-  {"smlawt", 0x012000c0, NULL,   NULL,        ARM_EXT_V5E, do_smla},
-
-  {"smlalbb",0x01400080, NULL,   NULL,        ARM_EXT_V5E, do_smlal},
-  {"smlaltb",0x014000a0, NULL,   NULL,        ARM_EXT_V5E, do_smlal},
-  {"smlalbt",0x014000c0, NULL,   NULL,        ARM_EXT_V5E, do_smlal},
-  {"smlaltt",0x014000e0, NULL,   NULL,        ARM_EXT_V5E, do_smlal},
-
-  {"smulbb", 0x01600080, NULL,   NULL,        ARM_EXT_V5E, do_smul},
-  {"smultb", 0x016000a0, NULL,   NULL,        ARM_EXT_V5E, do_smul},
-  {"smulbt", 0x016000c0, NULL,   NULL,        ARM_EXT_V5E, do_smul},
-  {"smultt", 0x016000e0, NULL,   NULL,        ARM_EXT_V5E, do_smul},
-
-  {"smulwb", 0x012000a0, NULL,   NULL,        ARM_EXT_V5E, do_smul},
-  {"smulwt", 0x012000e0, NULL,   NULL,        ARM_EXT_V5E, do_smul},
-
-  {"qadd",   0x01000050, NULL,   NULL,        ARM_EXT_V5E, do_qadd},
-  {"qdadd",  0x01400050, NULL,   NULL,        ARM_EXT_V5E, do_qadd},
-  {"qsub",   0x01200050, NULL,   NULL,        ARM_EXT_V5E, do_qadd},
-  {"qdsub",  0x01600050, NULL,   NULL,        ARM_EXT_V5E, do_qadd},
-
+/*  ARM Architecture 5ExP.  */
+  {"smlabb", 0x01000080, NULL,   NULL,        ARM_EXT_V5ExP, do_smla},
+  {"smlatb", 0x010000a0, NULL,   NULL,        ARM_EXT_V5ExP, do_smla},
+  {"smlabt", 0x010000c0, NULL,   NULL,        ARM_EXT_V5ExP, do_smla},
+  {"smlatt", 0x010000e0, NULL,   NULL,        ARM_EXT_V5ExP, do_smla},
+
+  {"smlawb", 0x01200080, NULL,   NULL,        ARM_EXT_V5ExP, do_smla},
+  {"smlawt", 0x012000c0, NULL,   NULL,        ARM_EXT_V5ExP, do_smla},
+
+  {"smlalbb",0x01400080, NULL,   NULL,        ARM_EXT_V5ExP, do_smlal},
+  {"smlaltb",0x014000a0, NULL,   NULL,        ARM_EXT_V5ExP, do_smlal},
+  {"smlalbt",0x014000c0, NULL,   NULL,        ARM_EXT_V5ExP, do_smlal},
+  {"smlaltt",0x014000e0, NULL,   NULL,        ARM_EXT_V5ExP, do_smlal},
+
+  {"smulbb", 0x01600080, NULL,   NULL,        ARM_EXT_V5ExP, do_smul},
+  {"smultb", 0x016000a0, NULL,   NULL,        ARM_EXT_V5ExP, do_smul},
+  {"smulbt", 0x016000c0, NULL,   NULL,        ARM_EXT_V5ExP, do_smul},
+  {"smultt", 0x016000e0, NULL,   NULL,        ARM_EXT_V5ExP, do_smul},
+
+  {"smulwb", 0x012000a0, NULL,   NULL,        ARM_EXT_V5ExP, do_smul},
+  {"smulwt", 0x012000e0, NULL,   NULL,        ARM_EXT_V5ExP, do_smul},
+
+  {"qadd",   0x01000050, NULL,   NULL,        ARM_EXT_V5ExP, do_qadd},
+  {"qdadd",  0x01400050, NULL,   NULL,        ARM_EXT_V5ExP, do_qadd},
+  {"qsub",   0x01200050, NULL,   NULL,        ARM_EXT_V5ExP, do_qadd},
+  {"qdsub",  0x01600050, NULL,   NULL,        ARM_EXT_V5ExP, do_qadd},
+
+  /*  ARM Architecture 5E.  */
+  {"pld",   0xf450f000, "",     NULL,         ARM_EXT_V5E, do_pld},
+  {"ldr",   0x000000d0, NULL,   ldr_flags,    ARM_EXT_V5E, do_ldrd},
+  {"str",   0x000000f0, NULL,   str_flags,    ARM_EXT_V5E, do_ldrd},
   {"mcrr",  0x0c400000, NULL,   NULL,         ARM_EXT_V5E, do_co_reg2c},
   {"mrrc",  0x0c500000, NULL,   NULL,         ARM_EXT_V5E, do_co_reg2c},
+
+  /* Core FPA instruction set (V1).  */
+  {"wfs",   0x0e200110, NULL,   NULL,        FPU_FPA_EXT_V1,      do_fpa_ctrl},
+  {"rfs",   0x0e300110, NULL,   NULL,        FPU_FPA_EXT_V1,      do_fpa_ctrl},
+  {"wfc",   0x0e400110, NULL,   NULL,        FPU_FPA_EXT_V1,      do_fpa_ctrl},
+  {"rfc",   0x0e500110, NULL,   NULL,        FPU_FPA_EXT_V1,      do_fpa_ctrl},
+  {"ldf",   0x0c100100, "sdep", NULL,        FPU_FPA_EXT_V1,      do_fpa_ldst},
+  {"stf",   0x0c000100, "sdep", NULL,        FPU_FPA_EXT_V1,      do_fpa_ldst},
+  {"mvf",   0x0e008100, "sde",  round_flags, FPU_FPA_EXT_V1,      do_fpa_monadic},
+  {"mnf",   0x0e108100, "sde",  round_flags, FPU_FPA_EXT_V1,      do_fpa_monadic},
+  {"abs",   0x0e208100, "sde",  round_flags, FPU_FPA_EXT_V1,      do_fpa_monadic},
+  {"rnd",   0x0e308100, "sde",  round_flags, FPU_FPA_EXT_V1,      do_fpa_monadic},
+  {"sqt",   0x0e408100, "sde",  round_flags, FPU_FPA_EXT_V1,      do_fpa_monadic},
+  {"log",   0x0e508100, "sde",  round_flags, FPU_FPA_EXT_V1,      do_fpa_monadic},
+  {"lgn",   0x0e608100, "sde",  round_flags, FPU_FPA_EXT_V1,      do_fpa_monadic},
+  {"exp",   0x0e708100, "sde",  round_flags, FPU_FPA_EXT_V1,      do_fpa_monadic},
+  {"sin",   0x0e808100, "sde",  round_flags, FPU_FPA_EXT_V1,      do_fpa_monadic},
+  {"cos",   0x0e908100, "sde",  round_flags, FPU_FPA_EXT_V1,      do_fpa_monadic},
+  {"tan",   0x0ea08100, "sde",  round_flags, FPU_FPA_EXT_V1,      do_fpa_monadic},
+  {"asn",   0x0eb08100, "sde",  round_flags, FPU_FPA_EXT_V1,      do_fpa_monadic},
+  {"acs",   0x0ec08100, "sde",  round_flags, FPU_FPA_EXT_V1,      do_fpa_monadic},
+  {"atn",   0x0ed08100, "sde",  round_flags, FPU_FPA_EXT_V1,      do_fpa_monadic},
+  {"urd",   0x0ee08100, "sde",  round_flags, FPU_FPA_EXT_V1,      do_fpa_monadic},
+  {"nrm",   0x0ef08100, "sde",  round_flags, FPU_FPA_EXT_V1,      do_fpa_monadic},
+  {"adf",   0x0e000100, "sde",  round_flags, FPU_FPA_EXT_V1,      do_fpa_dyadic},
+  {"suf",   0x0e200100, "sde",  round_flags, FPU_FPA_EXT_V1,      do_fpa_dyadic},
+  {"rsf",   0x0e300100, "sde",  round_flags, FPU_FPA_EXT_V1,      do_fpa_dyadic},
+  {"muf",   0x0e100100, "sde",  round_flags, FPU_FPA_EXT_V1,      do_fpa_dyadic},
+  {"dvf",   0x0e400100, "sde",  round_flags, FPU_FPA_EXT_V1,      do_fpa_dyadic},
+  {"rdf",   0x0e500100, "sde",  round_flags, FPU_FPA_EXT_V1,      do_fpa_dyadic},
+  {"pow",   0x0e600100, "sde",  round_flags, FPU_FPA_EXT_V1,      do_fpa_dyadic},
+  {"rpw",   0x0e700100, "sde",  round_flags, FPU_FPA_EXT_V1,      do_fpa_dyadic},
+  {"rmf",   0x0e800100, "sde",  round_flags, FPU_FPA_EXT_V1,      do_fpa_dyadic},
+  {"fml",   0x0e900100, "sde",  round_flags, FPU_FPA_EXT_V1,      do_fpa_dyadic},
+  {"fdv",   0x0ea00100, "sde",  round_flags, FPU_FPA_EXT_V1,      do_fpa_dyadic},
+  {"frd",   0x0eb00100, "sde",  round_flags, FPU_FPA_EXT_V1,      do_fpa_dyadic},
+  {"pol",   0x0ec00100, "sde",  round_flags, FPU_FPA_EXT_V1,      do_fpa_dyadic},
+  {"cmf",   0x0e90f110, NULL,   except_flag, FPU_FPA_EXT_V1,      do_fpa_cmp},
+  {"cnf",   0x0eb0f110, NULL,   except_flag, FPU_FPA_EXT_V1,      do_fpa_cmp},
+  /* The FPA10 data sheet suggests that the 'E' of cmfe/cnfe should not
+     be an optional suffix, but part of the instruction.  To be compatible,
+     we accept either.  */
+  {"cmfe",  0x0ed0f110, NULL,   NULL,        FPU_FPA_EXT_V1,      do_fpa_cmp},
+  {"cnfe",  0x0ef0f110, NULL,   NULL,        FPU_FPA_EXT_V1,      do_fpa_cmp},
+  {"flt",   0x0e000110, "sde",  round_flags, FPU_FPA_EXT_V1,      do_fpa_from_reg},
+  {"fix",   0x0e100110, NULL,   fix_flags,   FPU_FPA_EXT_V1,      do_fpa_to_reg},
+
+  /* Instructions that were new with the real FPA, call them V2.  */
+  {"lfm",   0x0c100200, NULL,   lfm_flags,   FPU_FPA_EXT_V2, do_fpa_ldmstm},
+  {"sfm",   0x0c000200, NULL,   sfm_flags,   FPU_FPA_EXT_V2, do_fpa_ldmstm},
+
+  /* Intel XScale extensions to ARM V5 ISA.  (All use CP0).  */
+  {"mia",   0x0e200010, NULL,   NULL,        ARM_EXT_XSCALE, do_mia},
+  {"miaph", 0x0e280010, NULL,   NULL,        ARM_EXT_XSCALE, do_mia},
+  {"miabb", 0x0e2c0010, NULL,   NULL,        ARM_EXT_XSCALE, do_mia},
+  {"miabt", 0x0e2d0010, NULL,   NULL,        ARM_EXT_XSCALE, do_mia},
+  {"miatb", 0x0e2e0010, NULL,   NULL,        ARM_EXT_XSCALE, do_mia},
+  {"miatt", 0x0e2f0010, NULL,   NULL,        ARM_EXT_XSCALE, do_mia},
+  {"mar",   0x0c400000, NULL,   NULL,        ARM_EXT_XSCALE, do_mar},
+  {"mra",   0x0c500000, NULL,   NULL,        ARM_EXT_XSCALE, do_mra},
+
+  /* Cirrus DSP instructions.  */
+  {"cfldrs",   0x0c100400,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_ldst_1},
+  {"cfldrd",   0x0c500400,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_ldst_2},
+  {"cfldr32",  0x0c100500,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_ldst_3},
+  {"cfldr64",  0x0c500500,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_ldst_4},
+  {"cfstrs",   0x0c000400,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_ldst_1},
+  {"cfstrd",   0x0c400400,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_ldst_2},
+  {"cfstr32",  0x0c000500,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_ldst_3},
+  {"cfstr64",  0x0c400500,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_ldst_4},
+  {"cfmvsr",   0x0e000450,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_binops_2},
+  {"cfmvrs",   0x0e100450,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_binops_1},
+  {"cfmvdlr",  0x0e000410,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_binops_2},
+  {"cfmvrdl",  0x0e100410,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_binops_1},
+  {"cfmvdhr",  0x0e000430,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_binops_2},
+  {"cfmvrdh",  0x0e100430,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_binops_1},
+  {"cfmv64lr", 0x0e000510,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_binops_2},
+  {"cfmvr64l", 0x0e100510,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_binops_1},
+  {"cfmv64hr", 0x0e000530,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_binops_2},
+  {"cfmvr64h", 0x0e100530,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_binops_1},
+  {"cfmval32", 0x0e100610,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_binops_3},
+  {"cfmv32al", 0x0e000610,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_binops_3},
+  {"cfmvam32", 0x0e100630,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_binops_3},
+  {"cfmv32am", 0x0e000630,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_binops_3},
+  {"cfmvah32", 0x0e100650,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_binops_3},
+  {"cfmv32ah", 0x0e000650,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_binops_3},
+  {"cfmv32a",  0x0e000670,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_binops_3},
+  {"cfmva32",  0x0e100670,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_binops_3},
+  {"cfmv64a",  0x0e000690,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_binops_3},
+  {"cfmva64",  0x0e100690,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_binops_3},
+  {"cfmvsc32", 0x0e1006b0,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_dspsc_1},
+  {"cfmv32sc", 0x0e0006b0,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_dspsc_2},
+  {"cfcpys",   0x0e000400,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_binops_1},
+  {"cfcpyd",   0x0e000420,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_binops_1},
+  {"cfcvtsd",  0x0e000460,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_binops_1},
+  {"cfcvtds",  0x0e000440,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_binops_1},
+  {"cfcvt32s", 0x0e000480,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_binops_1},
+  {"cfcvt32d", 0x0e0004a0,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_binops_1},
+  {"cfcvt64s", 0x0e0004c0,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_binops_1},
+  {"cfcvt64d", 0x0e0004e0,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_binops_1},
+  {"cfcvts32", 0x0e100580,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_binops_1},
+  {"cfcvtd32", 0x0e1005a0,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_binops_1},
+  {"cftruncs32",0x0e1005c0,    NULL,   NULL,   ARM_EXT_MAVERICK, do_c_binops_1},
+  {"cftruncd32",0x0e1005e0,    NULL,   NULL,   ARM_EXT_MAVERICK, do_c_binops_1},
+  {"cfrshl32", 0x0e000550,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_triple_4},
+  {"cfrshl64", 0x0e000570,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_triple_4},
+  {"cfsh32",   0x0e000500,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_shift_1},
+  {"cfsh64",   0x0e200500,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_shift_2},
+  {"cfcmps",   0x0e100490,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_triple_5},
+  {"cfcmpd",   0x0e1004b0,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_triple_5},
+  {"cfcmp32",  0x0e100590,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_triple_5},
+  {"cfcmp64",  0x0e1005b0,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_triple_5},
+  {"cfabss",   0x0e300400,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_binops_1},
+  {"cfabsd",   0x0e300420,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_binops_1},
+  {"cfnegs",   0x0e300440,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_binops_1},
+  {"cfnegd",   0x0e300460,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_binops_1},
+  {"cfadds",   0x0e300480,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_triple_5},
+  {"cfaddd",   0x0e3004a0,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_triple_5},
+  {"cfsubs",   0x0e3004c0,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_triple_5},
+  {"cfsubd",   0x0e3004e0,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_triple_5},
+  {"cfmuls",   0x0e100400,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_triple_5},
+  {"cfmuld",   0x0e100420,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_triple_5},
+  {"cfabs32",  0x0e300500,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_binops_1},
+  {"cfabs64",  0x0e300520,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_binops_1},
+  {"cfneg32",  0x0e300540,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_binops_1},
+  {"cfneg64",  0x0e300560,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_binops_1},
+  {"cfadd32",  0x0e300580,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_triple_5},
+  {"cfadd64",  0x0e3005a0,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_triple_5},
+  {"cfsub32",  0x0e3005c0,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_triple_5},
+  {"cfsub64",  0x0e3005e0,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_triple_5},
+  {"cfmul32",  0x0e100500,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_triple_5},
+  {"cfmul64",  0x0e100520,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_triple_5},
+  {"cfmac32",  0x0e100540,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_triple_5},
+  {"cfmsc32",  0x0e100560,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_triple_5},
+  {"cfmadd32", 0x0e000600,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_quad_6},
+  {"cfmsub32", 0x0e100600,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_quad_6},
+  {"cfmadda32",        0x0e200600,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_quad_6},
+  {"cfmsuba32",        0x0e300600,     NULL,   NULL,   ARM_EXT_MAVERICK, do_c_quad_6},
 };
 
 /* Defines for various bits that we will want to toggle.  */
@@ -918,6 +1092,7 @@ static CONST struct asm_opcode insns[] =
 #define OPCODE_BIC     14
 #define OPCODE_MVN     15
 
+/* Thumb v1 (ARMv4T).  */
 static void do_t_nop           PARAMS ((char *));
 static void do_t_arit          PARAMS ((char *));
 static void do_t_add           PARAMS ((char *));
@@ -943,6 +1118,10 @@ static void do_t_sub              PARAMS ((char *));
 static void do_t_swi           PARAMS ((char *));
 static void do_t_adr           PARAMS ((char *));
 
+/* Thumb v2 (ARMv5T).  */
+static void do_t_blx           PARAMS ((char *));
+static void do_t_bkpt          PARAMS ((char *));
+
 #define T_OPCODE_MUL 0x4340
 #define T_OPCODE_TST 0x4200
 #define T_OPCODE_CMN 0x42c0
@@ -1025,7 +1204,7 @@ static int thumb_reg              PARAMS ((char ** str, int hi_lo));
 struct thumb_opcode
 {
   /* Basic string to match.  */
-  CONST char * template;
+  const char * template;
 
   /* Basic instruction code.  */
   unsigned long value;
@@ -1039,73 +1218,75 @@ struct thumb_opcode
   void (* parms) PARAMS ((char *));
 };
 
-static CONST struct thumb_opcode tinsns[] =
-{
-  {"adc",      0x4140,         2,      ARM_EXT_THUMB, do_t_arit},
-  {"add",      0x0000,         2,      ARM_EXT_THUMB, do_t_add},
-  {"and",      0x4000,         2,      ARM_EXT_THUMB, do_t_arit},
-  {"asr",      0x0000,         2,      ARM_EXT_THUMB, do_t_asr},
-  {"b",                T_OPCODE_BRANCH, 2,     ARM_EXT_THUMB, do_t_branch12},
-  {"beq",      0xd0fe,         2,      ARM_EXT_THUMB, do_t_branch9},
-  {"bne",      0xd1fe,         2,      ARM_EXT_THUMB, do_t_branch9},
-  {"bcs",      0xd2fe,         2,      ARM_EXT_THUMB, do_t_branch9},
-  {"bhs",      0xd2fe,         2,      ARM_EXT_THUMB, do_t_branch9},
-  {"bcc",      0xd3fe,         2,      ARM_EXT_THUMB, do_t_branch9},
-  {"bul",      0xd3fe,         2,      ARM_EXT_THUMB, do_t_branch9},
-  {"blo",      0xd3fe,         2,      ARM_EXT_THUMB, do_t_branch9},
-  {"bmi",      0xd4fe,         2,      ARM_EXT_THUMB, do_t_branch9},
-  {"bpl",      0xd5fe,         2,      ARM_EXT_THUMB, do_t_branch9},
-  {"bvs",      0xd6fe,         2,      ARM_EXT_THUMB, do_t_branch9},
-  {"bvc",      0xd7fe,         2,      ARM_EXT_THUMB, do_t_branch9},
-  {"bhi",      0xd8fe,         2,      ARM_EXT_THUMB, do_t_branch9},
-  {"bls",      0xd9fe,         2,      ARM_EXT_THUMB, do_t_branch9},
-  {"bge",      0xdafe,         2,      ARM_EXT_THUMB, do_t_branch9},
-  {"blt",      0xdbfe,         2,      ARM_EXT_THUMB, do_t_branch9},
-  {"bgt",      0xdcfe,         2,      ARM_EXT_THUMB, do_t_branch9},
-  {"ble",      0xddfe,         2,      ARM_EXT_THUMB, do_t_branch9},
-  {"bal",      0xdefe,         2,      ARM_EXT_THUMB, do_t_branch9},
-  {"bic",      0x4380,         2,      ARM_EXT_THUMB, do_t_arit},
-  {"bl",       0xf7fffffe,     4,      ARM_EXT_THUMB, do_t_branch23},
-  {"blx",      0,              0,      ARM_EXT_V5, do_t_blx},
-  {"bkpt",     0xbe00,         2,      ARM_EXT_V5, do_t_bkpt},
-  {"bx",       0x4700,         2,      ARM_EXT_THUMB, do_t_bx},
-  {"cmn",      T_OPCODE_CMN,   2,      ARM_EXT_THUMB, do_t_arit},
-  {"cmp",      0x0000,         2,      ARM_EXT_THUMB, do_t_compare},
-  {"eor",      0x4040,         2,      ARM_EXT_THUMB, do_t_arit},
-  {"ldmia",    0xc800,         2,      ARM_EXT_THUMB, do_t_ldmstm},
-  {"ldr",      0x0000,         2,      ARM_EXT_THUMB, do_t_ldr},
-  {"ldrb",     0x0000,         2,      ARM_EXT_THUMB, do_t_ldrb},
-  {"ldrh",     0x0000,         2,      ARM_EXT_THUMB, do_t_ldrh},
-  {"ldrsb",    0x5600,         2,      ARM_EXT_THUMB, do_t_lds},
-  {"ldrsh",    0x5e00,         2,      ARM_EXT_THUMB, do_t_lds},
-  {"ldsb",     0x5600,         2,      ARM_EXT_THUMB, do_t_lds},
-  {"ldsh",     0x5e00,         2,      ARM_EXT_THUMB, do_t_lds},
-  {"lsl",      0x0000,         2,      ARM_EXT_THUMB, do_t_lsl},
-  {"lsr",      0x0000,         2,      ARM_EXT_THUMB, do_t_lsr},
-  {"mov",      0x0000,         2,      ARM_EXT_THUMB, do_t_mov},
-  {"mul",      T_OPCODE_MUL,   2,      ARM_EXT_THUMB, do_t_arit},
-  {"mvn",      T_OPCODE_MVN,   2,      ARM_EXT_THUMB, do_t_arit},
-  {"neg",      T_OPCODE_NEG,   2,      ARM_EXT_THUMB, do_t_arit},
-  {"orr",      0x4300,         2,      ARM_EXT_THUMB, do_t_arit},
-  {"pop",      0xbc00,         2,      ARM_EXT_THUMB, do_t_push_pop},
-  {"push",     0xb400,         2,      ARM_EXT_THUMB, do_t_push_pop},
-  {"ror",      0x41c0,         2,      ARM_EXT_THUMB, do_t_arit},
-  {"sbc",      0x4180,         2,      ARM_EXT_THUMB, do_t_arit},
-  {"stmia",    0xc000,         2,      ARM_EXT_THUMB, do_t_ldmstm},
-  {"str",      0x0000,         2,      ARM_EXT_THUMB, do_t_str},
-  {"strb",     0x0000,         2,      ARM_EXT_THUMB, do_t_strb},
-  {"strh",     0x0000,         2,      ARM_EXT_THUMB, do_t_strh},
-  {"swi",      0xdf00,         2,      ARM_EXT_THUMB, do_t_swi},
-  {"sub",      0x0000,         2,      ARM_EXT_THUMB, do_t_sub},
-  {"tst",      T_OPCODE_TST,   2,      ARM_EXT_THUMB, do_t_arit},
+static const struct thumb_opcode tinsns[] =
+{
+  /* Thumb v1 (ARMv4T).  */
+  {"adc",      0x4140,         2,      ARM_EXT_V4T, do_t_arit},
+  {"add",      0x0000,         2,      ARM_EXT_V4T, do_t_add},
+  {"and",      0x4000,         2,      ARM_EXT_V4T, do_t_arit},
+  {"asr",      0x0000,         2,      ARM_EXT_V4T, do_t_asr},
+  {"b",                T_OPCODE_BRANCH, 2,     ARM_EXT_V4T, do_t_branch12},
+  {"beq",      0xd0fe,         2,      ARM_EXT_V4T, do_t_branch9},
+  {"bne",      0xd1fe,         2,      ARM_EXT_V4T, do_t_branch9},
+  {"bcs",      0xd2fe,         2,      ARM_EXT_V4T, do_t_branch9},
+  {"bhs",      0xd2fe,         2,      ARM_EXT_V4T, do_t_branch9},
+  {"bcc",      0xd3fe,         2,      ARM_EXT_V4T, do_t_branch9},
+  {"bul",      0xd3fe,         2,      ARM_EXT_V4T, do_t_branch9},
+  {"blo",      0xd3fe,         2,      ARM_EXT_V4T, do_t_branch9},
+  {"bmi",      0xd4fe,         2,      ARM_EXT_V4T, do_t_branch9},
+  {"bpl",      0xd5fe,         2,      ARM_EXT_V4T, do_t_branch9},
+  {"bvs",      0xd6fe,         2,      ARM_EXT_V4T, do_t_branch9},
+  {"bvc",      0xd7fe,         2,      ARM_EXT_V4T, do_t_branch9},
+  {"bhi",      0xd8fe,         2,      ARM_EXT_V4T, do_t_branch9},
+  {"bls",      0xd9fe,         2,      ARM_EXT_V4T, do_t_branch9},
+  {"bge",      0xdafe,         2,      ARM_EXT_V4T, do_t_branch9},
+  {"blt",      0xdbfe,         2,      ARM_EXT_V4T, do_t_branch9},
+  {"bgt",      0xdcfe,         2,      ARM_EXT_V4T, do_t_branch9},
+  {"ble",      0xddfe,         2,      ARM_EXT_V4T, do_t_branch9},
+  {"bal",      0xdefe,         2,      ARM_EXT_V4T, do_t_branch9},
+  {"bic",      0x4380,         2,      ARM_EXT_V4T, do_t_arit},
+  {"bl",       0xf7fffffe,     4,      ARM_EXT_V4T, do_t_branch23},
+  {"bx",       0x4700,         2,      ARM_EXT_V4T, do_t_bx},
+  {"cmn",      T_OPCODE_CMN,   2,      ARM_EXT_V4T, do_t_arit},
+  {"cmp",      0x0000,         2,      ARM_EXT_V4T, do_t_compare},
+  {"eor",      0x4040,         2,      ARM_EXT_V4T, do_t_arit},
+  {"ldmia",    0xc800,         2,      ARM_EXT_V4T, do_t_ldmstm},
+  {"ldr",      0x0000,         2,      ARM_EXT_V4T, do_t_ldr},
+  {"ldrb",     0x0000,         2,      ARM_EXT_V4T, do_t_ldrb},
+  {"ldrh",     0x0000,         2,      ARM_EXT_V4T, do_t_ldrh},
+  {"ldrsb",    0x5600,         2,      ARM_EXT_V4T, do_t_lds},
+  {"ldrsh",    0x5e00,         2,      ARM_EXT_V4T, do_t_lds},
+  {"ldsb",     0x5600,         2,      ARM_EXT_V4T, do_t_lds},
+  {"ldsh",     0x5e00,         2,      ARM_EXT_V4T, do_t_lds},
+  {"lsl",      0x0000,         2,      ARM_EXT_V4T, do_t_lsl},
+  {"lsr",      0x0000,         2,      ARM_EXT_V4T, do_t_lsr},
+  {"mov",      0x0000,         2,      ARM_EXT_V4T, do_t_mov},
+  {"mul",      T_OPCODE_MUL,   2,      ARM_EXT_V4T, do_t_arit},
+  {"mvn",      T_OPCODE_MVN,   2,      ARM_EXT_V4T, do_t_arit},
+  {"neg",      T_OPCODE_NEG,   2,      ARM_EXT_V4T, do_t_arit},
+  {"orr",      0x4300,         2,      ARM_EXT_V4T, do_t_arit},
+  {"pop",      0xbc00,         2,      ARM_EXT_V4T, do_t_push_pop},
+  {"push",     0xb400,         2,      ARM_EXT_V4T, do_t_push_pop},
+  {"ror",      0x41c0,         2,      ARM_EXT_V4T, do_t_arit},
+  {"sbc",      0x4180,         2,      ARM_EXT_V4T, do_t_arit},
+  {"stmia",    0xc000,         2,      ARM_EXT_V4T, do_t_ldmstm},
+  {"str",      0x0000,         2,      ARM_EXT_V4T, do_t_str},
+  {"strb",     0x0000,         2,      ARM_EXT_V4T, do_t_strb},
+  {"strh",     0x0000,         2,      ARM_EXT_V4T, do_t_strh},
+  {"swi",      0xdf00,         2,      ARM_EXT_V4T, do_t_swi},
+  {"sub",      0x0000,         2,      ARM_EXT_V4T, do_t_sub},
+  {"tst",      T_OPCODE_TST,   2,      ARM_EXT_V4T, do_t_arit},
   /* Pseudo ops:  */
-  {"adr",       0x0000,         2,      ARM_EXT_THUMB, do_t_adr},
-  {"nop",       0x46C0,         2,      ARM_EXT_THUMB, do_t_nop},      /* mov r8,r8  */
+  {"adr",       0x0000,         2,      ARM_EXT_V4T, do_t_adr},
+  {"nop",       0x46C0,         2,      ARM_EXT_V4T, do_t_nop},      /* mov r8,r8  */
+  /* Thumb v2 (ARMv5T).  */
+  {"blx",      0,              0,      ARM_EXT_V5T, do_t_blx},
+  {"bkpt",     0xbe00,         2,      ARM_EXT_V5T, do_t_bkpt},
 };
 
 struct reg_entry
 {
-  CONST char * name;
+  const char * name;
   int          number;
 };
 
@@ -1113,12 +1294,22 @@ struct reg_entry
 #define cp_register(reg) ((reg) >= 32 && (reg) <= 47)
 #define fp_register(reg) ((reg) >= 16 && (reg) <= 23)
 
-#define REG_PC 15
-#define REG_LR  14
+#define ARM_EXT_MAVERICKSC_REG 134
+
+#define cirrus_register(reg)           ((reg) >= 50 && (reg) <= 134)
+#define cirrus_mvf_register(reg)       ((reg) >= 50 && (reg) <= 65)
+#define cirrus_mvd_register(reg)       ((reg) >= 70 && (reg) <= 85)
+#define cirrus_mvfx_register(reg)      ((reg) >= 90 && (reg) <= 105)
+#define cirrus_mvdx_register(reg)      ((reg) >= 110 && (reg) <= 125)
+#define cirrus_mvax_register(reg)      ((reg) >= 130 && (reg) <= 133)
+#define ARM_EXT_MAVERICKsc_register(reg)       ((reg) == ARM_EXT_MAVERICKSC_REG)
+
 #define REG_SP  13
+#define REG_LR  14
+#define REG_PC 15
 
 /* These are the standard names.  Users can add aliases with .req.  */
-static CONST struct reg_entry reg_table[] =
+static const struct reg_entry reg_table[] =
 {
   /* Processor Register Numbers.  */
   {"r0", 0},    {"r1", 1},      {"r2", 2},      {"r3", 3},
@@ -1148,6 +1339,25 @@ static CONST struct reg_entry reg_table[] =
   {"s4",20},   {"s5",21},      {"s6",22},      {"s7",23},
   {"d0",16},   {"d1",17},      {"d2",18},      {"d3",19},
   {"d4",20},   {"d5",21},      {"d6",22},      {"d7",23},
+  /* Cirrus DSP coprocessor registers.  */
+  {"mvf0", 50},        {"mvf1", 51},   {"mvf2", 52},   {"mvf3", 53},
+  {"mvf4", 54},        {"mvf5", 55},   {"mvf6", 56},   {"mvf7", 57},
+  {"mvf8", 58},        {"mvf9", 59},   {"mvf10", 60},  {"mvf11", 61},
+  {"mvf12", 62},{"mvf13", 63}, {"mvf14", 64},  {"mvf15", 65},
+  {"mvd0", 70},        {"mvd1", 71},   {"mvd2", 72},   {"mvd3", 73},
+  {"mvd4", 74},        {"mvd5", 75},   {"mvd6", 76},   {"mvd7", 77},
+  {"mvd8", 78},        {"mvd9", 79},   {"mvd10", 80},  {"mvd11", 81},
+  {"mvd12", 82},{"mvd13", 83}, {"mvd14", 84},  {"mvd15", 85},
+  {"mvfx0", 90},{"mvfx1", 91}, {"mvfx2", 92},  {"mvfx3", 93},
+  {"mvfx4", 94},{"mvfx5", 95}, {"mvfx6", 96},  {"mvfx7", 97},
+  {"mvfx8", 98},{"mvfx9", 99}, {"mvfx10", 100},{"mvfx11", 101},
+  {"mvfx12", 102},{"mvfx13", 103},{"mvfx14", 104},{"mvfx15", 105},
+  {"mvdx0", 110}, {"mvdx1", 111}, {"mvdx2", 112}, {"mvdx3", 113},
+  {"mvdx4", 114}, {"mvdx5", 115}, {"mvdx6", 116}, {"mvdx7", 117},
+  {"mvdx8", 118}, {"mvdx9", 119}, {"mvdx10", 120},{"mvdx11", 121},
+  {"mvdx12", 122},{"mvdx13", 123},{"mvdx14", 124},{"mvdx15", 125},
+  {"mvax0", 130}, {"mvax1", 131}, {"mvax2", 132}, {"mvax3", 133},
+  {"dspsc", ARM_EXT_MAVERICKSC_REG},
   /* FIXME: At some point we need to add VFP register names.  */
   /* Array terminator.  */
   {NULL, 0}
@@ -1192,7 +1402,7 @@ static void s_arm_elf_cons PARAMS ((int));
 
 static int my_get_expression PARAMS ((expressionS *, char **));
 
-CONST pseudo_typeS md_pseudo_table[] =
+const pseudo_typeS md_pseudo_table[] =
 {
   /* Never called becasue '.req' does not start line.  */
   { "req",         s_req,         0 },
@@ -1279,12 +1489,23 @@ add_to_lit_pool ()
              == inst.reloc.exp.X_add_number)
          && literals[lit_count].exp.X_unsigned == inst.reloc.exp.X_unsigned)
        break;
+
+      if (literals[lit_count].exp.X_op == inst.reloc.exp.X_op
+          && inst.reloc.exp.X_op == O_symbol
+          && (literals[lit_count].exp.X_add_number
+             == inst.reloc.exp.X_add_number)
+          && (literals[lit_count].exp.X_add_symbol
+             == inst.reloc.exp.X_add_symbol)
+          && (literals[lit_count].exp.X_op_symbol
+             == inst.reloc.exp.X_op_symbol))
+        break;
+
       lit_count++;
     }
 
   if (lit_count == next_literal_pool_place) /* New entry.  */
     {
-      if (next_literal_pool_place > MAX_LITERAL_POOL_SIZE)
+      if (next_literal_pool_place >= MAX_LITERAL_POOL_SIZE)
        {
          inst.error = _("Literal Pool Overflow");
          return FAIL;
@@ -1307,7 +1528,7 @@ add_to_lit_pool ()
 static void
 symbol_locate (symbolP, name, segment, valu, frag)
      symbolS *    symbolP;
-     CONST char * name;                /* It is copied, the caller can modify.  */
+     const char * name;                /* It is copied, the caller can modify.  */
      segT         segment;     /* Segment identifier (SEG_<something>).  */
      valueT       valu;                /* Symbol value.  */
      fragS *      frag;                /* Associated fragment.  */
@@ -1710,7 +1931,7 @@ opcode_select (width)
     case 16:
       if (! thumb_mode)
        {
-         if (! (cpu_variant & ARM_EXT_THUMB))
+         if (! (cpu_variant & ARM_EXT_V4T))
            as_bad (_("selected processor does not support THUMB opcodes"));
 
          thumb_mode = 1;
@@ -1723,7 +1944,7 @@ opcode_select (width)
     case 32:
       if (thumb_mode)
        {
-         if ((cpu_variant & ARM_ANY) == ARM_EXT_THUMB)
+         if ((cpu_variant & ARM_ANY) == ARM_EXT_V4T)
            as_bad (_("selected processor does not support ARM opcodes"));
 
          thumb_mode = 0;
@@ -1838,14 +2059,14 @@ reg_required_here (str, shift)
   return FAIL;
 }
 
-static CONST struct asm_psr *
+static const struct asm_psr *
 arm_psr_parse (ccp)
      register char ** ccp;
 {
   char * start = * ccp;
   char   c;
   char * p;
-  CONST struct asm_psr * psr;
+  const struct asm_psr * psr;
 
   p = start;
 
@@ -1854,7 +2075,7 @@ arm_psr_parse (ccp)
     {
       c = *p++;
     }
-  while (isalpha (c) || c == '_');
+  while (ISALPHA (c) || c == '_');
 
   /* Terminate the word.  */
   *--p = 0;
@@ -1867,7 +2088,7 @@ arm_psr_parse (ccp)
     strncpy (start, "SPSR", 4);
 
   /* Now locate the word in the psr hash table.  */
-  psr = (CONST struct asm_psr *) hash_find (arm_psr_hsh, start);
+  psr = (const struct asm_psr *) hash_find (arm_psr_hsh, start);
 
   /* Restore the input stream.  */
   *p = c;
@@ -1886,7 +2107,7 @@ psr_required_here (str)
      char ** str;
 {
   char * start = * str;
-  CONST struct asm_psr * psr;
+  const struct asm_psr * psr;
 
   psr = arm_psr_parse (str);
 
@@ -2278,12 +2499,17 @@ do_msr (str, flags)
       return;
     }
 
+#if 0  /* The first edition of the ARM architecture manual stated that
+         writing anything other than the flags with an immediate operation
+         had UNPREDICTABLE effects.  This constraint was removed in the
+         second edition of the specification.  */
   if ((cpu_variant & ARM_EXT_V5) != ARM_EXT_V5
       && inst.instruction & ((PSR_c | PSR_x | PSR_s) << PSR_SHIFT))
     {
       inst.error = _("immediate value cannot be used to set this field");
       return;
     }
+#endif
 
   flags |= INST_IMMEDIATE;
 
@@ -2502,7 +2728,7 @@ accum0_required_here (str)
 
   *str = p;                    /* Advance caller's string pointer too.  */
   c = *p++;
-  while (isalnum (c))
+  while (ISALNUM (c))
     c = *p++;
 
   *--p = 0;                    /* Aap nul into input buffer at non-alnum.  */
@@ -3377,7 +3603,7 @@ do_mra (str, flags)
     end_of_line (str);
 }
 
-/* Xscale: Preload-Cache
+/* ARMv5TE: Preload-Cache
 
     PLD <addr_mode>
 
@@ -3465,7 +3691,7 @@ do_pld (str, flags)
   end_of_line (str);
 }
 
-/* Xscale load-consecutive (argument parse)
+/* ARMv5TE load-consecutive (argument parse)
    Mode is like LDRH.
 
      LDRccD R, mode
@@ -3498,7 +3724,7 @@ do_ldrd (str, flags)
       static char buff[128];
 
       --str;
-      while (isspace (*str))
+      while (ISSPACE (*str))
        --str;
       str -= 4;
 
@@ -3695,7 +3921,7 @@ decode_shift (str, unrestrict)
 
   skip_whitespace (* str);
 
-  for (p = * str; isalpha (* p); p ++)
+  for (p = * str; ISALPHA (* p); p ++)
     ;
 
   if (p == * str)
@@ -4059,8 +4285,6 @@ do_adr (str, flags)
      char * str;
      unsigned long flags;
 {
-  /* This is a pseudo-op of the form "adr rd, label" to be converted
-     into a relative address of the form "add rd, pc, #label-.-8".  */
   skip_whitespace (str);
 
   if (reg_required_here (&str, 12) == FAIL
@@ -4072,48 +4296,33 @@ do_adr (str, flags)
       return;
     }
 
-  /* Frag hacking will turn this into a sub instruction if the offset turns
-     out to be negative.  */
-  inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
-  inst.reloc.exp.X_add_number -= 8; /* PC relative adjust.  */
-  inst.reloc.pc_rel = 1;
-  inst.instruction |= flags;
-
-  end_of_line (str);
-}
-
-static void
-do_adrl (str, flags)
-     char * str;
-     unsigned long flags;
-{
-  /* This is a pseudo-op of the form "adrl rd, label" to be converted
-     into a relative address of the form:
-       add rd, pc, #low(label-.-8)"
-       add rd, rd, #high(label-.-8)"  */
-
-  skip_whitespace (str);
-
-  if (reg_required_here (& str, 12) == FAIL
-      || skip_past_comma (& str) == FAIL
-      || my_get_expression (& inst.reloc.exp, & str))
+  if (flags & 0x00400000)
     {
-      if (!inst.error)
-       inst.error = BAD_ARGS;
-      return;
+      /* This is a pseudo-op of the form "adrl rd, label" to be converted
+        into a relative address of the form:
+        add rd, pc, #low(label-.-8)"
+        add rd, rd, #high(label-.-8)"  */
+      /* Frag hacking will turn this into a sub instruction if the offset turns
+        out to be negative.  */
+      inst.reloc.type              = BFD_RELOC_ARM_ADRL_IMMEDIATE;
+      inst.reloc.exp.X_add_number -= 8; /* PC relative adjust  */
+      inst.reloc.pc_rel            = 1;
+      inst.instruction            |= flags & ~0x00400000;
+      inst.size                    = INSN_SIZE * 2;
+    }
+  else
+    {
+      /* This is a pseudo-op of the form "adr rd, label" to be converted
+        into a relative address of the form "add rd, pc, #label-.-8".  */
+      /* Frag hacking will turn this into a sub instruction if the offset turns
+        out to be negative.  */
+      inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
+      inst.reloc.exp.X_add_number -= 8; /* PC relative adjust.  */
+      inst.reloc.pc_rel = 1;
+      inst.instruction |= flags;
     }
 
   end_of_line (str);
-
-  /* Frag hacking will turn this into a sub instruction if the offset turns
-     out to be negative.  */
-  inst.reloc.type              = BFD_RELOC_ARM_ADRL_IMMEDIATE;
-  inst.reloc.exp.X_add_number -= 8; /* PC relative adjust  */
-  inst.reloc.pc_rel            = 1;
-  inst.instruction            |= flags;
-  inst.size                    = INSN_SIZE * 2;
-
-  return;
 }
 
 static void
@@ -4269,7 +4478,7 @@ do_ldst (str, flags)
     {
       /* This is actually a load/store of a halfword, or a
          signed-extension load.  */
-      if ((cpu_variant & ARM_EXT_HALFWORD) == 0)
+      if ((cpu_variant & ARM_EXT_V4) == 0)
        {
          inst.error
            = _("Processor does not support halfwords or signed bytes");
@@ -4415,38 +4624,53 @@ do_ldst (str, flags)
          return;
        }
 
-      if (inst.reloc.exp.X_op == O_constant
-         && (value = validate_immediate (inst.reloc.exp.X_add_number)) != FAIL)
-       {
-         /* This can be done with a mov instruction.  */
-         inst.instruction &= LITERAL_MASK;
-         inst.instruction |= INST_IMMEDIATE | (OPCODE_MOV << DATA_OP_SHIFT);
-         inst.instruction |= (flags & COND_MASK) | (value & 0xfff);
-         end_of_line (str);
-         return;
-       }
-      else
+      if (inst.reloc.exp.X_op == O_constant)
        {
-         /* Insert into literal pool.  */
-         if (add_to_lit_pool () == FAIL)
+         value = validate_immediate (inst.reloc.exp.X_add_number);
+
+         if (value != FAIL)
            {
-             if (!inst.error)
-               inst.error = _("literal pool insertion failed");
+             /* This can be done with a mov instruction.  */
+             inst.instruction &= LITERAL_MASK;
+             inst.instruction |= INST_IMMEDIATE | (OPCODE_MOV << DATA_OP_SHIFT);
+             inst.instruction |= (flags & COND_MASK) | (value & 0xfff);
+             end_of_line (str);
              return;
            }
+         
+         value = validate_immediate (~ inst.reloc.exp.X_add_number);
 
-         /* Change the instruction exp to point to the pool.  */
-         if (halfword)
+         if (value != FAIL)
            {
-             inst.instruction |= HWOFFSET_IMM;
-             inst.reloc.type = BFD_RELOC_ARM_HWLITERAL;
+             /* This can be done with a mvn instruction.  */
+             inst.instruction &= LITERAL_MASK;
+             inst.instruction |= INST_IMMEDIATE | (OPCODE_MVN << DATA_OP_SHIFT);
+             inst.instruction |= (flags & COND_MASK) | (value & 0xfff);
+             end_of_line (str);
+             return;
            }
-         else
-           inst.reloc.type = BFD_RELOC_ARM_LITERAL;
-         inst.reloc.pc_rel = 1;
-         inst.instruction |= (REG_PC << 16);
-         pre_inc = 1;
        }
+
+      /* Insert into literal pool.  */
+      if (add_to_lit_pool () == FAIL)
+       {
+         if (!inst.error)
+           inst.error = _("literal pool insertion failed");
+         return;
+       }
+
+      /* Change the instruction exp to point to the pool.  */
+      if (halfword)
+       {
+         inst.instruction |= HWOFFSET_IMM;
+         inst.reloc.type = BFD_RELOC_ARM_HWLITERAL;
+       }
+      else
+       inst.reloc.type = BFD_RELOC_ARM_LITERAL;
+
+      inst.reloc.pc_rel = 1;
+      inst.instruction |= (REG_PC << 16);
+      pre_inc = 1;
     }
   else
     {
@@ -4972,7 +5196,7 @@ do_co_reg (str, flags)
 }
 
 static void
-do_fp_ctrl (str, flags)
+do_fpa_ctrl (str, flags)
      char * str;
      unsigned long flags ATTRIBUTE_UNUSED;
 {
@@ -4993,7 +5217,7 @@ do_fp_ctrl (str, flags)
 }
 
 static void
-do_fp_ldst (str, flags)
+do_fpa_ldst (str, flags)
      char * str;
      unsigned long flags ATTRIBUTE_UNUSED;
 {
@@ -5035,7 +5259,7 @@ do_fp_ldst (str, flags)
 }
 
 static void
-do_fp_ldmstm (str, flags)
+do_fpa_ldmstm (str, flags)
      char * str;
      unsigned long flags;
 {
@@ -5175,7 +5399,7 @@ do_fp_ldmstm (str, flags)
 }
 
 static void
-do_fp_dyadic (str, flags)
+do_fpa_dyadic (str, flags)
      char * str;
      unsigned long flags;
 {
@@ -5224,7 +5448,7 @@ do_fp_dyadic (str, flags)
 }
 
 static void
-do_fp_monadic (str, flags)
+do_fpa_monadic (str, flags)
      char * str;
      unsigned long flags;
 {
@@ -5265,7 +5489,7 @@ do_fp_monadic (str, flags)
 }
 
 static void
-do_fp_cmp (str, flags)
+do_fpa_cmp (str, flags)
      char * str;
      unsigned long flags;
 {
@@ -5292,7 +5516,7 @@ do_fp_cmp (str, flags)
 }
 
 static void
-do_fp_from_reg (str, flags)
+do_fpa_from_reg (str, flags)
      char * str;
      unsigned long flags;
 {
@@ -5333,7 +5557,7 @@ do_fp_from_reg (str, flags)
 }
 
 static void
-do_fp_to_reg (str, flags)
+do_fpa_to_reg (str, flags)
      char * str;
      unsigned long flags;
 {
@@ -5966,119 +6190,694 @@ thumb_load_store (str, load_store, size)
   end_of_line (str);
 }
 
-static void
-do_t_nop (str)
-     char * str;
+/* Given a register and a register type, return 1 if
+   the register is of the given type, else return 0.  */
+
+static int
+cirrus_valid_reg (reg, regtype)
+     int reg;
+     enum cirrus_regtype regtype;
 {
-  /* Do nothing.  */
-  end_of_line (str);
-  return;
-}
+  switch (regtype)
+    {
+    case CIRRUS_REGTYPE_ANY:
+      return 1;
 
-/* Handle the Format 4 instructions that do not have equivalents in other
-   formats.  That is, ADC, AND, EOR, SBC, ROR, TST, NEG, CMN, ORR, MUL,
-   BIC and MVN.  */
+    case CIRRUS_REGTYPE_MVF:
+      return cirrus_mvf_register (reg);
 
-static void
-do_t_arit (str)
-     char * str;
-{
-  int Rd, Rs, Rn;
+    case CIRRUS_REGTYPE_MVFX:
+      return cirrus_mvfx_register (reg);
 
-  skip_whitespace (str);
+    case CIRRUS_REGTYPE_MVD:
+      return cirrus_mvd_register (reg);
 
-  if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL
-      || skip_past_comma (&str) == FAIL
-      || (Rs = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
-    {
-      inst.error = BAD_ARGS;
-      return;
+    case CIRRUS_REGTYPE_MVDX:
+      return cirrus_mvdx_register (reg);
+
+    case CIRRUS_REGTYPE_MVAX:
+      return cirrus_mvax_register (reg);
+
+    case CIRRUS_REGTYPE_DSPSC:
+      return ARM_EXT_MAVERICKsc_register (reg);
     }
 
-  if (skip_past_comma (&str) != FAIL)
+  return 0;
+}
+
+/* A register must be given at this point.
+
+   If the register is a Cirrus register, convert it's reg# appropriately.
+
+   Shift is the place to put it in inst.instruction.
+
+   regtype is type register type expected, and is:
+       CIRRUS_REGTYPE_MVF
+       CIRRUS_REGTYPE_MVFX
+       CIRRUS_REGTYPE_MVD
+       CIRRUS_REGTYPE_MVDX
+       CIRRUS_REGTYPE_MVAX
+       CIRRUS_REGTYPE_DSPSC
+
+   Restores input start point on err.
+   Returns the reg#, or FAIL.  */
+
+static int
+cirrus_reg_required_here (str, shift, regtype)
+     char ** str;
+     int shift;
+     enum cirrus_regtype regtype;
+{
+  static char buff [135]; /* XXX */
+  int         reg;
+  char *      start = * str;
+
+  if ((reg = arm_reg_parse (str)) != FAIL
+      && (int_register (reg)
+         || cirrus_register (reg)))
     {
-      /* Three operand format not allowed for TST, CMN, NEG and MVN.
-        (It isn't allowed for CMP either, but that isn't handled by this
-        function.)  */
-      if (inst.instruction == T_OPCODE_TST
-         || inst.instruction == T_OPCODE_CMN
-         || inst.instruction == T_OPCODE_NEG
-         || inst.instruction == T_OPCODE_MVN)
+      int orig_reg = reg;
+
+      /* Calculate actual register # for opcode.  */
+      if (cirrus_register (reg)
+         && !ARM_EXT_MAVERICKsc_register (reg)) /* Leave this one as is.  */
        {
-         inst.error = BAD_ARGS;
-         return;
+         if (reg >= 130)
+           reg -= 130;
+         else if (reg >= 110)
+           reg -= 110;
+         else if (reg >= 90)
+           reg -= 90;
+         else if (reg >= 70)
+           reg -= 70;
+         else if (reg >= 50)
+           reg -= 50;
        }
 
-      if ((Rn = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
-       return;
-
-      if (Rs != Rd)
+      if (!cirrus_valid_reg (orig_reg, regtype))
        {
-         inst.error = _("dest and source1 one must be the same register");
-         return;
+         sprintf (buff, _("invalid register type at '%.100s'"), start);
+         inst.error = buff;
+         return FAIL;
        }
-      Rs = Rn;
-    }
 
-  if (inst.instruction == T_OPCODE_MUL
-      && Rs == Rd)
-    as_tsktsk (_("Rs and Rd must be different in MUL"));
+      if (shift >= 0)
+       inst.instruction |= reg << shift;
 
-  inst.instruction |= Rd | (Rs << 3);
-  end_of_line (str);
+      return orig_reg;
+    }
+
+  /* Restore the start point, we may have got a reg of the wrong class.  */
+  *str = start;
+  
+  /* In the few cases where we might be able to accept something else
+     this error can be overridden.  */
+  sprintf (buff, _("Cirrus register expected, not '%.100s'"), start);
+  inst.error = buff;
+  
+  return FAIL;
 }
 
+/* Cirrus Instructions.  */
+
+/* Wrapper functions.  */
+
 static void
-do_t_add (str)
+do_c_binops_1 (str, flags)
      char * str;
+     unsigned long flags;
 {
-  thumb_add_sub (str, 0);
+  do_c_binops (str, flags, CIRRUS_MODE1);
 }
 
 static void
-do_t_asr (str)
+do_c_binops_2 (str, flags)
      char * str;
+     unsigned long flags;
 {
-  thumb_shift (str, THUMB_ASR);
+  do_c_binops (str, flags, CIRRUS_MODE2);
 }
 
 static void
-do_t_branch9 (str)
+do_c_binops_3 (str, flags)
      char * str;
+     unsigned long flags;
 {
-  if (my_get_expression (&inst.reloc.exp, &str))
-    return;
-  inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH9;
-  inst.reloc.pc_rel = 1;
-  end_of_line (str);
+  do_c_binops (str, flags, CIRRUS_MODE3);
 }
 
 static void
-do_t_branch12 (str)
+do_c_triple_4 (str, flags)
      char * str;
+     unsigned long flags;
 {
-  if (my_get_expression (&inst.reloc.exp, &str))
-    return;
-  inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH12;
-  inst.reloc.pc_rel = 1;
-  end_of_line (str);
+  do_c_triple (str, flags, CIRRUS_MODE4);
 }
 
-/* Find the real, Thumb encoded start of a Thumb function.  */
+static void
+do_c_triple_5 (str, flags)
+     char * str;
+     unsigned long flags;
+{
+  do_c_triple (str, flags, CIRRUS_MODE5);
+}
 
-static symbolS *
-find_real_start (symbolP)
-     symbolS * symbolP;
+static void
+do_c_quad_6 (str, flags)
+     char * str;
+     unsigned long flags;
 {
-  char *       real_start;
-  const char * name = S_GET_NAME (symbolP);
-  symbolS *    new_target;
+  do_c_quad (str, flags, CIRRUS_MODE6);
+}
 
-  /* This definiton must agree with the one in gcc/config/arm/thumb.c.  */
-#define STUB_NAME ".real_start_of"
+static void
+do_c_dspsc_1 (str, flags)
+     char * str;
+     unsigned long flags;
+{
+  do_c_dspsc (str, flags, CIRRUS_MODE1);
+}
 
-  if (name == NULL)
-    abort ();
+static void
+do_c_dspsc_2 (str, flags)
+     char * str;
+     unsigned long flags;
+{
+  do_c_dspsc (str, flags, CIRRUS_MODE2);
+}
+
+static void
+do_c_shift_1 (str, flags)
+     char * str;
+     unsigned long flags;
+{
+  do_c_shift (str, flags, CIRRUS_MODE1);
+}
+
+static void
+do_c_shift_2 (str, flags)
+     char * str;
+     unsigned long flags;
+{
+  do_c_shift (str, flags, CIRRUS_MODE2);
+}
+
+static void
+do_c_ldst_1 (str, flags)
+     char * str;
+     unsigned long flags;
+{
+  do_c_ldst (str, flags, CIRRUS_MODE1);
+}
+
+static void
+do_c_ldst_2 (str, flags)
+     char * str;
+     unsigned long flags;
+{
+  do_c_ldst (str, flags, CIRRUS_MODE2);
+}
+
+static void
+do_c_ldst_3 (str, flags)
+     char * str;
+     unsigned long flags;
+{
+  do_c_ldst (str, flags, CIRRUS_MODE3);
+}
+
+static void
+do_c_ldst_4 (str, flags)
+     char * str;
+     unsigned long flags;
+{
+  do_c_ldst (str, flags, CIRRUS_MODE4);
+}
+
+/* Isnsn like "foo X,Y".  */
+
+static void
+do_c_binops (str, flags, mode)
+     char * str;
+     unsigned long flags;
+     int mode;
+{
+  int shift1, shift2;
+
+  shift1 = mode & 0xff;
+  shift2 = (mode >> 8) & 0xff;
+
+  skip_whitespace (str);
+
+  if (cirrus_reg_required_here (&str, shift1, CIRRUS_REGTYPE_ANY) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || cirrus_reg_required_here (&str, shift2, CIRRUS_REGTYPE_ANY) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+    }
+  else
+    end_of_line (str);
+  
+  inst.instruction |= flags;
+  return;
+}
+
+/* Isnsn like "foo X,Y,Z".  */
+
+static void
+do_c_triple (str, flags, mode)
+     char * str;
+     unsigned long flags;
+     int mode;
+{
+  int shift1, shift2, shift3;
+
+  shift1 = mode & 0xff;
+  shift2 = (mode >> 8) & 0xff;
+  shift3 = (mode >> 16) & 0xff;
+
+  skip_whitespace (str);
+
+  if (cirrus_reg_required_here (&str, shift1, CIRRUS_REGTYPE_ANY) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || cirrus_reg_required_here (&str, shift2, CIRRUS_REGTYPE_ANY) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || cirrus_reg_required_here (&str, shift3, CIRRUS_REGTYPE_ANY) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+    }
+  else
+    end_of_line (str);
+  
+  inst.instruction |= flags;
+  return;
+}
+
+/* Isnsn like "foo W,X,Y,Z".
+    where W=MVAX[0:3] and X,Y,Z=MVFX[0:15].  */
+
+static void
+do_c_quad (str, flags, mode)
+     char * str;
+     unsigned long flags;
+     int mode;
+{
+  int shift1, shift2, shift3, shift4;
+  enum cirrus_regtype rt;
+
+  rt = (inst.instruction << 4 == 0xe2006000
+       || inst.instruction << 4 == 0xe3006000) ? CIRRUS_REGTYPE_MVAX
+    : CIRRUS_REGTYPE_MVFX;
+
+  shift1 = mode & 0xff;
+  shift2 = (mode >> 8) & 0xff;
+  shift3 = (mode >> 16) & 0xff;
+  shift4 = (mode >> 24) & 0xff;
+
+  skip_whitespace (str);
+
+  if (cirrus_reg_required_here (&str, shift1, CIRRUS_REGTYPE_MVAX) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || cirrus_reg_required_here (&str, shift2, rt) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || cirrus_reg_required_here (&str, shift3, CIRRUS_REGTYPE_MVFX) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || cirrus_reg_required_here (&str, shift4, CIRRUS_REGTYPE_MVFX) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+    }
+  else
+    end_of_line (str);
+  
+  inst.instruction |= flags;
+  return;
+}
+
+/* cfmvsc32<cond> DSPSC,MVFX[15:0].
+   cfmv32sc<cond> MVFX[15:0],DSPSC.  */
+
+static void
+do_c_dspsc (str, flags, mode)
+     char * str;
+     unsigned long flags;
+     int mode;
+{
+  int error;
+
+  skip_whitespace (str);
+
+  error = 0;
+
+  if (mode == CIRRUS_MODE1)
+    {
+      /* cfmvsc32.  */
+      if (cirrus_reg_required_here (&str, -1, CIRRUS_REGTYPE_DSPSC) == FAIL
+         || skip_past_comma (&str) == FAIL
+         || cirrus_reg_required_here (&str, 16, CIRRUS_REGTYPE_MVFX) == FAIL)
+       error = 1;
+    }
+  else
+    {
+      /* cfmv32sc.  */
+      if (cirrus_reg_required_here (&str, 0, CIRRUS_REGTYPE_MVFX) == FAIL
+         || skip_past_comma (&str) == FAIL
+         || cirrus_reg_required_here (&str, -1, CIRRUS_REGTYPE_DSPSC) == FAIL)
+       error = 1;
+    }
+
+  if (error)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+    }
+  else
+    {
+      inst.instruction |= flags;
+      end_of_line (str);
+    }
+
+  return;
+}
+
+/* Cirrus shift immediate instructions.
+   cfsh32<cond> MVFX[15:0],MVFX[15:0],Shift[6:0].
+   cfsh64<cond> MVDX[15:0],MVDX[15:0],Shift[6:0].  */
+
+static void
+do_c_shift (str, flags, mode)
+     char * str;
+     unsigned long flags;
+     int mode;
+{
+  int error;
+  int imm, neg = 0;
+
+  skip_whitespace (str);
+
+  error = 0;
+
+  if (cirrus_reg_required_here (&str, 12,
+                               (mode == CIRRUS_MODE1)
+                               ? CIRRUS_REGTYPE_MVFX
+                               : CIRRUS_REGTYPE_MVDX) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || cirrus_reg_required_here (&str, 16,
+                                  (mode == CIRRUS_MODE1)
+                                  ? CIRRUS_REGTYPE_MVFX
+                                  : CIRRUS_REGTYPE_MVDX) == FAIL
+      || skip_past_comma  (&str) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  /* Calculate the immediate operand.
+     The operand is a 7bit signed number.  */
+  skip_whitespace (str);
+
+  if (*str == '#')
+    ++str;
+
+  if (!ISDIGIT (*str) && *str != '-')
+    {
+      inst.error = _("expecting immediate, 7bit operand");
+      return;
+    }
+
+  if (*str == '-')
+    {
+      neg = 1;
+      ++str;
+    }
+
+  for (imm = 0; *str && ISDIGIT (*str); ++str)
+    imm = imm * 10 + *str - '0';
+
+  if (imm > 64)
+    {
+      inst.error = _("immediate out of range");
+      return;
+    }
+
+  /* Make negative imm's into 7bit signed numbers.  */
+  if (neg)
+    {
+      imm = -imm;
+      imm &= 0x0000007f;
+    }
+
+  /* Bits 0-3 of the insn should have bits 0-3 of the immediate.
+     Bits 5-7 of the insn should have bits 4-6 of the immediate.
+     Bit 4 should be 0.  */
+  imm = (imm & 0xf) | ((imm & 0x70) << 1);
+
+  inst.instruction |= imm;
+  inst.instruction |= flags;
+
+  end_of_line (str);
+
+  return;
+}
+
+static int
+cirrus_parse_offset (str, negative)
+     char ** str;
+     int *negative;
+{
+  char * p = *str;
+  int offset;
+
+  *negative = 0;
+
+  skip_whitespace (p);
+
+  if (*p == '#')
+    ++p;
+
+  if (*p == '-')
+    {
+      *negative = 1;
+      ++p;
+    }
+
+  if (!ISDIGIT (*p))
+    {
+      inst.error = _("offset expected");
+      return 0;
+    }
+
+  for (offset = 0; *p && ISDIGIT (*p); ++p)
+    offset = offset * 10 + *p - '0';
+
+  if (offset > 0xff)
+    {
+      inst.error = _("offset out of range");
+      return 0;
+    }
+
+  *str = p;
+
+  return *negative ? -offset : offset;
+}
+
+/* Cirrus load/store instructions.
+  <insn><cond> CRd,[Rn,<offset>]{!}.
+  <insn><cond> CRd,[Rn],<offset>.  */
+
+static void
+do_c_ldst (str, flags, mode)
+     char * str;
+     unsigned long flags;
+     int mode;
+{
+  int offset, negative;
+  enum cirrus_regtype rt;
+
+  rt = mode == CIRRUS_MODE1 ? CIRRUS_REGTYPE_MVF
+    : mode == CIRRUS_MODE2 ? CIRRUS_REGTYPE_MVD
+    : mode == CIRRUS_MODE3 ? CIRRUS_REGTYPE_MVFX
+    : mode == CIRRUS_MODE4 ? CIRRUS_REGTYPE_MVDX : CIRRUS_REGTYPE_MVF;
+
+  skip_whitespace (str);
+
+  if (cirrus_reg_required_here (& str, 12, rt) == FAIL
+      || skip_past_comma (& str) == FAIL
+      || *str++ != '['
+      || reg_required_here (& str, 16) == FAIL)
+    goto fail_ldst;
+
+  if (skip_past_comma (& str) == SUCCESS)
+    {
+      /* You are here: "<offset>]{!}".  */
+      inst.instruction |= PRE_INDEX;
+
+      offset = cirrus_parse_offset (&str, &negative);
+
+      if (inst.error)
+       return;
+
+      if (*str++ != ']')
+       {
+         inst.error = _("missing ]");
+         return;
+       }
+
+      if (*str == '!')
+       {
+         inst.instruction |= WRITE_BACK;
+         ++str;
+       }
+    }
+  else
+    {
+      /* You are here: "], <offset>".  */
+      if (*str++ != ']')
+       {
+         inst.error = _("missing ]");
+         return;
+       }
+
+      if (skip_past_comma (&str) == FAIL
+         || (offset = cirrus_parse_offset (&str, &negative), inst.error))
+       goto fail_ldst;
+
+      inst.instruction |= CP_T_WB; /* Post indexed, set bit W.  */
+    }
+
+  if (negative)
+    offset = -offset;
+  else
+    inst.instruction |= CP_T_UD; /* Postive, so set bit U.  */
+
+  inst.instruction |= offset >> 2;
+  inst.instruction |= flags;
+
+  end_of_line (str);
+  return;
+
+fail_ldst:
+  if (!inst.error)
+     inst.error = BAD_ARGS;
+  return;
+}
+
+static void
+do_t_nop (str)
+     char * str;
+{
+  /* Do nothing.  */
+  end_of_line (str);
+  return;
+}
+
+/* Handle the Format 4 instructions that do not have equivalents in other
+   formats.  That is, ADC, AND, EOR, SBC, ROR, TST, NEG, CMN, ORR, MUL,
+   BIC and MVN.  */
+
+static void
+do_t_arit (str)
+     char * str;
+{
+  int Rd, Rs, Rn;
+
+  skip_whitespace (str);
+
+  if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || (Rs = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
+    {
+      inst.error = BAD_ARGS;
+      return;
+    }
+
+  if (skip_past_comma (&str) != FAIL)
+    {
+      /* Three operand format not allowed for TST, CMN, NEG and MVN.
+        (It isn't allowed for CMP either, but that isn't handled by this
+        function.)  */
+      if (inst.instruction == T_OPCODE_TST
+         || inst.instruction == T_OPCODE_CMN
+         || inst.instruction == T_OPCODE_NEG
+         || inst.instruction == T_OPCODE_MVN)
+       {
+         inst.error = BAD_ARGS;
+         return;
+       }
+
+      if ((Rn = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
+       return;
+
+      if (Rs != Rd)
+       {
+         inst.error = _("dest and source1 must be the same register");
+         return;
+       }
+      Rs = Rn;
+    }
+
+  if (inst.instruction == T_OPCODE_MUL
+      && Rs == Rd)
+    as_tsktsk (_("Rs and Rd must be different in MUL"));
+
+  inst.instruction |= Rd | (Rs << 3);
+  end_of_line (str);
+}
+
+static void
+do_t_add (str)
+     char * str;
+{
+  thumb_add_sub (str, 0);
+}
+
+static void
+do_t_asr (str)
+     char * str;
+{
+  thumb_shift (str, THUMB_ASR);
+}
+
+static void
+do_t_branch9 (str)
+     char * str;
+{
+  if (my_get_expression (&inst.reloc.exp, &str))
+    return;
+  inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH9;
+  inst.reloc.pc_rel = 1;
+  end_of_line (str);
+}
+
+static void
+do_t_branch12 (str)
+     char * str;
+{
+  if (my_get_expression (&inst.reloc.exp, &str))
+    return;
+  inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH12;
+  inst.reloc.pc_rel = 1;
+  end_of_line (str);
+}
+
+/* Find the real, Thumb encoded start of a Thumb function.  */
+
+static symbolS *
+find_real_start (symbolP)
+     symbolS * symbolP;
+{
+  char *       real_start;
+  const char * name = S_GET_NAME (symbolP);
+  symbolS *    new_target;
+
+  /* This definiton must agree with the one in gcc/config/arm/thumb.c.  */
+#define STUB_NAME ".real_start_of"
+
+  if (name == NULL)
+    abort ();
 
   /* Names that start with '.' are local labels, not function entry points.
      The compiler may generate BL instructions to these labels because it
@@ -6394,7 +7193,7 @@ insert_reg (entry)
   strcpy (buf + i, reg_table[entry].name);
 
   for (i = 0; buf[i]; i++)
-    buf2[i] = islower (buf[i]) ? toupper (buf[i]) : buf[i];
+    buf2[i] = TOUPPER (buf[i]);
 
   buf2[i] = '\0';
 
@@ -6467,7 +7266,7 @@ md_begin ()
     if (support_interwork) flags |= F_INTERWORK;
     if (uses_apcs_float)   flags |= F_APCS_FLOAT;
     if (pic_code)          flags |= F_PIC;
-    if ((cpu_variant & FPU_ALL) == FPU_NONE) flags |= F_SOFT_FLOAT;
+    if ((cpu_variant & FPU_ANY) == FPU_NONE) flags |= F_SOFT_FLOAT;
 
     bfd_set_private_flags (stdoutput, flags);
 
@@ -6502,40 +7301,37 @@ md_begin ()
       mach = bfd_mach_arm_2a;
       break;
 
+    case ARM_6:                        /* Also ARM_7.  */
+      mach = bfd_mach_arm_3;
+      break;
+
     default:
-    case ARM_6 | ARM_3 | ARM_2:        /* Actually no CPU type defined.  */
       mach = bfd_mach_arm_4;
       break;
 
-    case ARM_7:                /* Also ARM_6.  */
-      mach = bfd_mach_arm_3;
-      break;
     }
 
   /* Catch special cases.  */
-  if (cpu_variant != (FPU_DEFAULT | CPU_DEFAULT))
+  if (cpu_variant & ARM_EXT_XSCALE)
+    mach = bfd_mach_arm_XScale;
+  else if (cpu_variant & ARM_EXT_V5E)
+    mach = bfd_mach_arm_5TE;
+  else if (cpu_variant & ARM_EXT_V5)
+    {
+      if (cpu_variant & ARM_EXT_V4T)
+       mach = bfd_mach_arm_5T;
+      else
+       mach = bfd_mach_arm_5;
+    }
+  else if (cpu_variant & ARM_EXT_V4)
     {
-      if (cpu_variant & ARM_EXT_XSCALE)
-       mach = bfd_mach_arm_XScale;
-      else if (cpu_variant & ARM_EXT_V5E)
-       mach = bfd_mach_arm_5TE;
-      else if (cpu_variant & ARM_EXT_V5)
-       {
-         if (cpu_variant & ARM_EXT_THUMB)
-           mach = bfd_mach_arm_5T;
-         else
-           mach = bfd_mach_arm_5;
-       }
-      else if (cpu_variant & ARM_EXT_HALFWORD)
-       {
-         if (cpu_variant & ARM_EXT_THUMB)
-           mach = bfd_mach_arm_4T;
-         else
-           mach = bfd_mach_arm_4;
-       }
-      else if (cpu_variant & ARM_EXT_LONGMUL)
-       mach = bfd_mach_arm_3M;
+      if (cpu_variant & ARM_EXT_V4T)
+       mach = bfd_mach_arm_4T;
+      else
+       mach = bfd_mach_arm_4;
     }
+  else if (cpu_variant & ARM_EXT_V3M)
+    mach = bfd_mach_arm_3M;
 
   bfd_set_arch_mach (stdoutput, TARGET_ARCH, mach);
 }
@@ -6765,11 +7561,11 @@ arm_reg_parse (ccp)
     p++, start++;
 #endif
 #endif
-  if (!isalpha (*p) || !is_name_beginner (*p))
+  if (!ISALPHA (*p) || !is_name_beginner (*p))
     return FAIL;
 
   c = *p++;
-  while (isalpha (c) || isdigit (c) || c == '_')
+  while (ISALPHA (c) || ISDIGIT (c) || c == '_')
     c = *p++;
 
   *--p = 0;
@@ -6785,13 +7581,13 @@ arm_reg_parse (ccp)
   return FAIL;
 }
 
-int
-md_apply_fix3 (fixP, val, seg)
+void
+md_apply_fix3 (fixP, valP, seg)
      fixS *   fixP;
-     valueT * val;
+     valueT * valP;
      segT     seg;
 {
-  offsetT        value = * val;
+  offsetT        value = * valP;
   offsetT        newval;
   unsigned int   newimm;
   unsigned long  temp;
@@ -7051,7 +7847,7 @@ md_apply_fix3 (fixP, val, seg)
              && S_GET_SEGMENT (fixP->fx_addsy) == seg)
            {
              /* Get pc relative value to go into the branch.  */
-             value = * val;
+             value = * valP;
 
              /* Permit a backward branch provided that enough bits
                 are set.  Allow a forwards branch, provided that
@@ -7149,6 +7945,15 @@ md_apply_fix3 (fixP, val, seg)
 
        newval  = (newval  & 0xf800) | ((value & 0x7fffff) >> 12);
        newval2 = (newval2 & 0xf800) | ((value & 0xfff) >> 1);
+       if (fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BLX)
+         /* Remove bit zero of the adjusted offset.  Bit zero can only be
+            set if the upper insn is at a half-word boundary, since the
+            destination address, an ARM instruction, must always be on a
+            word boundary.  The semantics of the BLX (1) instruction, however,
+            are that bit zero in the offset must always be zero, and the
+            corresponding bit one in the target address will be set from bit
+            one of the source address.  */
+         newval2 &= ~1;
        md_number_to_chars (buf, newval, THUMB_SIZE);
        md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
       }
@@ -7378,15 +8183,13 @@ md_apply_fix3 (fixP, val, seg)
     case BFD_RELOC_VTABLE_INHERIT:
     case BFD_RELOC_VTABLE_ENTRY:
       fixP->fx_done = 0;
-      return 1;
+      return;
 
     case BFD_RELOC_NONE:
     default:
       as_bad_where (fixP->fx_file, fixP->fx_line,
                    _("Bad relocation fixup type (%d)"), fixP->fx_r_type);
     }
-
-  return 1;
 }
 
 /* Translate internal representation of relocation info to BFD target
@@ -7628,11 +8431,11 @@ md_assemble (str)
 
   if (thumb_mode)
     {
-      CONST struct thumb_opcode * opcode;
+      const struct thumb_opcode * opcode;
 
       c = *p;
       *p = '\0';
-      opcode = (CONST struct thumb_opcode *) hash_find (arm_tops_hsh, str);
+      opcode = (const struct thumb_opcode *) hash_find (arm_tops_hsh, str);
       *p = c;
 
       if (opcode)
@@ -7653,7 +8456,7 @@ md_assemble (str)
     }
   else
     {
-      CONST struct asm_opcode * opcode;
+      const struct asm_opcode * opcode;
       unsigned long cond_code;
 
       inst.size = INSN_SIZE;
@@ -7668,7 +8471,7 @@ md_assemble (str)
          c = *q;
          *q = '\0';
 
-         opcode = (CONST struct asm_opcode *) hash_find (arm_ops_hsh, str);
+         opcode = (const struct asm_opcode *) hash_find (arm_ops_hsh, str);
          *q = c;
 
          if (opcode && opcode->template)
@@ -7707,11 +8510,11 @@ md_assemble (str)
              r = q;
              if (p - r >= 2)
                {
-                 CONST struct asm_cond *cond;
+                 const struct asm_cond *cond;
                  char d = *(r + 2);
 
                  *(r + 2) = '\0';
-                 cond = (CONST struct asm_cond *) hash_find (arm_cond_hsh, r);
+                 cond = (const struct asm_cond *) hash_find (arm_cond_hsh, r);
                  *(r + 2) = d;
                  if (cond)
                    {
@@ -7746,7 +8549,7 @@ _("Warning: Use of the 'nv' conditional is deprecated\n"));
                 before any optional flags.  */
              if (opcode->comp_suffix && *opcode->comp_suffix != '\0')
                {
-                 CONST char *s = opcode->comp_suffix;
+                 const char *s = opcode->comp_suffix;
 
                  while (*s)
                    {
@@ -7771,7 +8574,7 @@ _("Warning: Use of the 'nv' conditional is deprecated\n"));
              if (r != p)
                {
                  char d;
-                 CONST struct asm_flg *flag = opcode->flags;
+                 const struct asm_flg *flag = opcode->flags;
 
                  if (flag)
                    {
@@ -7885,6 +8688,7 @@ _("Warning: Use of the 'nv' conditional is deprecated\n"));
               -m[arm]7[xx][t][[d]m]   Arm 7 processors
               -m[arm]8[10]            Arm 8 processors
               -m[arm]9[20][tdmi]      Arm 9 processors
+              -marm9e                 Allow Cirrus/DSP instructions
               -mstrongarm[110[0]]     StrongARM processors
               -mxscale                XScale processors
               -m[arm]v[2345[t[e]]]    Arm architectures
@@ -7905,7 +8709,7 @@ _("Warning: Use of the 'nv' conditional is deprecated\n"));
               -matpcs                 ARM/Thumb Procedure Call Standard
               -moabi                  Old ELF ABI  */
 
-CONST char * md_shortopts = "m:k";
+const char * md_shortopts = "m:k";
 
 struct option md_longopts[] =
 {
@@ -7946,19 +8750,17 @@ md_parse_option (c, arg)
       switch (*str)
        {
        case 'f':
-         if (streq (str, "fpa10"))
-           cpu_variant = (cpu_variant & ~FPU_ALL) | FPU_FPA10;
-         else if (streq (str, "fpa11"))
-           cpu_variant = (cpu_variant & ~FPU_ALL) | FPU_FPA11;
+         if (streq (str, "fpa10") || streq (str, "fpa11"))
+           cpu_variant = (cpu_variant & ~FPU_ANY) | FPU_ARCH_FPA;
          else if (streq (str, "fpe-old"))
-           cpu_variant = (cpu_variant & ~FPU_ALL) | FPU_CORE;
+           cpu_variant = (cpu_variant & ~FPU_ANY) | FPU_ARCH_FPE;
          else
            goto bad;
          break;
 
        case 'n':
          if (streq (str, "no-fpu"))
-           cpu_variant &= ~FPU_ALL;
+           cpu_variant &= ~FPU_ANY;
          break;
 
 #ifdef OBJ_ELF
@@ -7972,13 +8774,13 @@ md_parse_option (c, arg)
          /* Limit assembler to generating only Thumb instructions:  */
          if (streq (str, "thumb"))
            {
-             cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_EXT_THUMB;
-             cpu_variant = (cpu_variant & ~FPU_ALL) | FPU_NONE;
+             cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_EXT_V4T;
+             cpu_variant = (cpu_variant & ~FPU_ANY) | FPU_NONE;
              thumb_mode = 1;
            }
          else if (streq (str, "thumb-interwork"))
            {
-             if ((cpu_variant & ARM_EXT_THUMB) == 0)
+             if ((cpu_variant & ARM_EXT_V4T) == 0)
                cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_ARCH_V4T;
 #if defined OBJ_COFF || defined OBJ_ELF
              support_interwork = true;
@@ -7991,7 +8793,7 @@ md_parse_option (c, arg)
        default:
          if (streq (str, "all"))
            {
-             cpu_variant = ARM_ALL | FPU_ALL;
+             cpu_variant = ARM_ALL | FPU_DEFAULT;
              return 1;
            }
 #if defined OBJ_COFF || defined OBJ_ELF
@@ -8125,7 +8927,7 @@ md_parse_option (c, arg)
                      break;
 
                    case 'm':
-                     cpu_variant |= ARM_EXT_LONGMUL;
+                     cpu_variant |= ARM_EXT_V3M;
                      break;
 
                    case 'f': /* fe => fp enabled cpu.  */
@@ -8167,6 +8969,9 @@ md_parse_option (c, arg)
              else if (streq (str, "9tdmi"))
                cpu_variant = (cpu_variant & ~ARM_ANY)
                  | ARM_9 | ARM_ARCH_V4T;
+             else if (streq (str, "9e"))
+               cpu_variant = (cpu_variant & ~ARM_ANY)
+                 | ARM_9 | ARM_ARCH_V4T | ARM_EXT_MAVERICK;
              else
                goto bad;
              break;
@@ -8183,7 +8988,8 @@ md_parse_option (c, arg)
 
             case 'x':
              if (streq (str, "xscale"))
-               cpu_variant = ARM_9 | ARM_ARCH_XSCALE;
+               cpu_variant = (cpu_variant & ~ARM_ANY)
+                 | ARM_9 | ARM_ARCH_XSCALE;
              else
                goto bad;
              break;
@@ -8213,7 +9019,7 @@ md_parse_option (c, arg)
 
                  switch (*++str)
                    {
-                   case 'm': cpu_variant |= ARM_EXT_LONGMUL; break;
+                   case 'm': cpu_variant |= ARM_EXT_V3M; break;
                    case 0:   break;
                    default:
                      as_bad (_("Invalid architecture variant -m%s"), arg);
@@ -8226,7 +9032,7 @@ md_parse_option (c, arg)
 
                  switch (*++str)
                    {
-                   case 't': cpu_variant |= ARM_EXT_THUMB; break;
+                   case 't': cpu_variant |= ARM_EXT_V4T; break;
                    case 0:   break;
                    default:
                      as_bad (_("Invalid architecture variant -m%s"), arg);
@@ -8238,7 +9044,7 @@ md_parse_option (c, arg)
                  cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_9 | ARM_ARCH_V5;
                  switch (*++str)
                    {
-                   case 't': cpu_variant |= ARM_EXT_THUMB; break;
+                   case 't': cpu_variant |= ARM_EXT_V4T; break;
                    case 'e': cpu_variant |= ARM_EXT_V5E; break;
                    case 0:   break;
                    default:
@@ -8282,6 +9088,7 @@ md_show_usage (fp)
  ARM Specific Assembler Options:\n\
   -m[arm][<processor name>] select processor variant\n\
   -m[arm]v[2|2a|3|3m|4|4t|5[t][e]] select architecture variant\n\
+  -marm9e                   allow Cirrus/DSP instructions\n\
   -mthumb                   only allow Thumb instructions\n\
   -mthumb-interwork         mark the assembled code as supporting interworking\n\
   -mall                     allow any instruction\n\
@@ -8418,7 +9225,38 @@ arm_frob_label (sym)
   ARM_SET_INTERWORK (sym, support_interwork);
 #endif
 
-  if (label_is_thumb_function_name)
+  /* Note - do not allow local symbols (.Lxxx) to be labeled
+     as Thumb functions.  This is because these labels, whilst
+     they exist inside Thumb code, are not the entry points for
+     possible ARM->Thumb calls.  Also, these labels can be used
+     as part of a computed goto or switch statement.  eg gcc
+     can generate code that looks like this:
+
+                ldr  r2, [pc, .Laaa]
+                lsl  r3, r3, #2
+                ldr  r2, [r3, r2]
+                mov  pc, r2
+               
+       .Lbbb:  .word .Lxxx
+       .Lccc:  .word .Lyyy
+       ..etc...
+       .Laaa:   .word Lbbb
+
+     The first instruction loads the address of the jump table.
+     The second instruction converts a table index into a byte offset.
+     The third instruction gets the jump address out of the table.
+     The fourth instruction performs the jump.
+     
+     If the address stored at .Laaa is that of a symbol which has the
+     Thumb_Func bit set, then the linker will arrange for this address
+     to have the bottom bit set, which in turn would mean that the
+     address computation performed by the third instruction would end
+     up with the bottom bit set.  Since the ARM is capable of unaligned
+     word loads, the instruction would then load the incorrect address
+     out of the jump table, and chaos would ensue.  */
+  if (label_is_thumb_function_name
+      && (S_GET_NAME (sym)[0] != '.' || S_GET_NAME (sym)[1] != 'L')
+      && (bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE) != 0)
     {
       /* When the address of a Thumb function is taken the bottom
         bit of that address should be set.  This will allow
@@ -8674,9 +9512,9 @@ arm_parse_reloc ()
   };
 
   for (i = 0, ip = input_line_pointer;
-       i < sizeof (id) && (isalnum (*ip) || ispunct (*ip));
+       i < sizeof (id) && (ISALNUM (*ip) || ISPUNCT (*ip));
        i++, ip++)
-    id[i] = tolower (*ip);
+    id[i] = TOLOWER (*ip);
 
   for (i = 0; reloc_map[i].str; i++)
     if (strncmp (id, reloc_map[i].str, reloc_map[i].len) == 0)
@@ -8743,3 +9581,102 @@ s_arm_elf_cons (nbytes)
 }
 
 #endif /* OBJ_ELF */
+
+/* This is called from HANDLE_ALIGN in write.c.  Fill in the contents
+   of an rs_align_code fragment.  */
+
+void
+arm_handle_align (fragP)
+     fragS *fragP;
+{
+  static char const arm_noop[4] = { 0x00, 0x00, 0xa0, 0xe1 };
+  static char const thumb_noop[2] = { 0xc0, 0x46 };
+  static char const arm_bigend_noop[4] = { 0xe1, 0xa0, 0x00, 0x00 };
+  static char const thumb_bigend_noop[2] = { 0x46, 0xc0 };
+
+  int bytes, fix, noop_size;
+  char * p;
+  const char * noop;
+  
+  if (fragP->fr_type != rs_align_code)
+    return;
+
+  bytes = fragP->fr_next->fr_address - fragP->fr_address - fragP->fr_fix;
+  p = fragP->fr_literal + fragP->fr_fix;
+  fix = 0;
+  
+  if (bytes > MAX_MEM_FOR_RS_ALIGN_CODE)
+    bytes &= MAX_MEM_FOR_RS_ALIGN_CODE;
+  
+  if (fragP->tc_frag_data)
+    {
+      if (target_big_endian)
+       noop = thumb_bigend_noop;
+      else
+       noop = thumb_noop;
+      noop_size = sizeof (thumb_noop);
+    }
+  else
+    {
+      if (target_big_endian)
+       noop = arm_bigend_noop;
+      else
+       noop = arm_noop;
+      noop_size = sizeof (arm_noop);
+    }
+  
+  if (bytes & (noop_size - 1))
+    {
+      fix = bytes & (noop_size - 1);
+      memset (p, 0, fix);
+      p += fix;
+      bytes -= fix;
+    }
+
+  while (bytes >= noop_size)
+    {
+      memcpy (p, noop, noop_size);
+      p += noop_size;
+      bytes -= noop_size;
+      fix += noop_size;
+    }
+  
+  fragP->fr_fix += fix;
+  fragP->fr_var = noop_size;
+}
+
+/* Called from md_do_align.  Used to create an alignment
+   frag in a code section.  */
+
+void
+arm_frag_align_code (n, max)
+     int n;
+     int max;
+{
+  char * p;
+
+  /* We assume that there will never be a requirment
+     to support alignments greater than 32 bytes.  */
+  if (max > MAX_MEM_FOR_RS_ALIGN_CODE)
+    as_fatal (_("alignments greater than 32 bytes not supported in .text sections."));
+  
+  p = frag_var (rs_align_code,
+               MAX_MEM_FOR_RS_ALIGN_CODE,
+               1,
+               (relax_substateT) max,
+               (symbolS *) NULL,
+               (offsetT) n,
+               (char *) NULL);
+  *p = 0;
+
+}
+
+/* Perform target specific initialisation of a frag.  */
+
+void
+arm_init_frag (fragP)
+     fragS *fragP;
+{
+  /* Record whether this frag is in an ARM or a THUMB area.  */
+  fragP->tc_frag_data = thumb_mode;
+}
This page took 0.059963 seconds and 4 git commands to generate.