The patch below adds binutils support for the SHT_ARM_EXIDX, as defined by
[deliverable/binutils-gdb.git] / gas / config / tc-arm.c
index d2d70341145215016eb0a3cd04927e54c79ba713..9770ccd119d8eb28ace02481721ea13dc6e03d2e 100644 (file)
@@ -1,9 +1,11 @@
 /* tc-arm.c -- Assemble for the ARM
-   Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
+   Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
    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)
+       Cirrus coprocessor fixes by Petko Manolov (petkan@nucleusys.com)
+       Cirrus coprocessor fixes by Vladimir Ivanov (vladitx@nucleusys.com)
 
    This file is part of GAS, the GNU Assembler.
 
@@ -34,6 +36,8 @@
 #include "symbols.h"
 #include "listing.h"
 
+#include "opcode/arm.h"
+
 #ifdef OBJ_ELF
 #include "elf/arm.h"
 #include "dwarf2dbg.h"
 /* XXX Set this to 1 after the next binutils release */
 #define WARN_DEPRECATED 0
 
-/* 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.   */
-#define ARM_EXT_V5J     0x00000800     /* Jazelle extension.      */
-
-/* Co-processor space extensions.  */
-#define ARM_CEXT_XSCALE   0x00800000   /* Allow MIA etc.          */
-#define ARM_CEXT_MAVERICK 0x00400000   /* 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)
-#define ARM_ARCH_V5TEJ (ARM_ARCH_V5TE  | ARM_EXT_V5J)
-
-/* Processors with specific extensions in the co-processor space.  */
-#define ARM_ARCH_XSCALE        (ARM_ARCH_V5TE  | ARM_CEXT_XSCALE)
-
-/* Some useful combinations:  */
-#define ARM_ANY                0x0000ffff      /* Any basic core.  */
-#define ARM_ALL                0x00ffffff      /* Any core + co-processor */
-#define CPROC_ANY      0x00ff0000      /* Any co-processor */
-#define FPU_ANY                0xff000000      /* Note this is ~ARM_ALL.  */
-
-
-#define FPU_FPA_EXT_V1  0x80000000     /* Base FPA instruction set.  */
-#define FPU_FPA_EXT_V2  0x40000000     /* LFM/SFM.                   */
-#define FPU_VFP_EXT_NONE 0x20000000    /* Use VFP word-ordering.     */
-#define FPU_VFP_EXT_V1xD 0x10000000    /* Base VFP instruction set.  */
-#define FPU_VFP_EXT_V1  0x08000000     /* Double-precision insns.    */
-#define FPU_VFP_EXT_V2  0x04000000     /* ARM10E VFPr1.              */
-#define FPU_NONE        0
-
-#define FPU_ARCH_FPE    FPU_FPA_EXT_V1
-#define FPU_ARCH_FPA   (FPU_ARCH_FPE | FPU_FPA_EXT_V2)
-
-#define FPU_ARCH_VFP       FPU_VFP_EXT_NONE
-#define FPU_ARCH_VFP_V1xD (FPU_VFP_EXT_V1xD | FPU_VFP_EXT_NONE)
-#define FPU_ARCH_VFP_V1   (FPU_ARCH_VFP_V1xD | FPU_VFP_EXT_V1)
-#define FPU_ARCH_VFP_V2          (FPU_ARCH_VFP_V1 | FPU_VFP_EXT_V2)
+enum arm_float_abi
+{
+  ARM_FLOAT_ABI_HARD,
+  ARM_FLOAT_ABI_SOFTFP,
+  ARM_FLOAT_ABI_SOFT
+};
 
 /* Types of processor to assemble for.  */
 #define ARM_1          ARM_ARCH_V1
 #endif
 #endif
 
+#ifdef TE_LINUX
+#define FPU_DEFAULT FPU_ARCH_FPA
+#endif
+
+#ifdef TE_NetBSD
+#ifdef OBJ_ELF
+#define FPU_DEFAULT FPU_ARCH_VFP       /* Soft-float, but VFP order.  */
+#else
+/* Legacy a.out format.  */
+#define FPU_DEFAULT FPU_ARCH_FPA       /* Soft-float, but FPA order.  */
+#endif
+#endif
+
 /* For backwards compatibility we default to the FPA.  */
 #ifndef FPU_DEFAULT
 #define FPU_DEFAULT FPU_ARCH_FPA
@@ -144,11 +102,11 @@ static unsigned long cpu_variant;
 static int target_oabi = 0;
 
 /* Flags stored in private area of BFD structure.  */
-static int uses_apcs_26      = false;
-static int atpcs             = false;
-static int support_interwork = false;
-static int uses_apcs_float   = false;
-static int pic_code          = false;
+static int uses_apcs_26      = FALSE;
+static int atpcs             = FALSE;
+static int support_interwork = FALSE;
+static int uses_apcs_float   = FALSE;
+static int pic_code          = FALSE;
 
 /* Variables that we set while parsing command-line options.  Once all
    options have been read we re-process these values to set the real
@@ -161,6 +119,10 @@ static int mcpu_fpu_opt = -1;
 static int march_cpu_opt = -1;
 static int march_fpu_opt = -1;
 static int mfpu_opt = -1;
+static int mfloat_abi_opt = -1;
+#ifdef OBJ_ELF
+static int meabi_flags = EF_ARM_EABI_UNKNOWN;
+#endif
 
 /* This array holds the chars that always start a comment.  If the
    pre-processor is disabled, these aren't very useful.  */
@@ -273,8 +235,16 @@ static const struct asm_shift_name shift_names [] =
   { "RRX", shift_properties + SHIFT_RRX }
 };
 
+/* Any kind of shift is accepted.  */
 #define NO_SHIFT_RESTRICT 1
-#define SHIFT_RESTRICT   0
+/* The shift operand must be an immediate value, not a register.  */
+#define SHIFT_IMMEDIATE          0
+/* The shift must be LSL or ASR and the operand must be an immediate.  */
+#define SHIFT_LSL_OR_ASR_IMMEDIATE 2
+/* The shift must be ASR and the operand must be an immediate.  */
+#define SHIFT_ASR_IMMEDIATE 3
+/* The shift must be LSL and the operand must be an immediate.  */
+#define SHIFT_LSL_IMMEDIATE 4
 
 #define NUM_FLOAT_VALS 8
 
@@ -342,12 +312,12 @@ static const struct asm_cond conds[] =
 
 struct asm_psr
 {
-  const char *  template;
-  boolean       cpsr;
+  const char *template;
+  bfd_boolean cpsr;
   unsigned long field;
 };
 
-/* The bit that distnguishes CPSR and SPSR.  */
+/* The bit that distinguishes CPSR and SPSR.  */
 #define SPSR_BIT   (1 << 22)
 
 /* How many bits to shift the PSR_xxx bits up by.  */
@@ -360,143 +330,172 @@ struct asm_psr
 
 static const struct asm_psr psrs[] =
 {
-  {"CPSR",     true,  PSR_c | PSR_f},
-  {"CPSR_all", true,  PSR_c | PSR_f},
-  {"SPSR",     false, PSR_c | PSR_f},
-  {"SPSR_all", false, PSR_c | PSR_f},
-  {"CPSR_flg", true,  PSR_f},
-  {"CPSR_f",    true,  PSR_f},
-  {"SPSR_flg", false, PSR_f},
-  {"SPSR_f",    false, PSR_f},
-  {"CPSR_c",   true,  PSR_c},
-  {"CPSR_ctl", true,  PSR_c},
-  {"SPSR_c",   false, PSR_c},
-  {"SPSR_ctl", false, PSR_c},
-  {"CPSR_x",    true,  PSR_x},
-  {"CPSR_s",    true,  PSR_s},
-  {"SPSR_x",    false, PSR_x},
-  {"SPSR_s",    false, PSR_s},
+  {"CPSR",     TRUE,  PSR_c | PSR_f},
+  {"CPSR_all", TRUE,  PSR_c | PSR_f},
+  {"SPSR",     FALSE, PSR_c | PSR_f},
+  {"SPSR_all", FALSE, PSR_c | PSR_f},
+  {"CPSR_flg", TRUE,  PSR_f},
+  {"CPSR_f",    TRUE,  PSR_f},
+  {"SPSR_flg", FALSE, PSR_f},
+  {"SPSR_f",    FALSE, PSR_f},
+  {"CPSR_c",   TRUE,  PSR_c},
+  {"CPSR_ctl", TRUE,  PSR_c},
+  {"SPSR_c",   FALSE, PSR_c},
+  {"SPSR_ctl", FALSE, PSR_c},
+  {"CPSR_x",    TRUE,  PSR_x},
+  {"CPSR_s",    TRUE,  PSR_s},
+  {"SPSR_x",    FALSE, PSR_x},
+  {"SPSR_s",    FALSE, PSR_s},
   /* Combinations of flags.  */
-  {"CPSR_fs",  true, PSR_f | PSR_s},
-  {"CPSR_fx",  true, PSR_f | PSR_x},
-  {"CPSR_fc",  true, PSR_f | PSR_c},
-  {"CPSR_sf",  true, PSR_s | PSR_f},
-  {"CPSR_sx",  true, PSR_s | PSR_x},
-  {"CPSR_sc",  true, PSR_s | PSR_c},
-  {"CPSR_xf",  true, PSR_x | PSR_f},
-  {"CPSR_xs",  true, PSR_x | PSR_s},
-  {"CPSR_xc",  true, PSR_x | PSR_c},
-  {"CPSR_cf",  true, PSR_c | PSR_f},
-  {"CPSR_cs",  true, PSR_c | PSR_s},
-  {"CPSR_cx",  true, PSR_c | PSR_x},
-  {"CPSR_fsx", true, PSR_f | PSR_s | PSR_x},
-  {"CPSR_fsc", true, PSR_f | PSR_s | PSR_c},
-  {"CPSR_fxs", true, PSR_f | PSR_x | PSR_s},
-  {"CPSR_fxc", true, PSR_f | PSR_x | PSR_c},
-  {"CPSR_fcs", true, PSR_f | PSR_c | PSR_s},
-  {"CPSR_fcx", true, PSR_f | PSR_c | PSR_x},
-  {"CPSR_sfx", true, PSR_s | PSR_f | PSR_x},
-  {"CPSR_sfc", true, PSR_s | PSR_f | PSR_c},
-  {"CPSR_sxf", true, PSR_s | PSR_x | PSR_f},
-  {"CPSR_sxc", true, PSR_s | PSR_x | PSR_c},
-  {"CPSR_scf", true, PSR_s | PSR_c | PSR_f},
-  {"CPSR_scx", true, PSR_s | PSR_c | PSR_x},
-  {"CPSR_xfs", true, PSR_x | PSR_f | PSR_s},
-  {"CPSR_xfc", true, PSR_x | PSR_f | PSR_c},
-  {"CPSR_xsf", true, PSR_x | PSR_s | PSR_f},
-  {"CPSR_xsc", true, PSR_x | PSR_s | PSR_c},
-  {"CPSR_xcf", true, PSR_x | PSR_c | PSR_f},
-  {"CPSR_xcs", true, PSR_x | PSR_c | PSR_s},
-  {"CPSR_cfs", true, PSR_c | PSR_f | PSR_s},
-  {"CPSR_cfx", true, PSR_c | PSR_f | PSR_x},
-  {"CPSR_csf", true, PSR_c | PSR_s | PSR_f},
-  {"CPSR_csx", true, PSR_c | PSR_s | PSR_x},
-  {"CPSR_cxf", true, PSR_c | PSR_x | PSR_f},
-  {"CPSR_cxs", true, PSR_c | PSR_x | PSR_s},
-  {"CPSR_fsxc",        true, PSR_f | PSR_s | PSR_x | PSR_c},
-  {"CPSR_fscx",        true, PSR_f | PSR_s | PSR_c | PSR_x},
-  {"CPSR_fxsc",        true, PSR_f | PSR_x | PSR_s | PSR_c},
-  {"CPSR_fxcs",        true, PSR_f | PSR_x | PSR_c | PSR_s},
-  {"CPSR_fcsx",        true, PSR_f | PSR_c | PSR_s | PSR_x},
-  {"CPSR_fcxs",        true, PSR_f | PSR_c | PSR_x | PSR_s},
-  {"CPSR_sfxc",        true, PSR_s | PSR_f | PSR_x | PSR_c},
-  {"CPSR_sfcx",        true, PSR_s | PSR_f | PSR_c | PSR_x},
-  {"CPSR_sxfc",        true, PSR_s | PSR_x | PSR_f | PSR_c},
-  {"CPSR_sxcf",        true, PSR_s | PSR_x | PSR_c | PSR_f},
-  {"CPSR_scfx",        true, PSR_s | PSR_c | PSR_f | PSR_x},
-  {"CPSR_scxf",        true, PSR_s | PSR_c | PSR_x | PSR_f},
-  {"CPSR_xfsc",        true, PSR_x | PSR_f | PSR_s | PSR_c},
-  {"CPSR_xfcs",        true, PSR_x | PSR_f | PSR_c | PSR_s},
-  {"CPSR_xsfc",        true, PSR_x | PSR_s | PSR_f | PSR_c},
-  {"CPSR_xscf",        true, PSR_x | PSR_s | PSR_c | PSR_f},
-  {"CPSR_xcfs",        true, PSR_x | PSR_c | PSR_f | PSR_s},
-  {"CPSR_xcsf",        true, PSR_x | PSR_c | PSR_s | PSR_f},
-  {"CPSR_cfsx",        true, PSR_c | PSR_f | PSR_s | PSR_x},
-  {"CPSR_cfxs",        true, PSR_c | PSR_f | PSR_x | PSR_s},
-  {"CPSR_csfx",        true, PSR_c | PSR_s | PSR_f | PSR_x},
-  {"CPSR_csxf",        true, PSR_c | PSR_s | PSR_x | PSR_f},
-  {"CPSR_cxfs",        true, PSR_c | PSR_x | PSR_f | PSR_s},
-  {"CPSR_cxsf",        true, PSR_c | PSR_x | PSR_s | PSR_f},
-  {"SPSR_fs",  false, PSR_f | PSR_s},
-  {"SPSR_fx",  false, PSR_f | PSR_x},
-  {"SPSR_fc",  false, PSR_f | PSR_c},
-  {"SPSR_sf",  false, PSR_s | PSR_f},
-  {"SPSR_sx",  false, PSR_s | PSR_x},
-  {"SPSR_sc",  false, PSR_s | PSR_c},
-  {"SPSR_xf",  false, PSR_x | PSR_f},
-  {"SPSR_xs",  false, PSR_x | PSR_s},
-  {"SPSR_xc",  false, PSR_x | PSR_c},
-  {"SPSR_cf",  false, PSR_c | PSR_f},
-  {"SPSR_cs",  false, PSR_c | PSR_s},
-  {"SPSR_cx",  false, PSR_c | PSR_x},
-  {"SPSR_fsx", false, PSR_f | PSR_s | PSR_x},
-  {"SPSR_fsc", false, PSR_f | PSR_s | PSR_c},
-  {"SPSR_fxs", false, PSR_f | PSR_x | PSR_s},
-  {"SPSR_fxc", false, PSR_f | PSR_x | PSR_c},
-  {"SPSR_fcs", false, PSR_f | PSR_c | PSR_s},
-  {"SPSR_fcx", false, PSR_f | PSR_c | PSR_x},
-  {"SPSR_sfx", false, PSR_s | PSR_f | PSR_x},
-  {"SPSR_sfc", false, PSR_s | PSR_f | PSR_c},
-  {"SPSR_sxf", false, PSR_s | PSR_x | PSR_f},
-  {"SPSR_sxc", false, PSR_s | PSR_x | PSR_c},
-  {"SPSR_scf", false, PSR_s | PSR_c | PSR_f},
-  {"SPSR_scx", false, PSR_s | PSR_c | PSR_x},
-  {"SPSR_xfs", false, PSR_x | PSR_f | PSR_s},
-  {"SPSR_xfc", false, PSR_x | PSR_f | PSR_c},
-  {"SPSR_xsf", false, PSR_x | PSR_s | PSR_f},
-  {"SPSR_xsc", false, PSR_x | PSR_s | PSR_c},
-  {"SPSR_xcf", false, PSR_x | PSR_c | PSR_f},
-  {"SPSR_xcs", false, PSR_x | PSR_c | PSR_s},
-  {"SPSR_cfs", false, PSR_c | PSR_f | PSR_s},
-  {"SPSR_cfx", false, PSR_c | PSR_f | PSR_x},
-  {"SPSR_csf", false, PSR_c | PSR_s | PSR_f},
-  {"SPSR_csx", false, PSR_c | PSR_s | PSR_x},
-  {"SPSR_cxf", false, PSR_c | PSR_x | PSR_f},
-  {"SPSR_cxs", false, PSR_c | PSR_x | PSR_s},
-  {"SPSR_fsxc",        false, PSR_f | PSR_s | PSR_x | PSR_c},
-  {"SPSR_fscx",        false, PSR_f | PSR_s | PSR_c | PSR_x},
-  {"SPSR_fxsc",        false, PSR_f | PSR_x | PSR_s | PSR_c},
-  {"SPSR_fxcs",        false, PSR_f | PSR_x | PSR_c | PSR_s},
-  {"SPSR_fcsx",        false, PSR_f | PSR_c | PSR_s | PSR_x},
-  {"SPSR_fcxs",        false, PSR_f | PSR_c | PSR_x | PSR_s},
-  {"SPSR_sfxc",        false, PSR_s | PSR_f | PSR_x | PSR_c},
-  {"SPSR_sfcx",        false, PSR_s | PSR_f | PSR_c | PSR_x},
-  {"SPSR_sxfc",        false, PSR_s | PSR_x | PSR_f | PSR_c},
-  {"SPSR_sxcf",        false, PSR_s | PSR_x | PSR_c | PSR_f},
-  {"SPSR_scfx",        false, PSR_s | PSR_c | PSR_f | PSR_x},
-  {"SPSR_scxf",        false, PSR_s | PSR_c | PSR_x | PSR_f},
-  {"SPSR_xfsc",        false, PSR_x | PSR_f | PSR_s | PSR_c},
-  {"SPSR_xfcs",        false, PSR_x | PSR_f | PSR_c | PSR_s},
-  {"SPSR_xsfc",        false, PSR_x | PSR_s | PSR_f | PSR_c},
-  {"SPSR_xscf",        false, PSR_x | PSR_s | PSR_c | PSR_f},
-  {"SPSR_xcfs",        false, PSR_x | PSR_c | PSR_f | PSR_s},
-  {"SPSR_xcsf",        false, PSR_x | PSR_c | PSR_s | PSR_f},
-  {"SPSR_cfsx",        false, PSR_c | PSR_f | PSR_s | PSR_x},
-  {"SPSR_cfxs",        false, PSR_c | PSR_f | PSR_x | PSR_s},
-  {"SPSR_csfx",        false, PSR_c | PSR_s | PSR_f | PSR_x},
-  {"SPSR_csxf",        false, PSR_c | PSR_s | PSR_x | PSR_f},
-  {"SPSR_cxfs",        false, PSR_c | PSR_x | PSR_f | PSR_s},
-  {"SPSR_cxsf",        false, PSR_c | PSR_x | PSR_s | PSR_f},
+  {"CPSR_fs",  TRUE, PSR_f | PSR_s},
+  {"CPSR_fx",  TRUE, PSR_f | PSR_x},
+  {"CPSR_fc",  TRUE, PSR_f | PSR_c},
+  {"CPSR_sf",  TRUE, PSR_s | PSR_f},
+  {"CPSR_sx",  TRUE, PSR_s | PSR_x},
+  {"CPSR_sc",  TRUE, PSR_s | PSR_c},
+  {"CPSR_xf",  TRUE, PSR_x | PSR_f},
+  {"CPSR_xs",  TRUE, PSR_x | PSR_s},
+  {"CPSR_xc",  TRUE, PSR_x | PSR_c},
+  {"CPSR_cf",  TRUE, PSR_c | PSR_f},
+  {"CPSR_cs",  TRUE, PSR_c | PSR_s},
+  {"CPSR_cx",  TRUE, PSR_c | PSR_x},
+  {"CPSR_fsx", TRUE, PSR_f | PSR_s | PSR_x},
+  {"CPSR_fsc", TRUE, PSR_f | PSR_s | PSR_c},
+  {"CPSR_fxs", TRUE, PSR_f | PSR_x | PSR_s},
+  {"CPSR_fxc", TRUE, PSR_f | PSR_x | PSR_c},
+  {"CPSR_fcs", TRUE, PSR_f | PSR_c | PSR_s},
+  {"CPSR_fcx", TRUE, PSR_f | PSR_c | PSR_x},
+  {"CPSR_sfx", TRUE, PSR_s | PSR_f | PSR_x},
+  {"CPSR_sfc", TRUE, PSR_s | PSR_f | PSR_c},
+  {"CPSR_sxf", TRUE, PSR_s | PSR_x | PSR_f},
+  {"CPSR_sxc", TRUE, PSR_s | PSR_x | PSR_c},
+  {"CPSR_scf", TRUE, PSR_s | PSR_c | PSR_f},
+  {"CPSR_scx", TRUE, PSR_s | PSR_c | PSR_x},
+  {"CPSR_xfs", TRUE, PSR_x | PSR_f | PSR_s},
+  {"CPSR_xfc", TRUE, PSR_x | PSR_f | PSR_c},
+  {"CPSR_xsf", TRUE, PSR_x | PSR_s | PSR_f},
+  {"CPSR_xsc", TRUE, PSR_x | PSR_s | PSR_c},
+  {"CPSR_xcf", TRUE, PSR_x | PSR_c | PSR_f},
+  {"CPSR_xcs", TRUE, PSR_x | PSR_c | PSR_s},
+  {"CPSR_cfs", TRUE, PSR_c | PSR_f | PSR_s},
+  {"CPSR_cfx", TRUE, PSR_c | PSR_f | PSR_x},
+  {"CPSR_csf", TRUE, PSR_c | PSR_s | PSR_f},
+  {"CPSR_csx", TRUE, PSR_c | PSR_s | PSR_x},
+  {"CPSR_cxf", TRUE, PSR_c | PSR_x | PSR_f},
+  {"CPSR_cxs", TRUE, PSR_c | PSR_x | PSR_s},
+  {"CPSR_fsxc",        TRUE, PSR_f | PSR_s | PSR_x | PSR_c},
+  {"CPSR_fscx",        TRUE, PSR_f | PSR_s | PSR_c | PSR_x},
+  {"CPSR_fxsc",        TRUE, PSR_f | PSR_x | PSR_s | PSR_c},
+  {"CPSR_fxcs",        TRUE, PSR_f | PSR_x | PSR_c | PSR_s},
+  {"CPSR_fcsx",        TRUE, PSR_f | PSR_c | PSR_s | PSR_x},
+  {"CPSR_fcxs",        TRUE, PSR_f | PSR_c | PSR_x | PSR_s},
+  {"CPSR_sfxc",        TRUE, PSR_s | PSR_f | PSR_x | PSR_c},
+  {"CPSR_sfcx",        TRUE, PSR_s | PSR_f | PSR_c | PSR_x},
+  {"CPSR_sxfc",        TRUE, PSR_s | PSR_x | PSR_f | PSR_c},
+  {"CPSR_sxcf",        TRUE, PSR_s | PSR_x | PSR_c | PSR_f},
+  {"CPSR_scfx",        TRUE, PSR_s | PSR_c | PSR_f | PSR_x},
+  {"CPSR_scxf",        TRUE, PSR_s | PSR_c | PSR_x | PSR_f},
+  {"CPSR_xfsc",        TRUE, PSR_x | PSR_f | PSR_s | PSR_c},
+  {"CPSR_xfcs",        TRUE, PSR_x | PSR_f | PSR_c | PSR_s},
+  {"CPSR_xsfc",        TRUE, PSR_x | PSR_s | PSR_f | PSR_c},
+  {"CPSR_xscf",        TRUE, PSR_x | PSR_s | PSR_c | PSR_f},
+  {"CPSR_xcfs",        TRUE, PSR_x | PSR_c | PSR_f | PSR_s},
+  {"CPSR_xcsf",        TRUE, PSR_x | PSR_c | PSR_s | PSR_f},
+  {"CPSR_cfsx",        TRUE, PSR_c | PSR_f | PSR_s | PSR_x},
+  {"CPSR_cfxs",        TRUE, PSR_c | PSR_f | PSR_x | PSR_s},
+  {"CPSR_csfx",        TRUE, PSR_c | PSR_s | PSR_f | PSR_x},
+  {"CPSR_csxf",        TRUE, PSR_c | PSR_s | PSR_x | PSR_f},
+  {"CPSR_cxfs",        TRUE, PSR_c | PSR_x | PSR_f | PSR_s},
+  {"CPSR_cxsf",        TRUE, PSR_c | PSR_x | PSR_s | PSR_f},
+  {"SPSR_fs",  FALSE, PSR_f | PSR_s},
+  {"SPSR_fx",  FALSE, PSR_f | PSR_x},
+  {"SPSR_fc",  FALSE, PSR_f | PSR_c},
+  {"SPSR_sf",  FALSE, PSR_s | PSR_f},
+  {"SPSR_sx",  FALSE, PSR_s | PSR_x},
+  {"SPSR_sc",  FALSE, PSR_s | PSR_c},
+  {"SPSR_xf",  FALSE, PSR_x | PSR_f},
+  {"SPSR_xs",  FALSE, PSR_x | PSR_s},
+  {"SPSR_xc",  FALSE, PSR_x | PSR_c},
+  {"SPSR_cf",  FALSE, PSR_c | PSR_f},
+  {"SPSR_cs",  FALSE, PSR_c | PSR_s},
+  {"SPSR_cx",  FALSE, PSR_c | PSR_x},
+  {"SPSR_fsx", FALSE, PSR_f | PSR_s | PSR_x},
+  {"SPSR_fsc", FALSE, PSR_f | PSR_s | PSR_c},
+  {"SPSR_fxs", FALSE, PSR_f | PSR_x | PSR_s},
+  {"SPSR_fxc", FALSE, PSR_f | PSR_x | PSR_c},
+  {"SPSR_fcs", FALSE, PSR_f | PSR_c | PSR_s},
+  {"SPSR_fcx", FALSE, PSR_f | PSR_c | PSR_x},
+  {"SPSR_sfx", FALSE, PSR_s | PSR_f | PSR_x},
+  {"SPSR_sfc", FALSE, PSR_s | PSR_f | PSR_c},
+  {"SPSR_sxf", FALSE, PSR_s | PSR_x | PSR_f},
+  {"SPSR_sxc", FALSE, PSR_s | PSR_x | PSR_c},
+  {"SPSR_scf", FALSE, PSR_s | PSR_c | PSR_f},
+  {"SPSR_scx", FALSE, PSR_s | PSR_c | PSR_x},
+  {"SPSR_xfs", FALSE, PSR_x | PSR_f | PSR_s},
+  {"SPSR_xfc", FALSE, PSR_x | PSR_f | PSR_c},
+  {"SPSR_xsf", FALSE, PSR_x | PSR_s | PSR_f},
+  {"SPSR_xsc", FALSE, PSR_x | PSR_s | PSR_c},
+  {"SPSR_xcf", FALSE, PSR_x | PSR_c | PSR_f},
+  {"SPSR_xcs", FALSE, PSR_x | PSR_c | PSR_s},
+  {"SPSR_cfs", FALSE, PSR_c | PSR_f | PSR_s},
+  {"SPSR_cfx", FALSE, PSR_c | PSR_f | PSR_x},
+  {"SPSR_csf", FALSE, PSR_c | PSR_s | PSR_f},
+  {"SPSR_csx", FALSE, PSR_c | PSR_s | PSR_x},
+  {"SPSR_cxf", FALSE, PSR_c | PSR_x | PSR_f},
+  {"SPSR_cxs", FALSE, PSR_c | PSR_x | PSR_s},
+  {"SPSR_fsxc",        FALSE, PSR_f | PSR_s | PSR_x | PSR_c},
+  {"SPSR_fscx",        FALSE, PSR_f | PSR_s | PSR_c | PSR_x},
+  {"SPSR_fxsc",        FALSE, PSR_f | PSR_x | PSR_s | PSR_c},
+  {"SPSR_fxcs",        FALSE, PSR_f | PSR_x | PSR_c | PSR_s},
+  {"SPSR_fcsx",        FALSE, PSR_f | PSR_c | PSR_s | PSR_x},
+  {"SPSR_fcxs",        FALSE, PSR_f | PSR_c | PSR_x | PSR_s},
+  {"SPSR_sfxc",        FALSE, PSR_s | PSR_f | PSR_x | PSR_c},
+  {"SPSR_sfcx",        FALSE, PSR_s | PSR_f | PSR_c | PSR_x},
+  {"SPSR_sxfc",        FALSE, PSR_s | PSR_x | PSR_f | PSR_c},
+  {"SPSR_sxcf",        FALSE, PSR_s | PSR_x | PSR_c | PSR_f},
+  {"SPSR_scfx",        FALSE, PSR_s | PSR_c | PSR_f | PSR_x},
+  {"SPSR_scxf",        FALSE, PSR_s | PSR_c | PSR_x | PSR_f},
+  {"SPSR_xfsc",        FALSE, PSR_x | PSR_f | PSR_s | PSR_c},
+  {"SPSR_xfcs",        FALSE, PSR_x | PSR_f | PSR_c | PSR_s},
+  {"SPSR_xsfc",        FALSE, PSR_x | PSR_s | PSR_f | PSR_c},
+  {"SPSR_xscf",        FALSE, PSR_x | PSR_s | PSR_c | PSR_f},
+  {"SPSR_xcfs",        FALSE, PSR_x | PSR_c | PSR_f | PSR_s},
+  {"SPSR_xcsf",        FALSE, PSR_x | PSR_c | PSR_s | PSR_f},
+  {"SPSR_cfsx",        FALSE, PSR_c | PSR_f | PSR_s | PSR_x},
+  {"SPSR_cfxs",        FALSE, PSR_c | PSR_f | PSR_x | PSR_s},
+  {"SPSR_csfx",        FALSE, PSR_c | PSR_s | PSR_f | PSR_x},
+  {"SPSR_csxf",        FALSE, PSR_c | PSR_s | PSR_x | PSR_f},
+  {"SPSR_cxfs",        FALSE, PSR_c | PSR_x | PSR_f | PSR_s},
+  {"SPSR_cxsf",        FALSE, PSR_c | PSR_x | PSR_s | PSR_f},
+};
+
+enum wreg_type
+  {
+    IWMMXT_REG_WR = 0,
+    IWMMXT_REG_WC = 1,
+    IWMMXT_REG_WR_OR_WC = 2,
+    IWMMXT_REG_WCG
+  };
+
+enum iwmmxt_insn_type
+{
+  check_rd,
+  check_wr,
+  check_wrwr,
+  check_wrwrwr,
+  check_wrwrwcg,
+  check_tbcst,
+  check_tmovmsk,
+  check_tmia,
+  check_tmcrr,
+  check_tmrrc,
+  check_tmcr,
+  check_tmrc,
+  check_tinsr,
+  check_textrc,
+  check_waligni,
+  check_textrm,
+  check_wshufh
 };
 
 enum vfp_dp_reg_pos
@@ -536,6 +535,7 @@ struct reg_entry
 {
   const char * name;
   int          number;
+  bfd_boolean  builtin;
 };
 
 /* Some well known registers that we refer to directly elsewhere.  */
@@ -543,137 +543,176 @@ struct reg_entry
 #define REG_LR  14
 #define REG_PC 15
 
-/* These are the standard names.  Users can add aliases with .req.  */
+#define wr_register(reg)  ((reg ^ WR_PREFIX) >= 0 && (reg ^ WR_PREFIX) <= 15)
+#define wc_register(reg)  ((reg ^ WC_PREFIX) >= 0 && (reg ^ WC_PREFIX) <= 15)
+#define wcg_register(reg) ((reg ^ WC_PREFIX) >= 8 && (reg ^ WC_PREFIX) <= 11)
+
+/* These are the standard names.  Users can add aliases with .req.
+   and delete them with .unreq.  */
+
 /* Integer Register Numbers.  */
 static const struct reg_entry rn_table[] =
 {
-  {"r0",  0},  {"r1",  1},      {"r2",  2},      {"r3",  3},
-  {"r4",  4},  {"r5",  5},      {"r6",  6},      {"r7",  7},
-  {"r8",  8},  {"r9",  9},      {"r10", 10},     {"r11", 11},
-  {"r12", 12}, {"r13", REG_SP}, {"r14", REG_LR}, {"r15", REG_PC},
+  {"r0",  0, TRUE},  {"r1",  1, TRUE},      {"r2",  2, TRUE},      {"r3",  3, TRUE},
+  {"r4",  4, TRUE},  {"r5",  5, TRUE},      {"r6",  6, TRUE},      {"r7",  7, TRUE},
+  {"r8",  8, TRUE},  {"r9",  9, TRUE},      {"r10", 10, TRUE},     {"r11", 11, TRUE},
+  {"r12", 12, TRUE}, {"r13", REG_SP, TRUE}, {"r14", REG_LR, TRUE}, {"r15", REG_PC, TRUE},
   /* ATPCS Synonyms.  */
-  {"a1",  0},  {"a2",  1},      {"a3",  2},      {"a4",  3},
-  {"v1",  4},  {"v2",  5},      {"v3",  6},      {"v4",  7},
-  {"v5",  8},  {"v6",  9},      {"v7",  10},     {"v8",  11},
+  {"a1",  0, TRUE},  {"a2",  1, TRUE},      {"a3",  2, TRUE},      {"a4",  3, TRUE},
+  {"v1",  4, TRUE},  {"v2",  5, TRUE},      {"v3",  6, TRUE},      {"v4",  7, TRUE},
+  {"v5",  8, TRUE},  {"v6",  9, TRUE},      {"v7",  10, TRUE},     {"v8",  11, TRUE},
   /* Well-known aliases.  */
-                                                {"wr",  7},
-              {"sb",  9},      {"sl",  10},     {"fp",  11},
-  {"ip",  12}, {"sp",  REG_SP}, {"lr",  REG_LR}, {"pc",  REG_PC},
-  {NULL, 0}
+  {"wr",  7, TRUE},  {"sb",  9, TRUE},      {"sl",  10, TRUE},     {"fp",  11, TRUE},
+  {"ip",  12, TRUE}, {"sp",  REG_SP, TRUE}, {"lr",  REG_LR, TRUE}, {"pc",  REG_PC, TRUE},
+  {NULL, 0, TRUE}
+};
+
+#define WR_PREFIX 0x200
+#define WC_PREFIX 0x400
+
+static const struct reg_entry iwmmxt_table[] =
+{
+  /* Intel Wireless MMX technology register names.  */
+  {  "wr0", 0x0 | WR_PREFIX, TRUE},   {"wr1", 0x1 | WR_PREFIX, TRUE},
+  {  "wr2", 0x2 | WR_PREFIX, TRUE},   {"wr3", 0x3 | WR_PREFIX, TRUE},
+  {  "wr4", 0x4 | WR_PREFIX, TRUE},   {"wr5", 0x5 | WR_PREFIX, TRUE},
+  {  "wr6", 0x6 | WR_PREFIX, TRUE},   {"wr7", 0x7 | WR_PREFIX, TRUE},
+  {  "wr8", 0x8 | WR_PREFIX, TRUE},   {"wr9", 0x9 | WR_PREFIX, TRUE},
+  { "wr10", 0xa | WR_PREFIX, TRUE},  {"wr11", 0xb | WR_PREFIX, TRUE},
+  { "wr12", 0xc | WR_PREFIX, TRUE},  {"wr13", 0xd | WR_PREFIX, TRUE},
+  { "wr14", 0xe | WR_PREFIX, TRUE},  {"wr15", 0xf | WR_PREFIX, TRUE},
+  { "wcid", 0x0 | WC_PREFIX, TRUE},  {"wcon", 0x1 | WC_PREFIX, TRUE},
+  {"wcssf", 0x2 | WC_PREFIX, TRUE}, {"wcasf", 0x3 | WC_PREFIX, TRUE},
+  {"wcgr0", 0x8 | WC_PREFIX, TRUE}, {"wcgr1", 0x9 | WC_PREFIX, TRUE},
+  {"wcgr2", 0xa | WC_PREFIX, TRUE}, {"wcgr3", 0xb | WC_PREFIX, TRUE},
+
+  {  "wR0", 0x0 | WR_PREFIX, TRUE},   {"wR1", 0x1 | WR_PREFIX, TRUE},
+  {  "wR2", 0x2 | WR_PREFIX, TRUE},   {"wR3", 0x3 | WR_PREFIX, TRUE},
+  {  "wR4", 0x4 | WR_PREFIX, TRUE},   {"wR5", 0x5 | WR_PREFIX, TRUE},
+  {  "wR6", 0x6 | WR_PREFIX, TRUE},   {"wR7", 0x7 | WR_PREFIX, TRUE},
+  {  "wR8", 0x8 | WR_PREFIX, TRUE},   {"wR9", 0x9 | WR_PREFIX, TRUE},
+  { "wR10", 0xa | WR_PREFIX, TRUE},  {"wR11", 0xb | WR_PREFIX, TRUE},
+  { "wR12", 0xc | WR_PREFIX, TRUE},  {"wR13", 0xd | WR_PREFIX, TRUE},
+  { "wR14", 0xe | WR_PREFIX, TRUE},  {"wR15", 0xf | WR_PREFIX, TRUE},
+  { "wCID", 0x0 | WC_PREFIX, TRUE},  {"wCon", 0x1 | WC_PREFIX, TRUE},
+  {"wCSSF", 0x2 | WC_PREFIX, TRUE}, {"wCASF", 0x3 | WC_PREFIX, TRUE},
+  {"wCGR0", 0x8 | WC_PREFIX, TRUE}, {"wCGR1", 0x9 | WC_PREFIX, TRUE},
+  {"wCGR2", 0xa | WC_PREFIX, TRUE}, {"wCGR3", 0xb | WC_PREFIX, TRUE},
+  {NULL, 0, TRUE}
 };
 
 /* Co-processor Numbers.  */
 static const struct reg_entry cp_table[] =
 {
-  {"p0",  0},  {"p1",  1},  {"p2",  2},  {"p3", 3},
-  {"p4",  4},  {"p5",  5},  {"p6",  6},  {"p7", 7},
-  {"p8",  8},  {"p9",  9},  {"p10", 10}, {"p11", 11},
-  {"p12", 12}, {"p13", 13}, {"p14", 14}, {"p15", 15},
-  {NULL, 0}
+  {"p0",  0, TRUE},  {"p1",  1, TRUE},  {"p2",  2, TRUE},  {"p3", 3, TRUE},
+  {"p4",  4, TRUE},  {"p5",  5, TRUE},  {"p6",  6, TRUE},  {"p7", 7, TRUE},
+  {"p8",  8, TRUE},  {"p9",  9, TRUE},  {"p10", 10, TRUE}, {"p11", 11, TRUE},
+  {"p12", 12, TRUE}, {"p13", 13, TRUE}, {"p14", 14, TRUE}, {"p15", 15, TRUE},
+  {NULL, 0, TRUE}
 };
 
 /* Co-processor Register Numbers.  */
 static const struct reg_entry cn_table[] =
 {
-  {"c0",   0},  {"c1",   1},  {"c2",   2},  {"c3",   3},
-  {"c4",   4},  {"c5",   5},  {"c6",   6},  {"c7",   7},
-  {"c8",   8},  {"c9",   9},  {"c10",  10}, {"c11",  11},
-  {"c12",  12}, {"c13",  13}, {"c14",  14}, {"c15",  15},
+  {"c0",   0, TRUE},  {"c1",   1, TRUE},  {"c2",   2, TRUE},  {"c3",   3, TRUE},
+  {"c4",   4, TRUE},  {"c5",   5, TRUE},  {"c6",   6, TRUE},  {"c7",   7, TRUE},
+  {"c8",   8, TRUE},  {"c9",   9, TRUE},  {"c10",  10, TRUE}, {"c11",  11, TRUE},
+  {"c12",  12, TRUE}, {"c13",  13, TRUE}, {"c14",  14, TRUE}, {"c15",  15, TRUE},
   /* Not really valid, but kept for back-wards compatibility.  */
-  {"cr0",  0},  {"cr1",  1},  {"cr2",  2},  {"cr3",  3},
-  {"cr4",  4},  {"cr5",  5},  {"cr6",  6},  {"cr7",  7},
-  {"cr8",  8},  {"cr9",  9},  {"cr10", 10}, {"cr11", 11},
-  {"cr12", 12}, {"cr13", 13}, {"cr14", 14}, {"cr15", 15},
-  {NULL, 0}
+  {"cr0",  0, TRUE},  {"cr1",  1, TRUE},  {"cr2",  2, TRUE},  {"cr3",  3, TRUE},
+  {"cr4",  4, TRUE},  {"cr5",  5, TRUE},  {"cr6",  6, TRUE},  {"cr7",  7, TRUE},
+  {"cr8",  8, TRUE},  {"cr9",  9, TRUE},  {"cr10", 10, TRUE}, {"cr11", 11, TRUE},
+  {"cr12", 12, TRUE}, {"cr13", 13, TRUE}, {"cr14", 14, TRUE}, {"cr15", 15, TRUE},
+  {NULL, 0, TRUE}
 };
 
 /* FPA Registers.  */
 static const struct reg_entry fn_table[] =
 {
-  {"f0", 0},   {"f1", 1},   {"f2", 2},   {"f3", 3},
-  {"f4", 4},   {"f5", 5},   {"f6", 6},   {"f7", 7},
-  {NULL, 0}
+  {"f0", 0, TRUE},   {"f1", 1, TRUE},   {"f2", 2, TRUE},   {"f3", 3, TRUE},
+  {"f4", 4, TRUE},   {"f5", 5, TRUE},   {"f6", 6, TRUE},   {"f7", 7, TRUE},
+  {NULL, 0, TRUE}
 };
 
 /* VFP SP Registers.  */
 static const struct reg_entry sn_table[] =
 {
-  {"s0",  0},  {"s1",  1},  {"s2",  2},         {"s3", 3},
-  {"s4",  4},  {"s5",  5},  {"s6",  6},         {"s7", 7},
-  {"s8",  8},  {"s9",  9},  {"s10", 10}, {"s11", 11},
-  {"s12", 12}, {"s13", 13}, {"s14", 14}, {"s15", 15},
-  {"s16", 16}, {"s17", 17}, {"s18", 18}, {"s19", 19},
-  {"s20", 20}, {"s21", 21}, {"s22", 22}, {"s23", 23},
-  {"s24", 24}, {"s25", 25}, {"s26", 26}, {"s27", 27},
-  {"s28", 28}, {"s29", 29}, {"s30", 30}, {"s31", 31},
-  {NULL, 0}
+  {"s0",  0, TRUE},  {"s1",  1, TRUE},  {"s2",  2, TRUE},  {"s3", 3, TRUE},
+  {"s4",  4, TRUE},  {"s5",  5, TRUE},  {"s6",  6, TRUE},  {"s7", 7, TRUE},
+  {"s8",  8, TRUE},  {"s9",  9, TRUE},  {"s10", 10, TRUE}, {"s11", 11, TRUE},
+  {"s12", 12, TRUE}, {"s13", 13, TRUE}, {"s14", 14, TRUE}, {"s15", 15, TRUE},
+  {"s16", 16, TRUE}, {"s17", 17, TRUE}, {"s18", 18, TRUE}, {"s19", 19, TRUE},
+  {"s20", 20, TRUE}, {"s21", 21, TRUE}, {"s22", 22, TRUE}, {"s23", 23, TRUE},
+  {"s24", 24, TRUE}, {"s25", 25, TRUE}, {"s26", 26, TRUE}, {"s27", 27, TRUE},
+  {"s28", 28, TRUE}, {"s29", 29, TRUE}, {"s30", 30, TRUE}, {"s31", 31, TRUE},
+  {NULL, 0, TRUE}
 };
 
 /* VFP DP Registers.  */
 static const struct reg_entry dn_table[] =
 {
-  {"d0",  0},  {"d1",  1},  {"d2",  2},         {"d3", 3},
-  {"d4",  4},  {"d5",  5},  {"d6",  6},         {"d7", 7},
-  {"d8",  8},  {"d9",  9},  {"d10", 10}, {"d11", 11},
-  {"d12", 12}, {"d13", 13}, {"d14", 14}, {"d15", 15},
-  {NULL, 0}
+  {"d0",  0, TRUE},  {"d1",  1, TRUE},  {"d2",  2, TRUE},  {"d3", 3, TRUE},
+  {"d4",  4, TRUE},  {"d5",  5, TRUE},  {"d6",  6, TRUE},  {"d7", 7, TRUE},
+  {"d8",  8, TRUE},  {"d9",  9, TRUE},  {"d10", 10, TRUE}, {"d11", 11, TRUE},
+  {"d12", 12, TRUE}, {"d13", 13, TRUE}, {"d14", 14, TRUE}, {"d15", 15, TRUE},
+  {NULL, 0, TRUE}
 };
 
 /* Maverick DSP coprocessor registers.  */
 static const struct reg_entry mav_mvf_table[] =
 {
-  {"mvf0",  0},  {"mvf1",  1},  {"mvf2",  2},  {"mvf3",  3},
-  {"mvf4",  4},  {"mvf5",  5},  {"mvf6",  6},  {"mvf7",  7},
-  {"mvf8",  8},  {"mvf9",  9},  {"mvf10", 10}, {"mvf11", 11},
-  {"mvf12", 12}, {"mvf13", 13}, {"mvf14", 14}, {"mvf15", 15},
-  {NULL, 0}
+  {"mvf0",  0, TRUE},  {"mvf1",  1, TRUE},  {"mvf2",  2, TRUE},  {"mvf3",  3, TRUE},
+  {"mvf4",  4, TRUE},  {"mvf5",  5, TRUE},  {"mvf6",  6, TRUE},  {"mvf7",  7, TRUE},
+  {"mvf8",  8, TRUE},  {"mvf9",  9, TRUE},  {"mvf10", 10, TRUE}, {"mvf11", 11, TRUE},
+  {"mvf12", 12, TRUE}, {"mvf13", 13, TRUE}, {"mvf14", 14, TRUE}, {"mvf15", 15, TRUE},
+  {NULL, 0, TRUE}
 };
 
 static const struct reg_entry mav_mvd_table[] =
 {
-  {"mvd0",  0},  {"mvd1",  1},  {"mvd2",  2},  {"mvd3",  3},
-  {"mvd4",  4},  {"mvd5",  5},  {"mvd6",  6},  {"mvd7",  7},
-  {"mvd8",  8},  {"mvd9",  9},  {"mvd10", 10}, {"mvd11", 11},
-  {"mvd12", 12}, {"mvd13", 13}, {"mvd14", 14}, {"mvd15", 15},
-  {NULL, 0}
+  {"mvd0",  0, TRUE},  {"mvd1",  1, TRUE},  {"mvd2",  2, TRUE},  {"mvd3",  3, TRUE},
+  {"mvd4",  4, TRUE},  {"mvd5",  5, TRUE},  {"mvd6",  6, TRUE},  {"mvd7",  7, TRUE},
+  {"mvd8",  8, TRUE},  {"mvd9",  9, TRUE},  {"mvd10", 10, TRUE}, {"mvd11", 11, TRUE},
+  {"mvd12", 12, TRUE}, {"mvd13", 13, TRUE}, {"mvd14", 14, TRUE}, {"mvd15", 15, TRUE},
+  {NULL, 0, TRUE}
 };
 
 static const struct reg_entry mav_mvfx_table[] =
 {
-  {"mvfx0",  0},  {"mvfx1",  1},  {"mvfx2",  2},  {"mvfx3",  3},
-  {"mvfx4",  4},  {"mvfx5",  5},  {"mvfx6",  6},  {"mvfx7",  7},
-  {"mvfx8",  8},  {"mvfx9",  9},  {"mvfx10", 10}, {"mvfx11", 11},
-  {"mvfx12", 12}, {"mvfx13", 13}, {"mvfx14", 14}, {"mvfx15", 15},
-  {NULL, 0}
+  {"mvfx0",  0, TRUE},  {"mvfx1",  1, TRUE},  {"mvfx2",  2, TRUE},  {"mvfx3",  3, TRUE},
+  {"mvfx4",  4, TRUE},  {"mvfx5",  5, TRUE},  {"mvfx6",  6, TRUE},  {"mvfx7",  7, TRUE},
+  {"mvfx8",  8, TRUE},  {"mvfx9",  9, TRUE},  {"mvfx10", 10, TRUE}, {"mvfx11", 11, TRUE},
+  {"mvfx12", 12, TRUE}, {"mvfx13", 13, TRUE}, {"mvfx14", 14, TRUE}, {"mvfx15", 15, TRUE},
+  {NULL, 0, TRUE}
 };
 
 static const struct reg_entry mav_mvdx_table[] =
 {
-  {"mvdx0",  0},  {"mvdx1",  1},  {"mvdx2",  2},  {"mvdx3",  3},
-  {"mvdx4",  4},  {"mvdx5",  5},  {"mvdx6",  6},  {"mvdx7",  7},
-  {"mvdx8",  8},  {"mvdx9",  9},  {"mvdx10", 10}, {"mvdx11", 11},
-  {"mvdx12", 12}, {"mvdx13", 13}, {"mvdx14", 14}, {"mvdx15", 15},
-  {NULL, 0}
+  {"mvdx0",  0, TRUE},  {"mvdx1",  1, TRUE},  {"mvdx2",  2, TRUE},  {"mvdx3",  3, TRUE},
+  {"mvdx4",  4, TRUE},  {"mvdx5",  5, TRUE},  {"mvdx6",  6, TRUE},  {"mvdx7",  7, TRUE},
+  {"mvdx8",  8, TRUE},  {"mvdx9",  9, TRUE},  {"mvdx10", 10, TRUE}, {"mvdx11", 11, TRUE},
+  {"mvdx12", 12, TRUE}, {"mvdx13", 13, TRUE}, {"mvdx14", 14, TRUE}, {"mvdx15", 15, TRUE},
+  {NULL, 0, TRUE}
 };
 
 static const struct reg_entry mav_mvax_table[] =
 {
-  {"mvax0", 0}, {"mvax1", 1}, {"mvax2", 2}, {"mvax3", 3},
-  {NULL, 0}
+  {"mvax0", 0, TRUE}, {"mvax1", 1, TRUE}, {"mvax2", 2, TRUE}, {"mvax3", 3, TRUE},
+  {NULL, 0, TRUE}
 };
 
 static const struct reg_entry mav_dspsc_table[] =
 {
-  {"dspsc", 0},
-  {NULL, 0}
+  {"dspsc", 0, TRUE},
+  {NULL, 0, TRUE}
 };
 
 struct reg_map
 {
-  const struct reg_entry *names;
-  int max_regno;
-  struct hash_control *htab;
-  const char *expected;
+  const struct reg_entry * names;
+  int                      max_regno;
+  struct hash_control *    htab;
+  const char *             expected;
 };
 
 struct reg_map all_reg_maps[] =
@@ -687,9 +726,10 @@ struct reg_map all_reg_maps[] =
   {mav_mvf_table,   15, NULL, N_("Maverick MVF register expected")},
   {mav_mvd_table,   15, NULL, N_("Maverick MVD register expected")},
   {mav_mvfx_table,  15, NULL, N_("Maverick MVFX register expected")},
-  {mav_mvdx_table,  15, NULL, N_("Maverick MVFX register expected")},
+  {mav_mvdx_table,  15, NULL, N_("Maverick MVDX register expected")},
   {mav_mvax_table,   3, NULL, N_("Maverick MVAX register expected")},
   {mav_dspsc_table,  0, NULL, N_("Maverick DSPSC register expected")},
+  {iwmmxt_table,    23, NULL, N_("Intel Wireless MMX technology register expected")},
 };
 
 /* Enumeration matching entries in table above.  */
@@ -708,236 +748,11 @@ enum arm_reg_type
   REG_TYPE_MVDX = 9,
   REG_TYPE_MVAX = 10,
   REG_TYPE_DSPSC = 11,
+  REG_TYPE_IWMMXT = 12,
 
-  REG_TYPE_MAX = 12
+  REG_TYPE_MAX = 13
 };
 
-/* Functions called by parser.  */
-/* ARM instructions.  */
-static void do_arit            PARAMS ((char *));
-static void do_cmp             PARAMS ((char *));
-static void do_mov             PARAMS ((char *));
-static void do_ldst            PARAMS ((char *));
-static void do_ldstt           PARAMS ((char *));
-static void do_ldmstm          PARAMS ((char *));
-static void do_branch          PARAMS ((char *));
-static void do_swi             PARAMS ((char *));
-
-/* Pseudo Op codes.  */
-static void do_adr             PARAMS ((char *));
-static void do_adrl            PARAMS ((char *));
-static void do_empty           PARAMS ((char *));
-
-/* ARM v2.  */
-static void do_mul             PARAMS ((char *));
-static void do_mla             PARAMS ((char *));
-
-/* ARM v2S.  */
-static void do_swap            PARAMS ((char *));
-
-/* ARM v3.  */
-static void do_msr             PARAMS ((char *));
-static void do_mrs             PARAMS ((char *));
-
-/* ARM v3M.  */
-static void do_mull            PARAMS ((char *));
-
-/* ARM v4.  */
-static void do_ldstv4          PARAMS ((char *));
-
-/* ARM v4T.  */
-static void do_bx               PARAMS ((char *));
-
-/* ARM v5T.  */
-static void do_blx             PARAMS ((char *));
-static void do_bkpt            PARAMS ((char *));
-static void do_clz             PARAMS ((char *));
-static void do_lstc2           PARAMS ((char *));
-static void do_cdp2            PARAMS ((char *));
-static void do_co_reg2         PARAMS ((char *));
-
-/* ARM v5TExP.  */
-static void do_smla            PARAMS ((char *));
-static void do_smlal           PARAMS ((char *));
-static void do_smul            PARAMS ((char *));
-static void do_qadd            PARAMS ((char *));
-
-/* ARM v5TE.  */
-static void do_pld             PARAMS ((char *));
-static void do_ldrd            PARAMS ((char *));
-static void do_co_reg2c                PARAMS ((char *));
-
-/* ARM v5TEJ.  */
-static void do_bxj             PARAMS ((char *));
-
-/* Coprocessor Instructions.  */
-static void do_cdp             PARAMS ((char *));
-static void do_lstc            PARAMS ((char *));
-static void do_co_reg          PARAMS ((char *));
-
-/* FPA instructions.  */
-static void do_fpa_ctrl                PARAMS ((char *));
-static void do_fpa_ldst                PARAMS ((char *));
-static void do_fpa_ldmstm      PARAMS ((char *));
-static void do_fpa_dyadic      PARAMS ((char *));
-static void do_fpa_monadic     PARAMS ((char *));
-static void do_fpa_cmp         PARAMS ((char *));
-static void do_fpa_from_reg    PARAMS ((char *));
-static void do_fpa_to_reg      PARAMS ((char *));
-
-/* VFP instructions.  */
-static void do_vfp_sp_monadic  PARAMS ((char *));
-static void do_vfp_dp_monadic  PARAMS ((char *));
-static void do_vfp_sp_dyadic   PARAMS ((char *));
-static void do_vfp_dp_dyadic   PARAMS ((char *));
-static void do_vfp_reg_from_sp  PARAMS ((char *));
-static void do_vfp_sp_from_reg  PARAMS ((char *));
-static void do_vfp_sp_reg2     PARAMS ((char *));
-static void do_vfp_reg_from_dp  PARAMS ((char *));
-static void do_vfp_reg2_from_dp PARAMS ((char *));
-static void do_vfp_dp_from_reg  PARAMS ((char *));
-static void do_vfp_dp_from_reg2 PARAMS ((char *));
-static void do_vfp_reg_from_ctrl PARAMS ((char *));
-static void do_vfp_ctrl_from_reg PARAMS ((char *));
-static void do_vfp_sp_ldst     PARAMS ((char *));
-static void do_vfp_dp_ldst     PARAMS ((char *));
-static void do_vfp_sp_ldstmia  PARAMS ((char *));
-static void do_vfp_sp_ldstmdb  PARAMS ((char *));
-static void do_vfp_dp_ldstmia  PARAMS ((char *));
-static void do_vfp_dp_ldstmdb  PARAMS ((char *));
-static void do_vfp_xp_ldstmia  PARAMS ((char *));
-static void do_vfp_xp_ldstmdb  PARAMS ((char *));
-static void do_vfp_sp_compare_z        PARAMS ((char *));
-static void do_vfp_dp_compare_z        PARAMS ((char *));
-static void do_vfp_dp_sp_cvt   PARAMS ((char *));
-static void do_vfp_sp_dp_cvt   PARAMS ((char *));
-
-/* XScale.  */
-static void do_xsc_mia         PARAMS ((char *));
-static void do_xsc_mar         PARAMS ((char *));
-static void do_xsc_mra         PARAMS ((char *));
-
-/* Maverick.  */
-static void do_mav_binops      PARAMS ((char *, int, enum arm_reg_type,
-                                        enum arm_reg_type));
-static void do_mav_binops_1a   PARAMS ((char *));
-static void do_mav_binops_1b   PARAMS ((char *));
-static void do_mav_binops_1c   PARAMS ((char *));
-static void do_mav_binops_1d   PARAMS ((char *));
-static void do_mav_binops_1e   PARAMS ((char *));
-static void do_mav_binops_1f   PARAMS ((char *));
-static void do_mav_binops_1g   PARAMS ((char *));
-static void do_mav_binops_1h   PARAMS ((char *));
-static void do_mav_binops_1i   PARAMS ((char *));
-static void do_mav_binops_1j   PARAMS ((char *));
-static void do_mav_binops_1k   PARAMS ((char *));
-static void do_mav_binops_1l   PARAMS ((char *));
-static void do_mav_binops_1m   PARAMS ((char *));
-static void do_mav_binops_1n   PARAMS ((char *));
-static void do_mav_binops_1o   PARAMS ((char *));
-static void do_mav_binops_2a   PARAMS ((char *));
-static void do_mav_binops_2b   PARAMS ((char *));
-static void do_mav_binops_2c   PARAMS ((char *));
-static void do_mav_binops_3a   PARAMS ((char *));
-static void do_mav_binops_3b   PARAMS ((char *));
-static void do_mav_binops_3c   PARAMS ((char *));
-static void do_mav_binops_3d   PARAMS ((char *));
-static void do_mav_triple      PARAMS ((char *, int, enum arm_reg_type,
-                                        enum arm_reg_type,
-                                        enum arm_reg_type));
-static void do_mav_triple_4a   PARAMS ((char *));
-static void do_mav_triple_4b   PARAMS ((char *));
-static void do_mav_triple_5a   PARAMS ((char *));
-static void do_mav_triple_5b   PARAMS ((char *));
-static void do_mav_triple_5c   PARAMS ((char *));
-static void do_mav_triple_5d   PARAMS ((char *));
-static void do_mav_triple_5e   PARAMS ((char *));
-static void do_mav_triple_5f   PARAMS ((char *));
-static void do_mav_triple_5g   PARAMS ((char *));
-static void do_mav_triple_5h   PARAMS ((char *));
-static void do_mav_quad                PARAMS ((char *, int, enum arm_reg_type,
-                                        enum arm_reg_type,
-                                        enum arm_reg_type,
-                                        enum arm_reg_type));
-static void do_mav_quad_6a     PARAMS ((char *));
-static void do_mav_quad_6b     PARAMS ((char *));
-static void do_mav_dspsc_1     PARAMS ((char *));
-static void do_mav_dspsc_2     PARAMS ((char *));
-static void do_mav_shift       PARAMS ((char *, enum arm_reg_type,
-                                        enum arm_reg_type));
-static void do_mav_shift_1     PARAMS ((char *));
-static void do_mav_shift_2     PARAMS ((char *));
-static void do_mav_ldst                PARAMS ((char *, enum arm_reg_type));
-static void do_mav_ldst_1      PARAMS ((char *));
-static void do_mav_ldst_2      PARAMS ((char *));
-static void do_mav_ldst_3      PARAMS ((char *));
-static void do_mav_ldst_4      PARAMS ((char *));
-
-static int mav_reg_required_here       PARAMS ((char **, int,
-                                                enum arm_reg_type));
-static int mav_parse_offset    PARAMS ((char **, int *));
-
-static void fix_new_arm                PARAMS ((fragS *, int, short, expressionS *,
-                                        int, int));
-static int arm_reg_parse       PARAMS ((char **, struct hash_control *));
-static enum arm_reg_type arm_reg_parse_any PARAMS ((char *));
-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 *));
-static int validate_offset_imm PARAMS ((unsigned int, int));
-static void opcode_select      PARAMS ((int));
-static void end_of_line                PARAMS ((char *));
-static int reg_required_here   PARAMS ((char **, int));
-static int psr_required_here   PARAMS ((char **));
-static int co_proc_number      PARAMS ((char **));
-static int cp_opc_expr         PARAMS ((char **, int, int));
-static int cp_reg_required_here        PARAMS ((char **, int));
-static int fp_reg_required_here        PARAMS ((char **, int));
-static int vfp_sp_reg_required_here PARAMS ((char **, enum vfp_sp_reg_pos));
-static int vfp_dp_reg_required_here PARAMS ((char **, enum vfp_dp_reg_pos));
-static void vfp_sp_ldstm       PARAMS ((char *, enum vfp_ldstm_type));
-static void vfp_dp_ldstm       PARAMS ((char *, enum vfp_ldstm_type));
-static long vfp_sp_reg_list    PARAMS ((char **, enum vfp_sp_reg_pos));
-static long vfp_dp_reg_list    PARAMS ((char **));
-static int vfp_psr_required_here PARAMS ((char **str));
-static const struct vfp_reg *vfp_psr_parse PARAMS ((char **str));
-static int cp_address_offset   PARAMS ((char **));
-static int cp_address_required_here    PARAMS ((char **, int));
-static int my_get_float_expression     PARAMS ((char **));
-static int skip_past_comma     PARAMS ((char **));
-static int walk_no_bignums     PARAMS ((symbolS *));
-static int negate_data_op      PARAMS ((unsigned long *, unsigned long));
-static int data_op2            PARAMS ((char **));
-static int fp_op2              PARAMS ((char **));
-static long reg_list           PARAMS ((char **));
-static void thumb_load_store   PARAMS ((char *, int, int));
-static int decode_shift                PARAMS ((char **, int));
-static int ldst_extend         PARAMS ((char **));
-static int ldst_extend_v4              PARAMS ((char **));
-static void thumb_add_sub      PARAMS ((char *, int));
-static void insert_reg         PARAMS ((const struct reg_entry *,
-                                        struct hash_control *));
-static void thumb_shift                PARAMS ((char *, int));
-static void thumb_mov_compare  PARAMS ((char *, int));
-static void build_arm_ops_hsh  PARAMS ((void));
-static void set_constant_flonums       PARAMS ((void));
-static valueT md_chars_to_number       PARAMS ((char *, int));
-static void build_reg_hsh      PARAMS ((struct reg_map *));
-static void insert_reg_alias   PARAMS ((char *, int, struct hash_control *));
-static int create_register_alias       PARAMS ((char *, char *));
-static void output_inst                PARAMS ((const char *));
-static int accum0_required_here PARAMS ((char **));
-static int ld_mode_required_here PARAMS ((char **));
-static void do_branch25         PARAMS ((char *));
-static symbolS * find_real_start PARAMS ((symbolS *));
-#ifdef OBJ_ELF
-static bfd_reloc_code_real_type        arm_parse_reloc PARAMS ((void));
-#endif
-
 /* ARM instructions take 4bytes in the object file, Thumb instructions
    take 2:  */
 #define INSN_SIZE       4
@@ -948,8 +763,8 @@ static bfd_reloc_code_real_type     arm_parse_reloc PARAMS ((void));
 /* "INSN<cond> X,Y" where X:bit16, Y:bit12.  */
 #define MAV_MODE2      0x0c10
 
-/* "INSN<cond> X,Y" where X:0, Y:bit16.  */
-#define MAV_MODE3      0x1000
+/* "INSN<cond> X,Y" where X:bit12, Y:bit16.  */
+#define MAV_MODE3      0x100c
 
 /* "INSN<cond> X,Y,Z" where X:16, Y:0, Z:12.  */
 #define MAV_MODE4      0x0c0010
@@ -976,3163 +791,4511 @@ struct asm_opcode
   unsigned long variant;
 
   /* Function to call to parse args.  */
-  void (* parms) PARAMS ((char *));
+  void (* parms) (char *);
 };
 
-static const struct asm_opcode insns[] =
-{
-  /* Core ARM Instructions.  */
-  {"and",        0xe0000000, 3,  ARM_EXT_V1,       do_arit},
-  {"ands",       0xe0100000, 3,  ARM_EXT_V1,       do_arit},
-  {"eor",        0xe0200000, 3,  ARM_EXT_V1,       do_arit},
-  {"eors",       0xe0300000, 3,  ARM_EXT_V1,       do_arit},
-  {"sub",        0xe0400000, 3,  ARM_EXT_V1,       do_arit},
-  {"subs",       0xe0500000, 3,  ARM_EXT_V1,       do_arit},
-  {"rsb",        0xe0600000, 3,  ARM_EXT_V1,       do_arit},
-  {"rsbs",       0xe0700000, 3,  ARM_EXT_V1,       do_arit},
-  {"add",        0xe0800000, 3,  ARM_EXT_V1,       do_arit},
-  {"adds",       0xe0900000, 3,  ARM_EXT_V1,       do_arit},
-  {"adc",        0xe0a00000, 3,  ARM_EXT_V1,       do_arit},
-  {"adcs",       0xe0b00000, 3,  ARM_EXT_V1,       do_arit},
-  {"sbc",        0xe0c00000, 3,  ARM_EXT_V1,       do_arit},
-  {"sbcs",       0xe0d00000, 3,  ARM_EXT_V1,       do_arit},
-  {"rsc",        0xe0e00000, 3,  ARM_EXT_V1,       do_arit},
-  {"rscs",       0xe0f00000, 3,  ARM_EXT_V1,       do_arit},
-  {"orr",        0xe1800000, 3,  ARM_EXT_V1,       do_arit},
-  {"orrs",       0xe1900000, 3,  ARM_EXT_V1,       do_arit},
-  {"bic",        0xe1c00000, 3,  ARM_EXT_V1,       do_arit},
-  {"bics",       0xe1d00000, 3,  ARM_EXT_V1,       do_arit},
+/* Defines for various bits that we will want to toggle.  */
+#define INST_IMMEDIATE 0x02000000
+#define OFFSET_REG     0x02000000
+#define HWOFFSET_IMM    0x00400000
+#define SHIFT_BY_REG   0x00000010
+#define PRE_INDEX      0x01000000
+#define INDEX_UP       0x00800000
+#define WRITE_BACK     0x00200000
+#define LDM_TYPE_2_OR_3        0x00400000
 
-  {"tst",        0xe1100000, 3,  ARM_EXT_V1,       do_cmp},
-  {"tsts",       0xe1100000, 3,  ARM_EXT_V1,       do_cmp},
-  {"tstp",       0xe110f000, 3,  ARM_EXT_V1,       do_cmp},
-  {"teq",        0xe1300000, 3,  ARM_EXT_V1,       do_cmp},
-  {"teqs",       0xe1300000, 3,  ARM_EXT_V1,       do_cmp},
-  {"teqp",       0xe130f000, 3,  ARM_EXT_V1,       do_cmp},
-  {"cmp",        0xe1500000, 3,  ARM_EXT_V1,       do_cmp},
-  {"cmps",       0xe1500000, 3,  ARM_EXT_V1,       do_cmp},
-  {"cmpp",       0xe150f000, 3,  ARM_EXT_V1,       do_cmp},
-  {"cmn",        0xe1700000, 3,  ARM_EXT_V1,       do_cmp},
-  {"cmns",       0xe1700000, 3,  ARM_EXT_V1,       do_cmp},
-  {"cmnp",       0xe170f000, 3,  ARM_EXT_V1,       do_cmp},
+#define LITERAL_MASK   0xf000f000
+#define OPCODE_MASK    0xfe1fffff
+#define V4_STR_BIT     0x00000020
 
-  {"mov",        0xe1a00000, 3,  ARM_EXT_V1,       do_mov},
-  {"movs",       0xe1b00000, 3,  ARM_EXT_V1,       do_mov},
-  {"mvn",        0xe1e00000, 3,  ARM_EXT_V1,       do_mov},
-  {"mvns",       0xe1f00000, 3,  ARM_EXT_V1,       do_mov},
+#define DATA_OP_SHIFT  21
 
-  {"ldr",        0xe4100000, 3,  ARM_EXT_V1,       do_ldst},
-  {"ldrb",       0xe4500000, 3,  ARM_EXT_V1,       do_ldst},
-  {"ldrt",       0xe4300000, 3,  ARM_EXT_V1,       do_ldstt},
-  {"ldrbt",      0xe4700000, 3,  ARM_EXT_V1,       do_ldstt},
-  {"str",        0xe4000000, 3,  ARM_EXT_V1,       do_ldst},
-  {"strb",       0xe4400000, 3,  ARM_EXT_V1,       do_ldst},
-  {"strt",       0xe4200000, 3,  ARM_EXT_V1,       do_ldstt},
-  {"strbt",      0xe4600000, 3,  ARM_EXT_V1,       do_ldstt},
+/* Codes to distinguish the arithmetic instructions.  */
+#define OPCODE_AND     0
+#define OPCODE_EOR     1
+#define OPCODE_SUB     2
+#define OPCODE_RSB     3
+#define OPCODE_ADD     4
+#define OPCODE_ADC     5
+#define OPCODE_SBC     6
+#define OPCODE_RSC     7
+#define OPCODE_TST     8
+#define OPCODE_TEQ     9
+#define OPCODE_CMP     10
+#define OPCODE_CMN     11
+#define OPCODE_ORR     12
+#define OPCODE_MOV     13
+#define OPCODE_BIC     14
+#define OPCODE_MVN     15
 
-  {"stmia",      0xe8800000, 3,  ARM_EXT_V1,       do_ldmstm},
-  {"stmib",      0xe9800000, 3,  ARM_EXT_V1,       do_ldmstm},
-  {"stmda",      0xe8000000, 3,  ARM_EXT_V1,       do_ldmstm},
-  {"stmdb",      0xe9000000, 3,  ARM_EXT_V1,       do_ldmstm},
-  {"stmfd",      0xe9000000, 3,  ARM_EXT_V1,       do_ldmstm},
-  {"stmfa",      0xe9800000, 3,  ARM_EXT_V1,       do_ldmstm},
-  {"stmea",      0xe8800000, 3,  ARM_EXT_V1,       do_ldmstm},
-  {"stmed",      0xe8000000, 3,  ARM_EXT_V1,       do_ldmstm},
+#define T_OPCODE_MUL 0x4340
+#define T_OPCODE_TST 0x4200
+#define T_OPCODE_CMN 0x42c0
+#define T_OPCODE_NEG 0x4240
+#define T_OPCODE_MVN 0x43c0
 
-  {"ldmia",      0xe8900000, 3,  ARM_EXT_V1,       do_ldmstm},
-  {"ldmib",      0xe9900000, 3,  ARM_EXT_V1,       do_ldmstm},
-  {"ldmda",      0xe8100000, 3,  ARM_EXT_V1,       do_ldmstm},
-  {"ldmdb",      0xe9100000, 3,  ARM_EXT_V1,       do_ldmstm},
-  {"ldmfd",      0xe8900000, 3,  ARM_EXT_V1,       do_ldmstm},
-  {"ldmfa",      0xe8100000, 3,  ARM_EXT_V1,       do_ldmstm},
-  {"ldmea",      0xe9100000, 3,  ARM_EXT_V1,       do_ldmstm},
-  {"ldmed",      0xe9900000, 3,  ARM_EXT_V1,       do_ldmstm},
+#define T_OPCODE_ADD_R3        0x1800
+#define T_OPCODE_SUB_R3 0x1a00
+#define T_OPCODE_ADD_HI 0x4400
+#define T_OPCODE_ADD_ST 0xb000
+#define T_OPCODE_SUB_ST 0xb080
+#define T_OPCODE_ADD_SP 0xa800
+#define T_OPCODE_ADD_PC 0xa000
+#define T_OPCODE_ADD_I8 0x3000
+#define T_OPCODE_SUB_I8 0x3800
+#define T_OPCODE_ADD_I3 0x1c00
+#define T_OPCODE_SUB_I3 0x1e00
 
-  {"swi",        0xef000000, 3,  ARM_EXT_V1,       do_swi},
-#ifdef TE_WINCE
-  /* XXX This is the wrong place to do this.  Think multi-arch.  */
-  {"bl",         0xeb000000, 2,  ARM_EXT_V1,       do_branch},
-  {"b",          0xea000000, 1,  ARM_EXT_V1,       do_branch},
-#else
-  {"bl",         0xebfffffe, 2,  ARM_EXT_V1,       do_branch},
-  {"b",          0xeafffffe, 1,  ARM_EXT_V1,       do_branch},
-#endif
+#define T_OPCODE_ASR_R 0x4100
+#define T_OPCODE_LSL_R 0x4080
+#define T_OPCODE_LSR_R  0x40c0
+#define T_OPCODE_ASR_I 0x1000
+#define T_OPCODE_LSL_I 0x0000
+#define T_OPCODE_LSR_I 0x0800
 
-  /* Pseudo ops.  */
-  {"adr",        0xe28f0000, 3,  ARM_EXT_V1,       do_adr},
-  {"adrl",       0xe28f0000, 3,  ARM_EXT_V1,       do_adrl},
-  {"nop",        0xe1a00000, 3,  ARM_EXT_V1,       do_empty},
+#define T_OPCODE_MOV_I8        0x2000
+#define T_OPCODE_CMP_I8 0x2800
+#define T_OPCODE_CMP_LR 0x4280
+#define T_OPCODE_MOV_HR 0x4600
+#define T_OPCODE_CMP_HR 0x4500
 
-  /* ARM 2 multiplies.  */
-  {"mul",        0xe0000090, 3,  ARM_EXT_V2,       do_mul},
-  {"muls",       0xe0100090, 3,  ARM_EXT_V2,       do_mul},
-  {"mla",        0xe0200090, 3,  ARM_EXT_V2,       do_mla},
-  {"mlas",       0xe0300090, 3,  ARM_EXT_V2,       do_mla},
+#define T_OPCODE_LDR_PC 0x4800
+#define T_OPCODE_LDR_SP 0x9800
+#define T_OPCODE_STR_SP 0x9000
+#define T_OPCODE_LDR_IW 0x6800
+#define T_OPCODE_STR_IW 0x6000
+#define T_OPCODE_LDR_IH 0x8800
+#define T_OPCODE_STR_IH 0x8000
+#define T_OPCODE_LDR_IB 0x7800
+#define T_OPCODE_STR_IB 0x7000
+#define T_OPCODE_LDR_RW 0x5800
+#define T_OPCODE_STR_RW 0x5000
+#define T_OPCODE_LDR_RH 0x5a00
+#define T_OPCODE_STR_RH 0x5200
+#define T_OPCODE_LDR_RB 0x5c00
+#define T_OPCODE_STR_RB 0x5400
 
-  /* Generic copressor instructions.  */
-  {"cdp",        0xee000000, 3,  ARM_EXT_V2,       do_cdp},
-  {"ldc",        0xec100000, 3,  ARM_EXT_V2,       do_lstc},
-  {"ldcl",       0xec500000, 3,  ARM_EXT_V2,       do_lstc},
-  {"stc",        0xec000000, 3,  ARM_EXT_V2,       do_lstc},
-  {"stcl",       0xec400000, 3,  ARM_EXT_V2,       do_lstc},
-  {"mcr",        0xee000010, 3,  ARM_EXT_V2,       do_co_reg},
-  {"mrc",        0xee100010, 3,  ARM_EXT_V2,       do_co_reg},
+#define T_OPCODE_PUSH  0xb400
+#define T_OPCODE_POP   0xbc00
 
-  /* ARM 3 - swp instructions.  */
-  {"swp",        0xe1000090, 3,  ARM_EXT_V2S,      do_swap},
-  {"swpb",       0xe1400090, 3,  ARM_EXT_V2S,      do_swap},
+#define T_OPCODE_BRANCH 0xe7fe
 
-  /* ARM 6 Status register instructions.  */
-  {"mrs",        0xe10f0000, 3,  ARM_EXT_V3,       do_mrs},
-  {"msr",        0xe120f000, 3,  ARM_EXT_V3,       do_msr},
-  /* ScottB: our code uses     0xe128f000 for msr.
-     NickC:  but this is wrong because the bits 16 through 19 are
-             handled by the PSR_xxx defines above.  */
+#define THUMB_SIZE     2       /* Size of thumb instruction.  */
+#define THUMB_REG_LO   0x1
+#define THUMB_REG_HI   0x2
+#define THUMB_REG_ANY  0x3
 
-  /* ARM 7M long multiplies.  */
-  {"smull",      0xe0c00090, 5,  ARM_EXT_V3M,      do_mull},
-  {"smulls",     0xe0d00090, 5,  ARM_EXT_V3M,      do_mull},
-  {"umull",      0xe0800090, 5,  ARM_EXT_V3M,      do_mull},
-  {"umulls",     0xe0900090, 5,  ARM_EXT_V3M,      do_mull},
-  {"smlal",      0xe0e00090, 5,  ARM_EXT_V3M,      do_mull},
-  {"smlals",     0xe0f00090, 5,  ARM_EXT_V3M,      do_mull},
-  {"umlal",      0xe0a00090, 5,  ARM_EXT_V3M,      do_mull},
-  {"umlals",     0xe0b00090, 5,  ARM_EXT_V3M,      do_mull},
+#define THUMB_H1       0x0080
+#define THUMB_H2       0x0040
 
-  /* ARM Architecture 4.  */
-  {"ldrh",       0xe01000b0, 3,  ARM_EXT_V4,       do_ldstv4},
-  {"ldrsh",      0xe01000f0, 3,  ARM_EXT_V4,       do_ldstv4},
-  {"ldrsb",      0xe01000d0, 3,  ARM_EXT_V4,       do_ldstv4},
-  {"strh",       0xe00000b0, 3,  ARM_EXT_V4,       do_ldstv4},
+#define THUMB_ASR 0
+#define THUMB_LSL 1
+#define THUMB_LSR 2
 
-  /* ARM Architecture 4T.  */
-  /* Note: bx (and blx) are required on V5, even if the processor does
-     not support Thumb.  */
-  {"bx",         0xe12fff10, 2,  ARM_EXT_V4T | ARM_EXT_V5, do_bx},
+#define THUMB_MOVE 0
+#define THUMB_COMPARE 1
+#define THUMB_CPY 2
 
-  /*  ARM Architecture 5T.  */
-  /* Note: blx has 2 variants, so the .value is set dynamically.
-     Only one of the variants has conditional execution.  */
-  {"blx",        0xe0000000, 3,  ARM_EXT_V5,       do_blx},
-  {"clz",        0xe16f0f10, 3,  ARM_EXT_V5,       do_clz},
-  {"bkpt",       0xe1200070, 0,  ARM_EXT_V5,       do_bkpt},
-  {"ldc2",       0xfc100000, 0,  ARM_EXT_V5,       do_lstc2},
-  {"ldc2l",      0xfc500000, 0,  ARM_EXT_V5,       do_lstc2},
-  {"stc2",       0xfc000000, 0,  ARM_EXT_V5,       do_lstc2},
-  {"stc2l",      0xfc400000, 0,  ARM_EXT_V5,       do_lstc2},
-  {"cdp2",       0xfe000000, 0,  ARM_EXT_V5,       do_cdp2},
-  {"mcr2",       0xfe000010, 0,  ARM_EXT_V5,       do_co_reg2},
-  {"mrc2",       0xfe100010, 0,  ARM_EXT_V5,       do_co_reg2},
+#define THUMB_LOAD 0
+#define THUMB_STORE 1
 
-  /*  ARM Architecture 5TExP.  */
-  {"smlabb",     0xe1000080, 6,  ARM_EXT_V5ExP,    do_smla},
-  {"smlatb",     0xe10000a0, 6,  ARM_EXT_V5ExP,    do_smla},
-  {"smlabt",     0xe10000c0, 6,  ARM_EXT_V5ExP,    do_smla},
-  {"smlatt",     0xe10000e0, 6,  ARM_EXT_V5ExP,    do_smla},
+#define THUMB_PP_PC_LR 0x0100
 
-  {"smlawb",     0xe1200080, 6,  ARM_EXT_V5ExP,    do_smla},
-  {"smlawt",     0xe12000c0, 6,  ARM_EXT_V5ExP,    do_smla},
+/* These three are used for immediate shifts, do not alter.  */
+#define THUMB_WORD 2
+#define THUMB_HALFWORD 1
+#define THUMB_BYTE 0
 
-  {"smlalbb",    0xe1400080, 7,  ARM_EXT_V5ExP,    do_smlal},
-  {"smlaltb",    0xe14000a0, 7,  ARM_EXT_V5ExP,    do_smlal},
-  {"smlalbt",    0xe14000c0, 7,  ARM_EXT_V5ExP,    do_smlal},
-  {"smlaltt",    0xe14000e0, 7,  ARM_EXT_V5ExP,    do_smlal},
+struct thumb_opcode
+{
+  /* Basic string to match.  */
+  const char * template;
 
-  {"smulbb",     0xe1600080, 6,  ARM_EXT_V5ExP,    do_smul},
-  {"smultb",     0xe16000a0, 6,  ARM_EXT_V5ExP,    do_smul},
-  {"smulbt",     0xe16000c0, 6,  ARM_EXT_V5ExP,    do_smul},
-  {"smultt",     0xe16000e0, 6,  ARM_EXT_V5ExP,    do_smul},
+  /* Basic instruction code.  */
+  unsigned long value;
 
-  {"smulwb",     0xe12000a0, 6,  ARM_EXT_V5ExP,    do_smul},
-  {"smulwt",     0xe12000e0, 6,  ARM_EXT_V5ExP,    do_smul},
+  int size;
 
-  {"qadd",       0xe1000050, 4,  ARM_EXT_V5ExP,    do_qadd},
-  {"qdadd",      0xe1400050, 5,  ARM_EXT_V5ExP,    do_qadd},
-  {"qsub",       0xe1200050, 4,  ARM_EXT_V5ExP,    do_qadd},
-  {"qdsub",      0xe1600050, 5,  ARM_EXT_V5ExP,    do_qadd},
+  /* Which CPU variants this exists for.  */
+  unsigned long variant;
 
-  /*  ARM Architecture 5TE.  */
-  {"pld",        0xf450f000, 0,  ARM_EXT_V5E,      do_pld},
-  {"ldrd",       0xe00000d0, 3,  ARM_EXT_V5E,      do_ldrd},
-  {"strd",       0xe00000f0, 3,  ARM_EXT_V5E,      do_ldrd},
+  /* Function to call to parse args.  */
+  void (* parms) (char *);
+};
 
-  {"mcrr",       0xec400000, 4,  ARM_EXT_V5E,      do_co_reg2c},
-  {"mrrc",       0xec500000, 4,  ARM_EXT_V5E,      do_co_reg2c},
+#define BAD_ARGS       _("bad arguments to instruction")
+#define BAD_PC                 _("r15 not allowed here")
+#define BAD_COND       _("instruction is not conditional")
+#define ERR_NO_ACCUM   _("acc0 expected")
 
-  /*  ARM Architecture 5TEJ.  */
-  {"bxj",       0xe12fff20, 3,  ARM_EXT_V5J,      do_bxj},
+static struct hash_control * arm_ops_hsh   = NULL;
+static struct hash_control * arm_tops_hsh  = NULL;
+static struct hash_control * arm_cond_hsh  = NULL;
+static struct hash_control * arm_shift_hsh = NULL;
+static struct hash_control * arm_psr_hsh   = NULL;
 
-  /* Core FPA instruction set (V1).  */
-  {"wfs",        0xee200110, 3,  FPU_FPA_EXT_V1,   do_fpa_ctrl},
-  {"rfs",        0xee300110, 3,  FPU_FPA_EXT_V1,   do_fpa_ctrl},
-  {"wfc",        0xee400110, 3,  FPU_FPA_EXT_V1,   do_fpa_ctrl},
-  {"rfc",        0xee500110, 3,  FPU_FPA_EXT_V1,   do_fpa_ctrl},
+/* Stuff needed to resolve the label ambiguity
+   As:
+     ...
+     label:   <insn>
+   may differ from:
+     ...
+     label:
+              <insn>
+*/
 
-  {"ldfs",       0xec100100, 3,  FPU_FPA_EXT_V1,   do_fpa_ldst},
-  {"ldfd",       0xec108100, 3,  FPU_FPA_EXT_V1,   do_fpa_ldst},
-  {"ldfe",       0xec500100, 3,  FPU_FPA_EXT_V1,   do_fpa_ldst},
-  {"ldfp",       0xec508100, 3,  FPU_FPA_EXT_V1,   do_fpa_ldst},
+symbolS *  last_label_seen;
+static int label_is_thumb_function_name = FALSE;
+\f
+/* Literal Pool stuff.  */
 
-  {"stfs",       0xec000100, 3,  FPU_FPA_EXT_V1,   do_fpa_ldst},
-  {"stfd",       0xec008100, 3,  FPU_FPA_EXT_V1,   do_fpa_ldst},
-  {"stfe",       0xec400100, 3,  FPU_FPA_EXT_V1,   do_fpa_ldst},
-  {"stfp",       0xec408100, 3,  FPU_FPA_EXT_V1,   do_fpa_ldst},
+#define MAX_LITERAL_POOL_SIZE 1024
 
-  {"mvfs",       0xee008100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"mvfsp",      0xee008120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"mvfsm",      0xee008140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"mvfsz",      0xee008160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"mvfd",       0xee008180, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"mvfdp",      0xee0081a0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"mvfdm",      0xee0081c0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"mvfdz",      0xee0081e0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"mvfe",       0xee088100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"mvfep",      0xee088120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"mvfem",      0xee088140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"mvfez",      0xee088160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+/* Literal pool structure.  Held on a per-section
+   and per-sub-section basis.  */
 
-  {"mnfs",       0xee108100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"mnfsp",      0xee108120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"mnfsm",      0xee108140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"mnfsz",      0xee108160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"mnfd",       0xee108180, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"mnfdp",      0xee1081a0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"mnfdm",      0xee1081c0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"mnfdz",      0xee1081e0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"mnfe",       0xee188100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"mnfep",      0xee188120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"mnfem",      0xee188140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"mnfez",      0xee188160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+typedef struct literal_pool
+{
+  expressionS    literals [MAX_LITERAL_POOL_SIZE];
+  unsigned int   next_free_entry;
+  unsigned int   id;
+  symbolS *      symbol;
+  segT           section;
+  subsegT        sub_section;
+  struct literal_pool * next;
+} literal_pool;
 
-  {"abss",       0xee208100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"abssp",      0xee208120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"abssm",      0xee208140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"abssz",      0xee208160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"absd",       0xee208180, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"absdp",      0xee2081a0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"absdm",      0xee2081c0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"absdz",      0xee2081e0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"abse",       0xee288100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"absep",      0xee288120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"absem",      0xee288140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"absez",      0xee288160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+/* Pointer to a linked list of literal pools.  */
+literal_pool * list_of_pools = NULL;
 
-  {"rnds",       0xee308100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"rndsp",      0xee308120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"rndsm",      0xee308140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"rndsz",      0xee308160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"rndd",       0xee308180, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"rnddp",      0xee3081a0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"rnddm",      0xee3081c0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"rnddz",      0xee3081e0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"rnde",       0xee388100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"rndep",      0xee388120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"rndem",      0xee388140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"rndez",      0xee388160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+static literal_pool *
+find_literal_pool (void)
+{
+  literal_pool * pool;
 
-  {"sqts",       0xee408100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"sqtsp",      0xee408120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"sqtsm",      0xee408140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"sqtsz",      0xee408160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"sqtd",       0xee408180, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"sqtdp",      0xee4081a0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"sqtdm",      0xee4081c0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"sqtdz",      0xee4081e0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"sqte",       0xee488100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"sqtep",      0xee488120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"sqtem",      0xee488140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"sqtez",      0xee488160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  for (pool = list_of_pools; pool != NULL; pool = pool->next)
+    {
+      if (pool->section == now_seg
+         && pool->sub_section == now_subseg)
+       break;
+    }
 
-  {"logs",       0xee508100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"logsp",      0xee508120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"logsm",      0xee508140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"logsz",      0xee508160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"logd",       0xee508180, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"logdp",      0xee5081a0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"logdm",      0xee5081c0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"logdz",      0xee5081e0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"loge",       0xee588100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"logep",      0xee588120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"logem",      0xee588140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"logez",      0xee588160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  return pool;
+}
 
-  {"lgns",       0xee608100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"lgnsp",      0xee608120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"lgnsm",      0xee608140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"lgnsz",      0xee608160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"lgnd",       0xee608180, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"lgndp",      0xee6081a0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"lgndm",      0xee6081c0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"lgndz",      0xee6081e0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"lgne",       0xee688100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"lgnep",      0xee688120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"lgnem",      0xee688140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"lgnez",      0xee688160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+static literal_pool *
+find_or_make_literal_pool (void)
+{
+  /* Next literal pool ID number.  */
+  static unsigned int latest_pool_num = 1;
+  literal_pool *      pool;
 
-  {"exps",       0xee708100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"expsp",      0xee708120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"expsm",      0xee708140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"expsz",      0xee708160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"expd",       0xee708180, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"expdp",      0xee7081a0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"expdm",      0xee7081c0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"expdz",      0xee7081e0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"expe",       0xee788100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"expep",      0xee788120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"expem",      0xee788140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"expdz",      0xee788160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  pool = find_literal_pool ();
 
-  {"sins",       0xee808100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"sinsp",      0xee808120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"sinsm",      0xee808140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"sinsz",      0xee808160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"sind",       0xee808180, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"sindp",      0xee8081a0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"sindm",      0xee8081c0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"sindz",      0xee8081e0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"sine",       0xee888100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"sinep",      0xee888120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"sinem",      0xee888140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"sinez",      0xee888160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  if (pool == NULL)
+    {
+      /* Create a new pool.  */
+      pool = xmalloc (sizeof (* pool));
+      if (! pool)
+       return NULL;
 
-  {"coss",       0xee908100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"cossp",      0xee908120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"cossm",      0xee908140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"cossz",      0xee908160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"cosd",       0xee908180, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"cosdp",      0xee9081a0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"cosdm",      0xee9081c0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"cosdz",      0xee9081e0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"cose",       0xee988100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"cosep",      0xee988120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"cosem",      0xee988140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"cosez",      0xee988160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+      pool->next_free_entry = 0;
+      pool->section         = now_seg;
+      pool->sub_section     = now_subseg;
+      pool->next            = list_of_pools;
+      pool->symbol          = NULL;
 
-  {"tans",       0xeea08100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"tansp",      0xeea08120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"tansm",      0xeea08140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"tansz",      0xeea08160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"tand",       0xeea08180, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"tandp",      0xeea081a0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"tandm",      0xeea081c0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"tandz",      0xeea081e0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"tane",       0xeea88100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"tanep",      0xeea88120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"tanem",      0xeea88140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"tanez",      0xeea88160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+      /* Add it to the list.  */
+      list_of_pools = pool;
+    }
 
-  {"asns",       0xeeb08100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"asnsp",      0xeeb08120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"asnsm",      0xeeb08140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"asnsz",      0xeeb08160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"asnd",       0xeeb08180, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"asndp",      0xeeb081a0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"asndm",      0xeeb081c0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"asndz",      0xeeb081e0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"asne",       0xeeb88100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"asnep",      0xeeb88120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"asnem",      0xeeb88140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"asnez",      0xeeb88160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  /* New pools, and emptied pools, will have a NULL symbol.  */
+  if (pool->symbol == NULL)
+    {
+      pool->symbol = symbol_create (FAKE_LABEL_NAME, undefined_section,
+                                   (valueT) 0, &zero_address_frag);
+      pool->id = latest_pool_num ++;
+    }
+
+  /* Done.  */
+  return pool;
+}
+
+/* Add the literal in the global 'inst'
+   structure to the relevent literal pool.  */
+
+static int
+add_to_lit_pool (void)
+{
+  literal_pool * pool;
+  unsigned int entry;
+
+  pool = find_or_make_literal_pool ();
+
+  /* Check if this literal value is already in the pool.  */
+  for (entry = 0; entry < pool->next_free_entry; entry ++)
+    {
+      if ((pool->literals[entry].X_op == inst.reloc.exp.X_op)
+         && (inst.reloc.exp.X_op == O_constant)
+         && (pool->literals[entry].X_add_number
+             == inst.reloc.exp.X_add_number)
+         && (pool->literals[entry].X_unsigned
+             == inst.reloc.exp.X_unsigned))
+       break;
+
+      if ((pool->literals[entry].X_op == inst.reloc.exp.X_op)
+          && (inst.reloc.exp.X_op == O_symbol)
+          && (pool->literals[entry].X_add_number
+             == inst.reloc.exp.X_add_number)
+          && (pool->literals[entry].X_add_symbol
+             == inst.reloc.exp.X_add_symbol)
+          && (pool->literals[entry].X_op_symbol
+             == inst.reloc.exp.X_op_symbol))
+        break;
+    }
+
+  /* Do we need to create a new entry?  */
+  if (entry == pool->next_free_entry)
+    {
+      if (entry >= MAX_LITERAL_POOL_SIZE)
+       {
+         inst.error = _("literal pool overflow");
+         return FAIL;
+       }
+
+      pool->literals[entry] = inst.reloc.exp;
+      pool->next_free_entry += 1;
+    }
+
+  inst.reloc.exp.X_op         = O_symbol;
+  inst.reloc.exp.X_add_number = ((int) entry) * 4 - 8;
+  inst.reloc.exp.X_add_symbol = pool->symbol;
+
+  return SUCCESS;
+}
+
+/* Can't use symbol_new here, so have to create a symbol and then at
+   a later date assign it a value. Thats what these functions do.  */
+
+static void
+symbol_locate (symbolS *    symbolP,
+              const char * name,       /* It is copied, the caller can modify.  */
+              segT         segment,    /* Segment identifier (SEG_<something>).  */
+              valueT       valu,       /* Symbol value.  */
+              fragS *      frag)       /* Associated fragment.  */
+{
+  unsigned int name_length;
+  char * preserved_copy_of_name;
+
+  name_length = strlen (name) + 1;   /* +1 for \0.  */
+  obstack_grow (&notes, name, name_length);
+  preserved_copy_of_name = obstack_finish (&notes);
+#ifdef STRIP_UNDERSCORE
+  if (preserved_copy_of_name[0] == '_')
+    preserved_copy_of_name++;
+#endif
+
+#ifdef tc_canonicalize_symbol_name
+  preserved_copy_of_name =
+    tc_canonicalize_symbol_name (preserved_copy_of_name);
+#endif
+
+  S_SET_NAME (symbolP, preserved_copy_of_name);
+
+  S_SET_SEGMENT (symbolP, segment);
+  S_SET_VALUE (symbolP, valu);
+  symbol_clear_list_pointers (symbolP);
+
+  symbol_set_frag (symbolP, frag);
+
+  /* Link to end of symbol chain.  */
+  {
+    extern int symbol_table_frozen;
+
+    if (symbol_table_frozen)
+      abort ();
+  }
+
+  symbol_append (symbolP, symbol_lastP, & symbol_rootP, & symbol_lastP);
+
+  obj_symbol_new_hook (symbolP);
+
+#ifdef tc_symbol_new_hook
+  tc_symbol_new_hook (symbolP);
+#endif
+
+#ifdef DEBUG_SYMS
+  verify_symbol_chain (symbol_rootP, symbol_lastP);
+#endif /* DEBUG_SYMS  */
+}
+
+/* Check that an immediate is valid.
+   If so, convert it to the right format.  */
+
+static unsigned int
+validate_immediate (unsigned int val)
+{
+  unsigned int a;
+  unsigned int i;
+
+#define rotate_left(v, n) (v << n | v >> (32 - n))
+
+  for (i = 0; i < 32; i += 2)
+    if ((a = rotate_left (val, i)) <= 0xff)
+      return a | (i << 7); /* 12-bit pack: [shift-cnt,const].  */
+
+  return FAIL;
+}
+
+/* Check to see if an immediate can be computed as two separate immediate
+   values, added together.  We already know that this value cannot be
+   computed by just one ARM instruction.  */
+
+static unsigned int
+validate_immediate_twopart (unsigned int   val,
+                           unsigned int * highpart)
+{
+  unsigned int a;
+  unsigned int i;
+
+  for (i = 0; i < 32; i += 2)
+    if (((a = rotate_left (val, i)) & 0xff) != 0)
+      {
+       if (a & 0xff00)
+         {
+           if (a & ~ 0xffff)
+             continue;
+           * highpart = (a  >> 8) | ((i + 24) << 7);
+         }
+       else if (a & 0xff0000)
+         {
+           if (a & 0xff000000)
+             continue;
+           * highpart = (a >> 16) | ((i + 16) << 7);
+         }
+       else
+         {
+           assert (a & 0xff000000);
+           * highpart = (a >> 24) | ((i + 8) << 7);
+         }
+
+       return (a & 0xff) | (i << 7);
+      }
+
+  return FAIL;
+}
+
+static int
+validate_offset_imm (unsigned int val, int hwse)
+{
+  if ((hwse && val > 255) || val > 4095)
+    return FAIL;
+  return val;
+}
+
+\f
+#ifdef OBJ_ELF
+/* This code is to handle mapping symbols as defined in the ARM ELF spec.
+   (This text is taken from version B-02 of the spec):
+
+      4.4.7 Mapping and tagging symbols
+
+      A section of an ARM ELF file can contain a mixture of ARM code,
+      Thumb code, and data.  There are inline transitions between code
+      and data at literal pool boundaries. There can also be inline
+      transitions between ARM code and Thumb code, for example in
+      ARM-Thumb inter-working veneers.  Linkers, machine-level
+      debuggers, profiling tools, and disassembly tools need to map
+      images accurately. For example, setting an ARM breakpoint on a
+      Thumb location, or in a literal pool, can crash the program
+      being debugged, ruining the debugging session.
+
+      ARM ELF entities are mapped (see section 4.4.7.1 below) and
+      tagged (see section 4.4.7.2 below) using local symbols (with
+      binding STB_LOCAL).  To assist consumers, mapping and tagging
+      symbols should be collated first in the symbol table, before
+      other symbols with binding STB_LOCAL.
+
+      To allow properly collated mapping and tagging symbols to be
+      skipped by consumers that have no interest in them, the first
+      such symbol should have the name $m and its st_value field equal
+      to the total number of mapping and tagging symbols (including
+      the $m) in the symbol table.
+
+      4.4.7.1 Mapping symbols
+
+      $a    Labels the first byte of a sequence of ARM instructions.
+            Its type is STT_FUNC.
+
+      $d    Labels the first byte of a sequence of data items.
+            Its type is STT_OBJECT.
+
+      $t    Labels the first byte of a sequence of Thumb instructions.
+            Its type is STT_FUNC.
+
+      This list of mapping symbols may be extended in the future.
+
+      Section-relative mapping symbols
+
+      Mapping symbols defined in a section define a sequence of
+      half-open address intervals that cover the address range of the
+      section. Each interval starts at the address defined by a
+      mapping symbol, and continues up to, but not including, the
+      address defined by the next (in address order) mapping symbol or
+      the end of the section. A corollary is that there must be a
+      mapping symbol defined at the beginning of each section.
+      Consumers can ignore the size of a section-relative mapping
+      symbol. Producers can set it to 0.
+
+      Absolute mapping symbols
+
+      Because of the need to crystallize a Thumb address with the
+      Thumb-bit set, absolute symbol of type STT_FUNC (symbols of type
+      STT_FUNC defined in section SHN_ABS) need to be mapped with $a
+      or $t.
+
+      The extent of a mapping symbol defined in SHN_ABS is [st_value,
+      st_value + st_size), or [st_value, st_value + 1) if st_size = 0,
+      where [x, y) denotes the half-open address range from x,
+      inclusive, to y, exclusive.
+
+      In the absence of a mapping symbol, a consumer can interpret a
+      function symbol with an odd value as the Thumb code address
+      obtained by clearing the least significant bit of the
+      value. This interpretation is deprecated, and it may not work in
+      the future.
+
+   Note - the Tagging symbols ($b, $f, $p $m) have been dropped from
+   the EABI (which is still under development), so they are not
+   implemented here.  */
+
+static enum mstate mapstate = MAP_UNDEFINED;
+
+static void
+mapping_state (enum mstate state)
+{
+  symbolS * symbolP;
+  const char * symname;
+  int type;
+
+  if (mapstate == state)
+    /* The mapping symbol has already been emitted.
+       There is nothing else to do.  */
+    return;
+
+  mapstate = state;
+
+  switch (state)
+    {
+    case MAP_DATA:
+      symname = "$d";
+      type = BSF_OBJECT;
+      break;
+    case MAP_ARM:
+      symname = "$a";
+      type = BSF_FUNCTION;
+      break;
+    case MAP_THUMB:
+      symname = "$t";
+      type = BSF_FUNCTION;
+      break;
+    case MAP_UNDEFINED:
+      return;
+    default:
+      abort ();
+    }
+
+  seg_info (now_seg)->tc_segment_info_data = state;
+
+  symbolP = symbol_new (symname, now_seg, (valueT) frag_now_fix (), frag_now);
+  symbol_table_insert (symbolP);
+  symbol_get_bfdsym (symbolP)->flags |= type | BSF_LOCAL;
+
+  switch (state)
+    {
+    case MAP_ARM:
+      THUMB_SET_FUNC (symbolP, 0);
+      ARM_SET_THUMB (symbolP, 0);
+      ARM_SET_INTERWORK (symbolP, support_interwork);
+      break;
+
+    case MAP_THUMB:
+      THUMB_SET_FUNC (symbolP, 1);
+      ARM_SET_THUMB (symbolP, 1);
+      ARM_SET_INTERWORK (symbolP, support_interwork);
+      break;
+
+    case MAP_DATA:
+    default:
+      return;
+    }
+}
+
+/* When we change sections we need to issue a new mapping symbol.  */
+
+void
+arm_elf_change_section (void)
+{
+  flagword flags;
+
+  /* Link an unlinked unwind index table section to the .text section.  */
+  if (elf_section_type (now_seg) == SHT_ARM_EXIDX
+      && elf_linked_to_section (now_seg) == NULL)
+    elf_linked_to_section (now_seg) = text_section;
+
+  if (!SEG_NORMAL (now_seg))
+    return;
+
+  flags = bfd_get_section_flags (stdoutput, now_seg);
+
+  /* We can ignore sections that only contain debug info.  */
+  if ((flags & SEC_ALLOC) == 0)
+    return;
+
+  mapstate = seg_info (now_seg)->tc_segment_info_data;
+}
+
+int
+arm_elf_section_type (const char * str, size_t len)
+{
+  if (len == 5 && strncmp (str, "exidx", 5) == 0)
+    return SHT_ARM_EXIDX;
+
+  return -1;
+}
+#else
+#define mapping_state(a)
+#endif /* OBJ_ELF */
+\f
+/* arm_reg_parse () := if it looks like a register, return its token and
+   advance the pointer.  */
+
+static int
+arm_reg_parse (char ** ccp, struct hash_control * htab)
+{
+  char * start = * ccp;
+  char   c;
+  char * p;
+  struct reg_entry * reg;
+
+#ifdef REGISTER_PREFIX
+  if (*start != REGISTER_PREFIX)
+    return FAIL;
+  p = start + 1;
+#else
+  p = start;
+#ifdef OPTIONAL_REGISTER_PREFIX
+  if (*p == OPTIONAL_REGISTER_PREFIX)
+    p++, start++;
+#endif
+#endif
+  if (!ISALPHA (*p) || !is_name_beginner (*p))
+    return FAIL;
+
+  c = *p++;
+  while (ISALPHA (c) || ISDIGIT (c) || c == '_')
+    c = *p++;
+
+  *--p = 0;
+  reg = (struct reg_entry *) hash_find (htab, start);
+  *p = c;
+
+  if (reg)
+    {
+      *ccp = p;
+      return reg->number;
+    }
+
+  return FAIL;
+}
+
+/* Search for the following register name in each of the possible reg name
+   tables.  Return the classification if found, or REG_TYPE_MAX if not
+   present.  */
+
+static enum arm_reg_type
+arm_reg_parse_any (char *cp)
+{
+  int i;
+
+  for (i = (int) REG_TYPE_FIRST; i < (int) REG_TYPE_MAX; i++)
+    if (arm_reg_parse (&cp, all_reg_maps[i].htab) != FAIL)
+      return (enum arm_reg_type) i;
+
+  return REG_TYPE_MAX;
+}
+
+static void
+opcode_select (int width)
+{
+  switch (width)
+    {
+    case 16:
+      if (! thumb_mode)
+       {
+         if (! (cpu_variant & ARM_EXT_V4T))
+           as_bad (_("selected processor does not support THUMB opcodes"));
+
+         thumb_mode = 1;
+         /* No need to force the alignment, since we will have been
+             coming from ARM mode, which is word-aligned.  */
+         record_alignment (now_seg, 1);
+       }
+      mapping_state (MAP_THUMB);
+      break;
+
+    case 32:
+      if (thumb_mode)
+       {
+         if ((cpu_variant & ARM_ALL) == ARM_EXT_V4T)
+           as_bad (_("selected processor does not support ARM opcodes"));
+
+         thumb_mode = 0;
+
+         if (!need_pass_2)
+           frag_align (2, 0, 0);
+
+         record_alignment (now_seg, 1);
+       }
+      mapping_state (MAP_ARM);
+      break;
+
+    default:
+      as_bad (_("invalid instruction size selected (%d)"), width);
+    }
+}
+
+static void
+s_req (int a ATTRIBUTE_UNUSED)
+{
+  as_bad (_("invalid syntax for .req directive"));
+}
+
+/* The .unreq directive deletes an alias which was previously defined
+   by .req.  For example:
+
+       my_alias .req r11
+       .unreq my_alias    */
+
+static void
+s_unreq (int a ATTRIBUTE_UNUSED)
+{
+  char * name;
+  char saved_char;
+
+  skip_whitespace (input_line_pointer);
+  name = input_line_pointer;
+
+  while (*input_line_pointer != 0
+        && *input_line_pointer != ' '
+        && *input_line_pointer != '\n')
+    ++input_line_pointer;
+
+  saved_char = *input_line_pointer;
+  *input_line_pointer = 0;
+
+  if (*name)
+    {
+      enum arm_reg_type req_type = arm_reg_parse_any (name);
+
+      if (req_type != REG_TYPE_MAX)
+       {
+         char *temp_name = name;
+         int req_no = arm_reg_parse (&temp_name, all_reg_maps[req_type].htab);
+
+         if (req_no != FAIL)
+           {
+             struct reg_entry *req_entry;
+
+             /* Check to see if this alias is a builtin one.  */
+             req_entry = hash_delete (all_reg_maps[req_type].htab, name);
+
+             if (!req_entry)
+               as_bad (_("unreq: missing hash entry for \"%s\""), name);
+             else if (req_entry->builtin)
+               /* FIXME: We are deleting a built in register alias which
+                  points to a const data structure, so we only need to
+                  free up the memory used by the key in the hash table.
+                  Unfortunately we have not recorded this value, so this
+                  is a memory leak.  */
+                 /* FIXME: Should we issue a warning message ?  */
+               ;
+             else
+               {
+                 /* Deleting a user defined alias.  We need to free the
+                    key and the value, but fortunately the key is the same
+                    as the value->name field.  */
+                 free ((char *) req_entry->name);
+                 free (req_entry);
+               }
+           }
+          else
+            as_bad (_(".unreq: unrecognized symbol \"%s\""), name);
+       }
+      else
+        as_bad (_(".unreq: unrecognized symbol \"%s\""), name);
+    }
+  else
+    as_bad (_("invalid syntax for .unreq directive"));
+
+  *input_line_pointer = saved_char;
+  demand_empty_rest_of_line ();
+}
+
+static void
+s_bss (int ignore ATTRIBUTE_UNUSED)
+{
+  /* We don't support putting frags in the BSS segment, we fake it by
+     marking in_bss, then looking at s_skip for clues.  */
+  subseg_set (bss_section, 0);
+  demand_empty_rest_of_line ();
+  mapping_state (MAP_DATA);
+}
+
+static void
+s_even (int ignore ATTRIBUTE_UNUSED)
+{
+  /* Never make frag if expect extra pass.  */
+  if (!need_pass_2)
+    frag_align (1, 0, 0);
+
+  record_alignment (now_seg, 1);
+
+  demand_empty_rest_of_line ();
+}
+
+static void
+s_ltorg (int ignored ATTRIBUTE_UNUSED)
+{
+  unsigned int entry;
+  literal_pool * pool;
+  char sym_name[20];
+
+  pool = find_literal_pool ();
+  if (pool == NULL
+      || pool->symbol == NULL
+      || pool->next_free_entry == 0)
+    return;
+
+  mapping_state (MAP_DATA);
+
+  /* Align pool as you have word accesses.
+     Only make a frag if we have to.  */
+  if (!need_pass_2)
+    frag_align (2, 0, 0);
+
+  record_alignment (now_seg, 2);
+
+  sprintf (sym_name, "$$lit_\002%x", pool->id);
+
+  symbol_locate (pool->symbol, sym_name, now_seg,
+                (valueT) frag_now_fix (), frag_now);
+  symbol_table_insert (pool->symbol);
+
+  ARM_SET_THUMB (pool->symbol, thumb_mode);
+
+#if defined OBJ_COFF || defined OBJ_ELF
+  ARM_SET_INTERWORK (pool->symbol, support_interwork);
+#endif
+
+  for (entry = 0; entry < pool->next_free_entry; entry ++)
+    /* First output the expression in the instruction to the pool.  */
+    emit_expr (&(pool->literals[entry]), 4); /* .word  */
+
+  /* Mark the pool as empty.  */
+  pool->next_free_entry = 0;
+  pool->symbol = NULL;
+}
+
+/* Same as s_align_ptwo but align 0 => align 2.  */
+
+static void
+s_align (int unused ATTRIBUTE_UNUSED)
+{
+  int temp;
+  long temp_fill;
+  long max_alignment = 15;
+
+  temp = get_absolute_expression ();
+  if (temp > max_alignment)
+    as_bad (_("alignment too large: %d assumed"), temp = max_alignment);
+  else if (temp < 0)
+    {
+      as_bad (_("alignment negative. 0 assumed."));
+      temp = 0;
+    }
+
+  if (*input_line_pointer == ',')
+    {
+      input_line_pointer++;
+      temp_fill = get_absolute_expression ();
+    }
+  else
+    temp_fill = 0;
+
+  if (!temp)
+    temp = 2;
+
+  /* Only make a frag if we HAVE to.  */
+  if (temp && !need_pass_2)
+    frag_align (temp, (int) temp_fill, 0);
+  demand_empty_rest_of_line ();
+
+  record_alignment (now_seg, temp);
+}
+
+static void
+s_force_thumb (int ignore ATTRIBUTE_UNUSED)
+{
+  /* If we are not already in thumb mode go into it, EVEN if
+     the target processor does not support thumb instructions.
+     This is used by gcc/config/arm/lib1funcs.asm for example
+     to compile interworking support functions even if the
+     target processor should not support interworking.  */
+  if (! thumb_mode)
+    {
+      thumb_mode = 2;
+
+      record_alignment (now_seg, 1);
+    }
+
+  demand_empty_rest_of_line ();
+}
+
+static void
+s_thumb_func (int ignore ATTRIBUTE_UNUSED)
+{
+  if (! thumb_mode)
+    opcode_select (16);
+
+  /* The following label is the name/address of the start of a Thumb function.
+     We need to know this for the interworking support.  */
+  label_is_thumb_function_name = TRUE;
+
+  demand_empty_rest_of_line ();
+}
+
+/* Perform a .set directive, but also mark the alias as
+   being a thumb function.  */
+
+static void
+s_thumb_set (int equiv)
+{
+  /* XXX the following is a duplicate of the code for s_set() in read.c
+     We cannot just call that code as we need to get at the symbol that
+     is created.  */
+  char *    name;
+  char      delim;
+  char *    end_name;
+  symbolS * symbolP;
+
+  /* Especial apologies for the random logic:
+     This just grew, and could be parsed much more simply!
+     Dean - in haste.  */
+  name      = input_line_pointer;
+  delim     = get_symbol_end ();
+  end_name  = input_line_pointer;
+  *end_name = delim;
+
+  SKIP_WHITESPACE ();
+
+  if (*input_line_pointer != ',')
+    {
+      *end_name = 0;
+      as_bad (_("expected comma after name \"%s\""), name);
+      *end_name = delim;
+      ignore_rest_of_line ();
+      return;
+    }
+
+  input_line_pointer++;
+  *end_name = 0;
+
+  if (name[0] == '.' && name[1] == '\0')
+    {
+      /* XXX - this should not happen to .thumb_set.  */
+      abort ();
+    }
+
+  if ((symbolP = symbol_find (name)) == NULL
+      && (symbolP = md_undefined_symbol (name)) == NULL)
+    {
+#ifndef NO_LISTING
+      /* When doing symbol listings, play games with dummy fragments living
+        outside the normal fragment chain to record the file and line info
+         for this symbol.  */
+      if (listing & LISTING_SYMBOLS)
+       {
+         extern struct list_info_struct * listing_tail;
+         fragS * dummy_frag = xmalloc (sizeof (fragS));
+
+         memset (dummy_frag, 0, sizeof (fragS));
+         dummy_frag->fr_type = rs_fill;
+         dummy_frag->line = listing_tail;
+         symbolP = symbol_new (name, undefined_section, 0, dummy_frag);
+         dummy_frag->fr_symbol = symbolP;
+       }
+      else
+#endif
+       symbolP = symbol_new (name, undefined_section, 0, &zero_address_frag);
+
+#ifdef OBJ_COFF
+      /* "set" symbols are local unless otherwise specified.  */
+      SF_SET_LOCAL (symbolP);
+#endif /* OBJ_COFF  */
+    }                          /* Make a new symbol.  */
+
+  symbol_table_insert (symbolP);
+
+  * end_name = delim;
+
+  if (equiv
+      && S_IS_DEFINED (symbolP)
+      && S_GET_SEGMENT (symbolP) != reg_section)
+    as_bad (_("symbol `%s' already defined"), S_GET_NAME (symbolP));
+
+  pseudo_set (symbolP);
+
+  demand_empty_rest_of_line ();
+
+  /* XXX Now we come to the Thumb specific bit of code.  */
+
+  THUMB_SET_FUNC (symbolP, 1);
+  ARM_SET_THUMB (symbolP, 1);
+#if defined OBJ_ELF || defined OBJ_COFF
+  ARM_SET_INTERWORK (symbolP, support_interwork);
+#endif
+}
+
+static void
+s_arm (int ignore ATTRIBUTE_UNUSED)
+{
+  opcode_select (32);
+  demand_empty_rest_of_line ();
+}
+
+static void
+s_thumb (int ignore ATTRIBUTE_UNUSED)
+{
+  opcode_select (16);
+  demand_empty_rest_of_line ();
+}
+
+static void
+s_code (int unused ATTRIBUTE_UNUSED)
+{
+  int temp;
+
+  temp = get_absolute_expression ();
+  switch (temp)
+    {
+    case 16:
+    case 32:
+      opcode_select (temp);
+      break;
+
+    default:
+      as_bad (_("invalid operand to .code directive (%d) (expecting 16 or 32)"), temp);
+    }
+}
+
+static void
+end_of_line (char * str)
+{
+  skip_whitespace (str);
+
+  if (*str != '\0' && !inst.error)
+    inst.error = _("garbage following instruction");
+}
+
+static int
+skip_past_comma (char ** str)
+{
+  char * p = * str, c;
+  int comma = 0;
+
+  while ((c = *p) == ' ' || c == ',')
+    {
+      p++;
+      if (c == ',' && comma++)
+       return FAIL;
+    }
+
+  if (c == '\0')
+    return FAIL;
+
+  *str = p;
+  return comma ? SUCCESS : FAIL;
+}
+
+/* Return TRUE if anything in the expression is a bignum.  */
+
+static int
+walk_no_bignums (symbolS * sp)
+{
+  if (symbol_get_value_expression (sp)->X_op == O_big)
+    return 1;
+
+  if (symbol_get_value_expression (sp)->X_add_symbol)
+    {
+      return (walk_no_bignums (symbol_get_value_expression (sp)->X_add_symbol)
+             || (symbol_get_value_expression (sp)->X_op_symbol
+                 && walk_no_bignums (symbol_get_value_expression (sp)->X_op_symbol)));
+    }
+
+  return 0;
+}
+
+static int in_my_get_expression = 0;
+
+static int
+my_get_expression (expressionS * ep, char ** str)
+{
+  char * save_in;
+  segT   seg;
+
+  save_in = input_line_pointer;
+  input_line_pointer = *str;
+  in_my_get_expression = 1;
+  seg = expression (ep);
+  in_my_get_expression = 0;
+
+  if (ep->X_op == O_illegal)
+    {
+      /* We found a bad expression in md_operand().  */
+      *str = input_line_pointer;
+      input_line_pointer = save_in;
+      return 1;
+    }
+
+#ifdef OBJ_AOUT
+  if (seg != absolute_section
+      && seg != text_section
+      && seg != data_section
+      && seg != bss_section
+      && seg != undefined_section)
+    {
+      inst.error = _("bad_segment");
+      *str = input_line_pointer;
+      input_line_pointer = save_in;
+      return 1;
+    }
+#endif
+
+  /* Get rid of any bignums now, so that we don't generate an error for which
+     we can't establish a line number later on.  Big numbers are never valid
+     in instructions, which is where this routine is always called.  */
+  if (ep->X_op == O_big
+      || (ep->X_add_symbol
+         && (walk_no_bignums (ep->X_add_symbol)
+             || (ep->X_op_symbol
+                 && walk_no_bignums (ep->X_op_symbol)))))
+    {
+      inst.error = _("invalid constant");
+      *str = input_line_pointer;
+      input_line_pointer = save_in;
+      return 1;
+    }
+
+  *str = input_line_pointer;
+  input_line_pointer = save_in;
+  return 0;
+}
+
+/* A standard register must be given at this point.
+   SHIFT is the place to put it in inst.instruction.
+   Restores input start point on error.
+   Returns the reg#, or FAIL.  */
+
+static int
+reg_required_here (char ** str, int shift)
+{
+  static char buff [128]; /* XXX  */
+  int         reg;
+  char *      start = * str;
+
+  if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_RN].htab)) != FAIL)
+    {
+      if (shift >= 0)
+       inst.instruction |= reg << shift;
+      return 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, _("register expected, not '%.100s'"), start);
+  inst.error = buff;
+
+  return FAIL;
+}
+
+/* A Intel Wireless MMX technology register
+   must be given at this point.
+   Shift is the place to put it in inst.instruction.
+   Restores input start point on err.
+   Returns the reg#, or FAIL.  */
+
+static int
+wreg_required_here (char ** str,
+                   int shift,
+                   enum wreg_type reg_type)
+{
+  static char buff [128];
+  int    reg;
+  char * start = *str;
+
+  if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_IWMMXT].htab)) != FAIL)
+    {
+      if (wr_register (reg)
+         && (reg_type == IWMMXT_REG_WR || reg_type == IWMMXT_REG_WR_OR_WC))
+        {
+          if (shift >= 0)
+            inst.instruction |= (reg ^ WR_PREFIX) << shift;
+          return reg;
+        }
+      else if (wc_register (reg)
+              && (reg_type == IWMMXT_REG_WC || reg_type == IWMMXT_REG_WR_OR_WC))
+        {
+          if (shift >= 0)
+            inst.instruction |= (reg ^ WC_PREFIX) << shift;
+          return reg;
+        }
+      else if ((wcg_register (reg) && reg_type == IWMMXT_REG_WCG))
+        {
+          if (shift >= 0)
+            inst.instruction |= ((reg ^ WC_PREFIX) - 8) << shift;
+          return 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, _("Intel Wireless MMX technology register expected, not '%.100s'"), start);
+  inst.error = buff;
+
+  return FAIL;
+}
+
+static const struct asm_psr *
+arm_psr_parse (char ** ccp)
+{
+  char * start = * ccp;
+  char   c;
+  char * p;
+  const struct asm_psr * psr;
+
+  p = start;
+
+  /* Skip to the end of the next word in the input stream.  */
+  do
+    {
+      c = *p++;
+    }
+  while (ISALPHA (c) || c == '_');
+
+  /* Terminate the word.  */
+  *--p = 0;
+
+  /* CPSR's and SPSR's can now be lowercase.  This is just a convenience
+     feature for ease of use and backwards compatibility.  */
+  if (!strncmp (start, "cpsr", 4))
+    strncpy (start, "CPSR", 4);
+  else if (!strncmp (start, "spsr", 4))
+    strncpy (start, "SPSR", 4);
+
+  /* Now locate the word in the psr hash table.  */
+  psr = (const struct asm_psr *) hash_find (arm_psr_hsh, start);
+
+  /* Restore the input stream.  */
+  *p = c;
+
+  /* If we found a valid match, advance the
+     stream pointer past the end of the word.  */
+  *ccp = p;
+
+  return psr;
+}
+
+/* Parse the input looking for a PSR flag.  */
+
+static int
+psr_required_here (char ** str)
+{
+  char * start = * str;
+  const struct asm_psr * psr;
+
+  psr = arm_psr_parse (str);
+
+  if (psr)
+    {
+      /* If this is the SPSR that is being modified, set the R bit.  */
+      if (! psr->cpsr)
+       inst.instruction |= SPSR_BIT;
+
+      /* Set the psr flags in the MSR instruction.  */
+      inst.instruction |= psr->field << PSR_SHIFT;
+
+      return SUCCESS;
+    }
+
+  /* In the few cases where we might be able to accept
+     something else this error can be overridden.  */
+  inst.error = _("flag for {c}psr instruction expected");
+
+  /* Restore the start point.  */
+  *str = start;
+  return FAIL;
+}
+
+static int
+co_proc_number (char ** str)
+{
+  int processor, pchar;
+  char *start;
+
+  skip_whitespace (*str);
+  start = *str;
+
+  /* The data sheet seems to imply that just a number on its own is valid
+     here, but the RISC iX assembler seems to accept a prefix 'p'.  We will
+     accept either.  */
+  if ((processor = arm_reg_parse (str, all_reg_maps[REG_TYPE_CP].htab))
+      == FAIL)
+    {
+      *str = start;
+
+      pchar = *(*str)++;
+      if (pchar >= '0' && pchar <= '9')
+       {
+         processor = pchar - '0';
+         if (**str >= '0' && **str <= '9')
+           {
+             processor = processor * 10 + *(*str)++ - '0';
+             if (processor > 15)
+               {
+                 inst.error = _("illegal co-processor number");
+                 return FAIL;
+               }
+           }
+       }
+      else
+       {
+         inst.error = all_reg_maps[REG_TYPE_CP].expected;
+         return FAIL;
+       }
+    }
+
+  inst.instruction |= processor << 8;
+  return SUCCESS;
+}
+
+static int
+cp_opc_expr (char ** str, int where, int length)
+{
+  expressionS expr;
+
+  skip_whitespace (* str);
+
+  memset (&expr, '\0', sizeof (expr));
+
+  if (my_get_expression (&expr, str))
+    return FAIL;
+  if (expr.X_op != O_constant)
+    {
+      inst.error = _("bad or missing expression");
+      return FAIL;
+    }
+
+  if ((expr.X_add_number & ((1 << length) - 1)) != expr.X_add_number)
+    {
+      inst.error = _("immediate co-processor expression too large");
+      return FAIL;
+    }
+
+  inst.instruction |= expr.X_add_number << where;
+  return SUCCESS;
+}
+
+static int
+cp_reg_required_here (char ** str, int where)
+{
+  int    reg;
+  char * start = *str;
+
+  if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_CN].htab)) != FAIL)
+    {
+      inst.instruction |= reg << where;
+      return reg;
+    }
+
+  /* In the few cases where we might be able to accept something else
+     this error can be overridden.  */
+  inst.error = all_reg_maps[REG_TYPE_CN].expected;
+
+  /* Restore the start point.  */
+  *str = start;
+  return FAIL;
+}
+
+static int
+fp_reg_required_here (char ** str, int where)
+{
+  int    reg;
+  char * start = * str;
+
+  if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_FN].htab)) != FAIL)
+    {
+      inst.instruction |= reg << where;
+      return reg;
+    }
+
+  /* In the few cases where we might be able to accept something else
+     this error can be overridden.  */
+  inst.error = all_reg_maps[REG_TYPE_FN].expected;
+
+  /* Restore the start point.  */
+  *str = start;
+  return FAIL;
+}
+
+static int
+cp_address_offset (char ** str)
+{
+  int offset;
+
+  skip_whitespace (* str);
+
+  if (! is_immediate_prefix (**str))
+    {
+      inst.error = _("immediate expression expected");
+      return FAIL;
+    }
+
+  (*str)++;
+
+  if (my_get_expression (& inst.reloc.exp, str))
+    return FAIL;
+
+  if (inst.reloc.exp.X_op == O_constant)
+    {
+      offset = inst.reloc.exp.X_add_number;
+
+      if (offset & 3)
+       {
+         inst.error = _("co-processor address must be word aligned");
+         return FAIL;
+       }
+
+      if (offset > 1023 || offset < -1023)
+       {
+         inst.error = _("offset too large");
+         return FAIL;
+       }
+
+      if (offset >= 0)
+       inst.instruction |= INDEX_UP;
+      else
+       offset = -offset;
+
+      inst.instruction |= offset >> 2;
+    }
+  else
+    inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM;
+
+  return SUCCESS;
+}
+
+static int
+cp_address_required_here (char ** str, int wb_ok)
+{
+  char * p = * str;
+  int    pre_inc = 0;
+  int    write_back = 0;
+
+  if (*p == '[')
+    {
+      int reg;
+
+      p++;
+      skip_whitespace (p);
+
+      if ((reg = reg_required_here (& p, 16)) == FAIL)
+       return FAIL;
+
+      skip_whitespace (p);
+
+      if (*p == ']')
+       {
+         p++;
+
+         skip_whitespace (p);
+
+         if (*p == '\0')
+           {
+             /* As an extension to the official ARM syntax we allow:
+                  [Rn]
+                as a short hand for:
+                  [Rn,#0]  */
+             inst.instruction |= PRE_INDEX | INDEX_UP;
+             *str = p;
+             return SUCCESS;
+           }
+
+         if (skip_past_comma (& p) == FAIL)
+           {
+             inst.error = _("comma expected after closing square bracket");
+             return FAIL;
+           }
+
+         skip_whitespace (p);
+
+         if (*p == '#')
+           {
+             if (wb_ok)
+               {
+                 /* [Rn], #expr  */
+                 write_back = WRITE_BACK;
+
+                 if (reg == REG_PC)
+                   {
+                     inst.error = _("pc may not be used in post-increment");
+                     return FAIL;
+                   }
+
+                 if (cp_address_offset (& p) == FAIL)
+                   return FAIL;
+               }
+             else
+               pre_inc = PRE_INDEX | INDEX_UP;
+           }
+         else if (*p == '{')
+           {
+             int option;
+
+             /* [Rn], {<expr>}  */
+             p++;
+
+             skip_whitespace (p);
+
+             if (my_get_expression (& inst.reloc.exp, & p))
+               return FAIL;
+
+             if (inst.reloc.exp.X_op == O_constant)
+               {
+                 option = inst.reloc.exp.X_add_number;
+
+                 if (option > 255 || option < 0)
+                   {
+                     inst.error = _("'option' field too large");
+                     return FAIL;
+                   }
+
+                 skip_whitespace (p);
+
+                 if (*p != '}')
+                   {
+                     inst.error = _("'}' expected at end of 'option' field");
+                     return FAIL;
+                   }
+                 else
+                   {
+                     p++;
+                     inst.instruction |= option;
+                     inst.instruction |= INDEX_UP;
+                   }
+               }
+             else
+               {
+                 inst.error = _("non-constant expressions for 'option' field not supported");
+                 return FAIL;
+               }
+           }
+         else
+           {
+             inst.error = _("# or { expected after comma");
+             return FAIL;
+           }
+       }
+      else
+       {
+         /* '['Rn, #expr']'[!]  */
+
+         if (skip_past_comma (& p) == FAIL)
+           {
+             inst.error = _("pre-indexed expression expected");
+             return FAIL;
+           }
+
+         pre_inc = PRE_INDEX;
+
+         if (cp_address_offset (& p) == FAIL)
+           return FAIL;
+
+         skip_whitespace (p);
+
+         if (*p++ != ']')
+           {
+             inst.error = _("missing ]");
+             return FAIL;
+           }
+
+         skip_whitespace (p);
+
+         if (wb_ok && *p == '!')
+           {
+             if (reg == REG_PC)
+               {
+                 inst.error = _("pc may not be used with write-back");
+                 return FAIL;
+               }
+
+             p++;
+             write_back = WRITE_BACK;
+           }
+       }
+    }
+  else
+    {
+      if (my_get_expression (&inst.reloc.exp, &p))
+       return FAIL;
+
+      inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM;
+      inst.reloc.exp.X_add_number -= 8;  /* PC rel adjust.  */
+      inst.reloc.pc_rel = 1;
+      inst.instruction |= (REG_PC << 16);
+      pre_inc = PRE_INDEX;
+    }
+
+  inst.instruction |= write_back | pre_inc;
+  *str = p;
+  return SUCCESS;
+}
+
+static int
+cp_byte_address_offset (char ** str)
+{
+  int offset;
+
+  skip_whitespace (* str);
+
+  if (! is_immediate_prefix (**str))
+    {
+      inst.error = _("immediate expression expected");
+      return FAIL;
+    }
+
+  (*str)++;
+
+  if (my_get_expression (& inst.reloc.exp, str))
+    return FAIL;
+
+  if (inst.reloc.exp.X_op == O_constant)
+    {
+      offset = inst.reloc.exp.X_add_number;
+
+      if (offset > 255 || offset < -255)
+        {
+          inst.error = _("offset too large");
+          return FAIL;
+        }
+
+      if (offset >= 0)
+        inst.instruction |= INDEX_UP;
+      else
+        offset = -offset;
+
+      inst.instruction |= offset;
+    }
+  else
+    inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM_S2;
 
-  {"acss",       0xeec08100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"acssp",      0xeec08120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"acssm",      0xeec08140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"acssz",      0xeec08160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"acsd",       0xeec08180, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"acsdp",      0xeec081a0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"acsdm",      0xeec081c0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"acsdz",      0xeec081e0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"acse",       0xeec88100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"acsep",      0xeec88120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"acsem",      0xeec88140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"acsez",      0xeec88160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  return SUCCESS;
+}
 
-  {"atns",       0xeed08100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"atnsp",      0xeed08120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"atnsm",      0xeed08140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"atnsz",      0xeed08160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"atnd",       0xeed08180, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"atndp",      0xeed081a0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"atndm",      0xeed081c0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"atndz",      0xeed081e0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"atne",       0xeed88100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"atnep",      0xeed88120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"atnem",      0xeed88140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"atnez",      0xeed88160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+static int
+cp_byte_address_required_here (char ** str)
+{
+  char * p = * str;
+  int    pre_inc = 0;
+  int    write_back = 0;
 
-  {"urds",       0xeee08100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"urdsp",      0xeee08120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"urdsm",      0xeee08140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"urdsz",      0xeee08160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"urdd",       0xeee08180, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"urddp",      0xeee081a0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"urddm",      0xeee081c0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"urddz",      0xeee081e0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"urde",       0xeee88100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"urdep",      0xeee88120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"urdem",      0xeee88140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"urdez",      0xeee88160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  if (*p == '[')
+    {
+      int reg;
 
-  {"nrms",       0xeef08100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"nrmsp",      0xeef08120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"nrmsm",      0xeef08140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"nrmsz",      0xeef08160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"nrmd",       0xeef08180, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"nrmdp",      0xeef081a0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"nrmdm",      0xeef081c0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"nrmdz",      0xeef081e0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"nrme",       0xeef88100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"nrmep",      0xeef88120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"nrmem",      0xeef88140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
-  {"nrmez",      0xeef88160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+      p++;
+      skip_whitespace (p);
 
-  {"adfs",       0xee000100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"adfsp",      0xee000120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"adfsm",      0xee000140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"adfsz",      0xee000160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"adfd",       0xee000180, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"adfdp",      0xee0001a0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"adfdm",      0xee0001c0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"adfdz",      0xee0001e0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"adfe",       0xee080100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"adfep",      0xee080120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"adfem",      0xee080140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"adfez",      0xee080160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+      if ((reg = reg_required_here (& p, 16)) == FAIL)
+        return FAIL;
 
-  {"sufs",       0xee200100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"sufsp",      0xee200120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"sufsm",      0xee200140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"sufsz",      0xee200160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"sufd",       0xee200180, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"sufdp",      0xee2001a0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"sufdm",      0xee2001c0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"sufdz",      0xee2001e0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"sufe",       0xee280100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"sufep",      0xee280120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"sufem",      0xee280140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"sufez",      0xee280160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+      skip_whitespace (p);
 
-  {"rsfs",       0xee300100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rsfsp",      0xee300120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rsfsm",      0xee300140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rsfsz",      0xee300160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rsfd",       0xee300180, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rsfdp",      0xee3001a0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rsfdm",      0xee3001c0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rsfdz",      0xee3001e0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rsfe",       0xee380100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rsfep",      0xee380120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rsfem",      0xee380140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rsfez",      0xee380160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+      if (*p == ']')
+        {
+          p++;
+
+          if (skip_past_comma (& p) == SUCCESS)
+            {
+              /* [Rn], #expr */
+              write_back = WRITE_BACK;
+
+              if (reg == REG_PC)
+                {
+                  inst.error = _("pc may not be used in post-increment");
+                  return FAIL;
+                }
+
+              if (cp_byte_address_offset (& p) == FAIL)
+                return FAIL;
+            }
+          else
+            pre_inc = PRE_INDEX | INDEX_UP;
+        }
+      else
+        {
+          /* '['Rn, #expr']'[!] */
 
-  {"mufs",       0xee100100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"mufsp",      0xee100120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"mufsm",      0xee100140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"mufsz",      0xee100160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"mufd",       0xee100180, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"mufdp",      0xee1001a0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"mufdm",      0xee1001c0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"mufdz",      0xee1001e0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"mufe",       0xee180100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"mufep",      0xee180120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"mufem",      0xee180140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"mufez",      0xee180160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+          if (skip_past_comma (& p) == FAIL)
+            {
+              inst.error = _("pre-indexed expression expected");
+              return FAIL;
+            }
 
-  {"dvfs",       0xee400100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"dvfsp",      0xee400120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"dvfsm",      0xee400140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"dvfsz",      0xee400160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"dvfd",       0xee400180, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"dvfdp",      0xee4001a0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"dvfdm",      0xee4001c0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"dvfdz",      0xee4001e0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"dvfe",       0xee480100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"dvfep",      0xee480120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"dvfem",      0xee480140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"dvfez",      0xee480160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+          pre_inc = PRE_INDEX;
 
-  {"rdfs",       0xee500100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rdfsp",      0xee500120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rdfsm",      0xee500140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rdfsz",      0xee500160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rdfd",       0xee500180, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rdfdp",      0xee5001a0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rdfdm",      0xee5001c0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rdfdz",      0xee5001e0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rdfe",       0xee580100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rdfep",      0xee580120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rdfem",      0xee580140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rdfez",      0xee580160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+          if (cp_byte_address_offset (& p) == FAIL)
+            return FAIL;
 
-  {"pows",       0xee600100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"powsp",      0xee600120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"powsm",      0xee600140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"powsz",      0xee600160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"powd",       0xee600180, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"powdp",      0xee6001a0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"powdm",      0xee6001c0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"powdz",      0xee6001e0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"powe",       0xee680100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"powep",      0xee680120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"powem",      0xee680140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"powez",      0xee680160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+          skip_whitespace (p);
 
-  {"rpws",       0xee700100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rpwsp",      0xee700120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rpwsm",      0xee700140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rpwsz",      0xee700160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rpwd",       0xee700180, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rpwdp",      0xee7001a0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rpwdm",      0xee7001c0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rpwdz",      0xee7001e0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rpwe",       0xee780100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rpwep",      0xee780120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rpwem",      0xee780140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rpwez",      0xee780160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+          if (*p++ != ']')
+            {
+              inst.error = _("missing ]");
+              return FAIL;
+            }
 
-  {"rmfs",       0xee800100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rmfsp",      0xee800120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rmfsm",      0xee800140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rmfsz",      0xee800160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rmfd",       0xee800180, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rmfdp",      0xee8001a0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rmfdm",      0xee8001c0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rmfdz",      0xee8001e0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rmfe",       0xee880100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rmfep",      0xee880120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rmfem",      0xee880140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"rmfez",      0xee880160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+          skip_whitespace (p);
 
-  {"fmls",       0xee900100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"fmlsp",      0xee900120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"fmlsm",      0xee900140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"fmlsz",      0xee900160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"fmld",       0xee900180, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"fmldp",      0xee9001a0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"fmldm",      0xee9001c0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"fmldz",      0xee9001e0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"fmle",       0xee980100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"fmlep",      0xee980120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"fmlem",      0xee980140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"fmlez",      0xee980160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+          if (*p == '!')
+            {
+              if (reg == REG_PC)
+                {
+                  inst.error = _("pc may not be used with write-back");
+                  return FAIL;
+                }
+
+              p++;
+              write_back = WRITE_BACK;
+            }
+        }
+    }
+  else
+    {
+      if (my_get_expression (&inst.reloc.exp, &p))
+        return FAIL;
+
+      inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM_S2;
+      inst.reloc.exp.X_add_number -= 8;  /* PC rel adjust.  */
+      inst.reloc.pc_rel = 1;
+      inst.instruction |= (REG_PC << 16);
+      pre_inc = PRE_INDEX;
+    }
+
+  inst.instruction |= write_back | pre_inc;
+  *str = p;
+  return SUCCESS;
+}
+
+static void
+do_nop (char * str)
+{
+  skip_whitespace (str);
+  if (*str == '{')
+    {
+      str++;
+
+      if (my_get_expression (&inst.reloc.exp, &str))
+       inst.reloc.exp.X_op = O_illegal;
+      else
+       {
+         skip_whitespace (str);
+         if (*str == '}')
+           str++;
+         else
+           inst.reloc.exp.X_op = O_illegal;
+       }
+
+      if (inst.reloc.exp.X_op != O_constant
+         || inst.reloc.exp.X_add_number > 255
+         || inst.reloc.exp.X_add_number < 0)
+       {
+         inst.error = _("Invalid NOP hint");
+         return;
+       }
+
+      /* Arcitectural NOP hints are CPSR sets with no bits selected.  */
+      inst.instruction &= 0xf0000000;
+      inst.instruction |= 0x0320f000 + inst.reloc.exp.X_add_number;
+    }
+
+  end_of_line (str);
+}
+
+static void
+do_empty (char * str)
+{
+  /* Do nothing really.  */
+  end_of_line (str);
+}
+
+static void
+do_mrs (char * str)
+{
+  int skip = 0;
+
+  /* Only one syntax.  */
+  skip_whitespace (str);
+
+  if (reg_required_here (&str, 12) == FAIL)
+    {
+      inst.error = BAD_ARGS;
+      return;
+    }
+
+  if (skip_past_comma (&str) == FAIL)
+    {
+      inst.error = _("comma expected after register name");
+      return;
+    }
+
+  skip_whitespace (str);
+
+  if (   streq (str, "CPSR")
+      || streq (str, "SPSR")
+        /* Lower case versions for backwards compatibility.  */
+      || streq (str, "cpsr")
+      || streq (str, "spsr"))
+    skip = 4;
+
+  /* This is for backwards compatibility with older toolchains.  */
+  else if (   streq (str, "cpsr_all")
+          || streq (str, "spsr_all"))
+    skip = 8;
+  else
+    {
+      inst.error = _("CPSR or SPSR expected");
+      return;
+    }
 
-  {"fdvs",       0xeea00100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"fdvsp",      0xeea00120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"fdvsm",      0xeea00140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"fdvsz",      0xeea00160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"fdvd",       0xeea00180, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"fdvdp",      0xeea001a0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"fdvdm",      0xeea001c0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"fdvdz",      0xeea001e0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"fdve",       0xeea80100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"fdvep",      0xeea80120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"fdvem",      0xeea80140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"fdvez",      0xeea80160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  if (* str == 's' || * str == 'S')
+    inst.instruction |= SPSR_BIT;
+  str += skip;
 
-  {"frds",       0xeeb00100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"frdsp",      0xeeb00120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"frdsm",      0xeeb00140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"frdsz",      0xeeb00160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"frdd",       0xeeb00180, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"frddp",      0xeeb001a0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"frddm",      0xeeb001c0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"frddz",      0xeeb001e0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"frde",       0xeeb80100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"frdep",      0xeeb80120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"frdem",      0xeeb80140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"frdez",      0xeeb80160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  end_of_line (str);
+}
 
-  {"pols",       0xeec00100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"polsp",      0xeec00120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"polsm",      0xeec00140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"polsz",      0xeec00160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"pold",       0xeec00180, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"poldp",      0xeec001a0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"poldm",      0xeec001c0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"poldz",      0xeec001e0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"pole",       0xeec80100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"polep",      0xeec80120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"polem",      0xeec80140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
-  {"polez",      0xeec80160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+/* Two possible forms:
+      "{C|S}PSR_<field>, Rm",
+      "{C|S}PSR_f, #expression".  */
 
-  {"cmf",        0xee90f110, 3,  FPU_FPA_EXT_V1,   do_fpa_cmp},
-  {"cmfe",       0xeed0f110, 3,  FPU_FPA_EXT_V1,   do_fpa_cmp},
-  {"cnf",        0xeeb0f110, 3,  FPU_FPA_EXT_V1,   do_fpa_cmp},
-  {"cnfe",       0xeef0f110, 3,  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",       0xeed0f110, 4,  FPU_FPA_EXT_V1,   do_fpa_cmp},
-  {"cnfe",       0xeef0f110, 4,  FPU_FPA_EXT_V1,   do_fpa_cmp},
+static void
+do_msr (char * str)
+{
+  skip_whitespace (str);
 
-  {"flts",       0xee000110, 3,  FPU_FPA_EXT_V1,   do_fpa_from_reg},
-  {"fltsp",      0xee000130, 3,  FPU_FPA_EXT_V1,   do_fpa_from_reg},
-  {"fltsm",      0xee000150, 3,  FPU_FPA_EXT_V1,   do_fpa_from_reg},
-  {"fltsz",      0xee000170, 3,  FPU_FPA_EXT_V1,   do_fpa_from_reg},
-  {"fltd",       0xee000190, 3,  FPU_FPA_EXT_V1,   do_fpa_from_reg},
-  {"fltdp",      0xee0001b0, 3,  FPU_FPA_EXT_V1,   do_fpa_from_reg},
-  {"fltdm",      0xee0001d0, 3,  FPU_FPA_EXT_V1,   do_fpa_from_reg},
-  {"fltdz",      0xee0001f0, 3,  FPU_FPA_EXT_V1,   do_fpa_from_reg},
-  {"flte",       0xee080110, 3,  FPU_FPA_EXT_V1,   do_fpa_from_reg},
-  {"fltep",      0xee080130, 3,  FPU_FPA_EXT_V1,   do_fpa_from_reg},
-  {"fltem",      0xee080150, 3,  FPU_FPA_EXT_V1,   do_fpa_from_reg},
-  {"fltez",      0xee080170, 3,  FPU_FPA_EXT_V1,   do_fpa_from_reg},
+  if (psr_required_here (& str) == FAIL)
+    return;
 
-  /* The implementation of the FIX instruction is broken on some
-     assemblers, 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.  */
-  {"fix",        0xee100110, 3,  FPU_FPA_EXT_V1,   do_fpa_to_reg},
-  {"fixp",       0xee100130, 3,  FPU_FPA_EXT_V1,   do_fpa_to_reg},
-  {"fixm",       0xee100150, 3,  FPU_FPA_EXT_V1,   do_fpa_to_reg},
-  {"fixz",       0xee100170, 3,  FPU_FPA_EXT_V1,   do_fpa_to_reg},
-  {"fixsp",      0xee100130, 3,  FPU_FPA_EXT_V1,   do_fpa_to_reg},
-  {"fixsm",      0xee100150, 3,  FPU_FPA_EXT_V1,   do_fpa_to_reg},
-  {"fixsz",      0xee100170, 3,  FPU_FPA_EXT_V1,   do_fpa_to_reg},
-  {"fixdp",      0xee100130, 3,  FPU_FPA_EXT_V1,   do_fpa_to_reg},
-  {"fixdm",      0xee100150, 3,  FPU_FPA_EXT_V1,   do_fpa_to_reg},
-  {"fixdz",      0xee100170, 3,  FPU_FPA_EXT_V1,   do_fpa_to_reg},
-  {"fixep",      0xee100130, 3,  FPU_FPA_EXT_V1,   do_fpa_to_reg},
-  {"fixem",      0xee100150, 3,  FPU_FPA_EXT_V1,   do_fpa_to_reg},
-  {"fixez",      0xee100170, 3,  FPU_FPA_EXT_V1,   do_fpa_to_reg},
+  if (skip_past_comma (& str) == FAIL)
+    {
+      inst.error = _("comma missing after psr flags");
+      return;
+    }
 
-  /* Instructions that were new with the real FPA, call them V2.  */
-  {"lfm",        0xec100200, 3,  FPU_FPA_EXT_V2,   do_fpa_ldmstm},
-  {"lfmfd",      0xec900200, 3,  FPU_FPA_EXT_V2,   do_fpa_ldmstm},
-  {"lfmea",      0xed100200, 3,  FPU_FPA_EXT_V2,   do_fpa_ldmstm},
-  {"sfm",        0xec000200, 3,  FPU_FPA_EXT_V2,   do_fpa_ldmstm},
-  {"sfmfd",      0xed000200, 3,  FPU_FPA_EXT_V2,   do_fpa_ldmstm},
-  {"sfmea",      0xec800200, 3,  FPU_FPA_EXT_V2,   do_fpa_ldmstm},
+  skip_whitespace (str);
 
-  /* VFP V1xD (single precision).  */
-  /* Moves and type conversions.  */
-  {"fcpys",   0xeeb00a40, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
-  {"fmrs",    0xee100a10, 4, FPU_VFP_EXT_V1xD, do_vfp_reg_from_sp},
-  {"fmsr",    0xee000a10, 4, FPU_VFP_EXT_V1xD, do_vfp_sp_from_reg},
-  {"fmstat",  0xeef1fa10, 6, FPU_VFP_EXT_V1xD, do_empty},
-  {"fsitos",  0xeeb80ac0, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
-  {"fuitos",  0xeeb80a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
-  {"ftosis",  0xeebd0a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
-  {"ftosizs", 0xeebd0ac0, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
-  {"ftouis",  0xeebc0a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
-  {"ftouizs", 0xeebc0ac0, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
-  {"fmrx",    0xeef00a10, 4, FPU_VFP_EXT_V1xD, do_vfp_reg_from_ctrl},
-  {"fmxr",    0xeee00a10, 4, FPU_VFP_EXT_V1xD, do_vfp_ctrl_from_reg},
+  if (reg_required_here (& str, 0) != FAIL)
+    {
+      inst.error = NULL;
+      end_of_line (str);
+      return;
+    }
 
-  /* Memory operations.  */
-  {"flds",    0xed100a00, 4, FPU_VFP_EXT_V1xD, do_vfp_sp_ldst},
-  {"fsts",    0xed000a00, 4, FPU_VFP_EXT_V1xD, do_vfp_sp_ldst},
-  {"fldmias", 0xec900a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmia},
-  {"fldmfds", 0xec900a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmia},
-  {"fldmdbs", 0xed300a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmdb},
-  {"fldmeas", 0xed300a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmdb},
-  {"fldmiax", 0xec900b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmia},
-  {"fldmfdx", 0xec900b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmia},
-  {"fldmdbx", 0xed300b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmdb},
-  {"fldmeax", 0xed300b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmdb},
-  {"fstmias", 0xec800a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmia},
-  {"fstmeas", 0xec800a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmia},
-  {"fstmdbs", 0xed200a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmdb},
-  {"fstmfds", 0xed200a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmdb},
-  {"fstmiax", 0xec800b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmia},
-  {"fstmeax", 0xec800b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmia},
-  {"fstmdbx", 0xed200b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmdb},
-  {"fstmfdx", 0xed200b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmdb},
+  if (! is_immediate_prefix (* str))
+    {
+      inst.error =
+       _("only a register or immediate value can follow a psr flag");
+      return;
+    }
 
-  /* Monadic operations.  */
-  {"fabss",   0xeeb00ac0, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
-  {"fnegs",   0xeeb10a40, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
-  {"fsqrts",  0xeeb10ac0, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
+  str ++;
+  inst.error = NULL;
 
-  /* Dyadic operations.  */
-  {"fadds",   0xee300a00, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
-  {"fsubs",   0xee300a40, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
-  {"fmuls",   0xee200a00, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
-  {"fdivs",   0xee800a00, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
-  {"fmacs",   0xee000a00, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
-  {"fmscs",   0xee100a00, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
-  {"fnmuls",  0xee200a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
-  {"fnmacs",  0xee000a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
-  {"fnmscs",  0xee100a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
+  if (my_get_expression (& inst.reloc.exp, & str))
+    {
+      inst.error =
+       _("only a register or immediate value can follow a psr flag");
+      return;
+    }
 
-  /* Comparisons.  */
-  {"fcmps",   0xeeb40a40, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
-  {"fcmpzs",  0xeeb50a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_compare_z},
-  {"fcmpes",  0xeeb40ac0, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
-  {"fcmpezs", 0xeeb50ac0, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_compare_z},
+#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
 
-  /* VFP V1 (Double precision).  */
-  /* Moves and type conversions.  */
-  {"fcpyd",   0xeeb00b40, 5, FPU_VFP_EXT_V1,   do_vfp_dp_monadic},
-  {"fcvtds",  0xeeb70ac0, 6, FPU_VFP_EXT_V1,   do_vfp_dp_sp_cvt},
-  {"fcvtsd",  0xeeb70bc0, 6, FPU_VFP_EXT_V1,   do_vfp_sp_dp_cvt},
-  {"fmdhr",   0xee200b10, 5, FPU_VFP_EXT_V1,   do_vfp_dp_from_reg},
-  {"fmdlr",   0xee000b10, 5, FPU_VFP_EXT_V1,   do_vfp_dp_from_reg},
-  {"fmrdh",   0xee300b10, 5, FPU_VFP_EXT_V1,   do_vfp_reg_from_dp},
-  {"fmrdl",   0xee100b10, 5, FPU_VFP_EXT_V1,   do_vfp_reg_from_dp},
-  {"fsitod",  0xeeb80bc0, 6, FPU_VFP_EXT_V1,   do_vfp_dp_sp_cvt},
-  {"fuitod",  0xeeb80b40, 6, FPU_VFP_EXT_V1,   do_vfp_dp_sp_cvt},
-  {"ftosid",  0xeebd0b40, 6, FPU_VFP_EXT_V1,   do_vfp_sp_dp_cvt},
-  {"ftosizd", 0xeebd0bc0, 7, FPU_VFP_EXT_V1,   do_vfp_sp_dp_cvt},
-  {"ftouid",  0xeebc0b40, 6, FPU_VFP_EXT_V1,   do_vfp_sp_dp_cvt},
-  {"ftouizd", 0xeebc0bc0, 7, FPU_VFP_EXT_V1,   do_vfp_sp_dp_cvt},
+  inst.instruction |= INST_IMMEDIATE;
 
-  /* Memory operations.  */
-  {"fldd",    0xed100b00, 4, FPU_VFP_EXT_V1,   do_vfp_dp_ldst},
-  {"fstd",    0xed000b00, 4, FPU_VFP_EXT_V1,   do_vfp_dp_ldst},
-  {"fldmiad", 0xec900b00, 7, FPU_VFP_EXT_V1,   do_vfp_dp_ldstmia},
-  {"fldmfdd", 0xec900b00, 7, FPU_VFP_EXT_V1,   do_vfp_dp_ldstmia},
-  {"fldmdbd", 0xed300b00, 7, FPU_VFP_EXT_V1,   do_vfp_dp_ldstmdb},
-  {"fldmead", 0xed300b00, 7, FPU_VFP_EXT_V1,   do_vfp_dp_ldstmdb},
-  {"fstmiad", 0xec800b00, 7, FPU_VFP_EXT_V1,   do_vfp_dp_ldstmia},
-  {"fstmead", 0xec800b00, 7, FPU_VFP_EXT_V1,   do_vfp_dp_ldstmia},
-  {"fstmdbd", 0xed200b00, 7, FPU_VFP_EXT_V1,   do_vfp_dp_ldstmdb},
-  {"fstmfdd", 0xed200b00, 7, FPU_VFP_EXT_V1,   do_vfp_dp_ldstmdb},
+  if (inst.reloc.exp.X_add_symbol)
+    {
+      inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
+      inst.reloc.pc_rel = 0;
+    }
+  else
+    {
+      unsigned value = validate_immediate (inst.reloc.exp.X_add_number);
 
-  /* Monadic operations.  */
-  {"fabsd",   0xeeb00bc0, 5, FPU_VFP_EXT_V1,   do_vfp_dp_monadic},
-  {"fnegd",   0xeeb10b40, 5, FPU_VFP_EXT_V1,   do_vfp_dp_monadic},
-  {"fsqrtd",  0xeeb10bc0, 6, FPU_VFP_EXT_V1,   do_vfp_dp_monadic},
+      if (value == (unsigned) FAIL)
+       {
+         inst.error = _("invalid constant");
+         return;
+       }
 
-  /* Dyadic operations.  */
-  {"faddd",   0xee300b00, 5, FPU_VFP_EXT_V1,   do_vfp_dp_dyadic},
-  {"fsubd",   0xee300b40, 5, FPU_VFP_EXT_V1,   do_vfp_dp_dyadic},
-  {"fmuld",   0xee200b00, 5, FPU_VFP_EXT_V1,   do_vfp_dp_dyadic},
-  {"fdivd",   0xee800b00, 5, FPU_VFP_EXT_V1,   do_vfp_dp_dyadic},
-  {"fmacd",   0xee000b00, 5, FPU_VFP_EXT_V1,   do_vfp_dp_dyadic},
-  {"fmscd",   0xee100b00, 5, FPU_VFP_EXT_V1,   do_vfp_dp_dyadic},
-  {"fnmuld",  0xee200b40, 6, FPU_VFP_EXT_V1,   do_vfp_dp_dyadic},
-  {"fnmacd",  0xee000b40, 6, FPU_VFP_EXT_V1,   do_vfp_dp_dyadic},
-  {"fnmscd",  0xee100b40, 6, FPU_VFP_EXT_V1,   do_vfp_dp_dyadic},
+      inst.instruction |= value;
+    }
+
+  inst.error = NULL;
+  end_of_line (str);
+}
+
+/* Long Multiply Parser
+   UMULL RdLo, RdHi, Rm, Rs
+   SMULL RdLo, RdHi, Rm, Rs
+   UMLAL RdLo, RdHi, Rm, Rs
+   SMLAL RdLo, RdHi, Rm, Rs.  */
+
+static void
+do_mull (char * str)
+{
+  int rdlo, rdhi, rm, rs;
 
-  /* Comparisons.  */
-  {"fcmpd",   0xeeb40b40, 5, FPU_VFP_EXT_V1,   do_vfp_dp_monadic},
-  {"fcmpzd",  0xeeb50b40, 6, FPU_VFP_EXT_V1,   do_vfp_dp_compare_z},
-  {"fcmped",  0xeeb40bc0, 6, FPU_VFP_EXT_V1,   do_vfp_dp_monadic},
-  {"fcmpezd", 0xeeb50bc0, 7, FPU_VFP_EXT_V1,   do_vfp_dp_compare_z},
+  /* Only one format "rdlo, rdhi, rm, rs".  */
+  skip_whitespace (str);
 
-  /* VFP V2.  */
-  {"fmsrr",   0xec400a10, 5, FPU_VFP_EXT_V2,   do_vfp_sp_reg2},
-  {"fmrrs",   0xec500a10, 5, FPU_VFP_EXT_V2,   do_vfp_sp_reg2},
-  {"fmdrr",   0xec400b10, 5, FPU_VFP_EXT_V2,   do_vfp_dp_from_reg2},
-  {"fmrrd",   0xec500b10, 5, FPU_VFP_EXT_V2,   do_vfp_reg2_from_dp},
+  if ((rdlo = reg_required_here (&str, 12)) == FAIL)
+    {
+      inst.error = BAD_ARGS;
+      return;
+    }
 
-  /* Intel XScale extensions to ARM V5 ISA.  (All use CP0).  */
-  {"mia",        0xee200010, 3,  ARM_CEXT_XSCALE,   do_xsc_mia},
-  {"miaph",      0xee280010, 5,  ARM_CEXT_XSCALE,   do_xsc_mia},
-  {"miabb",      0xee2c0010, 5,  ARM_CEXT_XSCALE,   do_xsc_mia},
-  {"miabt",      0xee2d0010, 5,  ARM_CEXT_XSCALE,   do_xsc_mia},
-  {"miatb",      0xee2e0010, 5,  ARM_CEXT_XSCALE,   do_xsc_mia},
-  {"miatt",      0xee2f0010, 5,  ARM_CEXT_XSCALE,   do_xsc_mia},
-  {"mar",        0xec400000, 3,  ARM_CEXT_XSCALE,   do_xsc_mar},
-  {"mra",        0xec500000, 3,  ARM_CEXT_XSCALE,   do_xsc_mra},
+  if (skip_past_comma (&str) == FAIL
+      || (rdhi = reg_required_here (&str, 16)) == FAIL)
+    {
+      inst.error = BAD_ARGS;
+      return;
+    }
 
-  /* Cirrus Maverick instructions.  */
-  {"cfldrs",     0xec100400, 6,  ARM_CEXT_MAVERICK, do_mav_ldst_1},
-  {"cfldrd",     0xec500400, 6,  ARM_CEXT_MAVERICK, do_mav_ldst_2},
-  {"cfldr32",    0xec100500, 7,  ARM_CEXT_MAVERICK, do_mav_ldst_3},
-  {"cfldr64",    0xec500500, 7,  ARM_CEXT_MAVERICK, do_mav_ldst_4},
-  {"cfstrs",     0xec000400, 6,  ARM_CEXT_MAVERICK, do_mav_ldst_1},
-  {"cfstrd",     0xec400400, 6,  ARM_CEXT_MAVERICK, do_mav_ldst_2},
-  {"cfstr32",    0xec000500, 7,  ARM_CEXT_MAVERICK, do_mav_ldst_3},
-  {"cfstr64",    0xec400500, 7,  ARM_CEXT_MAVERICK, do_mav_ldst_4},
-  {"cfmvsr",     0xee000450, 6,  ARM_CEXT_MAVERICK, do_mav_binops_2a},
-  {"cfmvrs",     0xee100450, 6,  ARM_CEXT_MAVERICK, do_mav_binops_1a},
-  {"cfmvdlr",    0xee000410, 7,  ARM_CEXT_MAVERICK, do_mav_binops_2b},
-  {"cfmvrdl",    0xee100410, 7,  ARM_CEXT_MAVERICK, do_mav_binops_1b},
-  {"cfmvdhr",    0xee000430, 7,  ARM_CEXT_MAVERICK, do_mav_binops_2b},
-  {"cfmvrdh",    0xee100430, 7,  ARM_CEXT_MAVERICK, do_mav_binops_1b},
-  {"cfmv64lr",   0xee000510, 8,  ARM_CEXT_MAVERICK, do_mav_binops_2c},
-  {"cfmvr64l",   0xee100510, 8,  ARM_CEXT_MAVERICK, do_mav_binops_1c},
-  {"cfmv64hr",   0xee000530, 8,  ARM_CEXT_MAVERICK, do_mav_binops_2c},
-  {"cfmvr64h",   0xee100530, 8,  ARM_CEXT_MAVERICK, do_mav_binops_1c},
-  {"cfmval32",   0xee100610, 8,  ARM_CEXT_MAVERICK, do_mav_binops_3a},
-  {"cfmv32al",   0xee000610, 8,  ARM_CEXT_MAVERICK, do_mav_binops_3b},
-  {"cfmvam32",   0xee100630, 8,  ARM_CEXT_MAVERICK, do_mav_binops_3a},
-  {"cfmv32am",   0xee000630, 8,  ARM_CEXT_MAVERICK, do_mav_binops_3b},
-  {"cfmvah32",   0xee100650, 8,  ARM_CEXT_MAVERICK, do_mav_binops_3a},
-  {"cfmv32ah",   0xee000650, 8,  ARM_CEXT_MAVERICK, do_mav_binops_3b},
-  {"cfmva32",    0xee100670, 7,  ARM_CEXT_MAVERICK, do_mav_binops_3a},
-  {"cfmv32a",    0xee000670, 7,  ARM_CEXT_MAVERICK, do_mav_binops_3b},
-  {"cfmva64",    0xee100690, 7,  ARM_CEXT_MAVERICK, do_mav_binops_3c},
-  {"cfmv64a",    0xee000690, 7,  ARM_CEXT_MAVERICK, do_mav_binops_3d},
-  {"cfmvsc32",   0xee1006b0, 8,  ARM_CEXT_MAVERICK, do_mav_dspsc_1},
-  {"cfmv32sc",   0xee0006b0, 8,  ARM_CEXT_MAVERICK, do_mav_dspsc_2},
-  {"cfcpys",     0xee000400, 6,  ARM_CEXT_MAVERICK, do_mav_binops_1d},
-  {"cfcpyd",     0xee000420, 6,  ARM_CEXT_MAVERICK, do_mav_binops_1e},
-  {"cfcvtsd",    0xee000460, 7,  ARM_CEXT_MAVERICK, do_mav_binops_1f},
-  {"cfcvtds",    0xee000440, 7,  ARM_CEXT_MAVERICK, do_mav_binops_1g},
-  {"cfcvt32s",   0xee000480, 8,  ARM_CEXT_MAVERICK, do_mav_binops_1h},
-  {"cfcvt32d",   0xee0004a0, 8,  ARM_CEXT_MAVERICK, do_mav_binops_1i},
-  {"cfcvt64s",   0xee0004c0, 8,  ARM_CEXT_MAVERICK, do_mav_binops_1j},
-  {"cfcvt64d",   0xee0004e0, 8,  ARM_CEXT_MAVERICK, do_mav_binops_1k},
-  {"cfcvts32",   0xee100580, 8,  ARM_CEXT_MAVERICK, do_mav_binops_1l},
-  {"cfcvtd32",   0xee1005a0, 8,  ARM_CEXT_MAVERICK, do_mav_binops_1m},
-  {"cftruncs32", 0xee1005c0, 10, ARM_CEXT_MAVERICK, do_mav_binops_1l},
-  {"cftruncd32", 0xee1005e0, 10, ARM_CEXT_MAVERICK, do_mav_binops_1m},
-  {"cfrshl32",   0xee000550, 8,  ARM_CEXT_MAVERICK, do_mav_triple_4a},
-  {"cfrshl64",   0xee000570, 8,  ARM_CEXT_MAVERICK, do_mav_triple_4b},
-  {"cfsh32",     0xee000500, 6,  ARM_CEXT_MAVERICK, do_mav_shift_1},
-  {"cfsh64",     0xee200500, 6,  ARM_CEXT_MAVERICK, do_mav_shift_2},
-  {"cfcmps",     0xee100490, 6,  ARM_CEXT_MAVERICK, do_mav_triple_5a},
-  {"cfcmpd",     0xee1004b0, 6,  ARM_CEXT_MAVERICK, do_mav_triple_5b},
-  {"cfcmp32",    0xee100590, 7,  ARM_CEXT_MAVERICK, do_mav_triple_5c},
-  {"cfcmp64",    0xee1005b0, 7,  ARM_CEXT_MAVERICK, do_mav_triple_5d},
-  {"cfabss",     0xee300400, 6,  ARM_CEXT_MAVERICK, do_mav_binops_1d},
-  {"cfabsd",     0xee300420, 6,  ARM_CEXT_MAVERICK, do_mav_binops_1e},
-  {"cfnegs",     0xee300440, 6,  ARM_CEXT_MAVERICK, do_mav_binops_1d},
-  {"cfnegd",     0xee300460, 6,  ARM_CEXT_MAVERICK, do_mav_binops_1e},
-  {"cfadds",     0xee300480, 6,  ARM_CEXT_MAVERICK, do_mav_triple_5e},
-  {"cfaddd",     0xee3004a0, 6,  ARM_CEXT_MAVERICK, do_mav_triple_5f},
-  {"cfsubs",     0xee3004c0, 6,  ARM_CEXT_MAVERICK, do_mav_triple_5e},
-  {"cfsubd",     0xee3004e0, 6,  ARM_CEXT_MAVERICK, do_mav_triple_5f},
-  {"cfmuls",     0xee100400, 6,  ARM_CEXT_MAVERICK, do_mav_triple_5e},
-  {"cfmuld",     0xee100420, 6,  ARM_CEXT_MAVERICK, do_mav_triple_5f},
-  {"cfabs32",    0xee300500, 7,  ARM_CEXT_MAVERICK, do_mav_binops_1n},
-  {"cfabs64",    0xee300520, 7,  ARM_CEXT_MAVERICK, do_mav_binops_1o},
-  {"cfneg32",    0xee300540, 7,  ARM_CEXT_MAVERICK, do_mav_binops_1n},
-  {"cfneg64",    0xee300560, 7,  ARM_CEXT_MAVERICK, do_mav_binops_1o},
-  {"cfadd32",    0xee300580, 7,  ARM_CEXT_MAVERICK, do_mav_triple_5g},
-  {"cfadd64",    0xee3005a0, 7,  ARM_CEXT_MAVERICK, do_mav_triple_5h},
-  {"cfsub32",    0xee3005c0, 7,  ARM_CEXT_MAVERICK, do_mav_triple_5g},
-  {"cfsub64",    0xee3005e0, 7,  ARM_CEXT_MAVERICK, do_mav_triple_5h},
-  {"cfmul32",    0xee100500, 7,  ARM_CEXT_MAVERICK, do_mav_triple_5g},
-  {"cfmul64",    0xee100520, 7,  ARM_CEXT_MAVERICK, do_mav_triple_5h},
-  {"cfmac32",    0xee100540, 7,  ARM_CEXT_MAVERICK, do_mav_triple_5g},
-  {"cfmsc32",    0xee100560, 7,  ARM_CEXT_MAVERICK, do_mav_triple_5g},
-  {"cfmadd32",   0xee000600, 8,  ARM_CEXT_MAVERICK, do_mav_quad_6a},
-  {"cfmsub32",   0xee100600, 8,  ARM_CEXT_MAVERICK, do_mav_quad_6a},
-  {"cfmadda32",  0xee200600, 9,  ARM_CEXT_MAVERICK, do_mav_quad_6b},
-  {"cfmsuba32",  0xee300600, 9,  ARM_CEXT_MAVERICK, do_mav_quad_6b},
-};
+  if (skip_past_comma (&str) == FAIL
+      || (rm = reg_required_here (&str, 0)) == FAIL)
+    {
+      inst.error = BAD_ARGS;
+      return;
+    }
 
-/* Defines for various bits that we will want to toggle.  */
-#define INST_IMMEDIATE 0x02000000
-#define OFFSET_REG     0x02000000
-#define HWOFFSET_IMM    0x00400000
-#define SHIFT_BY_REG   0x00000010
-#define PRE_INDEX      0x01000000
-#define INDEX_UP       0x00800000
-#define WRITE_BACK     0x00200000
-#define LDM_TYPE_2_OR_3        0x00400000
+  /* rdhi, rdlo and rm must all be different.  */
+  if (rdlo == rdhi || rdlo == rm || rdhi == rm)
+    as_tsktsk (_("rdhi, rdlo and rm must all be different"));
 
-#define LITERAL_MASK   0xf000f000
-#define OPCODE_MASK    0xfe1fffff
-#define V4_STR_BIT     0x00000020
+  if (skip_past_comma (&str) == FAIL
+      || (rs = reg_required_here (&str, 8)) == FAIL)
+    {
+      inst.error = BAD_ARGS;
+      return;
+    }
 
-#define DATA_OP_SHIFT  21
+  if (rdhi == REG_PC || rdhi == REG_PC || rdhi == REG_PC || rdhi == REG_PC)
+    {
+      inst.error = BAD_PC;
+      return;
+    }
 
-/* Codes to distinguish the arithmetic instructions.  */
-#define OPCODE_AND     0
-#define OPCODE_EOR     1
-#define OPCODE_SUB     2
-#define OPCODE_RSB     3
-#define OPCODE_ADD     4
-#define OPCODE_ADC     5
-#define OPCODE_SBC     6
-#define OPCODE_RSC     7
-#define OPCODE_TST     8
-#define OPCODE_TEQ     9
-#define OPCODE_CMP     10
-#define OPCODE_CMN     11
-#define OPCODE_ORR     12
-#define OPCODE_MOV     13
-#define OPCODE_BIC     14
-#define OPCODE_MVN     15
+  end_of_line (str);
+}
 
-/* Thumb v1 (ARMv4T).  */
-static void do_t_nop           PARAMS ((char *));
-static void do_t_arit          PARAMS ((char *));
-static void do_t_add           PARAMS ((char *));
-static void do_t_asr           PARAMS ((char *));
-static void do_t_branch9       PARAMS ((char *));
-static void do_t_branch12      PARAMS ((char *));
-static void do_t_branch23      PARAMS ((char *));
-static void do_t_bx            PARAMS ((char *));
-static void do_t_compare       PARAMS ((char *));
-static void do_t_ldmstm                PARAMS ((char *));
-static void do_t_ldr           PARAMS ((char *));
-static void do_t_ldrb          PARAMS ((char *));
-static void do_t_ldrh          PARAMS ((char *));
-static void do_t_lds           PARAMS ((char *));
-static void do_t_lsl           PARAMS ((char *));
-static void do_t_lsr           PARAMS ((char *));
-static void do_t_mov           PARAMS ((char *));
-static void do_t_push_pop      PARAMS ((char *));
-static void do_t_str           PARAMS ((char *));
-static void do_t_strb          PARAMS ((char *));
-static void do_t_strh          PARAMS ((char *));
-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 *));
+static void
+do_mul (char * str)
+{
+  int rd, rm;
 
-#define T_OPCODE_MUL 0x4340
-#define T_OPCODE_TST 0x4200
-#define T_OPCODE_CMN 0x42c0
-#define T_OPCODE_NEG 0x4240
-#define T_OPCODE_MVN 0x43c0
+  /* Only one format "rd, rm, rs".  */
+  skip_whitespace (str);
 
-#define T_OPCODE_ADD_R3        0x1800
-#define T_OPCODE_SUB_R3 0x1a00
-#define T_OPCODE_ADD_HI 0x4400
-#define T_OPCODE_ADD_ST 0xb000
-#define T_OPCODE_SUB_ST 0xb080
-#define T_OPCODE_ADD_SP 0xa800
-#define T_OPCODE_ADD_PC 0xa000
-#define T_OPCODE_ADD_I8 0x3000
-#define T_OPCODE_SUB_I8 0x3800
-#define T_OPCODE_ADD_I3 0x1c00
-#define T_OPCODE_SUB_I3 0x1e00
+  if ((rd = reg_required_here (&str, 16)) == FAIL)
+    {
+      inst.error = BAD_ARGS;
+      return;
+    }
 
-#define T_OPCODE_ASR_R 0x4100
-#define T_OPCODE_LSL_R 0x4080
-#define T_OPCODE_LSR_R  0x40c0
-#define T_OPCODE_ASR_I 0x1000
-#define T_OPCODE_LSL_I 0x0000
-#define T_OPCODE_LSR_I 0x0800
+  if (rd == REG_PC)
+    {
+      inst.error = BAD_PC;
+      return;
+    }
 
-#define T_OPCODE_MOV_I8        0x2000
-#define T_OPCODE_CMP_I8 0x2800
-#define T_OPCODE_CMP_LR 0x4280
-#define T_OPCODE_MOV_HR 0x4600
-#define T_OPCODE_CMP_HR 0x4500
+  if (skip_past_comma (&str) == FAIL
+      || (rm = reg_required_here (&str, 0)) == FAIL)
+    {
+      inst.error = BAD_ARGS;
+      return;
+    }
 
-#define T_OPCODE_LDR_PC 0x4800
-#define T_OPCODE_LDR_SP 0x9800
-#define T_OPCODE_STR_SP 0x9000
-#define T_OPCODE_LDR_IW 0x6800
-#define T_OPCODE_STR_IW 0x6000
-#define T_OPCODE_LDR_IH 0x8800
-#define T_OPCODE_STR_IH 0x8000
-#define T_OPCODE_LDR_IB 0x7800
-#define T_OPCODE_STR_IB 0x7000
-#define T_OPCODE_LDR_RW 0x5800
-#define T_OPCODE_STR_RW 0x5000
-#define T_OPCODE_LDR_RH 0x5a00
-#define T_OPCODE_STR_RH 0x5200
-#define T_OPCODE_LDR_RB 0x5c00
-#define T_OPCODE_STR_RB 0x5400
+  if (rm == REG_PC)
+    {
+      inst.error = BAD_PC;
+      return;
+    }
 
-#define T_OPCODE_PUSH  0xb400
-#define T_OPCODE_POP   0xbc00
+  if (rm == rd)
+    as_tsktsk (_("rd and rm should be different in mul"));
 
-#define T_OPCODE_BRANCH 0xe7fe
+  if (skip_past_comma (&str) == FAIL
+      || (rm = reg_required_here (&str, 8)) == FAIL)
+    {
+      inst.error = BAD_ARGS;
+      return;
+    }
 
-static int thumb_reg           PARAMS ((char ** str, int hi_lo));
+  if (rm == REG_PC)
+    {
+      inst.error = BAD_PC;
+      return;
+    }
 
-#define THUMB_SIZE     2       /* Size of thumb instruction.  */
-#define THUMB_REG_LO   0x1
-#define THUMB_REG_HI   0x2
-#define THUMB_REG_ANY  0x3
+  end_of_line (str);
+}
 
-#define THUMB_H1       0x0080
-#define THUMB_H2       0x0040
+static void
+do_mla (char * str)
+{
+  int rd, rm;
 
-#define THUMB_ASR 0
-#define THUMB_LSL 1
-#define THUMB_LSR 2
+  /* Only one format "rd, rm, rs, rn".  */
+  skip_whitespace (str);
 
-#define THUMB_MOVE 0
-#define THUMB_COMPARE 1
+  if ((rd = reg_required_here (&str, 16)) == FAIL)
+    {
+      inst.error = BAD_ARGS;
+      return;
+    }
 
-#define THUMB_LOAD 0
-#define THUMB_STORE 1
+  if (rd == REG_PC)
+    {
+      inst.error = BAD_PC;
+      return;
+    }
 
-#define THUMB_PP_PC_LR 0x0100
+  if (skip_past_comma (&str) == FAIL
+      || (rm = reg_required_here (&str, 0)) == FAIL)
+    {
+      inst.error = BAD_ARGS;
+      return;
+    }
 
-/* These three are used for immediate shifts, do not alter.  */
-#define THUMB_WORD 2
-#define THUMB_HALFWORD 1
-#define THUMB_BYTE 0
+  if (rm == REG_PC)
+    {
+      inst.error = BAD_PC;
+      return;
+    }
 
-struct thumb_opcode
-{
-  /* Basic string to match.  */
-  const char * template;
+  if (rm == rd)
+    as_tsktsk (_("rd and rm should be different in mla"));
 
-  /* Basic instruction code.  */
-  unsigned long value;
+  if (skip_past_comma (&str) == FAIL
+      || (rd = reg_required_here (&str, 8)) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || (rm = reg_required_here (&str, 12)) == FAIL)
+    {
+      inst.error = BAD_ARGS;
+      return;
+    }
 
-  int size;
+  if (rd == REG_PC || rm == REG_PC)
+    {
+      inst.error = BAD_PC;
+      return;
+    }
 
-  /* Which CPU variants this exists for.  */
-  unsigned long variant;
+  end_of_line (str);
+}
 
-  /* Function to call to parse args.  */
-  void (* parms) PARAMS ((char *));
-};
+/* Expects *str -> the characters "acc0", possibly with leading blanks.
+   Advances *str to the next non-alphanumeric.
+   Returns 0, or else FAIL (in which case sets inst.error).
 
-static const struct thumb_opcode tinsns[] =
+  (In a future XScale, there may be accumulators other than zero.
+  At that time this routine and its callers can be upgraded to suit.)  */
+
+static int
+accum0_required_here (char ** str)
 {
-  /* 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_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},
-};
+  static char buff [128];      /* Note the address is taken.  Hence, static.  */
+  char * p = * str;
+  char   c;
+  int result = 0;              /* The accum number.  */
 
-#define BAD_ARGS       _("bad arguments to instruction")
-#define BAD_PC                 _("r15 not allowed here")
-#define BAD_COND       _("instruction is not conditional")
-#define ERR_NO_ACCUM   _("acc0 expected")
+  skip_whitespace (p);
 
-static struct hash_control * arm_ops_hsh   = NULL;
-static struct hash_control * arm_tops_hsh  = NULL;
-static struct hash_control * arm_cond_hsh  = NULL;
-static struct hash_control * arm_shift_hsh = NULL;
-static struct hash_control * arm_psr_hsh   = NULL;
+  *str = p;                    /* Advance caller's string pointer too.  */
+  c = *p++;
+  while (ISALNUM (c))
+    c = *p++;
 
-/* This table describes all the machine specific pseudo-ops the assembler
-   has to support.  The fields are:
-     pseudo-op name without dot
-     function to call to execute this pseudo-op
-     Integer arg to pass to the function.  */
+  *--p = 0;                    /* Aap nul into input buffer at non-alnum.  */
 
-static void s_req PARAMS ((int));
-static void s_align PARAMS ((int));
-static void s_bss PARAMS ((int));
-static void s_even PARAMS ((int));
-static void s_ltorg PARAMS ((int));
-static void s_arm PARAMS ((int));
-static void s_thumb PARAMS ((int));
-static void s_code PARAMS ((int));
-static void s_force_thumb PARAMS ((int));
-static void s_thumb_func PARAMS ((int));
-static void s_thumb_set PARAMS ((int));
-#ifdef OBJ_ELF
-static void s_arm_elf_cons PARAMS ((int));
-#endif
+  if (! ( streq (*str, "acc0") || streq (*str, "ACC0")))
+    {
+      sprintf (buff, _("acc0 expected, not '%.100s'"), *str);
+      inst.error = buff;
+      result = FAIL;
+    }
 
-static int my_get_expression PARAMS ((expressionS *, char **));
+  *p = c;                      /* Unzap.  */
+  *str = p;                    /* Caller's string pointer to after match.  */
+  return result;
+}
 
-const pseudo_typeS md_pseudo_table[] =
+static int
+ldst_extend_v4 (char ** str)
 {
-  /* Never called becasue '.req' does not start line.  */
-  { "req",         s_req,         0 },
-  { "bss",         s_bss,         0 },
-  { "align",       s_align,       0 },
-  { "arm",         s_arm,         0 },
-  { "thumb",       s_thumb,       0 },
-  { "code",        s_code,        0 },
-  { "force_thumb", s_force_thumb, 0 },
-  { "thumb_func",  s_thumb_func,  0 },
-  { "thumb_set",   s_thumb_set,   0 },
-  { "even",        s_even,        0 },
-  { "ltorg",       s_ltorg,       0 },
-  { "pool",        s_ltorg,       0 },
-#ifdef OBJ_ELF
-  { "word",        s_arm_elf_cons, 4 },
-  { "long",        s_arm_elf_cons, 4 },
-  { "file",        (void (*) PARAMS ((int))) dwarf2_directive_file, 0 },
-  { "loc",         dwarf2_directive_loc,  0 },
-#else
-  { "word",        cons, 4},
-#endif
-  { "extend",      float_cons, 'x' },
-  { "ldouble",     float_cons, 'x' },
-  { "packed",      float_cons, 'p' },
-  { 0, 0, 0 }
-};
+  int add = INDEX_UP;
 
-/* Other internal functions.  */
-static int arm_parse_extension PARAMS ((char *, int *));
-static int arm_parse_cpu PARAMS ((char *));
-static int arm_parse_arch PARAMS ((char *));
-static int arm_parse_fpu PARAMS ((char *));
+  switch (**str)
+    {
+    case '#':
+    case '$':
+      (*str)++;
+      if (my_get_expression (& inst.reloc.exp, str))
+       return FAIL;
 
-/* Stuff needed to resolve the label ambiguity
-   As:
-     ...
-     label:   <insn>
-   may differ from:
-     ...
-     label:
-              <insn>
-*/
+      if (inst.reloc.exp.X_op == O_constant)
+       {
+         int value = inst.reloc.exp.X_add_number;
 
-symbolS *  last_label_seen;
-static int label_is_thumb_function_name = false;
+         if (value < -255 || value > 255)
+           {
+             inst.error = _("address offset too large");
+             return FAIL;
+           }
 
-/* Literal Pool stuff.  */
+         if (value < 0)
+           {
+             value = -value;
+             add = 0;
+           }
 
-#define MAX_LITERAL_POOL_SIZE 1024
+         /* Halfword and signextension instructions have the
+             immediate value split across bits 11..8 and bits 3..0.  */
+         inst.instruction |= (add | HWOFFSET_IMM
+                              | ((value >> 4) << 8) | (value & 0xF));
+       }
+      else
+       {
+         inst.instruction |= HWOFFSET_IMM;
+         inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM8;
+         inst.reloc.pc_rel = 0;
+       }
+      return SUCCESS;
 
-/* Literal pool structure.  Held on a per-section
-   and per-sub-section basis.  */
-typedef struct literal_pool
-{
-  expressionS    literals [MAX_LITERAL_POOL_SIZE];
-  unsigned int   next_free_entry;
-  unsigned int   id;
-  symbolS *      symbol;
-  segT           section;
-  subsegT        sub_section;
-  struct literal_pool * next;  
-} literal_pool;
+    case '-':
+      add = 0;
+      /* Fall through.  */
 
-/* Pointer to a linked list of literal pools.  */
-literal_pool * list_of_pools = NULL;
+    case '+':
+      (*str)++;
+      /* Fall through.  */
+
+    default:
+      if (reg_required_here (str, 0) == FAIL)
+       return FAIL;
+
+      inst.instruction |= add;
+      return SUCCESS;
+    }
+}
 
-static literal_pool * find_literal_pool PARAMS ((void));
-static literal_pool * find_or_make_literal_pool PARAMS ((void));
+/* Expects **str -> after a comma. May be leading blanks.
+   Advances *str, recognizing a load  mode, and setting inst.instruction.
+   Returns rn, or else FAIL (in which case may set inst.error
+   and not advance str)
 
-static literal_pool *
-find_literal_pool ()
+   Note: doesn't know Rd, so no err checks that require such knowledge.  */
+
+static int
+ld_mode_required_here (char ** string)
 {
-  literal_pool * pool;
+  char * str = * string;
+  int    rn;
+  int    pre_inc = 0;
 
-  for (pool = list_of_pools; pool != NULL; pool = pool->next)
+  skip_whitespace (str);
+
+  if (* str == '[')
     {
-      if (pool->section == now_seg
-         && pool->sub_section == now_subseg)
-       break;
-    }
+      str++;
 
-  return pool;
-}
+      skip_whitespace (str);
 
-static literal_pool *
-find_or_make_literal_pool ()
-{
-  /* Next literal pool ID number.  */
-  static unsigned int latest_pool_num = 1;
-  literal_pool *      pool;
+      if ((rn = reg_required_here (& str, 16)) == FAIL)
+       return FAIL;
 
-  pool = find_literal_pool ();
+      skip_whitespace (str);
 
-  if (pool == NULL)
-    {
-      /* Create a new pool.  */
-      pool = (literal_pool *) xmalloc (sizeof (* pool));
-      if (! pool)
-       return NULL;
+      if (* str == ']')
+       {
+         str ++;
 
-      pool->next_free_entry = 0;
-      pool->section         = now_seg;
-      pool->sub_section     = now_subseg;
-      pool->next            = list_of_pools;
-      pool->symbol          = NULL;
+         if (skip_past_comma (& str) == SUCCESS)
+           {
+             /* [Rn],... (post inc) */
+             if (ldst_extend_v4 (&str) == FAIL)
+               return FAIL;
+           }
+         else        /* [Rn] */
+           {
+             skip_whitespace (str);
 
-      /* Add it to the list.  */
-      list_of_pools = pool;
-    }
+             if (* str == '!')
+               {
+                 str ++;
+                 inst.instruction |= WRITE_BACK;
+               }
 
-  /* New pools, and emptied pools, will have a NULL symbol.  */
-  if (pool->symbol == NULL)
-    {
-      pool->symbol = symbol_create (FAKE_LABEL_NAME, undefined_section,
-                                   (valueT) 0, &zero_address_frag);
-      pool->id = latest_pool_num ++;
-    }
+             inst.instruction |= INDEX_UP | HWOFFSET_IMM;
+             pre_inc = 1;
+           }
+       }
+      else       /* [Rn,...] */
+       {
+         if (skip_past_comma (& str) == FAIL)
+           {
+             inst.error = _("pre-indexed expression expected");
+             return FAIL;
+           }
 
-  /* Done.  */
-  return pool;
-}
+         pre_inc = 1;
 
-/* Add the literal in the global 'inst'
-   structure to the relevent literal pool.  */
-static int
-add_to_lit_pool ()
-{
-  literal_pool * pool;  
-  unsigned int entry;
+         if (ldst_extend_v4 (&str) == FAIL)
+           return FAIL;
 
-  pool = find_or_make_literal_pool ();
+         skip_whitespace (str);
 
-  /* Check if this literal value is already in the pool.  */
-  for (entry = 0; entry < pool->next_free_entry; entry ++)
-    {
-      if ((pool->literals[entry].X_op == inst.reloc.exp.X_op)
-         && (inst.reloc.exp.X_op == O_constant)
-         && (pool->literals[entry].X_add_number
-             == inst.reloc.exp.X_add_number)
-         && (pool->literals[entry].X_unsigned
-             == inst.reloc.exp.X_unsigned))
-       break;
+         if (* str ++ != ']')
+           {
+             inst.error = _("missing ]");
+             return FAIL;
+           }
 
-      if ((pool->literals[entry].X_op == inst.reloc.exp.X_op)
-          && (inst.reloc.exp.X_op == O_symbol)
-          && (pool->literals[entry].X_add_number
-             == inst.reloc.exp.X_add_number)
-          && (pool->literals[entry].X_add_symbol
-             == inst.reloc.exp.X_add_symbol)
-          && (pool->literals[entry].X_op_symbol
-             == inst.reloc.exp.X_op_symbol))
-        break;
-    }
+         skip_whitespace (str);
 
-  /* Do we need to create a new entry?  */
-  if (entry == pool->next_free_entry)
-    {
-      if (entry >= MAX_LITERAL_POOL_SIZE)
-       {
-         inst.error = _("literal pool overflow");
-         return FAIL;
+         if (* str == '!')
+           {
+             str ++;
+             inst.instruction |= WRITE_BACK;
+           }
        }
+    }
+  else if (* str == '=')       /* ldr's "r,=label" syntax */
+    /* We should never reach here, because <text> = <expression> is
+       caught gas/read.c read_a_source_file() as a .set operation.  */
+    return FAIL;
+  else                         /* PC +- 8 bit immediate offset.  */
+    {
+      if (my_get_expression (& inst.reloc.exp, & str))
+       return FAIL;
 
-      pool->literals[entry] = inst.reloc.exp;
-      pool->next_free_entry += 1;
+      inst.instruction            |= HWOFFSET_IMM;     /* The I bit.  */
+      inst.reloc.type              = BFD_RELOC_ARM_OFFSET_IMM8;
+      inst.reloc.exp.X_add_number -= 8;                /* PC rel adjust.  */
+      inst.reloc.pc_rel            = 1;
+      inst.instruction            |= (REG_PC << 16);
+
+      rn = REG_PC;
+      pre_inc = 1;
     }
 
-  inst.reloc.exp.X_op         = O_symbol;
-  inst.reloc.exp.X_add_number = ((int) entry) * 4 - 8;
-  inst.reloc.exp.X_add_symbol = pool->symbol;
+  inst.instruction |= (pre_inc ? PRE_INDEX : 0);
+  * string = str;
 
-  return SUCCESS;
+  return rn;
 }
 
-/* Can't use symbol_new here, so have to create a symbol and then at
-   a later date assign it a value. Thats what these functions do.  */
+/* ARM V5E (El Segundo) signed-multiply-accumulate (argument parse)
+   SMLAxy{cond} Rd,Rm,Rs,Rn
+   SMLAWy{cond} Rd,Rm,Rs,Rn
+   Error if any register is R15.  */
 
 static void
-symbol_locate (symbolP, name, segment, valu, frag)
-     symbolS *    symbolP;
-     const char * name;                /* It is copied, the caller can modify.  */
-     segT         segment;     /* Segment identifier (SEG_<something>).  */
-     valueT       valu;                /* Symbol value.  */
-     fragS *      frag;                /* Associated fragment.  */
+do_smla (char * str)
 {
-  unsigned int name_length;
-  char * preserved_copy_of_name;
+  int rd, rm, rs, rn;
 
-  name_length = strlen (name) + 1;   /* +1 for \0.  */
-  obstack_grow (&notes, name, name_length);
-  preserved_copy_of_name = obstack_finish (&notes);
-#ifdef STRIP_UNDERSCORE
-  if (preserved_copy_of_name[0] == '_')
-    preserved_copy_of_name++;
-#endif
+  skip_whitespace (str);
 
-#ifdef tc_canonicalize_symbol_name
-  preserved_copy_of_name =
-    tc_canonicalize_symbol_name (preserved_copy_of_name);
-#endif
+  if ((rd = reg_required_here (& str, 16)) == FAIL
+      || skip_past_comma (& str) == FAIL
+      || (rm = reg_required_here (& str, 0)) == FAIL
+      || skip_past_comma (& str) == FAIL
+      || (rs = reg_required_here (& str, 8)) == FAIL
+      || skip_past_comma (& str) == FAIL
+      || (rn = reg_required_here (& str, 12)) == FAIL)
+    inst.error = BAD_ARGS;
 
-  S_SET_NAME (symbolP, preserved_copy_of_name);
+  else if (rd == REG_PC || rm == REG_PC || rs == REG_PC || rn == REG_PC)
+    inst.error = BAD_PC;
 
-  S_SET_SEGMENT (symbolP, segment);
-  S_SET_VALUE (symbolP, valu);
-  symbol_clear_list_pointers (symbolP);
+  else
+    end_of_line (str);
+}
 
-  symbol_set_frag (symbolP, frag);
+/* ARM V5E (El Segundo) signed-multiply-accumulate-long (argument parse)
+   SMLALxy{cond} Rdlo,Rdhi,Rm,Rs
+   Error if any register is R15.
+   Warning if Rdlo == Rdhi.  */
 
-  /* Link to end of symbol chain.  */
-  {
-    extern int symbol_table_frozen;
-    if (symbol_table_frozen)
-      abort ();
-  }
+static void
+do_smlal (char * str)
+{
+  int rdlo, rdhi, rm, rs;
 
-  symbol_append (symbolP, symbol_lastP, & symbol_rootP, & symbol_lastP);
+  skip_whitespace (str);
 
-  obj_symbol_new_hook (symbolP);
+  if ((rdlo = reg_required_here (& str, 12)) == FAIL
+      || skip_past_comma (& str) == FAIL
+      || (rdhi = reg_required_here (& str, 16)) == FAIL
+      || skip_past_comma (& str) == FAIL
+      || (rm = reg_required_here (& str, 0)) == FAIL
+      || skip_past_comma (& str) == FAIL
+      || (rs = reg_required_here (& str, 8)) == FAIL)
+    {
+      inst.error = BAD_ARGS;
+      return;
+    }
 
-#ifdef tc_symbol_new_hook
-  tc_symbol_new_hook (symbolP);
-#endif
+  if (rdlo == REG_PC || rdhi == REG_PC || rm == REG_PC || rs == REG_PC)
+    {
+      inst.error = BAD_PC;
+      return;
+    }
 
-#ifdef DEBUG_SYMS
-  verify_symbol_chain (symbol_rootP, symbol_lastP);
-#endif /* DEBUG_SYMS  */
+  if (rdlo == rdhi)
+    as_tsktsk (_("rdhi and rdlo must be different"));
+
+  end_of_line (str);
 }
 
-/* Check that an immediate is valid.
-   If so, convert it to the right format.  */
+/* ARM V5E (El Segundo) signed-multiply (argument parse)
+   SMULxy{cond} Rd,Rm,Rs
+   Error if any register is R15.  */
 
-static unsigned int
-validate_immediate (val)
-     unsigned int val;
+static void
+do_smul (char * str)
 {
-  unsigned int a;
-  unsigned int i;
+  int rd, rm, rs;
 
-#define rotate_left(v, n) (v << n | v >> (32 - n))
+  skip_whitespace (str);
+
+  if ((rd = reg_required_here (& str, 16)) == FAIL
+      || skip_past_comma (& str) == FAIL
+      || (rm = reg_required_here (& str, 0)) == FAIL
+      || skip_past_comma (& str) == FAIL
+      || (rs = reg_required_here (& str, 8)) == FAIL)
+    inst.error = BAD_ARGS;
 
-  for (i = 0; i < 32; i += 2)
-    if ((a = rotate_left (val, i)) <= 0xff)
-      return a | (i << 7); /* 12-bit pack: [shift-cnt,const].  */
+  else if (rd == REG_PC || rm == REG_PC || rs == REG_PC)
+    inst.error = BAD_PC;
 
-  return FAIL;
+  else
+    end_of_line (str);
 }
 
-/* Check to see if an immediate can be computed as two seperate immediate
-   values, added together.  We already know that this value cannot be
-   computed by just one ARM instruction.  */
+/* ARM V5E (El Segundo) saturating-add/subtract (argument parse)
+   Q[D]{ADD,SUB}{cond} Rd,Rm,Rn
+   Error if any register is R15.  */
 
-static unsigned int
-validate_immediate_twopart (val, highpart)
-     unsigned int   val;
-     unsigned int * highpart;
+static void
+do_qadd (char * str)
 {
-  unsigned int a;
-  unsigned int i;
+  int rd, rm, rn;
 
-  for (i = 0; i < 32; i += 2)
-    if (((a = rotate_left (val, i)) & 0xff) != 0)
-      {
-       if (a & 0xff00)
-         {
-           if (a & ~ 0xffff)
-             continue;
-           * highpart = (a  >> 8) | ((i + 24) << 7);
-         }
-       else if (a & 0xff0000)
-         {
-           if (a & 0xff000000)
-             continue;
-           * highpart = (a >> 16) | ((i + 16) << 7);
-         }
-       else
-         {
-           assert (a & 0xff000000);
-           * highpart = (a >> 24) | ((i + 8) << 7);
-         }
+  skip_whitespace (str);
 
-       return (a & 0xff) | (i << 7);
-      }
+  if ((rd = reg_required_here (& str, 12)) == FAIL
+      || skip_past_comma (& str) == FAIL
+      || (rm = reg_required_here (& str, 0)) == FAIL
+      || skip_past_comma (& str) == FAIL
+      || (rn = reg_required_here (& str, 16)) == FAIL)
+    inst.error = BAD_ARGS;
 
-  return FAIL;
-}
+  else if (rd == REG_PC || rm == REG_PC || rn == REG_PC)
+    inst.error = BAD_PC;
 
-static int
-validate_offset_imm (val, hwse)
-     unsigned int val;
-     int hwse;
-{
-  if ((hwse && val > 255) || val > 4095)
-    return FAIL;
-  return val;
+  else
+    end_of_line (str);
 }
 
-static void
-s_req (a)
-     int a ATTRIBUTE_UNUSED;
-{
-  as_bad (_("invalid syntax for .req directive"));
-}
+/* ARM V5E (el Segundo)
+   MCRRcc <coproc>, <opcode>, <Rd>, <Rn>, <CRm>.
+   MRRCcc <coproc>, <opcode>, <Rd>, <Rn>, <CRm>.
 
-static void
-s_bss (ignore)
-     int ignore ATTRIBUTE_UNUSED;
-{
-  /* We don't support putting frags in the BSS segment, we fake it by
-     marking in_bss, then looking at s_skip for clues.  */
-  subseg_set (bss_section, 0);
-  demand_empty_rest_of_line ();
-}
+   These are equivalent to the XScale instructions MAR and MRA,
+   respectively, when coproc == 0, opcode == 0, and CRm == 0.
+
+   Result unpredicatable if Rd or Rn is R15.  */
 
 static void
-s_even (ignore)
-     int ignore ATTRIBUTE_UNUSED;
+do_co_reg2c (char * str)
 {
-  /* Never make frag if expect extra pass.  */
-  if (!need_pass_2)
-    frag_align (1, 0, 0);
+  int rd, rn;
 
-  record_alignment (now_seg, 1);
+  skip_whitespace (str);
 
-  demand_empty_rest_of_line ();
-}
+  if (co_proc_number (& str) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
 
-static void
-s_ltorg (ignored)
-     int ignored ATTRIBUTE_UNUSED;
-{
-  unsigned int entry;
-  literal_pool * pool;
-  char sym_name[20];
+  if (skip_past_comma (& str) == FAIL
+      || cp_opc_expr (& str, 4, 4) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
 
-  pool = find_literal_pool ();
-  if (pool == NULL
-      || pool->symbol == NULL
-      || pool->next_free_entry == 0)
-    return;
+  if (skip_past_comma (& str) == FAIL
+      || (rd = reg_required_here (& str, 12)) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
 
-  /* Align pool as you have word accesses.
-     Only make a frag if we have to.  */
-  if (!need_pass_2)
-    frag_align (2, 0, 0);
+  if (skip_past_comma (& str) == FAIL
+      || (rn = reg_required_here (& str, 16)) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
 
-  record_alignment (now_seg, 2);
+  /* Unpredictable result if rd or rn is R15.  */
+  if (rd == REG_PC || rn == REG_PC)
+    as_tsktsk
+      (_("Warning: instruction unpredictable when using r15"));
 
-  sprintf (sym_name, "$$lit_\002%x", pool->id);
+  if (skip_past_comma (& str) == FAIL
+      || cp_reg_required_here (& str, 0) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
 
-  symbol_locate (pool->symbol, sym_name, now_seg,
-                (valueT) frag_now_fix (), frag_now);
-  symbol_table_insert (pool->symbol);
+  end_of_line (str);
+}
 
-  ARM_SET_THUMB (pool->symbol, thumb_mode);
+/* ARM V5 count-leading-zeroes instruction (argument parse)
+     CLZ{<cond>} <Rd>, <Rm>
+     Condition defaults to COND_ALWAYS.
+     Error if Rd or Rm are R15.  */
 
-#if defined OBJ_COFF || defined OBJ_ELF
-  ARM_SET_INTERWORK (pool->symbol, support_interwork);
-#endif
+static void
+do_clz (char * str)
+{
+  int rd, rm;
 
-  for (entry = 0; entry < pool->next_free_entry; entry ++)
-    /* First output the expression in the instruction to the pool.  */
-    emit_expr (&(pool->literals[entry]), 4); /* .word  */
+  skip_whitespace (str);
 
-  /* Mark the pool as empty.  */
-  pool->next_free_entry = 0;
-  pool->symbol = NULL;
+  if (((rd = reg_required_here (& str, 12)) == FAIL)
+      || (skip_past_comma (& str) == FAIL)
+      || ((rm = reg_required_here (& str, 0)) == FAIL))
+    inst.error = BAD_ARGS;
+
+  else if (rd == REG_PC || rm == REG_PC )
+    inst.error = BAD_PC;
+
+  else
+    end_of_line (str);
 }
 
-/* Same as s_align_ptwo but align 0 => align 2.  */
+/* ARM V5 (argument parse)
+     LDC2{L} <coproc>, <CRd>, <addressing mode>
+     STC2{L} <coproc>, <CRd>, <addressing mode>
+     Instruction is not conditional, and has 0xf in the condition field.
+     Otherwise, it's the same as LDC/STC.  */
 
 static void
-s_align (unused)
-     int unused ATTRIBUTE_UNUSED;
+do_lstc2 (char * str)
 {
-  register int temp;
-  register long temp_fill;
-  long max_alignment = 15;
+  skip_whitespace (str);
 
-  temp = get_absolute_expression ();
-  if (temp > max_alignment)
-    as_bad (_("alignment too large: %d assumed"), temp = max_alignment);
-  else if (temp < 0)
+  if (co_proc_number (& str) == FAIL)
     {
-      as_bad (_("alignment negative. 0 assumed."));
-      temp = 0;
+      if (!inst.error)
+       inst.error = BAD_ARGS;
     }
-
-  if (*input_line_pointer == ',')
+  else if (skip_past_comma (& str) == FAIL
+          || cp_reg_required_here (& str, 12) == FAIL)
     {
-      input_line_pointer++;
-      temp_fill = get_absolute_expression ();
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+    }
+  else if (skip_past_comma (& str) == FAIL
+          || cp_address_required_here (&str, CP_WB_OK) == FAIL)
+    {
+      if (! inst.error)
+       inst.error = BAD_ARGS;
     }
   else
-    temp_fill = 0;
-
-  if (!temp)
-    temp = 2;
-
-  /* Only make a frag if we HAVE to.  */
-  if (temp && !need_pass_2)
-    frag_align (temp, (int) temp_fill, 0);
-  demand_empty_rest_of_line ();
-
-  record_alignment (now_seg, temp);
+    end_of_line (str);
 }
 
+/* ARM V5 (argument parse)
+     CDP2 <coproc>, <opcode_1>, <CRd>, <CRn>, <CRm>, <opcode_2>
+     Instruction is not conditional, and has 0xf in the condition field.
+     Otherwise, it's the same as CDP.  */
+
 static void
-s_force_thumb (ignore)
-     int ignore ATTRIBUTE_UNUSED;
+do_cdp2 (char * str)
 {
-  /* If we are not already in thumb mode go into it, EVEN if
-     the target processor does not support thumb instructions.
-     This is used by gcc/config/arm/lib1funcs.asm for example
-     to compile interworking support functions even if the
-     target processor should not support interworking.  */
-  if (! thumb_mode)
+  skip_whitespace (str);
+
+  if (co_proc_number (& str) == FAIL)
     {
-      thumb_mode = 2;
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
 
-      record_alignment (now_seg, 1);
+  if (skip_past_comma (& str) == FAIL
+      || cp_opc_expr (& str, 20,4) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  if (skip_past_comma (& str) == FAIL
+      || cp_reg_required_here (& str, 12) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  if (skip_past_comma (& str) == FAIL
+      || cp_reg_required_here (& str, 16) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
     }
 
-  demand_empty_rest_of_line ();
-}
-
-static void
-s_thumb_func (ignore)
-     int ignore ATTRIBUTE_UNUSED;
-{
-  if (! thumb_mode)
-    opcode_select (16);
+  if (skip_past_comma (& str) == FAIL
+      || cp_reg_required_here (& str, 0) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
 
-  /* The following label is the name/address of the start of a Thumb function.
-     We need to know this for the interworking support.  */
-  label_is_thumb_function_name = true;
+  if (skip_past_comma (& str) == SUCCESS)
+    {
+      if (cp_opc_expr (& str, 5, 3) == FAIL)
+       {
+         if (!inst.error)
+           inst.error = BAD_ARGS;
+         return;
+       }
+    }
 
-  demand_empty_rest_of_line ();
+  end_of_line (str);
 }
 
-/* Perform a .set directive, but also mark the alias as
-   being a thumb function.  */
+/* ARM V5 (argument parse)
+     MCR2 <coproc>, <opcode_1>, <Rd>, <CRn>, <CRm>, <opcode_2>
+     MRC2 <coproc>, <opcode_1>, <Rd>, <CRn>, <CRm>, <opcode_2>
+     Instruction is not conditional, and has 0xf in the condition field.
+     Otherwise, it's the same as MCR/MRC.  */
 
 static void
-s_thumb_set (equiv)
-     int equiv;
+do_co_reg2 (char * str)
 {
-  /* XXX the following is a duplicate of the code for s_set() in read.c
-     We cannot just call that code as we need to get at the symbol that
-     is created.  */
-  register char *    name;
-  register char      delim;
-  register char *    end_name;
-  register symbolS * symbolP;
+  skip_whitespace (str);
 
-  /* Especial apologies for the random logic:
-     This just grew, and could be parsed much more simply!
-     Dean - in haste.  */
-  name      = input_line_pointer;
-  delim     = get_symbol_end ();
-  end_name  = input_line_pointer;
-  *end_name = delim;
+  if (co_proc_number (& str) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
 
-  SKIP_WHITESPACE ();
+  if (skip_past_comma (& str) == FAIL
+      || cp_opc_expr (& str, 21, 3) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
 
-  if (*input_line_pointer != ',')
+  if (skip_past_comma (& str) == FAIL
+      || reg_required_here (& str, 12) == FAIL)
     {
-      *end_name = 0;
-      as_bad (_("expected comma after name \"%s\""), name);
-      *end_name = delim;
-      ignore_rest_of_line ();
+      if (!inst.error)
+       inst.error = BAD_ARGS;
       return;
     }
 
-  input_line_pointer++;
-  *end_name = 0;
+  if (skip_past_comma (& str) == FAIL
+      || cp_reg_required_here (& str, 16) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
 
-  if (name[0] == '.' && name[1] == '\0')
+  if (skip_past_comma (& str) == FAIL
+      || cp_reg_required_here (& str, 0) == FAIL)
     {
-      /* XXX - this should not happen to .thumb_set.  */
-      abort ();
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
     }
 
-  if ((symbolP = symbol_find (name)) == NULL
-      && (symbolP = md_undefined_symbol (name)) == NULL)
+  if (skip_past_comma (& str) == SUCCESS)
     {
-#ifndef NO_LISTING
-      /* When doing symbol listings, play games with dummy fragments living
-        outside the normal fragment chain to record the file and line info
-         for this symbol.  */
-      if (listing & LISTING_SYMBOLS)
+      if (cp_opc_expr (& str, 5, 3) == FAIL)
        {
-         extern struct list_info_struct * listing_tail;
-         fragS * dummy_frag = (fragS *) xmalloc (sizeof (fragS));
-
-         memset (dummy_frag, 0, sizeof (fragS));
-         dummy_frag->fr_type = rs_fill;
-         dummy_frag->line = listing_tail;
-         symbolP = symbol_new (name, undefined_section, 0, dummy_frag);
-         dummy_frag->fr_symbol = symbolP;
+         if (!inst.error)
+           inst.error = BAD_ARGS;
+         return;
        }
-      else
-#endif
-       symbolP = symbol_new (name, undefined_section, 0, &zero_address_frag);
-
-#ifdef OBJ_COFF
-      /* "set" symbols are local unless otherwise specified.  */
-      SF_SET_LOCAL (symbolP);
-#endif /* OBJ_COFF  */
-    }                          /* Make a new symbol.  */
-
-  symbol_table_insert (symbolP);
-
-  * end_name = delim;
-
-  if (equiv
-      && S_IS_DEFINED (symbolP)
-      && S_GET_SEGMENT (symbolP) != reg_section)
-    as_bad (_("symbol `%s' already defined"), S_GET_NAME (symbolP));
-
-  pseudo_set (symbolP);
-
-  demand_empty_rest_of_line ();
-
-  /* XXX Now we come to the Thumb specific bit of code.  */
+    }
 
-  THUMB_SET_FUNC (symbolP, 1);
-  ARM_SET_THUMB (symbolP, 1);
-#if defined OBJ_ELF || defined OBJ_COFF
-  ARM_SET_INTERWORK (symbolP, support_interwork);
-#endif
+  end_of_line (str);
 }
 
 static void
-opcode_select (width)
-     int width;
+do_bx (char * str)
 {
-  switch (width)
+  int reg;
+
+  skip_whitespace (str);
+
+  if ((reg = reg_required_here (&str, 0)) == FAIL)
     {
-    case 16:
-      if (! thumb_mode)
-       {
-         if (! (cpu_variant & ARM_EXT_V4T))
-           as_bad (_("selected processor does not support THUMB opcodes"));
+      inst.error = BAD_ARGS;
+      return;
+    }
 
-         thumb_mode = 1;
-         /* No need to force the alignment, since we will have been
-             coming from ARM mode, which is word-aligned.  */
-         record_alignment (now_seg, 1);
-       }
-      break;
+  /* Note - it is not illegal to do a "bx pc".  Useless, but not illegal.  */
+  if (reg == REG_PC)
+    as_tsktsk (_("use of r15 in bx in ARM mode is not really useful"));
 
-    case 32:
-      if (thumb_mode)
-       {
-         if ((cpu_variant & ARM_ALL) == ARM_EXT_V4T)
-           as_bad (_("selected processor does not support ARM opcodes"));
+  end_of_line (str);
+}
 
-         thumb_mode = 0;
+/* ARM v5TEJ.  Jump to Jazelle code.  */
 
-         if (!need_pass_2)
-           frag_align (2, 0, 0);
+static void
+do_bxj (char * str)
+{
+  int reg;
 
-         record_alignment (now_seg, 1);
-       }
-      break;
+  skip_whitespace (str);
 
-    default:
-      as_bad (_("invalid instruction size selected (%d)"), width);
+  if ((reg = reg_required_here (&str, 0)) == FAIL)
+    {
+      inst.error = BAD_ARGS;
+      return;
     }
-}
 
-static void
-s_arm (ignore)
-     int ignore ATTRIBUTE_UNUSED;
-{
-  opcode_select (32);
-  demand_empty_rest_of_line ();
-}
+  /* Note - it is not illegal to do a "bxj pc".  Useless, but not illegal.  */
+  if (reg == REG_PC)
+    as_tsktsk (_("use of r15 in bxj is not really useful"));
 
-static void
-s_thumb (ignore)
-     int ignore ATTRIBUTE_UNUSED;
-{
-  opcode_select (16);
-  demand_empty_rest_of_line ();
+  end_of_line (str);
 }
 
+/* ARM V6 umaal (argument parse).  */
+
 static void
-s_code (unused)
-     int unused ATTRIBUTE_UNUSED;
+do_umaal (char * str)
 {
-  register int temp;
+  int rdlo, rdhi, rm, rs;
 
-  temp = get_absolute_expression ();
-  switch (temp)
+  skip_whitespace (str);
+  if ((rdlo = reg_required_here (& str, 12)) == FAIL
+      || skip_past_comma (& str) == FAIL
+      || (rdhi = reg_required_here (& str, 16)) == FAIL
+      || skip_past_comma (& str) == FAIL
+      || (rm = reg_required_here (& str, 0)) == FAIL
+      || skip_past_comma (& str) == FAIL
+      || (rs = reg_required_here (& str, 8)) == FAIL)
     {
-    case 16:
-    case 32:
-      opcode_select (temp);
-      break;
+      inst.error = BAD_ARGS;
+      return;
+    }
 
-    default:
-      as_bad (_("invalid operand to .code directive (%d) (expecting 16 or 32)"), temp);
+  if (rdlo == REG_PC || rdhi == REG_PC || rm == REG_PC || rs == REG_PC)
+    {
+      inst.error = BAD_PC;
+      return;
     }
+
+  end_of_line (str);
 }
 
+/* ARM V6 strex (argument parse).  */
+
 static void
-end_of_line (str)
-     char *str;
+do_strex (char * str)
 {
+  int rd, rm, rn;
+
+  /* Parse Rd, Rm,.  */
   skip_whitespace (str);
+  if ((rd = reg_required_here (& str, 12)) == FAIL
+      || skip_past_comma (& str) == FAIL
+      || (rm = reg_required_here (& str, 0)) == FAIL
+      || skip_past_comma (& str) == FAIL)
+    {
+      inst.error = BAD_ARGS;
+      return;
+    }
+  if (rd == REG_PC || rm == REG_PC)
+    {
+      inst.error = BAD_PC;
+      return;
+    }
+  if (rd == rm)
+    {
+      inst.error = _("Rd equal to Rm or Rn yields unpredictable results");
+      return;
+    }
 
-  if (*str != '\0' && !inst.error)
-    inst.error = _("garbage following instruction");
-}
+  /* Skip past '['.  */
+  if ((strlen (str) >= 1)
+      && strncmp (str, "[", 1) == 0)
+    str += 1;
 
-static int
-skip_past_comma (str)
-     char ** str;
-{
-  char * p = * str, c;
-  int comma = 0;
+  skip_whitespace (str);
 
-  while ((c = *p) == ' ' || c == ',')
+  /* Parse Rn.  */
+  if ((rn = reg_required_here (& str, 16)) == FAIL)
+    {
+      inst.error = BAD_ARGS;
+      return;
+    }
+  else if (rn == REG_PC)
     {
-      p++;
-      if (c == ',' && comma++)
-       return FAIL;
+      inst.error = BAD_PC;
+      return;
+    }
+  if (rd == rn)
+    {
+      inst.error = _("Rd equal to Rm or Rn yields unpredictable results");
+      return;
     }
+  skip_whitespace (str);
 
-  if (c == '\0')
-    return FAIL;
+  /* Skip past ']'.  */
+  if ((strlen (str) >= 1)
+      && strncmp (str, "]", 1) == 0)
+    str += 1;
 
-  *str = p;
-  return comma ? SUCCESS : FAIL;
+  end_of_line (str);
 }
 
-/* A standard register must be given at this point.
-   SHIFT is the place to put it in inst.instruction.
-   Restores input start point on error.
-   Returns the reg#, or FAIL.  */
+/* KIND indicates what kind of shifts are accepted.  */
 
 static int
-reg_required_here (str, shift)
-     char ** str;
-     int     shift;
+decode_shift (char ** str, int kind)
 {
-  static char buff [128]; /* XXX  */
-  int         reg;
-  char *      start = * str;
+  const struct asm_shift_name * shift;
+  char * p;
+  char   c;
 
-  if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_RN].htab)) != FAIL)
+  skip_whitespace (* str);
+
+  for (p = * str; ISALPHA (* p); p ++)
+    ;
+
+  if (p == * str)
     {
-      if (shift >= 0)
-       inst.instruction |= reg << shift;
-      return reg;
+      inst.error = _("shift expression expected");
+      return FAIL;
     }
 
-  /* Restore the start point, we may have got a reg of the wrong class.  */
-  *str = start;
+  c = * p;
+  * p = '\0';
+  shift = (const struct asm_shift_name *) hash_find (arm_shift_hsh, * str);
+  * p = c;
 
-  /* In the few cases where we might be able to accept something else
-     this error can be overridden.  */
-  sprintf (buff, _("register expected, not '%.100s'"), start);
-  inst.error = buff;
+  if (shift == NULL)
+    {
+      inst.error = _("shift expression expected");
+      return FAIL;
+    }
 
-  return FAIL;
-}
+  assert (shift->properties->index == shift_properties[shift->properties->index].index);
 
-static const struct asm_psr *
-arm_psr_parse (ccp)
-     register char ** ccp;
-{
-  char * start = * ccp;
-  char   c;
-  char * p;
-  const struct asm_psr * psr;
+  if (kind == SHIFT_LSL_OR_ASR_IMMEDIATE
+      && shift->properties->index != SHIFT_LSL
+      && shift->properties->index != SHIFT_ASR)
+    {
+      inst.error = _("'LSL' or 'ASR' required");
+      return FAIL;
+    }
+  else if (kind == SHIFT_LSL_IMMEDIATE
+          && shift->properties->index != SHIFT_LSL)
+    {
+      inst.error = _("'LSL' required");
+      return FAIL;
+    }
+  else if (kind == SHIFT_ASR_IMMEDIATE
+          && shift->properties->index != SHIFT_ASR)
+    {
+      inst.error = _("'ASR' required");
+      return FAIL;
+    }
 
-  p = start;
+  if (shift->properties->index == SHIFT_RRX)
+    {
+      * str = p;
+      inst.instruction |= shift->properties->bit_field;
+      return SUCCESS;
+    }
 
-  /* Skip to the end of the next word in the input stream.  */
-  do
+  skip_whitespace (p);
+
+  if (kind == NO_SHIFT_RESTRICT && reg_required_here (& p, 8) != FAIL)
     {
-      c = *p++;
+      inst.instruction |= shift->properties->bit_field | SHIFT_BY_REG;
+      * str = p;
+      return SUCCESS;
+    }
+  else if (! is_immediate_prefix (* p))
+    {
+      inst.error = (NO_SHIFT_RESTRICT
+                   ? _("shift requires register or #expression")
+                   : _("shift requires #expression"));
+      * str = p;
+      return FAIL;
     }
-  while (ISALPHA (c) || c == '_');
 
-  /* Terminate the word.  */
-  *--p = 0;
+  inst.error = NULL;
+  p ++;
 
-  /* CPSR's and SPSR's can now be lowercase.  This is just a convenience
-     feature for ease of use and backwards compatibility.  */
-  if (!strncmp (start, "cpsr", 4))
-    strncpy (start, "CPSR", 4);
-  else if (!strncmp (start, "spsr", 4))
-    strncpy (start, "SPSR", 4);
+  if (my_get_expression (& inst.reloc.exp, & p))
+    return FAIL;
 
-  /* Now locate the word in the psr hash table.  */
-  psr = (const struct asm_psr *) hash_find (arm_psr_hsh, start);
+  /* Validate some simple #expressions.  */
+  if (inst.reloc.exp.X_op == O_constant)
+    {
+      unsigned num = inst.reloc.exp.X_add_number;
 
-  /* Restore the input stream.  */
-  *p = c;
+      /* Reject operations greater than 32.  */
+      if (num > 32
+         /* Reject a shift of 0 unless the mode allows it.  */
+         || (num == 0 && shift->properties->allows_0 == 0)
+         /* Reject a shift of 32 unless the mode allows it.  */
+         || (num == 32 && shift->properties->allows_32 == 0)
+         )
+       {
+         /* As a special case we allow a shift of zero for
+            modes that do not support it to be recoded as an
+            logical shift left of zero (ie nothing).  We warn
+            about this though.  */
+         if (num == 0)
+           {
+             as_warn (_("shift of 0 ignored."));
+             shift = & shift_names[0];
+             assert (shift->properties->index == SHIFT_LSL);
+           }
+         else
+           {
+             inst.error = _("invalid immediate shift");
+             return FAIL;
+           }
+       }
 
-  /* If we found a valid match, advance the
-     stream pointer past the end of the word.  */
-  *ccp = p;
+      /* Shifts of 32 are encoded as 0, for those shifts that
+        support it.  */
+      if (num == 32)
+       num = 0;
 
-  return psr;
-}
+      inst.instruction |= (num << 7) | shift->properties->bit_field;
+    }
+  else
+    {
+      inst.reloc.type   = BFD_RELOC_ARM_SHIFT_IMM;
+      inst.reloc.pc_rel = 0;
+      inst.instruction |= shift->properties->bit_field;
+    }
 
-/* Parse the input looking for a PSR flag.  */
+  * str = p;
+  return SUCCESS;
+}
 
-static int
-psr_required_here (str)
-     char ** str;
+static void
+do_sat (char ** str, int bias)
 {
-  char * start = * str;
-  const struct asm_psr * psr;
+  int rd, rm;
+  expressionS expr;
 
-  psr = arm_psr_parse (str);
+  skip_whitespace (*str);
 
-  if (psr)
+  /* Parse <Rd>, field.  */
+  if ((rd = reg_required_here (str, 12)) == FAIL
+      || skip_past_comma (str) == FAIL)
     {
-      /* If this is the SPSR that is being modified, set the R bit.  */
-      if (! psr->cpsr)
-       inst.instruction |= SPSR_BIT;
-
-      /* Set the psr flags in the MSR instruction.  */
-      inst.instruction |= psr->field << PSR_SHIFT;
+      inst.error = BAD_ARGS;
+      return;
+    }
+  if (rd == REG_PC)
+    {
+      inst.error = BAD_PC;
+      return;
+    }
 
-      return SUCCESS;
+  /* Parse #<immed>,  field.  */
+  if (is_immediate_prefix (**str))
+    (*str)++;
+  else
+    {
+      inst.error = _("immediate expression expected");
+      return;
+    }
+  if (my_get_expression (&expr, str))
+    {
+      inst.error = _("bad expression");
+      return;
+    }
+  if (expr.X_op != O_constant)
+    {
+      inst.error = _("constant expression expected");
+      return;
+    }
+  if (expr.X_add_number + bias < 0
+      || expr.X_add_number + bias > 31)
+    {
+      inst.error = _("immediate value out of range");
+      return;
+    }
+  inst.instruction |= (expr.X_add_number + bias) << 16;
+  if (skip_past_comma (str) == FAIL)
+    {
+      inst.error = BAD_ARGS;
+      return;
     }
 
-  /* In the few cases where we might be able to accept
-     something else this error can be overridden.  */
-  inst.error = _("flag for {c}psr instruction expected");
+  /* Parse <Rm> field.  */
+  if ((rm = reg_required_here (str, 0)) == FAIL)
+    {
+      inst.error = BAD_ARGS;
+      return;
+    }
+  if (rm == REG_PC)
+    {
+      inst.error = BAD_PC;
+      return;
+    }
 
-  /* Restore the start point.  */
-  *str = start;
-  return FAIL;
+  if (skip_past_comma (str) == SUCCESS)
+    decode_shift (str, SHIFT_LSL_OR_ASR_IMMEDIATE);
 }
 
-static int
-co_proc_number (str)
-     char **str;
-{
-  int processor, pchar;
-  char *start;
+/* ARM V6 ssat (argument parse).  */
 
-  skip_whitespace (*str);
-  start = *str;
-
-  /* The data sheet seems to imply that just a number on its own is valid
-     here, but the RISC iX assembler seems to accept a prefix 'p'.  We will
-     accept either.  */
-  if ((processor = arm_reg_parse (str, all_reg_maps[REG_TYPE_CP].htab))
-      == FAIL)
-    {
-      *str = start;
+static void
+do_ssat (char * str)
+{
+  do_sat (&str, /*bias=*/-1);
+  end_of_line (str);
+}
 
-      pchar = *(*str)++;
-      if (pchar >= '0' && pchar <= '9')
-       {
-         processor = pchar - '0';
-         if (**str >= '0' && **str <= '9')
-           {
-             processor = processor * 10 + *(*str)++ - '0';
-             if (processor > 15)
-               {
-                 inst.error = _("illegal co-processor number");
-                 return FAIL;
-               }
-           }
-       }
-      else
-       {
-         inst.error = _("bad or missing co-processor number");
-         return FAIL;
-       }
-    }
+/* ARM V6 usat (argument parse).  */
 
-  inst.instruction |= processor << 8;
-  return SUCCESS;
+static void
+do_usat (char * str)
+{
+  do_sat (&str, /*bias=*/0);
+  end_of_line (str);
 }
 
-static int
-cp_opc_expr (str, where, length)
-     char ** str;
-     int where;
-     int length;
+static void
+do_sat16 (char ** str, int bias)
 {
+  int rd, rm;
   expressionS expr;
 
-  skip_whitespace (* str);
+  skip_whitespace (*str);
 
-  memset (&expr, '\0', sizeof (expr));
+  /* Parse the <Rd> field.  */
+  if ((rd = reg_required_here (str, 12)) == FAIL
+      || skip_past_comma (str) == FAIL)
+    {
+      inst.error = BAD_ARGS;
+      return;
+    }
+  if (rd == REG_PC)
+    {
+      inst.error = BAD_PC;
+      return;
+    }
 
+  /* Parse #<immed>, field.  */
+  if (is_immediate_prefix (**str))
+    (*str)++;
+  else
+    {
+      inst.error = _("immediate expression expected");
+      return;
+    }
   if (my_get_expression (&expr, str))
-    return FAIL;
+    {
+      inst.error = _("bad expression");
+      return;
+    }
   if (expr.X_op != O_constant)
     {
-      inst.error = _("bad or missing expression");
-      return FAIL;
+      inst.error = _("constant expression expected");
+      return;
     }
-
-  if ((expr.X_add_number & ((1 << length) - 1)) != expr.X_add_number)
+  if (expr.X_add_number + bias < 0
+      || expr.X_add_number + bias > 15)
     {
-      inst.error = _("immediate co-processor expression too large");
-      return FAIL;
+      inst.error = _("immediate value out of range");
+      return;
+    }
+  inst.instruction |= (expr.X_add_number + bias) << 16;
+  if (skip_past_comma (str) == FAIL)
+    {
+      inst.error = BAD_ARGS;
+      return;
     }
 
-  inst.instruction |= expr.X_add_number << where;
-  return SUCCESS;
-}
-
-static int
-cp_reg_required_here (str, where)
-     char ** str;
-     int     where;
-{
-  int    reg;
-  char * start = *str;
-
-  if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_CN].htab)) != FAIL)
+  /* Parse <Rm> field.  */
+  if ((rm = reg_required_here (str, 0)) == FAIL)
     {
-      inst.instruction |= reg << where;
-      return reg;
+      inst.error = BAD_ARGS;
+      return;
+    }
+  if (rm == REG_PC)
+    {
+      inst.error = BAD_PC;
+      return;
     }
+}
 
-  /* In the few cases where we might be able to accept something else
-     this error can be overridden.  */
-  inst.error = _("co-processor register expected");
+/* ARM V6 ssat16 (argument parse).  */
 
-  /* Restore the start point.  */
-  *str = start;
-  return FAIL;
+static void
+do_ssat16 (char * str)
+{
+  do_sat16 (&str, /*bias=*/-1);
+  end_of_line (str);
 }
 
-static int
-fp_reg_required_here (str, where)
-     char ** str;
-     int     where;
+static void
+do_usat16 (char * str)
 {
-  int    reg;
-  char * start = * str;
-
-  if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_FN].htab)) != FAIL)
-    {
-      inst.instruction |= reg << where;
-      return reg;
-    }
-
-  /* In the few cases where we might be able to accept something else
-     this error can be overridden.  */
-  inst.error = _("floating point register expected");
-
-  /* Restore the start point.  */
-  *str = start;
-  return FAIL;
+  do_sat16 (&str, /*bias=*/0);
+  end_of_line (str);
 }
 
-static int
-cp_address_offset (str)
-     char ** str;
+static void
+do_cps_mode (char ** str)
 {
-  int offset;
+  expressionS expr;
 
-  skip_whitespace (* str);
+  skip_whitespace (*str);
 
   if (! is_immediate_prefix (**str))
     {
       inst.error = _("immediate expression expected");
-      return FAIL;
+      return;
     }
 
-  (*str)++;
-
-  if (my_get_expression (& inst.reloc.exp, str))
-    return FAIL;
-
-  if (inst.reloc.exp.X_op == O_constant)
+  (*str)++; /* Strip off the immediate signifier.  */
+  if (my_get_expression (&expr, str))
     {
-      offset = inst.reloc.exp.X_add_number;
-
-      if (offset & 3)
-       {
-         inst.error = _("co-processor address must be word aligned");
-         return FAIL;
-       }
-
-      if (offset > 1023 || offset < -1023)
-       {
-         inst.error = _("offset too large");
-         return FAIL;
-       }
+      inst.error = _("bad expression");
+      return;
+    }
 
-      if (offset >= 0)
-       inst.instruction |= INDEX_UP;
-      else
-       offset = -offset;
+  if (expr.X_op != O_constant)
+    {
+      inst.error = _("constant expression expected");
+      return;
+    }
 
-      inst.instruction |= offset >> 2;
+  /* The mode is a 5 bit field.  Valid values are 0-31.  */
+  if (((unsigned) expr.X_add_number) > 31
+      || (inst.reloc.exp.X_add_number) < 0)
+    {
+      inst.error = _("invalid constant");
+      return;
     }
-  else
-    inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM;
 
-  return SUCCESS;
+  inst.instruction |= expr.X_add_number;
 }
 
-static int
-cp_address_required_here (str, wb_ok)
-     char ** str;
-     int wb_ok;
-{
-  char * p = * str;
-  int    pre_inc = 0;
-  int    write_back = 0;
+/* ARM V6 srs (argument parse).  */
 
-  if (*p == '[')
+static void
+do_srs (char * str)
+{
+  char *exclam;
+  skip_whitespace (str);
+  exclam = strchr (str, '!');
+  if (exclam)
+    *exclam = '\0';
+  do_cps_mode (&str);
+  if (exclam)
+    *exclam = '!';
+  if (*str == '!')
     {
-      int reg;
-
-      p++;
-      skip_whitespace (p);
-
-      if ((reg = reg_required_here (& p, 16)) == FAIL)
-       return FAIL;
-
-      skip_whitespace (p);
-
-      if (*p == ']')
-       {
-         p++;
-
-         if (wb_ok && skip_past_comma (& p) == SUCCESS)
-           {
-             /* [Rn], #expr  */
-             write_back = WRITE_BACK;
-
-             if (reg == REG_PC)
-               {
-                 inst.error = _("pc may not be used in post-increment");
-                 return FAIL;
-               }
-
-             if (cp_address_offset (& p) == FAIL)
-               return FAIL;
-           }
-         else
-           pre_inc = PRE_INDEX | INDEX_UP;
-       }
-      else
-       {
-         /* '['Rn, #expr']'[!]  */
+      inst.instruction |= WRITE_BACK;
+      str++;
+    }
+  end_of_line (str);
+}
 
-         if (skip_past_comma (& p) == FAIL)
-           {
-             inst.error = _("pre-indexed expression expected");
-             return FAIL;
-           }
+/* ARM V6 SMMUL (argument parse).  */
 
-         pre_inc = PRE_INDEX;
+static void
+do_smmul (char * str)
+{
+  int rd, rm, rs;
 
-         if (cp_address_offset (& p) == FAIL)
-           return FAIL;
+  skip_whitespace (str);
+  if ((rd = reg_required_here (&str, 16)) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || (rm = reg_required_here (&str, 0)) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || (rs = reg_required_here (&str, 8)) == FAIL)
+    {
+      inst.error = BAD_ARGS;
+      return;
+    }
 
-         skip_whitespace (p);
+  if (   rd == REG_PC
+      || rm == REG_PC
+      || rs == REG_PC)
+    {
+      inst.error = BAD_PC;
+      return;
+    }
 
-         if (*p++ != ']')
-           {
-             inst.error = _("missing ]");
-             return FAIL;
-           }
+  end_of_line (str);
+}
 
-         skip_whitespace (p);
+/* ARM V6 SMLALD (argument parse).  */
 
-         if (wb_ok && *p == '!')
-           {
-             if (reg == REG_PC)
-               {
-                 inst.error = _("pc may not be used with write-back");
-                 return FAIL;
-               }
+static void
+do_smlald (char * str)
+{
+  int rdlo, rdhi, rm, rs;
 
-             p++;
-             write_back = WRITE_BACK;
-           }
-       }
-    }
-  else
+  skip_whitespace (str);
+  if ((rdlo = reg_required_here (&str, 12)) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || (rdhi = reg_required_here (&str, 16)) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || (rm = reg_required_here (&str, 0)) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || (rs = reg_required_here (&str, 8)) == FAIL)
     {
-      if (my_get_expression (&inst.reloc.exp, &p))
-       return FAIL;
-
-      inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM;
-      inst.reloc.exp.X_add_number -= 8;  /* PC rel adjust.  */
-      inst.reloc.pc_rel = 1;
-      inst.instruction |= (REG_PC << 16);
-      pre_inc = PRE_INDEX;
+      inst.error = BAD_ARGS;
+      return;
     }
 
-  inst.instruction |= write_back | pre_inc;
-  *str = p;
-  return SUCCESS;
-}
+  if (   rdlo == REG_PC
+      || rdhi == REG_PC
+      || rm == REG_PC
+      || rs == REG_PC)
+    {
+      inst.error = BAD_PC;
+      return;
+    }
 
-static void
-do_empty (str)
-     char * str;
-{
-  /* Do nothing really.  */
   end_of_line (str);
-  return;
 }
 
+/* ARM V6 SMLAD (argument parse).  Signed multiply accumulate dual.
+   smlad{x}{<cond>} Rd, Rm, Rs, Rn */
+
 static void
-do_mrs (str)
-     char *str;
+do_smlad (char * str)
 {
-  int skip = 0;
+  int rd, rm, rs, rn;
 
-  /* Only one syntax.  */
   skip_whitespace (str);
-
-  if (reg_required_here (&str, 12) == FAIL)
+  if ((rd = reg_required_here (&str, 16)) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || (rm = reg_required_here (&str, 0)) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || (rs = reg_required_here (&str, 8)) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || (rn = reg_required_here (&str, 12)) == FAIL)
     {
       inst.error = BAD_ARGS;
       return;
     }
 
-  if (skip_past_comma (&str) == FAIL)
+  if (   rd == REG_PC
+      || rn == REG_PC
+      || rs == REG_PC
+      || rm == REG_PC)
     {
-      inst.error = _("comma expected after register name");
+      inst.error = BAD_PC;
       return;
     }
 
-  skip_whitespace (str);
+  end_of_line (str);
+}
 
-  if (   strcmp (str, "CPSR") == 0
-      || strcmp (str, "SPSR") == 0
-        /* Lower case versions for backwards compatability.  */
-      || strcmp (str, "cpsr") == 0
-      || strcmp (str, "spsr") == 0)
-    skip = 4;
+/* Returns true if the endian-specifier indicates big-endianness.  */
 
-  /* This is for backwards compatability with older toolchains.  */
-  else if (   strcmp (str, "cpsr_all") == 0
-          || strcmp (str, "spsr_all") == 0)
-    skip = 8;
-  else
+static int
+do_endian_specifier (char * str)
+{
+  int big_endian = 0;
+
+  skip_whitespace (str);
+  if (strlen (str) < 2)
+    inst.error = _("missing endian specifier");
+  else if (strncasecmp (str, "BE", 2) == 0)
     {
-      inst.error = _("CPSR or SPSR expected");
-      return;
+      str += 2;
+      big_endian = 1;
     }
-
-  if (* str == 's' || * str == 'S')
-    inst.instruction |= SPSR_BIT;
-  str += skip;
+  else if (strncasecmp (str, "LE", 2) == 0)
+    str += 2;
+  else
+    inst.error = _("valid endian specifiers are be or le");
 
   end_of_line (str);
+
+  return big_endian;
 }
 
-/* Two possible forms:
-      "{C|S}PSR_<field>, Rm",
-      "{C|S}PSR_f, #expression".  */
+/* ARM V6 SETEND (argument parse).  Sets the E bit in the CPSR while
+   preserving the other bits.
+
+   setend <endian_specifier>, where <endian_specifier> is either
+   BE or LE.  */
 
 static void
-do_msr (str)
-     char * str;
+do_setend (char * str)
 {
-  skip_whitespace (str);
+  if (do_endian_specifier (str))
+    inst.instruction |= 0x200;
+}
 
-  if (psr_required_here (& str) == FAIL)
-    return;
+/* ARM V6 SXTH.
 
-  if (skip_past_comma (& str) == FAIL)
+   SXTH {<cond>} <Rd>, <Rm>{, <rotation>}
+   Condition defaults to COND_ALWAYS.
+   Error if any register uses R15.  */
+
+static void
+do_sxth (char * str)
+{
+  int rd, rm;
+  expressionS expr;
+  int rotation_clear_mask = 0xfffff3ff;
+  int rotation_eight_mask = 0x00000400;
+  int rotation_sixteen_mask = 0x00000800;
+  int rotation_twenty_four_mask = 0x00000c00;
+
+  skip_whitespace (str);
+  if ((rd = reg_required_here (&str, 12)) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || (rm = reg_required_here (&str, 0)) == FAIL)
     {
-      inst.error = _("comma missing after psr flags");
+      inst.error = BAD_ARGS;
       return;
     }
 
-  skip_whitespace (str);
+  else if (rd == REG_PC || rm == REG_PC)
+    {
+      inst.error = BAD_PC;
+      return;
+    }
 
-  if (reg_required_here (& str, 0) != FAIL)
+  /* Zero out the rotation field.  */
+  inst.instruction &= rotation_clear_mask;
+
+  /* Check for lack of optional rotation field.  */
+  if (skip_past_comma (&str) == FAIL)
     {
-      inst.error = NULL;
       end_of_line (str);
       return;
     }
 
-  if (! is_immediate_prefix (* str))
+  /* Move past 'ROR'.  */
+  skip_whitespace (str);
+  if (strncasecmp (str, "ROR", 3) == 0)
+    str += 3;
+  else
     {
-      inst.error =
-       _("only a register or immediate value can follow a psr flag");
+      inst.error = _("missing rotation field after comma");
       return;
     }
 
-  str ++;
-  inst.error = NULL;
-
-  if (my_get_expression (& inst.reloc.exp, & str))
+  /* Get the immediate constant.  */
+  skip_whitespace (str);
+  if (is_immediate_prefix (* str))
+    str++;
+  else
     {
-      inst.error =
-       _("only a register or immediate value can follow a psr flag");
+      inst.error = _("immediate expression expected");
       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))
+  if (my_get_expression (&expr, &str))
     {
-      inst.error = _("immediate value cannot be used to set this field");
+      inst.error = _("bad expression");
       return;
     }
-#endif
 
-  inst.instruction |= INST_IMMEDIATE;
-
-  if (inst.reloc.exp.X_add_symbol)
+  if (expr.X_op != O_constant)
     {
-      inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
-      inst.reloc.pc_rel = 0;
+      inst.error = _("constant expression expected");
+      return;
     }
-  else
+
+  switch (expr.X_add_number)
     {
-      unsigned value = validate_immediate (inst.reloc.exp.X_add_number);
+    case 0:
+      /* Rotation field has already been zeroed.  */
+      break;
+    case 8:
+      inst.instruction |= rotation_eight_mask;
+      break;
 
-      if (value == (unsigned) FAIL)
-       {
-         inst.error = _("invalid constant");
-         return;
-       }
+    case 16:
+      inst.instruction |= rotation_sixteen_mask;
+      break;
 
-      inst.instruction |= value;
+    case 24:
+      inst.instruction |= rotation_twenty_four_mask;
+      break;
+
+    default:
+      inst.error = _("rotation can be 8, 16, 24 or 0 when field is ommited");
+      break;
     }
 
-  inst.error = NULL;
   end_of_line (str);
 }
 
-/* Long Multiply Parser
-   UMULL RdLo, RdHi, Rm, Rs
-   SMULL RdLo, RdHi, Rm, Rs
-   UMLAL RdLo, RdHi, Rm, Rs
-   SMLAL RdLo, RdHi, Rm, Rs.  */
+/* ARM V6 SXTAH extracts a 16-bit value from a register, sign
+   extends it to 32-bits, and adds the result to a value in another
+   register.  You can specify a rotation by 0, 8, 16, or 24 bits
+   before extracting the 16-bit value.
+   SXTAH{<cond>} <Rd>, <Rn>, <Rm>{, <rotation>}
+   Condition defaults to COND_ALWAYS.
+   Error if any register uses R15.  */
 
 static void
-do_mull (str)
-     char * str;
+do_sxtah (char * str)
 {
-  int rdlo, rdhi, rm, rs;
+  int rd, rn, rm;
+  expressionS expr;
+  int rotation_clear_mask = 0xfffff3ff;
+  int rotation_eight_mask = 0x00000400;
+  int rotation_sixteen_mask = 0x00000800;
+  int rotation_twenty_four_mask = 0x00000c00;
 
-  /* Only one format "rdlo, rdhi, rm, rs".  */
   skip_whitespace (str);
-
-  if ((rdlo = reg_required_here (&str, 12)) == FAIL)
+  if ((rd = reg_required_here (&str, 12)) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || (rn = reg_required_here (&str, 16)) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || (rm = reg_required_here (&str, 0)) == FAIL)
     {
       inst.error = BAD_ARGS;
       return;
     }
 
-  if (skip_past_comma (&str) == FAIL
-      || (rdhi = reg_required_here (&str, 16)) == FAIL)
+  else if (rd == REG_PC || rn == REG_PC || rm == REG_PC)
     {
-      inst.error = BAD_ARGS;
+      inst.error = BAD_PC;
       return;
     }
 
-  if (skip_past_comma (&str) == FAIL
-      || (rm = reg_required_here (&str, 0)) == FAIL)
+  /* Zero out the rotation field.  */
+  inst.instruction &= rotation_clear_mask;
+
+  /* Check for lack of optional rotation field.  */
+  if (skip_past_comma (&str) == FAIL)
     {
-      inst.error = BAD_ARGS;
+      end_of_line (str);
       return;
     }
 
-  /* rdhi, rdlo and rm must all be different.  */
-  if (rdlo == rdhi || rdlo == rm || rdhi == rm)
-    as_tsktsk (_("rdhi, rdlo and rm must all be different"));
+  /* Move past 'ROR'.  */
+  skip_whitespace (str);
+  if (strncasecmp (str, "ROR", 3) == 0)
+    str += 3;
+  else
+    {
+      inst.error = _("missing rotation field after comma");
+      return;
+    }
 
-  if (skip_past_comma (&str) == FAIL
-      || (rs = reg_required_here (&str, 8)) == FAIL)
+  /* Get the immediate constant.  */
+  skip_whitespace (str);
+  if (is_immediate_prefix (* str))
+    str++;
+  else
     {
-      inst.error = BAD_ARGS;
+      inst.error = _("immediate expression expected");
       return;
     }
 
-  if (rdhi == REG_PC || rdhi == REG_PC || rdhi == REG_PC || rdhi == REG_PC)
+  if (my_get_expression (&expr, &str))
     {
-      inst.error = BAD_PC;
+      inst.error = _("bad expression");
+      return;
+    }
+
+  if (expr.X_op != O_constant)
+    {
+      inst.error = _("constant expression expected");
       return;
     }
 
+  switch (expr.X_add_number)
+    {
+    case 0:
+      /* Rotation field has already been zeroed.  */
+      break;
+
+    case 8:
+      inst.instruction |= rotation_eight_mask;
+      break;
+
+    case 16:
+      inst.instruction |= rotation_sixteen_mask;
+      break;
+
+    case 24:
+      inst.instruction |= rotation_twenty_four_mask;
+      break;
+
+    default:
+      inst.error = _("rotation can be 8, 16, 24 or 0 when field is ommited");
+      break;
+    }
+
   end_of_line (str);
-  return;
 }
 
+
+/* ARM V6 RFE (Return from Exception) loads the PC and CPSR from the
+   word at the specified address and the following word
+   respectively.
+   Unconditionally executed.
+   Error if Rn is R15.  */
+
 static void
-do_mul (str)
-     char * str;
+do_rfe (char * str)
 {
-  int rd, rm;
+  int rn;
 
-  /* Only one format "rd, rm, rs".  */
   skip_whitespace (str);
 
-  if ((rd = reg_required_here (&str, 16)) == FAIL)
+  if ((rn = reg_required_here (&str, 16)) == FAIL)
+    return;
+
+  if (rn == REG_PC)
     {
-      inst.error = BAD_ARGS;
+      inst.error = BAD_PC;
       return;
     }
 
-  if (rd == REG_PC)
+  skip_whitespace (str);
+
+  if (*str == '!')
     {
-      inst.error = BAD_PC;
-      return;
+      inst.instruction |= WRITE_BACK;
+      str++;
     }
+  end_of_line (str);
+}
 
-  if (skip_past_comma (&str) == FAIL
+/* ARM V6 REV (Byte Reverse Word) reverses the byte order in a 32-bit
+   register (argument parse).
+   REV{<cond>} Rd, Rm.
+   Condition defaults to COND_ALWAYS.
+   Error if Rd or Rm are R15.  */
+
+static void
+do_rev (char * str)
+{
+  int rd, rm;
+
+  skip_whitespace (str);
+
+  if ((rd = reg_required_here (&str, 12)) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || (rm = reg_required_here (&str, 0)) == FAIL)
+    inst.error = BAD_ARGS;
+
+  else if (rd == REG_PC || rm == REG_PC)
+    inst.error = BAD_PC;
+
+  else
+    end_of_line (str);
+}
+
+/* ARM V6 Perform Two Sixteen Bit Integer Additions. (argument parse).
+   QADD16{<cond>} <Rd>, <Rn>, <Rm>
+   Condition defaults to COND_ALWAYS.
+   Error if Rd, Rn or Rm are R15.  */
+
+static void
+do_qadd16 (char * str)
+{
+  int rd, rm, rn;
+
+  skip_whitespace (str);
+
+  if ((rd = reg_required_here (&str, 12)) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || (rn = reg_required_here (&str, 16)) == FAIL
+      || skip_past_comma (&str) == FAIL
       || (rm = reg_required_here (&str, 0)) == FAIL)
+    inst.error = BAD_ARGS;
+
+  else if (rd == REG_PC || rm == REG_PC || rn == REG_PC)
+    inst.error = BAD_PC;
+
+  else
+    end_of_line (str);
+}
+
+static void
+do_pkh_core (char * str, int shift)
+{
+  int rd, rn, rm;
+
+  skip_whitespace (str);
+  if (((rd = reg_required_here (&str, 12)) == FAIL)
+      || (skip_past_comma (&str) == FAIL)
+      || ((rn = reg_required_here (&str, 16)) == FAIL)
+      || (skip_past_comma (&str) == FAIL)
+      || ((rm = reg_required_here (&str, 0)) == FAIL))
     {
       inst.error = BAD_ARGS;
       return;
     }
 
-  if (rm == REG_PC)
+  else if (rd == REG_PC || rn == REG_PC || rm == REG_PC)
     {
       inst.error = BAD_PC;
       return;
     }
 
-  if (rm == rd)
-    as_tsktsk (_("rd and rm should be different in mul"));
-
-  if (skip_past_comma (&str) == FAIL
-      || (rm = reg_required_here (&str, 8)) == FAIL)
-    {
-      inst.error = BAD_ARGS;
-      return;
-    }
-
-  if (rm == REG_PC)
+  /* Check for optional shift immediate constant.  */
+  if (skip_past_comma (&str) == FAIL)
     {
-      inst.error = BAD_PC;
+      if (shift == SHIFT_ASR_IMMEDIATE)
+       {
+         /* If the shift specifier is ommited, turn the instruction
+            into pkhbt rd, rm, rn.  First, switch the instruction
+            code, and clear the rn and rm fields.  */
+         inst.instruction &= 0xfff0f010;
+         /* Now, re-encode the registers.  */
+         inst.instruction |= (rm << 16) | rn;
+       }
       return;
     }
 
-  end_of_line (str);
-  return;
+  decode_shift (&str, shift);
 }
 
+/* ARM V6 Pack Halfword Bottom Top instruction (argument parse).
+   PKHBT {<cond>} <Rd>, <Rn>, <Rm> {, LSL #<shift_imm>}
+   Condition defaults to COND_ALWAYS.
+   Error if Rd, Rn or Rm are R15.  */
+
 static void
-do_mla (str)
-     char * str;
+do_pkhbt (char * str)
 {
-  int rd, rm;
+  do_pkh_core (str, SHIFT_LSL_IMMEDIATE);
+}
 
-  /* Only one format "rd, rm, rs, rn".  */
-  skip_whitespace (str);
+/* ARM V6 PKHTB (Argument Parse).  */
 
-  if ((rd = reg_required_here (&str, 16)) == FAIL)
-    {
-      inst.error = BAD_ARGS;
-      return;
-    }
+static void
+do_pkhtb (char * str)
+{
+  do_pkh_core (str, SHIFT_ASR_IMMEDIATE);
+}
+
+/* ARM V6 Load Register Exclusive instruction (argument parse).
+   LDREX{,B,D,H}{<cond>} <Rd, [<Rn>]
+   Condition defaults to COND_ALWAYS.
+   Error if Rd or Rn are R15.
+   See ARMARMv6 A4.1.27: LDREX.  */
 
-  if (rd == REG_PC)
-    {
-      inst.error = BAD_PC;
-      return;
-    }
+static void
+do_ldrex (char * str)
+{
+  int rd, rn;
 
-  if (skip_past_comma (&str) == FAIL
-      || (rm = reg_required_here (&str, 0)) == FAIL)
+  skip_whitespace (str);
+
+  /* Parse Rd.  */
+  if (((rd = reg_required_here (&str, 12)) == FAIL)
+      || (skip_past_comma (&str) == FAIL))
     {
       inst.error = BAD_ARGS;
       return;
     }
-
-  if (rm == REG_PC)
+  else if (rd == REG_PC)
     {
       inst.error = BAD_PC;
       return;
     }
+  skip_whitespace (str);
 
-  if (rm == rd)
-    as_tsktsk (_("rd and rm should be different in mla"));
+  /* Skip past '['.  */
+  if ((strlen (str) >= 1)
+      &&strncmp (str, "[", 1) == 0)
+    str += 1;
+  skip_whitespace (str);
 
-  if (skip_past_comma (&str) == FAIL
-      || (rd = reg_required_here (&str, 8)) == FAIL
-      || skip_past_comma (&str) == FAIL
-      || (rm = reg_required_here (&str, 12)) == FAIL)
+  /* Parse Rn.  */
+  if ((rn = reg_required_here (&str, 16)) == FAIL)
     {
       inst.error = BAD_ARGS;
       return;
     }
-
-  if (rd == REG_PC || rm == REG_PC)
+  else if (rn == REG_PC)
     {
       inst.error = BAD_PC;
       return;
     }
+  skip_whitespace (str);
+
+  /* Skip past ']'.  */
+  if ((strlen (str) >= 1)
+      && strncmp (str, "]", 1) == 0)
+    str += 1;
 
   end_of_line (str);
-  return;
 }
 
-/* Expects *str -> the characters "acc0", possibly with leading blanks.
-   Advances *str to the next non-alphanumeric.
-   Returns 0, or else FAIL (in which case sets inst.error).
-
-  (In a future XScale, there may be accumulators other than zero.
-  At that time this routine and its callers can be upgraded to suit.)  */
+/* ARM V6 change processor state instruction (argument parse)
+      CPS, CPSIE, CSPID .  */
 
-static int
-accum0_required_here (str)
-     char ** str;
+static void
+do_cps (char * str)
 {
-  static char buff [128];      /* Note the address is taken.  Hence, static.  */
-  char * p = * str;
-  char   c;
-  int result = 0;              /* The accum number.  */
+  do_cps_mode (&str);
+  end_of_line (str);
+}
 
-  skip_whitespace (p);
+static void
+do_cps_flags (char ** str, int thumb_p)
+{
+  struct cps_flag
+  {
+    char character;
+    unsigned long arm_value;
+    unsigned long thumb_value;
+  };
+  static struct cps_flag flag_table[] =
+  {
+    {'a', 0x100, 0x4 },
+    {'i', 0x080, 0x2 },
+    {'f', 0x040, 0x1 }
+  };
 
-  *str = p;                    /* Advance caller's string pointer too.  */
-  c = *p++;
-  while (ISALNUM (c))
-    c = *p++;
+  int saw_a_flag = 0;
 
-  *--p = 0;                    /* Aap nul into input buffer at non-alnum.  */
+  skip_whitespace (*str);
 
-  if (! ( streq (*str, "acc0") || streq (*str, "ACC0")))
+  /* Get the a, f and i flags.  */
+  while (**str && **str != ',')
     {
-      sprintf (buff, _("acc0 expected, not '%.100s'"), *str);
-      inst.error = buff;
-      result = FAIL;
+      struct cps_flag *p;
+      struct cps_flag *q = flag_table + sizeof (flag_table)/sizeof (*p);
+
+      for (p = flag_table; p < q; ++p)
+       if (strncasecmp (*str, &p->character, 1) == 0)
+         {
+           inst.instruction |= (thumb_p ? p->thumb_value : p->arm_value);
+           saw_a_flag = 1;
+           break;
+         }
+      if (p == q)
+       {
+         inst.error = _("unrecognized flag");
+         return;
+       }
+      (*str)++;
     }
 
-  *p = c;                      /* Unzap.  */
-  *str = p;                    /* Caller's string pointer to after match.  */
-  return result;
+  if (!saw_a_flag)
+    inst.error = _("no 'a', 'i', or 'f' flags for 'cps'");
 }
 
-/* Expects **str -> after a comma. May be leading blanks.
-   Advances *str, recognizing a load  mode, and setting inst.instruction.
-   Returns rn, or else FAIL (in which case may set inst.error
-   and not advance str)
-
-   Note: doesn't know Rd, so no err checks that require such knowledge.  */
-
-static int
-ld_mode_required_here (string)
-     char ** string;
+static void
+do_cpsi (char * str)
 {
-  char * str = * string;
-  int    rn;
-  int    pre_inc = 0;
-
-  skip_whitespace (str);
+  do_cps_flags (&str, /*thumb_p=*/0);
 
-  if (* str == '[')
+  if (skip_past_comma (&str) == SUCCESS)
     {
-      str++;
-
-      skip_whitespace (str);
-
-      if ((rn = reg_required_here (& str, 16)) == FAIL)
-       return FAIL;
-
       skip_whitespace (str);
+      do_cps_mode (&str);
+    }
+  end_of_line (str);
+}
 
-      if (* str == ']')
-       {
-         str ++;
+/* THUMB V5 breakpoint instruction (argument parse)
+       BKPT <immed_8>.  */
 
-         if (skip_past_comma (& str) == SUCCESS)
-           {
-             /* [Rn],... (post inc) */
-             if (ldst_extend_v4 (&str) == FAIL)
-               return FAIL;
-           }
-         else        /* [Rn] */
-           {
-             skip_whitespace (str);
+static void
+do_t_bkpt (char * str)
+{
+  expressionS expr;
+  unsigned long number;
 
-             if (* str == '!')
-               {
-                 str ++;
-                 inst.instruction |= WRITE_BACK;
-               }
+  skip_whitespace (str);
 
-             inst.instruction |= INDEX_UP | HWOFFSET_IMM;
-             pre_inc = 1;
-           }
-       }
-      else       /* [Rn,...] */
-       {
-         if (skip_past_comma (& str) == FAIL)
-           {
-             inst.error = _("pre-indexed expression expected");
-             return FAIL;
-           }
+  /* Allow optional leading '#'.  */
+  if (is_immediate_prefix (*str))
+    str ++;
 
-         pre_inc = 1;
+  memset (& expr, '\0', sizeof (expr));
+  if (my_get_expression (& expr, & str)
+      || (expr.X_op != O_constant
+         /* As a convenience we allow 'bkpt' without an operand.  */
+         && expr.X_op != O_absent))
+    {
+      inst.error = _("bad expression");
+      return;
+    }
 
-         if (ldst_extend_v4 (&str) == FAIL)
-           return FAIL;
+  number = expr.X_add_number;
 
-         skip_whitespace (str);
+  /* Check it fits an 8 bit unsigned.  */
+  if (number != (number & 0xff))
+    {
+      inst.error = _("immediate value out of range");
+      return;
+    }
 
-         if (* str ++ != ']')
-           {
-             inst.error = _("missing ]");
-             return FAIL;
-           }
+  inst.instruction |= number;
 
-         skip_whitespace (str);
+  end_of_line (str);
+}
 
-         if (* str == '!')
-           {
-             str ++;
-             inst.instruction |= WRITE_BACK;
-           }
-       }
-    }
-  else if (* str == '=')       /* ldr's "r,=label" syntax */
-    /* We should never reach here, because <text> = <expression> is
-       caught gas/read.c read_a_source_file() as a .set operation.  */
-    return FAIL;
-  else                         /* PC +- 8 bit immediate offset.  */
-    {
-      if (my_get_expression (& inst.reloc.exp, & str))
-       return FAIL;
+static bfd_reloc_code_real_type
+arm_parse_reloc (void)
+{
+  char         id [16];
+  char *       ip;
+  unsigned int i;
+  static struct
+  {
+    char * str;
+    int    len;
+    bfd_reloc_code_real_type reloc;
+  }
+  reloc_map[] =
+  {
+#define MAP(str,reloc) { str, sizeof (str) - 1, reloc }
+    MAP ("(got)",    BFD_RELOC_ARM_GOT32),
+    MAP ("(gotoff)", BFD_RELOC_ARM_GOTOFF),
+    /* ScottB: Jan 30, 1998 - Added support for parsing "var(PLT)"
+       branch instructions generated by GCC for PLT relocs.  */
+    MAP ("(plt)",    BFD_RELOC_ARM_PLT32),
+    MAP ("(target1)", BFD_RELOC_ARM_TARGET1),
+    MAP ("(sbrel)", BFD_RELOC_ARM_SBREL32),
+    MAP ("(target2)", BFD_RELOC_ARM_TARGET2),
+    { NULL, 0,         BFD_RELOC_UNUSED }
+#undef MAP
+  };
 
-      inst.instruction            |= HWOFFSET_IMM;     /* The I bit.  */
-      inst.reloc.type              = BFD_RELOC_ARM_OFFSET_IMM8;
-      inst.reloc.exp.X_add_number -= 8;                /* PC rel adjust.  */
-      inst.reloc.pc_rel            = 1;
-      inst.instruction            |= (REG_PC << 16);
+  for (i = 0, ip = input_line_pointer;
+       i < sizeof (id) && (ISALNUM (*ip) || ISPUNCT (*ip));
+       i++, ip++)
+    id[i] = TOLOWER (*ip);
 
-      rn = REG_PC;
-      pre_inc = 1;
-    }
+  for (i = 0; reloc_map[i].str; i++)
+    if (strncmp (id, reloc_map[i].str, reloc_map[i].len) == 0)
+      break;
 
-  inst.instruction |= (pre_inc ? PRE_INDEX : 0);
-  * string = str;
+  input_line_pointer += reloc_map[i].len;
 
-  return rn;
+  return reloc_map[i].reloc;
 }
 
-/* ARM V5E (El Segundo) signed-multiply-accumulate (argument parse)
-   SMLAxy{cond} Rd,Rm,Rs,Rn
-   SMLAWy{cond} Rd,Rm,Rs,Rn
-   Error if any register is R15.  */
+/* ARM V5 branch-link-exchange (argument parse) for BLX(1) only.
+   Expects inst.instruction is set for BLX(1).
+   Note: this is cloned from do_branch, and the reloc changed to be a
+       new one that can cope with setting one extra bit (the H bit).  */
 
 static void
-do_smla (str)
-     char *        str;
+do_branch25 (char * str)
 {
-  int rd, rm, rs, rn;
+  if (my_get_expression (& inst.reloc.exp, & str))
+    return;
 
-  skip_whitespace (str);
+#ifdef OBJ_ELF
+  {
+    char * save_in;
 
-  if ((rd = reg_required_here (& str, 16)) == FAIL
-      || skip_past_comma (& str) == FAIL
-      || (rm = reg_required_here (& str, 0)) == FAIL
-      || skip_past_comma (& str) == FAIL
-      || (rs = reg_required_here (& str, 8)) == FAIL
-      || skip_past_comma (& str) == FAIL
-      || (rn = reg_required_here (& str, 12)) == FAIL)
-    inst.error = BAD_ARGS;
+    /* ScottB: February 5, 1998 */
+    /* Check to see of PLT32 reloc required for the instruction.  */
+
+    /* arm_parse_reloc() works on input_line_pointer.
+       We actually want to parse the operands to the branch instruction
+       passed in 'str'.  Save the input pointer and restore it later.  */
+    save_in = input_line_pointer;
+    input_line_pointer = str;
+
+    if (inst.reloc.exp.X_op == O_symbol
+       && *str == '('
+       && arm_parse_reloc () == BFD_RELOC_ARM_PLT32)
+      {
+       inst.reloc.type   = BFD_RELOC_ARM_PLT32;
+       inst.reloc.pc_rel = 0;
+       /* Modify str to point to after parsed operands, otherwise
+          end_of_line() will complain about the (PLT) left in str.  */
+       str = input_line_pointer;
+      }
+    else
+      {
+       inst.reloc.type   = BFD_RELOC_ARM_PCREL_BLX;
+       inst.reloc.pc_rel = 1;
+      }
 
-  else if (rd == REG_PC || rm == REG_PC || rs == REG_PC || rn == REG_PC)
-    inst.error = BAD_PC;
+    input_line_pointer = save_in;
+  }
+#else
+  inst.reloc.type   = BFD_RELOC_ARM_PCREL_BLX;
+  inst.reloc.pc_rel = 1;
+#endif /* OBJ_ELF */
 
-  else
-    end_of_line (str);
+  end_of_line (str);
 }
 
-/* ARM V5E (El Segundo) signed-multiply-accumulate-long (argument parse)
-   SMLALxy{cond} Rdlo,Rdhi,Rm,Rs
-   Error if any register is R15.
-   Warning if Rdlo == Rdhi.  */
+/* ARM V5 branch-link-exchange instruction (argument parse)
+     BLX <target_addr>         ie BLX(1)
+     BLX{<condition>} <Rm>     ie BLX(2)
+   Unfortunately, there are two different opcodes for this mnemonic.
+   So, the insns[].value is not used, and the code here zaps values
+       into inst.instruction.
+   Also, the <target_addr> can be 25 bits, hence has its own reloc.  */
 
 static void
-do_smlal (str)
-     char *        str;
+do_blx (char * str)
 {
-  int rdlo, rdhi, rm, rs;
+  char * mystr = str;
+  int rm;
 
-  skip_whitespace (str);
+  skip_whitespace (mystr);
+  rm = reg_required_here (& mystr, 0);
 
-  if ((rdlo = reg_required_here (& str, 12)) == FAIL
-      || skip_past_comma (& str) == FAIL
-      || (rdhi = reg_required_here (& str, 16)) == FAIL
-      || skip_past_comma (& str) == FAIL
-      || (rm = reg_required_here (& str, 0)) == FAIL
-      || skip_past_comma (& str) == FAIL
-      || (rs = reg_required_here (& str, 8)) == FAIL)
-    {
-      inst.error = BAD_ARGS;
-      return;
-    }
+  /* The above may set inst.error.  Ignore his opinion.  */
+  inst.error = 0;
 
-  if (rdlo == REG_PC || rdhi == REG_PC || rm == REG_PC || rs == REG_PC)
+  if (rm != FAIL)
     {
-      inst.error = BAD_PC;
-      return;
+      /* Arg is a register.
+        Use the condition code our caller put in inst.instruction.
+        Pass ourselves off as a BX with a funny opcode.  */
+      inst.instruction |= 0x012fff30;
+      do_bx (str);
     }
+  else
+    {
+      /* This must be is BLX <target address>, no condition allowed.  */
+      if (inst.instruction != COND_ALWAYS)
+       {
+         inst.error = BAD_COND;
+         return;
+       }
 
-  if (rdlo == rdhi)
-    as_tsktsk (_("rdhi and rdlo must be different"));
+      inst.instruction = 0xfafffffe;
 
-  end_of_line (str);
+      /* Process like a B/BL, but with a different reloc.
+        Note that B/BL expecte fffffe, not 0, offset in the opcode table.  */
+      do_branch25 (str);
+    }
 }
 
-/* ARM V5E (El Segundo) signed-multiply (argument parse)
-   SMULxy{cond} Rd,Rm,Rs
-   Error if any register is R15.  */
+/* ARM V5 Thumb BLX (argument parse)
+       BLX <target_addr>       which is BLX(1)
+       BLX <Rm>                which is BLX(2)
+   Unfortunately, there are two different opcodes for this mnemonic.
+   So, the tinsns[].value is not used, and the code here zaps values
+       into inst.instruction.  */
 
 static void
-do_smul (str)
-     char *        str;
+do_t_blx (char * str)
 {
-  int rd, rm, rs;
-
-  skip_whitespace (str);
+  char * mystr = str;
+  int rm;
 
-  if ((rd = reg_required_here (& str, 16)) == FAIL
-      || skip_past_comma (& str) == FAIL
-      || (rm = reg_required_here (& str, 0)) == FAIL
-      || skip_past_comma (& str) == FAIL
-      || (rs = reg_required_here (& str, 8)) == FAIL)
-    inst.error = BAD_ARGS;
+  skip_whitespace (mystr);
+  inst.instruction = 0x4780;
 
-  else if (rd == REG_PC || rm == REG_PC || rs == REG_PC)
-    inst.error = BAD_PC;
+  /* Note that this call is to the ARM register recognizer.  BLX(2)
+     uses the ARM register space, not the Thumb one, so a call to
+     thumb_reg() would be wrong.  */
+  rm = reg_required_here (& mystr, 3);
+  inst.error = 0;
 
+  if (rm != FAIL)
+    {
+      /* It's BLX(2).  The .instruction was zapped with rm & is final.  */
+      inst.size = 2;
+    }
   else
-    end_of_line (str);
-}
-
-/* ARM V5E (El Segundo) saturating-add/subtract (argument parse)
-   Q[D]{ADD,SUB}{cond} Rd,Rm,Rn
-   Error if any register is R15.  */
-
-static void
-do_qadd (str)
-     char *        str;
-{
-  int rd, rm, rn;
-
-  skip_whitespace (str);
+    {
+      /* No ARM register.  This must be BLX(1).  Change the .instruction.  */
+      inst.instruction = 0xf7ffeffe;
+      inst.size = 4;
 
-  if ((rd = reg_required_here (& str, 12)) == FAIL
-      || skip_past_comma (& str) == FAIL
-      || (rm = reg_required_here (& str, 0)) == FAIL
-      || skip_past_comma (& str) == FAIL
-      || (rn = reg_required_here (& str, 16)) == FAIL)
-    inst.error = BAD_ARGS;
+      if (my_get_expression (& inst.reloc.exp, & mystr))
+       return;
 
-  else if (rd == REG_PC || rm == REG_PC || rn == REG_PC)
-    inst.error = BAD_PC;
+      inst.reloc.type   = BFD_RELOC_THUMB_PCREL_BLX;
+      inst.reloc.pc_rel = 1;
+    }
 
-  else
-    end_of_line (str);
+  end_of_line (mystr);
 }
 
-/* ARM V5E (el Segundo)
-   MCRRcc <coproc>, <opcode>, <Rd>, <Rn>, <CRm>.
-   MRRCcc <coproc>, <opcode>, <Rd>, <Rn>, <CRm>.
-
-   These are equivalent to the XScale instructions MAR and MRA,
-   respectively, when coproc == 0, opcode == 0, and CRm == 0.
-
-   Result unpredicatable if Rd or Rn is R15.  */
+/* ARM V5 breakpoint instruction (argument parse)
+     BKPT <16 bit unsigned immediate>
+     Instruction is not conditional.
+       The bit pattern given in insns[] has the COND_ALWAYS condition,
+       and it is an error if the caller tried to override that.  */
 
 static void
-do_co_reg2c (str)
-     char *        str;
+do_bkpt (char * str)
 {
-  int rd, rn;
+  expressionS expr;
+  unsigned long number;
 
   skip_whitespace (str);
 
-  if (co_proc_number (& str) == FAIL)
-    {
-      if (!inst.error)
-       inst.error = BAD_ARGS;
-      return;
-    }
+  /* Allow optional leading '#'.  */
+  if (is_immediate_prefix (* str))
+    str++;
 
-  if (skip_past_comma (& str) == FAIL
-      || cp_opc_expr (& str, 4, 4) == FAIL)
-    {
-      if (!inst.error)
-       inst.error = BAD_ARGS;
-      return;
-    }
+  memset (& expr, '\0', sizeof (expr));
 
-  if (skip_past_comma (& str) == FAIL
-      || (rd = reg_required_here (& str, 12)) == FAIL)
+  if (my_get_expression (& expr, & str)
+      || (expr.X_op != O_constant
+         /* As a convenience we allow 'bkpt' without an operand.  */
+         && expr.X_op != O_absent))
     {
-      if (!inst.error)
-       inst.error = BAD_ARGS;
+      inst.error = _("bad expression");
       return;
     }
 
-  if (skip_past_comma (& str) == FAIL
-      || (rn = reg_required_here (& str, 16)) == FAIL)
+  number = expr.X_add_number;
+
+  /* Check it fits a 16 bit unsigned.  */
+  if (number != (number & 0xffff))
     {
-      if (!inst.error)
-       inst.error = BAD_ARGS;
+      inst.error = _("immediate value out of range");
       return;
     }
 
-  /* Unpredictable result if rd or rn is R15.  */
-  if (rd == REG_PC || rn == REG_PC)
-    as_tsktsk
-      (_("Warning: instruction unpredictable when using r15"));
+  /* Top 12 of 16 bits to bits 19:8.  */
+  inst.instruction |= (number & 0xfff0) << 4;
 
-  if (skip_past_comma (& str) == FAIL
-      || cp_reg_required_here (& str, 0) == FAIL)
-    {
-      if (!inst.error)
-       inst.error = BAD_ARGS;
-      return;
-    }
+  /* Bottom 4 of 16 bits to bits 3:0.  */
+  inst.instruction |= number & 0xf;
 
   end_of_line (str);
 }
 
-/* ARM V5 count-leading-zeroes instruction (argument parse)
-     CLZ{<cond>} <Rd>, <Rm>
-     Condition defaults to COND_ALWAYS.
-     Error if Rd or Rm are R15.  */
+/* THUMB CPS instruction (argument parse).  */
 
 static void
-do_clz (str)
-     char *        str;
+do_t_cps (char * str)
 {
-  int rd, rm;
-
-  skip_whitespace (str);
-
-  if (((rd = reg_required_here (& str, 12)) == FAIL)
-      || (skip_past_comma (& str) == FAIL)
-      || ((rm = reg_required_here (& str, 0)) == FAIL))
-    inst.error = BAD_ARGS;
-
-  else if (rd == REG_PC || rm == REG_PC )
-    inst.error = BAD_PC;
-
-  else
-    end_of_line (str);
+  do_cps_flags (&str, /*thumb_p=*/1);
+  end_of_line (str);
 }
 
-/* ARM V5 (argument parse)
-     LDC2{L} <coproc>, <CRd>, <addressing mode>
-     STC2{L} <coproc>, <CRd>, <addressing mode>
-     Instruction is not conditional, and has 0xf in the codition field.
-     Otherwise, it's the same as LDC/STC.  */
+/* Parse and validate that a register is of the right form, this saves
+   repeated checking of this information in many similar cases.
+   Unlike the 32-bit case we do not insert the register into the opcode
+   here, since the position is often unknown until the full instruction
+   has been parsed.  */
 
-static void
-do_lstc2 (str)
-     char *        str;
+static int
+thumb_reg (char ** strp, int hi_lo)
 {
-  skip_whitespace (str);
+  int reg;
 
-  if (co_proc_number (& str) == FAIL)
-    {
-      if (!inst.error)
-       inst.error = BAD_ARGS;
-    }
-  else if (skip_past_comma (& str) == FAIL
-          || cp_reg_required_here (& str, 12) == FAIL)
-    {
-      if (!inst.error)
-       inst.error = BAD_ARGS;
-    }
-  else if (skip_past_comma (& str) == FAIL
-          || cp_address_required_here (&str, CP_WB_OK) == FAIL)
+  if ((reg = reg_required_here (strp, -1)) == FAIL)
+    return FAIL;
+
+  switch (hi_lo)
     {
-      if (! inst.error)
-       inst.error = BAD_ARGS;
+    case THUMB_REG_LO:
+      if (reg > 7)
+       {
+         inst.error = _("lo register required");
+         return FAIL;
+       }
+      break;
+
+    case THUMB_REG_HI:
+      if (reg < 8)
+       {
+         inst.error = _("hi register required");
+         return FAIL;
+       }
+      break;
+
+    default:
+      break;
     }
-  else
-    end_of_line (str);
-}
 
-/* ARM V5 (argument parse)
-     CDP2 <coproc>, <opcode_1>, <CRd>, <CRn>, <CRm>, <opcode_2>
-     Instruction is not conditional, and has 0xf in the condition field.
-     Otherwise, it's the same as CDP.  */
+  return reg;
+}
 
 static void
-do_cdp2 (str)
-     char *        str;
+thumb_mov_compare (char * str, int move)
 {
+  int Rd, Rs = FAIL;
+
   skip_whitespace (str);
 
-  if (co_proc_number (& str) == FAIL)
+  if ((Rd = thumb_reg (&str, THUMB_REG_ANY)) == FAIL
+      || skip_past_comma (&str) == FAIL)
     {
-      if (!inst.error)
+      if (! inst.error)
        inst.error = BAD_ARGS;
       return;
     }
 
-  if (skip_past_comma (& str) == FAIL
-      || cp_opc_expr (& str, 20,4) == FAIL)
+  if (move != THUMB_CPY && is_immediate_prefix (*str))
     {
-      if (!inst.error)
-       inst.error = BAD_ARGS;
-      return;
+      str++;
+      if (my_get_expression (&inst.reloc.exp, &str))
+       return;
     }
+  else if ((Rs = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
+    return;
 
-  if (skip_past_comma (& str) == FAIL
-      || cp_reg_required_here (& str, 12) == FAIL)
+  if (Rs != FAIL)
     {
-      if (!inst.error)
-       inst.error = BAD_ARGS;
-      return;
-    }
+      if (move != THUMB_CPY && Rs < 8 && Rd < 8)
+       {
+         if (move == THUMB_MOVE)
+           /* A move of two lowregs is encoded as ADD Rd, Rs, #0
+              since a MOV instruction produces unpredictable results.  */
+           inst.instruction = T_OPCODE_ADD_I3;
+         else
+           inst.instruction = T_OPCODE_CMP_LR;
+         inst.instruction |= Rd | (Rs << 3);
+       }
+      else
+       {
+         if (move == THUMB_MOVE)
+           inst.instruction = T_OPCODE_MOV_HR;
+         else if (move != THUMB_CPY)
+           inst.instruction = T_OPCODE_CMP_HR;
 
-  if (skip_past_comma (& str) == FAIL
-      || cp_reg_required_here (& str, 16) == FAIL)
-    {
-      if (!inst.error)
-       inst.error = BAD_ARGS;
-      return;
-    }
+         if (Rd > 7)
+           inst.instruction |= THUMB_H1;
 
-  if (skip_past_comma (& str) == FAIL
-      || cp_reg_required_here (& str, 0) == FAIL)
-    {
-      if (!inst.error)
-       inst.error = BAD_ARGS;
-      return;
-    }
+         if (Rs > 7)
+           inst.instruction |= THUMB_H2;
 
-  if (skip_past_comma (& str) == SUCCESS)
+         inst.instruction |= (Rd & 7) | ((Rs & 7) << 3);
+       }
+    }
+  else
     {
-      if (cp_opc_expr (& str, 5, 3) == FAIL)
+      if (Rd > 7)
        {
-         if (!inst.error)
-           inst.error = BAD_ARGS;
+         inst.error = _("only lo regs allowed with immediate");
          return;
        }
+
+      if (move == THUMB_MOVE)
+       inst.instruction = T_OPCODE_MOV_I8;
+      else
+       inst.instruction = T_OPCODE_CMP_I8;
+
+      inst.instruction |= Rd << 8;
+
+      if (inst.reloc.exp.X_op != O_constant)
+       inst.reloc.type = BFD_RELOC_ARM_THUMB_IMM;
+      else
+       {
+         unsigned value = inst.reloc.exp.X_add_number;
+
+         if (value > 255)
+           {
+             inst.error = _("invalid immediate");
+             return;
+           }
+
+         inst.instruction |= value;
+       }
     }
 
   end_of_line (str);
 }
 
-/* ARM V5 (argument parse)
-     MCR2 <coproc>, <opcode_1>, <Rd>, <CRn>, <CRm>, <opcode_2>
-     MRC2 <coproc>, <opcode_1>, <Rd>, <CRn>, <CRm>, <opcode_2>
-     Instruction is not conditional, and has 0xf in the condition field.
-     Otherwise, it's the same as MCR/MRC.  */
+/* THUMB CPY instruction (argument parse).  */
+
+static void
+do_t_cpy (char * str)
+{
+  thumb_mov_compare (str, THUMB_CPY);
+}
+
+/* THUMB SETEND instruction (argument parse).  */
 
 static void
-do_co_reg2 (str)
-     char *        str;
+do_t_setend (char * str)
+{
+  if (do_endian_specifier (str))
+    inst.instruction |= 0x8;
+}
+
+/* Parse INSN_TYPE insn STR having a possible IMMEDIATE_SIZE immediate.  */
+
+static unsigned long
+check_iwmmxt_insn (char * str,
+                  enum iwmmxt_insn_type insn_type,
+                  int immediate_size)
 {
+  int reg = 0;
+  const char *  inst_error;
+  expressionS expr;
+  unsigned long number;
+
+  inst_error = inst.error;
+  if (!inst.error)
+    inst.error = BAD_ARGS;
   skip_whitespace (str);
 
-  if (co_proc_number (& str) == FAIL)
+  switch (insn_type)
     {
-      if (!inst.error)
-       inst.error = BAD_ARGS;
-      return;
-    }
+    case check_rd:
+      if ((reg = reg_required_here (&str, 12)) == FAIL)
+       return FAIL;
+      break;
 
-  if (skip_past_comma (& str) == FAIL
-      || cp_opc_expr (& str, 21, 3) == FAIL)
-    {
-      if (!inst.error)
-       inst.error = BAD_ARGS;
-      return;
-    }
+    case check_wr:
+       if ((wreg_required_here (&str, 0, IWMMXT_REG_WR)) == FAIL)
+        return FAIL;
+       break;
 
-  if (skip_past_comma (& str) == FAIL
-      || reg_required_here (& str, 12) == FAIL)
-    {
-      if (!inst.error)
-       inst.error = BAD_ARGS;
-      return;
-    }
+    case check_wrwr:
+      if ((wreg_required_here (&str, 12, IWMMXT_REG_WR) == FAIL
+          || skip_past_comma (&str) == FAIL
+          || wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL))
+       return FAIL;
+      break;
 
-  if (skip_past_comma (& str) == FAIL
-      || cp_reg_required_here (& str, 16) == FAIL)
-    {
-      if (!inst.error)
-       inst.error = BAD_ARGS;
-      return;
-    }
+    case check_wrwrwr:
+      if ((wreg_required_here (&str, 12, IWMMXT_REG_WR) == FAIL
+          || skip_past_comma (&str) == FAIL
+          || wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL
+          || skip_past_comma (&str) == FAIL
+          || wreg_required_here (&str, 0, IWMMXT_REG_WR) == FAIL))
+       return FAIL;
+      break;
 
-  if (skip_past_comma (& str) == FAIL
-      || cp_reg_required_here (& str, 0) == FAIL)
-    {
-      if (!inst.error)
-       inst.error = BAD_ARGS;
-      return;
-    }
+    case check_wrwrwcg:
+      if ((wreg_required_here (&str, 12, IWMMXT_REG_WR) == FAIL
+          || skip_past_comma (&str) == FAIL
+          || wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL
+          || skip_past_comma (&str) == FAIL
+          || wreg_required_here (&str, 0, IWMMXT_REG_WCG) == FAIL))
+       return FAIL;
+      break;
 
-  if (skip_past_comma (& str) == SUCCESS)
-    {
-      if (cp_opc_expr (& str, 5, 3) == FAIL)
-       {
-         if (!inst.error)
-           inst.error = BAD_ARGS;
-         return;
-       }
-    }
+    case check_tbcst:
+      if ((wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL
+          || skip_past_comma (&str) == FAIL
+          || reg_required_here (&str, 12) == FAIL))
+       return FAIL;
+      break;
 
-  end_of_line (str);
-}
+    case check_tmovmsk:
+      if ((reg_required_here (&str, 12) == FAIL
+          || skip_past_comma (&str) == FAIL
+          || wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL))
+       return FAIL;
+      break;
 
-/* ARM v5TEJ.  Jump to Jazelle code.  */
-static void
-do_bxj (str)
-     char * str;
-{
-  int reg;
+    case check_tmia:
+      if ((wreg_required_here (&str, 5, IWMMXT_REG_WR) == FAIL
+          || skip_past_comma (&str) == FAIL
+          || reg_required_here (&str, 0) == FAIL
+          || skip_past_comma (&str) == FAIL
+          || reg_required_here (&str, 12) == FAIL))
+       return FAIL;
+      break;
 
-  skip_whitespace (str);
+    case check_tmcrr:
+      if ((wreg_required_here (&str, 0, IWMMXT_REG_WR) == FAIL
+          || skip_past_comma (&str) == FAIL
+          || reg_required_here (&str, 12) == FAIL
+          || skip_past_comma (&str) == FAIL
+          || reg_required_here (&str, 16) == FAIL))
+       return FAIL;
+      break;
 
-  if ((reg = reg_required_here (&str, 0)) == FAIL)
+    case check_tmrrc:
+      if ((reg_required_here (&str, 12) == FAIL
+          || skip_past_comma (&str) == FAIL
+          || reg_required_here (&str, 16) == FAIL
+          || skip_past_comma (&str) == FAIL
+          || wreg_required_here (&str, 0, IWMMXT_REG_WR) == FAIL))
+       return FAIL;
+      break;
+
+    case check_tmcr:
+      if ((wreg_required_here (&str, 16, IWMMXT_REG_WC) == FAIL
+          || skip_past_comma (&str) == FAIL
+          || reg_required_here (&str, 12) == FAIL))
+       return FAIL;
+      break;
+
+    case check_tmrc:
+      if ((reg_required_here (&str, 12) == FAIL
+          || skip_past_comma (&str) == FAIL
+          || wreg_required_here (&str, 16, IWMMXT_REG_WC) == FAIL))
+       return FAIL;
+      break;
+
+    case check_tinsr:
+      if ((wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL
+          || skip_past_comma (&str) == FAIL
+          || reg_required_here (&str, 12) == FAIL
+          || skip_past_comma (&str) == FAIL))
+       return FAIL;
+      break;
+
+    case check_textrc:
+      if ((reg_required_here (&str, 12) == FAIL
+          || skip_past_comma (&str) == FAIL))
+       return FAIL;
+      break;
+
+    case check_waligni:
+      if ((wreg_required_here (&str, 12, IWMMXT_REG_WR) == FAIL
+          || skip_past_comma (&str) == FAIL
+          || wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL
+          || skip_past_comma (&str) == FAIL
+          || wreg_required_here (&str, 0, IWMMXT_REG_WR) == FAIL
+          || skip_past_comma (&str) == FAIL))
+       return FAIL;
+      break;
+
+    case check_textrm:
+      if ((reg_required_here (&str, 12) == FAIL
+          || skip_past_comma (&str) == FAIL
+          || wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL
+          || skip_past_comma (&str) == FAIL))
+       return FAIL;
+      break;
+
+    case check_wshufh:
+      if ((wreg_required_here (&str, 12, IWMMXT_REG_WR) == FAIL
+          || skip_past_comma (&str) == FAIL
+          || wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL
+          || skip_past_comma (&str) == FAIL))
+       return FAIL;
+      break;
+    }
+
+  if (immediate_size == 0)
     {
-      inst.error = BAD_ARGS;
-      return;
+      end_of_line (str);
+      inst.error = inst_error;
+      return reg;
     }
+  else
+    {
+      skip_whitespace (str);
 
-  /* Note - it is not illegal to do a "bxj pc".  Useless, but not illegal.  */
-  if (reg == REG_PC)
-    as_tsktsk (_("use of r15 in bxj is not really useful"));
+      /* Allow optional leading '#'.  */
+      if (is_immediate_prefix (* str))
+        str++;
 
-  end_of_line (str);
-}
+      memset (& expr, '\0', sizeof (expr));
 
-/* THUMB V5 breakpoint instruction (argument parse)
-       BKPT <immed_8>.  */
+      if (my_get_expression (& expr, & str) || (expr.X_op != O_constant))
+        {
+          inst.error = _("bad or missing expression");
+          return FAIL;
+        }
+
+      number = expr.X_add_number;
+
+      if (number != (number & immediate_size))
+        {
+          inst.error = _("immediate value out of range");
+          return FAIL;
+        }
+      end_of_line (str);
+      inst.error = inst_error;
+      return number;
+    }
+}
 
 static void
-do_t_bkpt (str)
-     char * str;
+do_iwmmxt_byte_addr (char * str)
 {
-  expressionS expr;
-  unsigned long number;
+  int op = (inst.instruction & 0x300) >> 8;
+  int reg;
 
-  skip_whitespace (str);
+  inst.instruction &= ~0x300;
+  inst.instruction |= (op & 1) << 22 | (op & 2) << 7;
 
-  /* Allow optional leading '#'.  */
-  if (is_immediate_prefix (*str))
-    str ++;
+  skip_whitespace (str);
 
-  memset (& expr, '\0', sizeof (expr));
-  if (my_get_expression (& expr, & str) || (expr.X_op != O_constant))
+  if ((reg = wreg_required_here (&str, 12, IWMMXT_REG_WR_OR_WC)) == FAIL
+      || skip_past_comma (& str) == FAIL
+      || cp_byte_address_required_here (&str) == FAIL)
     {
-      inst.error = _("bad or missing expression");
-      return;
+      if (! inst.error)
+        inst.error = BAD_ARGS;
     }
+  else
+    end_of_line (str);
 
-  number = expr.X_add_number;
-
-  /* Check it fits an 8 bit unsigned.  */
-  if (number != (number & 0xff))
+  if (wc_register (reg))
     {
-      inst.error = _("immediate value out of range");
-      return;
+      as_bad (_("non-word size not supported with control register"));
+      inst.instruction |=  0xf0000100;
+      inst.instruction &= ~0x00400000;
     }
+}
 
-  inst.instruction |= number;
+static void
+do_iwmmxt_tandc (char * str)
+{
+  int reg;
 
-  end_of_line (str);
+  reg = check_iwmmxt_insn (str, check_rd, 0);
+
+  if (reg != REG_PC && !inst.error)
+    inst.error = _("only r15 allowed here");
 }
 
-/* ARM V5 branch-link-exchange (argument parse) for BLX(1) only.
-   Expects inst.instruction is set for BLX(1).
-   Note: this is cloned from do_branch, and the reloc changed to be a
-       new one that can cope with setting one extra bit (the H bit).  */
+static void
+do_iwmmxt_tbcst (char * str)
+{
+  check_iwmmxt_insn (str, check_tbcst, 0);
+}
 
 static void
-do_branch25 (str)
-     char *        str;
+do_iwmmxt_textrc (char * str)
 {
-  if (my_get_expression (& inst.reloc.exp, & str))
+  unsigned long number;
+
+  if ((number = check_iwmmxt_insn (str, check_textrc, 7)) == (unsigned long) FAIL)
     return;
 
-#ifdef OBJ_ELF
-  {
-    char * save_in;
+  inst.instruction |= number & 0x7;
+}
 
-    /* ScottB: February 5, 1998 */
-    /* Check to see of PLT32 reloc required for the instruction.  */
+static void
+do_iwmmxt_textrm (char * str)
+{
+  unsigned long number;
 
-    /* arm_parse_reloc() works on input_line_pointer.
-       We actually want to parse the operands to the branch instruction
-       passed in 'str'.  Save the input pointer and restore it later.  */
-    save_in = input_line_pointer;
-    input_line_pointer = str;
+  if ((number = check_iwmmxt_insn (str, check_textrm, 7)) == (unsigned long) FAIL)
+    return;
 
-    if (inst.reloc.exp.X_op == O_symbol
-       && *str == '('
-       && arm_parse_reloc () == BFD_RELOC_ARM_PLT32)
-      {
-       inst.reloc.type   = BFD_RELOC_ARM_PLT32;
-       inst.reloc.pc_rel = 0;
-       /* Modify str to point to after parsed operands, otherwise
-          end_of_line() will complain about the (PLT) left in str.  */
-       str = input_line_pointer;
-      }
-    else
-      {
-       inst.reloc.type   = BFD_RELOC_ARM_PCREL_BLX;
-       inst.reloc.pc_rel = 1;
-      }
+  inst.instruction |= number & 0x7;
+}
 
-    input_line_pointer = save_in;
-  }
-#else
-  inst.reloc.type   = BFD_RELOC_ARM_PCREL_BLX;
-  inst.reloc.pc_rel = 1;
-#endif /* OBJ_ELF */
+static void
+do_iwmmxt_tinsr (char * str)
+{
+  unsigned long number;
 
-  end_of_line (str);
+  if ((number = check_iwmmxt_insn (str, check_tinsr, 7)) == (unsigned long) FAIL)
+    return;
+
+  inst.instruction |= number & 0x7;
 }
 
-/* ARM V5 branch-link-exchange instruction (argument parse)
-     BLX <target_addr>         ie BLX(1)
-     BLX{<condition>} <Rm>     ie BLX(2)
-   Unfortunately, there are two different opcodes for this mnemonic.
-   So, the insns[].value is not used, and the code here zaps values
-       into inst.instruction.
-   Also, the <target_addr> can be 25 bits, hence has its own reloc.  */
+static void
+do_iwmmxt_tmcr (char * str)
+{
+  check_iwmmxt_insn (str, check_tmcr, 0);
+}
 
 static void
-do_blx (str)
-     char *        str;
+do_iwmmxt_tmcrr (char * str)
 {
-  char * mystr = str;
-  int rm;
+  check_iwmmxt_insn (str, check_tmcrr, 0);
+}
 
-  skip_whitespace (mystr);
-  rm = reg_required_here (& mystr, 0);
+static void
+do_iwmmxt_tmia (char * str)
+{
+  check_iwmmxt_insn (str, check_tmia, 0);
+}
 
-  /* The above may set inst.error.  Ignore his opinion.  */
-  inst.error = 0;
+static void
+do_iwmmxt_tmovmsk (char * str)
+{
+  check_iwmmxt_insn (str, check_tmovmsk, 0);
+}
 
-  if (rm != FAIL)
-    {
-      /* Arg is a register.
-        Use the condition code our caller put in inst.instruction.
-        Pass ourselves off as a BX with a funny opcode.  */
-      inst.instruction |= 0x012fff30;
-      do_bx (str);
-    }
-  else
-    {
-      /* This must be is BLX <target address>, no condition allowed.  */
-      if (inst.instruction != COND_ALWAYS)
-       {
-         inst.error = BAD_COND;
-         return;
-       }
+static void
+do_iwmmxt_tmrc (char * str)
+{
+  check_iwmmxt_insn (str, check_tmrc, 0);
+}
 
-      inst.instruction = 0xfafffffe;
+static void
+do_iwmmxt_tmrrc (char * str)
+{
+  check_iwmmxt_insn (str, check_tmrrc, 0);
+}
 
-      /* Process like a B/BL, but with a different reloc.
-        Note that B/BL expecte fffffe, not 0, offset in the opcode table.  */
-      do_branch25 (str);
-    }
+static void
+do_iwmmxt_torc (char * str)
+{
+  check_iwmmxt_insn (str, check_rd, 0);
 }
 
-/* ARM V5 Thumb BLX (argument parse)
-       BLX <target_addr>       which is BLX(1)
-       BLX <Rm>                which is BLX(2)
-   Unfortunately, there are two different opcodes for this mnemonic.
-   So, the tinsns[].value is not used, and the code here zaps values
-       into inst.instruction.  */
+static void
+do_iwmmxt_waligni (char * str)
+{
+  unsigned long number;
+
+  if ((number = check_iwmmxt_insn (str, check_waligni, 7)) == (unsigned long) FAIL)
+    return;
+
+  inst.instruction |= ((number & 0x7) << 20);
+}
 
 static void
-do_t_blx (str)
-     char * str;
+do_iwmmxt_wmov (char * str)
 {
-  char * mystr = str;
-  int rm;
+  if (check_iwmmxt_insn (str, check_wrwr, 0) == (unsigned long) FAIL)
+    return;
 
-  skip_whitespace (mystr);
-  inst.instruction = 0x4780;
+  inst.instruction |= ((inst.instruction >> 16) & 0xf);
+}
 
-  /* Note that this call is to the ARM register recognizer.  BLX(2)
-     uses the ARM register space, not the Thumb one, so a call to
-     thumb_reg() would be wrong.  */
-  rm = reg_required_here (& mystr, 3);
-  inst.error = 0;
+static void
+do_iwmmxt_word_addr (char * str)
+{
+  int op = (inst.instruction & 0x300) >> 8;
+  int reg;
 
-  if (rm != FAIL)
+  inst.instruction &= ~0x300;
+  inst.instruction |= (op & 1) << 22 | (op & 2) << 7;
+
+  skip_whitespace (str);
+
+  if ((reg = wreg_required_here (&str, 12, IWMMXT_REG_WR_OR_WC)) == FAIL
+      || skip_past_comma (& str) == FAIL
+      || cp_address_required_here (& str, CP_WB_OK) == FAIL)
     {
-      /* It's BLX(2).  The .instruction was zapped with rm & is final.  */
-      inst.size = 2;
+      if (! inst.error)
+        inst.error = BAD_ARGS;
     }
   else
-    {
-      /* No ARM register.  This must be BLX(1).  Change the .instruction.  */
-      inst.instruction = 0xf7ffeffe;
-      inst.size = 4;
-
-      if (my_get_expression (& inst.reloc.exp, & mystr))
-       return;
+    end_of_line (str);
 
-      inst.reloc.type   = BFD_RELOC_THUMB_PCREL_BLX;
-      inst.reloc.pc_rel = 1;
+  if (wc_register (reg))
+    {
+      if ((inst.instruction & COND_MASK) != COND_ALWAYS)
+       as_bad (_("conditional execution not supported with control register"));
+      if (op != 2)
+       as_bad (_("non-word size not supported with control register"));
+      inst.instruction |=  0xf0000100;
+      inst.instruction &= ~0x00400000;
     }
-
-  end_of_line (mystr);
 }
 
-/* ARM V5 breakpoint instruction (argument parse)
-     BKPT <16 bit unsigned immediate>
-     Instruction is not conditional.
-       The bit pattern given in insns[] has the COND_ALWAYS condition,
-       and it is an error if the caller tried to override that.  */
-
 static void
-do_bkpt (str)
-     char *        str;
+do_iwmmxt_wrwr (char * str)
 {
-  expressionS expr;
-  unsigned long number;
-
-  skip_whitespace (str);
-
-  /* Allow optional leading '#'.  */
-  if (is_immediate_prefix (* str))
-    str++;
+  check_iwmmxt_insn (str, check_wrwr, 0);
+}
 
-  memset (& expr, '\0', sizeof (expr));
+static void
+do_iwmmxt_wrwrwcg (char * str)
+{
+  check_iwmmxt_insn (str, check_wrwrwcg, 0);
+}
 
-  if (my_get_expression (& expr, & str) || (expr.X_op != O_constant))
-    {
-      inst.error = _("bad or missing expression");
-      return;
-    }
+static void
+do_iwmmxt_wrwrwr (char * str)
+{
+  check_iwmmxt_insn (str, check_wrwrwr, 0);
+}
 
-  number = expr.X_add_number;
+static void
+do_iwmmxt_wshufh (char * str)
+{
+  unsigned long number;
 
-  /* Check it fits a 16 bit unsigned.  */
-  if (number != (number & 0xffff))
-    {
-      inst.error = _("immediate value out of range");
-      return;
-    }
+  if ((number = check_iwmmxt_insn (str, check_wshufh, 0xff)) == (unsigned long) FAIL)
+    return;
 
-  /* Top 12 of 16 bits to bits 19:8.  */
-  inst.instruction |= (number & 0xfff0) << 4;
+  inst.instruction |= ((number & 0xf0) << 16) | (number & 0xf);
+}
 
-  /* Bottom 4 of 16 bits to bits 3:0.  */
-  inst.instruction |= number & 0xf;
+static void
+do_iwmmxt_wzero (char * str)
+{
+  if (check_iwmmxt_insn (str, check_wr, 0) == (unsigned long) FAIL)
+    return;
 
-  end_of_line (str);
+  inst.instruction |= ((inst.instruction & 0xf) << 12) | ((inst.instruction & 0xf) << 16);
 }
 
 /* Xscale multiply-accumulate (argument parse)
@@ -4141,8 +5304,7 @@ do_bkpt (str)
      MIAxycc acc0,Rm,Rs.  */
 
 static void
-do_xsc_mia (str)
-     char * str;
+do_xsc_mia (char * str)
 {
   int rs;
   int rm;
@@ -4171,8 +5333,7 @@ do_xsc_mia (str)
      MARcc   acc0,RdLo,RdHi.  */
 
 static void
-do_xsc_mar (str)
-     char * str;
+do_xsc_mar (char * str)
 {
   int rdlo, rdhi;
 
@@ -4199,34 +5360,91 @@ do_xsc_mar (str)
 
      MRAcc   RdLo,RdHi,acc0.  */
 
-static void
-do_xsc_mra (str)
-     char * str;
-{
-  int rdlo;
-  int rdhi;
+static void
+do_xsc_mra (char * str)
+{
+  int rdlo;
+  int rdhi;
+
+  skip_whitespace (str);
+
+  if ((rdlo = reg_required_here (& str, 12)) == FAIL)
+    inst.error = BAD_ARGS;
+
+  else if (skip_past_comma (& str) == FAIL
+          || (rdhi = reg_required_here (& str, 16)) == FAIL)
+    inst.error = BAD_ARGS;
+
+  else if  (skip_past_comma (& str) == FAIL
+           || accum0_required_here (& str) == FAIL)
+    inst.error = ERR_NO_ACCUM;
+
+  /* inst.instruction has now been zapped with both rdlo and rdhi.  */
+  else if (rdlo == rdhi)
+    inst.error = BAD_ARGS;     /* Undefined result if 2 writes to same reg.  */
+
+  else if (rdlo == REG_PC || rdhi == REG_PC)
+    inst.error = BAD_PC;       /* Undefined result if rdlo or rdhi is R15.  */
+  else
+    end_of_line (str);
+}
+
+static int
+ldst_extend (char ** str)
+{
+  int add = INDEX_UP;
+
+  switch (**str)
+    {
+    case '#':
+    case '$':
+      (*str)++;
+      if (my_get_expression (& inst.reloc.exp, str))
+       return FAIL;
+
+      if (inst.reloc.exp.X_op == O_constant)
+       {
+         int value = inst.reloc.exp.X_add_number;
+
+         if (value < -4095 || value > 4095)
+           {
+             inst.error = _("address offset too large");
+             return FAIL;
+           }
+
+         if (value < 0)
+           {
+             value = -value;
+             add = 0;
+           }
 
-  skip_whitespace (str);
+         inst.instruction |= add | value;
+       }
+      else
+       {
+         inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM;
+         inst.reloc.pc_rel = 0;
+       }
+      return SUCCESS;
 
-  if ((rdlo = reg_required_here (& str, 12)) == FAIL)
-    inst.error = BAD_ARGS;
+    case '-':
+      add = 0;
+      /* Fall through.  */
 
-  else if (skip_past_comma (& str) == FAIL
-          || (rdhi = reg_required_here (& str, 16)) == FAIL)
-    inst.error = BAD_ARGS;
+    case '+':
+      (*str)++;
+      /* Fall through.  */
 
-  else if  (skip_past_comma (& str) == FAIL
-           || accum0_required_here (& str) == FAIL)
-    inst.error = ERR_NO_ACCUM;
+    default:
+      if (reg_required_here (str, 0) == FAIL)
+       return FAIL;
 
-  /* inst.instruction has now been zapped with both rdlo and rdhi.  */
-  else if (rdlo == rdhi)
-    inst.error = BAD_ARGS;     /* Undefined result if 2 writes to same reg.  */
+      inst.instruction |= add | OFFSET_REG;
+      if (skip_past_comma (str) == SUCCESS)
+       return decode_shift (str, SHIFT_IMMEDIATE);
 
-  else if (rdlo == REG_PC || rdhi == REG_PC)
-    inst.error = BAD_PC;       /* Undefined result if rdlo or rdhi is R15.  */
-  else
-    end_of_line (str);
+      return SUCCESS;
+    }
 }
 
 /* ARMv5TE: Preload-Cache
@@ -4236,8 +5454,7 @@ do_xsc_mra (str)
   Syntactically, like LDR with B=1, W=0, L=1.  */
 
 static void
-do_pld (str)
-     char * str;
+do_pld (char * str)
 {
   int rd;
 
@@ -4319,8 +5536,7 @@ do_pld (str)
      STRccD R, mode.  */
 
 static void
-do_ldrd (str)
-     char * str;
+do_ldrd (char * str)
 {
   int rd;
   int rn;
@@ -4338,318 +5554,125 @@ do_ldrd (str)
     {
       if (!inst.error)
        inst.error = BAD_ARGS;
-      return;
-    }
-
-  /* inst.instruction has now been zapped with Rd and the addressing mode.  */
-  if (rd & 1)          /* Unpredictable result if Rd is odd.  */
-    {
-      inst.error = _("destination register must be even");
-      return;
-    }
-
-  if (rd == REG_LR)
-    {
-      inst.error = _("r14 not allowed here");
-      return;
-    }
-
-  if (((rd == rn) || (rd + 1 == rn))
-      && ((inst.instruction & WRITE_BACK)
-         || (!(inst.instruction & PRE_INDEX))))
-    as_warn (_("pre/post-indexing used when modified address register is destination"));
-
-  /* For an index-register load, the index register must not overlap the
-     destination (even if not write-back).  */
-  if ((inst.instruction & V4_STR_BIT) == 0
-      && (inst.instruction & HWOFFSET_IMM) == 0)
-    {
-      int rm = inst.instruction & 0x0000000f;
-
-      if (rm == rd || (rm == rd + 1))
-       as_warn (_("ldrd destination registers must not overlap index register"));
-    }
-
-  end_of_line (str);
-}
-
-/* Returns the index into fp_values of a floating point number,
-   or -1 if not in the table.  */
-
-static int
-my_get_float_expression (str)
-     char ** str;
-{
-  LITTLENUM_TYPE words[MAX_LITTLENUMS];
-  char *         save_in;
-  expressionS    exp;
-  int            i;
-  int            j;
-
-  memset (words, 0, MAX_LITTLENUMS * sizeof (LITTLENUM_TYPE));
-
-  /* Look for a raw floating point number.  */
-  if ((save_in = atof_ieee (*str, 'x', words)) != NULL
-      && is_end_of_line[(unsigned char) *save_in])
-    {
-      for (i = 0; i < NUM_FLOAT_VALS; i++)
-       {
-         for (j = 0; j < MAX_LITTLENUMS; j++)
-           {
-             if (words[j] != fp_values[i][j])
-               break;
-           }
-
-         if (j == MAX_LITTLENUMS)
-           {
-             *str = save_in;
-             return i;
-           }
-       }
-    }
-
-  /* Try and parse a more complex expression, this will probably fail
-     unless the code uses a floating point prefix (eg "0f").  */
-  save_in = input_line_pointer;
-  input_line_pointer = *str;
-  if (expression (&exp) == absolute_section
-      && exp.X_op == O_big
-      && exp.X_add_number < 0)
-    {
-      /* FIXME: 5 = X_PRECISION, should be #define'd where we can use it.
-        Ditto for 15.  */
-      if (gen_to_words (words, 5, (long) 15) == 0)
-       {
-         for (i = 0; i < NUM_FLOAT_VALS; i++)
-           {
-             for (j = 0; j < MAX_LITTLENUMS; j++)
-               {
-                 if (words[j] != fp_values[i][j])
-                   break;
-               }
-
-             if (j == MAX_LITTLENUMS)
-               {
-                 *str = input_line_pointer;
-                 input_line_pointer = save_in;
-                 return i;
-               }
-           }
-       }
-    }
-
-  *str = input_line_pointer;
-  input_line_pointer = save_in;
-  return -1;
-}
-
-/* Return true if anything in the expression is a bignum.  */
-
-static int
-walk_no_bignums (sp)
-     symbolS * sp;
-{
-  if (symbol_get_value_expression (sp)->X_op == O_big)
-    return 1;
-
-  if (symbol_get_value_expression (sp)->X_add_symbol)
-    {
-      return (walk_no_bignums (symbol_get_value_expression (sp)->X_add_symbol)
-             || (symbol_get_value_expression (sp)->X_op_symbol
-                 && walk_no_bignums (symbol_get_value_expression (sp)->X_op_symbol)));
-    }
-
-  return 0;
-}
-
-static int in_my_get_expression = 0;
-
-static int
-my_get_expression (ep, str)
-     expressionS * ep;
-     char ** str;
-{
-  char * save_in;
-  segT   seg;
-
-  save_in = input_line_pointer;
-  input_line_pointer = *str;
-  in_my_get_expression = 1;
-  seg = expression (ep);
-  in_my_get_expression = 0;
-
-  if (ep->X_op == O_illegal)
-    {
-      /* We found a bad expression in md_operand().  */
-      *str = input_line_pointer;
-      input_line_pointer = save_in;
-      return 1;
-    }
-
-#ifdef OBJ_AOUT
-  if (seg != absolute_section
-      && seg != text_section
-      && seg != data_section
-      && seg != bss_section
-      && seg != undefined_section)
-    {
-      inst.error = _("bad_segment");
-      *str = input_line_pointer;
-      input_line_pointer = save_in;
-      return 1;
-    }
-#endif
-
-  /* Get rid of any bignums now, so that we don't generate an error for which
-     we can't establish a line number later on.  Big numbers are never valid
-     in instructions, which is where this routine is always called.  */
-  if (ep->X_op == O_big
-      || (ep->X_add_symbol
-         && (walk_no_bignums (ep->X_add_symbol)
-             || (ep->X_op_symbol
-                 && walk_no_bignums (ep->X_op_symbol)))))
-    {
-      inst.error = _("invalid constant");
-      *str = input_line_pointer;
-      input_line_pointer = save_in;
-      return 1;
-    }
-
-  *str = input_line_pointer;
-  input_line_pointer = save_in;
-  return 0;
-}
-
-/* We handle all bad expressions here, so that we can report the faulty
-   instruction in the error message.  */
-void
-md_operand (expr)
-     expressionS *expr;
-{
-  if (in_my_get_expression)
-    {
-      expr->X_op = O_illegal;
-      if (inst.error == NULL)
-       inst.error = _("bad expression");
-    }
-}
-
-/* UNRESTRICT should be one if <shift> <register> is permitted for this
-   instruction.  */
-
-static int
-decode_shift (str, unrestrict)
-     char ** str;
-     int     unrestrict;
-{
-  const struct asm_shift_name * shift;
-  char * p;
-  char   c;
-
-  skip_whitespace (* str);
-
-  for (p = * str; ISALPHA (* p); p ++)
-    ;
-
-  if (p == * str)
-    {
-      inst.error = _("shift expression expected");
-      return FAIL;
-    }
-
-  c = * p;
-  * p = '\0';
-  shift = (const struct asm_shift_name *) hash_find (arm_shift_hsh, * str);
-  * p = c;
+      return;
+    }
 
-  if (shift == NULL)
+  /* inst.instruction has now been zapped with Rd and the addressing mode.  */
+  if (rd & 1)          /* Unpredictable result if Rd is odd.  */
     {
-      inst.error = _("shift expression expected");
-      return FAIL;
+      inst.error = _("destination register must be even");
+      return;
     }
 
-  assert (shift->properties->index == shift_properties[shift->properties->index].index);
-
-  if (shift->properties->index == SHIFT_RRX)
+  if (rd == REG_LR)
     {
-      * str = p;
-      inst.instruction |= shift->properties->bit_field;
-      return SUCCESS;
+      inst.error = _("r14 not allowed here");
+      return;
     }
 
-  skip_whitespace (p);
+  if (((rd == rn) || (rd + 1 == rn))
+      && ((inst.instruction & WRITE_BACK)
+         || (!(inst.instruction & PRE_INDEX))))
+    as_warn (_("pre/post-indexing used when modified address register is destination"));
 
-  if (unrestrict && reg_required_here (& p, 8) != FAIL)
-    {
-      inst.instruction |= shift->properties->bit_field | SHIFT_BY_REG;
-      * str = p;
-      return SUCCESS;
-    }
-  else if (! is_immediate_prefix (* p))
+  /* For an index-register load, the index register must not overlap the
+     destination (even if not write-back).  */
+  if ((inst.instruction & V4_STR_BIT) == 0
+      && (inst.instruction & HWOFFSET_IMM) == 0)
     {
-      inst.error = (unrestrict
-                   ? _("shift requires register or #expression")
-                   : _("shift requires #expression"));
-      * str = p;
-      return FAIL;
+      int rm = inst.instruction & 0x0000000f;
+
+      if (rm == rd || (rm == rd + 1))
+       as_warn (_("ldrd destination registers must not overlap index register"));
     }
 
-  inst.error = NULL;
-  p ++;
+  end_of_line (str);
+}
 
-  if (my_get_expression (& inst.reloc.exp, & p))
-    return FAIL;
+/* Returns the index into fp_values of a floating point number,
+   or -1 if not in the table.  */
 
-  /* Validate some simple #expressions.  */
-  if (inst.reloc.exp.X_op == O_constant)
-    {
-      unsigned num = inst.reloc.exp.X_add_number;
+static int
+my_get_float_expression (char ** str)
+{
+  LITTLENUM_TYPE words[MAX_LITTLENUMS];
+  char *         save_in;
+  expressionS    exp;
+  int            i;
+  int            j;
 
-      /* Reject operations greater than 32.  */
-      if (num > 32
-         /* Reject a shift of 0 unless the mode allows it.  */
-         || (num == 0 && shift->properties->allows_0 == 0)
-         /* Reject a shift of 32 unless the mode allows it.  */
-         || (num == 32 && shift->properties->allows_32 == 0)
-         )
+  memset (words, 0, MAX_LITTLENUMS * sizeof (LITTLENUM_TYPE));
+
+  /* Look for a raw floating point number.  */
+  if ((save_in = atof_ieee (*str, 'x', words)) != NULL
+      && is_end_of_line[(unsigned char) *save_in])
+    {
+      for (i = 0; i < NUM_FLOAT_VALS; i++)
        {
-         /* As a special case we allow a shift of zero for
-            modes that do not support it to be recoded as an
-            logical shift left of zero (ie nothing).  We warn
-            about this though.  */
-         if (num == 0)
+         for (j = 0; j < MAX_LITTLENUMS; j++)
            {
-             as_warn (_("shift of 0 ignored."));
-             shift = & shift_names[0];
-             assert (shift->properties->index == SHIFT_LSL);
+             if (words[j] != fp_values[i][j])
+               break;
            }
-         else
+
+         if (j == MAX_LITTLENUMS)
            {
-             inst.error = _("invalid immediate shift");
-             return FAIL;
+             *str = save_in;
+             return i;
            }
        }
+    }
 
-      /* Shifts of 32 are encoded as 0, for those shifts that
-        support it.  */
-      if (num == 32)
-       num = 0;
+  /* Try and parse a more complex expression, this will probably fail
+     unless the code uses a floating point prefix (eg "0f").  */
+  save_in = input_line_pointer;
+  input_line_pointer = *str;
+  if (expression (&exp) == absolute_section
+      && exp.X_op == O_big
+      && exp.X_add_number < 0)
+    {
+      /* FIXME: 5 = X_PRECISION, should be #define'd where we can use it.
+        Ditto for 15.  */
+      if (gen_to_words (words, 5, (long) 15) == 0)
+       {
+         for (i = 0; i < NUM_FLOAT_VALS; i++)
+           {
+             for (j = 0; j < MAX_LITTLENUMS; j++)
+               {
+                 if (words[j] != fp_values[i][j])
+                   break;
+               }
 
-      inst.instruction |= (num << 7) | shift->properties->bit_field;
+             if (j == MAX_LITTLENUMS)
+               {
+                 *str = input_line_pointer;
+                 input_line_pointer = save_in;
+                 return i;
+               }
+           }
+       }
     }
-  else
+
+  *str = input_line_pointer;
+  input_line_pointer = save_in;
+  return -1;
+}
+
+/* We handle all bad expressions here, so that we can report the faulty
+   instruction in the error message.  */
+void
+md_operand (expressionS * expr)
+{
+  if (in_my_get_expression)
     {
-      inst.reloc.type   = BFD_RELOC_ARM_SHIFT_IMM;
-      inst.reloc.pc_rel = 0;
-      inst.instruction |= shift->properties->bit_field;
+      expr->X_op = O_illegal;
+      if (inst.error == NULL)
+       inst.error = _("bad expression");
     }
-
-  * str = p;
-  return SUCCESS;
 }
 
 /* Do those data_ops which can take a negative immediate constant
-   by altering the instuction.  A bit of a hack really.
+   by altering the instruction.  A bit of a hack really.
         MOV <-> MVN
         AND <-> BIC
         ADC <-> SBC
@@ -4659,9 +5682,8 @@ decode_shift (str, unrestrict)
         by negating the second operand.  */
 
 static int
-negate_data_op (instruction, value)
-     unsigned long * instruction;
-     unsigned long   value;
+negate_data_op (unsigned long * instruction,
+               unsigned long   value)
 {
   int op, new_inst;
   unsigned long negated, inverted;
@@ -4738,8 +5760,7 @@ negate_data_op (instruction, value)
 }
 
 static int
-data_op2 (str)
-     char ** str;
+data_op2 (char ** str)
 {
   int value;
   expressionS expr;
@@ -4828,8 +5849,7 @@ data_op2 (str)
 }
 
 static int
-fp_op2 (str)
-     char ** str;
+fp_op2 (char ** str)
 {
   skip_whitespace (* str);
 
@@ -4885,8 +5905,7 @@ fp_op2 (str)
 }
 
 static void
-do_arit (str)
-     char * str;
+do_arit (char * str)
 {
   skip_whitespace (str);
 
@@ -4902,12 +5921,10 @@ do_arit (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
-do_adr (str)
-     char * str;
+do_adr (char * str)
 {
   /* 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".  */
@@ -4925,15 +5942,16 @@ do_adr (str)
   /* Frag hacking will turn this into a sub instruction if the offset turns
      out to be negative.  */
   inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
+#ifndef TE_WINCE
   inst.reloc.exp.X_add_number -= 8; /* PC relative adjust.  */
+#endif
   inst.reloc.pc_rel = 1;
 
   end_of_line (str);
 }
 
 static void
-do_adrl (str)
-     char * str;
+do_adrl (char * str)
 {
   /* This is a pseudo-op of the form "adrl rd, label" to be converted
      into a relative address of the form:
@@ -4956,16 +5974,15 @@ do_adrl (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;
+#ifndef TE_WINCE
   inst.reloc.exp.X_add_number -= 8; /* PC relative adjust  */
+#endif
   inst.reloc.pc_rel            = 1;
   inst.size                    = INSN_SIZE * 2;
-
-  return;
 }
 
 static void
-do_cmp (str)
-     char * str;
+do_cmp (char * str)
 {
   skip_whitespace (str);
 
@@ -4985,12 +6002,10 @@ do_cmp (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
-do_mov (str)
-     char * str;
+do_mov (char * str)
 {
   skip_whitespace (str);
 
@@ -5010,71 +6025,10 @@ do_mov (str)
     }
 
   end_of_line (str);
-  return;
-}
-
-static int
-ldst_extend (str)
-     char ** str;
-{
-  int add = INDEX_UP;
-
-  switch (**str)
-    {
-    case '#':
-    case '$':
-      (*str)++;
-      if (my_get_expression (& inst.reloc.exp, str))
-       return FAIL;
-
-      if (inst.reloc.exp.X_op == O_constant)
-       {
-         int value = inst.reloc.exp.X_add_number;
-
-         if (value < -4095 || value > 4095)
-           {
-             inst.error = _("address offset too large");
-             return FAIL;
-           }
-
-         if (value < 0)
-           {
-             value = -value;
-             add = 0;
-           }
-
-         inst.instruction |= add | value;
-       }
-      else
-       {
-         inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM;
-         inst.reloc.pc_rel = 0;
-       }
-      return SUCCESS;
-
-    case '-':
-      add = 0;
-      /* Fall through.  */
-
-    case '+':
-      (*str)++;
-      /* Fall through.  */
-
-    default:
-      if (reg_required_here (str, 0) == FAIL)
-       return FAIL;
-
-      inst.instruction |= add | OFFSET_REG;
-      if (skip_past_comma (str) == SUCCESS)
-       return decode_shift (str, SHIFT_RESTRICT);
-
-      return SUCCESS;
-    }
 }
 
 static void
-do_ldst (str)
-     char *        str;
+do_ldst (char * str)
 {
   int pre_inc = 0;
   int conflict_reg;
@@ -5261,12 +6215,10 @@ do_ldst (str)
 
   inst.instruction |= (pre_inc ? PRE_INDEX : 0);
   end_of_line (str);
-  return;
 }
 
 static void
-do_ldstt (str)
-     char *        str;
+do_ldstt (char * str)
 {
   int conflict_reg;
 
@@ -5329,84 +6281,23 @@ do_ldstt (str)
        }
       else
        {
-         inst.error = _("post-indexed expression expected");
-         return;
-       }
-    }
-  else
-    {
-      inst.error = _("post-indexed expression expected");
-      return;
-    }
-
-  end_of_line (str);
-  return;
-}
-
-static int
-ldst_extend_v4 (str)
-     char ** str;
-{
-  int add = INDEX_UP;
-
-  switch (**str)
-    {
-    case '#':
-    case '$':
-      (*str)++;
-      if (my_get_expression (& inst.reloc.exp, str))
-       return FAIL;
-
-      if (inst.reloc.exp.X_op == O_constant)
-       {
-         int value = inst.reloc.exp.X_add_number;
-
-         if (value < -255 || value > 255)
-           {
-             inst.error = _("address offset too large");
-             return FAIL;
-           }
-
-         if (value < 0)
-           {
-             value = -value;
-             add = 0;
-           }
-
-         /* Halfword and signextension instructions have the
-             immediate value split across bits 11..8 and bits 3..0.  */
-         inst.instruction |= (add | HWOFFSET_IMM
-                              | ((value >> 4) << 8) | (value & 0xF));
-       }
-      else
-       {
-         inst.instruction |= HWOFFSET_IMM;
-         inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM8;
-         inst.reloc.pc_rel = 0;
+         inst.error = _("post-indexed expression expected");
+         return;
        }
-      return SUCCESS;
-
-    case '-':
-      add = 0;
-      /* Fall through.  */
-
-    case '+':
-      (*str)++;
-      /* Fall through.  */
-
-    default:
-      if (reg_required_here (str, 0) == FAIL)
-       return FAIL;
-
-      inst.instruction |= add;
-      return SUCCESS;
     }
+  else
+    {
+      inst.error = _("post-indexed expression expected");
+      return;
+    }
+
+  end_of_line (str);
 }
 
 /* Halfword and signed-byte load/store operations.  */
+
 static void
-do_ldstv4 (str)
-     char *        str;
+do_ldstv4 (char * str)
 {
   int pre_inc = 0;
   int conflict_reg;
@@ -5596,12 +6487,10 @@ do_ldstv4 (str)
 
   inst.instruction |= (pre_inc ? PRE_INDEX : 0);
   end_of_line (str);
-  return;
 }
 
 static long
-reg_list (strp)
-     char ** strp;
+reg_list (char ** strp)
 {
   char * str = * strp;
   long   range = 0;
@@ -5727,8 +6616,7 @@ reg_list (strp)
 }
 
 static void
-do_ldmstm (str)
-     char * str;
+do_ldmstm (char * str)
 {
   int base_reg;
   long range;
@@ -5766,14 +6654,37 @@ do_ldmstm (str)
       inst.instruction |= LDM_TYPE_2_OR_3;
     }
 
+  if (inst.instruction & WRITE_BACK)
+    {
+      /* Check for unpredictable uses of writeback.  */
+      if (inst.instruction & LOAD_BIT)
+       {
+         /* Not allowed in LDM type 2.  */
+         if ((inst.instruction & LDM_TYPE_2_OR_3)
+             && ((range & (1 << REG_PC)) == 0))
+           as_warn (_("writeback of base register is UNPREDICTABLE"));
+         /* Only allowed if base reg not in list for other types.  */
+         else if (range & (1 << base_reg))
+           as_warn (_("writeback of base register when in register list is UNPREDICTABLE"));
+       }
+      else /* STM.  */
+       {
+         /* Not allowed for type 2.  */
+         if (inst.instruction & LDM_TYPE_2_OR_3)
+           as_warn (_("writeback of base register is UNPREDICTABLE"));
+         /* Only allowed if base reg not in list, or first in list.  */
+         else if ((range & (1 << base_reg))
+                  && (range & ((1 << base_reg) - 1)))
+           as_warn (_("if writeback register is in list, it must be the lowest reg in the list"));
+       }
+    }
+
   inst.instruction |= range;
   end_of_line (str);
-  return;
 }
 
 static void
-do_swi (str)
-     char * str;
+do_smi (char * str)
 {
   skip_whitespace (str);
 
@@ -5784,16 +6695,30 @@ do_swi (str)
   if (my_get_expression (& inst.reloc.exp, & str))
     return;
 
-  inst.reloc.type = BFD_RELOC_ARM_SWI;
+  inst.reloc.type = BFD_RELOC_ARM_SMI;
   inst.reloc.pc_rel = 0;
   end_of_line (str);
+}
 
-  return;
+static void
+do_swi (char * str)
+{
+  skip_whitespace (str);
+
+  /* Allow optional leading '#'.  */
+  if (is_immediate_prefix (*str))
+    str++;
+
+  if (my_get_expression (& inst.reloc.exp, & str))
+    return;
+
+  inst.reloc.type = BFD_RELOC_ARM_SWI;
+  inst.reloc.pc_rel = 0;
+  end_of_line (str);
 }
 
 static void
-do_swap (str)
-     char * str;
+do_swap (char * str)
 {
   int reg;
 
@@ -5849,12 +6774,10 @@ do_swap (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
-do_branch (str)
-     char * str;
+do_branch (char * str)
 {
   if (my_get_expression (&inst.reloc.exp, &str))
     return;
@@ -5894,33 +6817,10 @@ do_branch (str)
 #endif /* OBJ_ELF  */
 
   end_of_line (str);
-  return;
-}
-
-static void
-do_bx (str)
-     char * str;
-{
-  int reg;
-
-  skip_whitespace (str);
-
-  if ((reg = reg_required_here (&str, 0)) == FAIL)
-    {
-      inst.error = BAD_ARGS;
-      return;
-    }
-
-  /* Note - it is not illegal to do a "bx pc".  Useless, but not illegal.  */
-  if (reg == REG_PC)
-    as_tsktsk (_("use of r15 in bx in ARM mode is not really useful"));
-
-  end_of_line (str);
 }
 
 static void
-do_cdp (str)
-     char * str;
+do_cdp (char * str)
 {
   /* Co-processor data operation.
      Format: CDP{cond} CP#,<expr>,CRd,CRn,CRm{,<expr>}  */
@@ -5976,12 +6876,10 @@ do_cdp (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
-do_lstc (str)
-     char * str;
+do_lstc (char * str)
 {
   /* Co-processor register load/store.
      Format: <LDC|STC{cond}[L] CP#,CRd,<address>  */
@@ -6012,12 +6910,10 @@ do_lstc (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
-do_co_reg (str)
-     char * str;
+do_co_reg (char * str)
 {
   /* Co-processor register transfer.
      Format: <MCR|MRC>{cond} CP#,<expr1>,Rd,CRn,CRm{,<expr2>}  */
@@ -6074,12 +6970,10 @@ do_co_reg (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
-do_fpa_ctrl (str)
-     char * str;
+do_fpa_ctrl (char * str)
 {
   /* FP control registers.
      Format: <WFS|RFS|WFC|RFC>{cond} Rn  */
@@ -6094,12 +6988,10 @@ do_fpa_ctrl (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
-do_fpa_ldst (str)
-     char * str;
+do_fpa_ldst (char * str)
 {
   skip_whitespace (str);
 
@@ -6122,8 +7014,7 @@ do_fpa_ldst (str)
 }
 
 static void
-do_fpa_ldmstm (str)
-     char * str;
+do_fpa_ldmstm (char * str)
 {
   int num_regs;
 
@@ -6261,8 +7152,7 @@ do_fpa_ldmstm (str)
 }
 
 static void
-do_fpa_dyadic (str)
-     char * str;
+do_fpa_dyadic (char * str)
 {
   skip_whitespace (str);
 
@@ -6290,12 +7180,10 @@ do_fpa_dyadic (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
-do_fpa_monadic (str)
-     char * str;
+do_fpa_monadic (char * str)
 {
   skip_whitespace (str);
 
@@ -6315,12 +7203,10 @@ do_fpa_monadic (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
-do_fpa_cmp (str)
-     char * str;
+do_fpa_cmp (char * str)
 {
   skip_whitespace (str);
 
@@ -6340,12 +7226,10 @@ do_fpa_cmp (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
-do_fpa_from_reg (str)
-     char * str;
+do_fpa_from_reg (char * str)
 {
   skip_whitespace (str);
 
@@ -6365,12 +7249,10 @@ do_fpa_from_reg (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
-do_fpa_to_reg (str)
-     char * str;
+do_fpa_to_reg (char * str)
 {
   skip_whitespace (str);
 
@@ -6386,13 +7268,11 @@ do_fpa_to_reg (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static int
-vfp_sp_reg_required_here (str, pos)
-     char **str;
-     enum vfp_sp_reg_pos pos;
+vfp_sp_reg_required_here (char ** str,
+                         enum vfp_sp_reg_pos pos)
 {
   int    reg;
   char *start = *str;
@@ -6429,12 +7309,11 @@ vfp_sp_reg_required_here (str, pos)
 }
 
 static int
-vfp_dp_reg_required_here (str, pos)
-     char **str;
-     enum vfp_dp_reg_pos pos;
+vfp_dp_reg_required_here (char ** str,
+                         enum vfp_dp_reg_pos pos)
 {
-  int   reg;
-  char *start = *str;
+  int    reg;
+  char * start = *str;
 
   if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_DN].htab)) != FAIL)
     {
@@ -6462,110 +7341,262 @@ vfp_dp_reg_required_here (str, pos)
      this error can be overridden.  */
   inst.error = _(all_reg_maps[REG_TYPE_DN].expected);
 
-  /* Restore the start point.  */
-  *str = start;
-  return FAIL;
-}
+  /* Restore the start point.  */
+  *str = start;
+  return FAIL;
+}
+
+static void
+do_vfp_sp_monadic (char * str)
+{
+  skip_whitespace (str);
+
+  if (vfp_sp_reg_required_here (&str, VFP_REG_Sd) == FAIL)
+    return;
+
+  if (skip_past_comma (&str) == FAIL
+      || vfp_sp_reg_required_here (&str, VFP_REG_Sm) == FAIL)
+    {
+      if (! inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  end_of_line (str);
+}
+
+static void
+do_vfp_dp_monadic (char * str)
+{
+  skip_whitespace (str);
+
+  if (vfp_dp_reg_required_here (&str, VFP_REG_Dd) == FAIL)
+    return;
+
+  if (skip_past_comma (&str) == FAIL
+      || vfp_dp_reg_required_here (&str, VFP_REG_Dm) == FAIL)
+    {
+      if (! inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  end_of_line (str);
+}
+
+static void
+do_vfp_sp_dyadic (char * str)
+{
+  skip_whitespace (str);
+
+  if (vfp_sp_reg_required_here (&str, VFP_REG_Sd) == FAIL)
+    return;
+
+  if (skip_past_comma (&str) == FAIL
+      || vfp_sp_reg_required_here (&str, VFP_REG_Sn) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || vfp_sp_reg_required_here (&str, VFP_REG_Sm) == FAIL)
+    {
+      if (! inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  end_of_line (str);
+}
+
+static void
+do_vfp_dp_dyadic (char * str)
+{
+  skip_whitespace (str);
+
+  if (vfp_dp_reg_required_here (&str, VFP_REG_Dd) == FAIL)
+    return;
+
+  if (skip_past_comma (&str) == FAIL
+      || vfp_dp_reg_required_here (&str, VFP_REG_Dn) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || vfp_dp_reg_required_here (&str, VFP_REG_Dm) == FAIL)
+    {
+      if (! inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  end_of_line (str);
+}
+
+static void
+do_vfp_reg_from_sp (char * str)
+{
+  skip_whitespace (str);
+
+  if (reg_required_here (&str, 12) == FAIL)
+    return;
+
+  if (skip_past_comma (&str) == FAIL
+      || vfp_sp_reg_required_here (&str, VFP_REG_Sn) == FAIL)
+    {
+      if (! inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  end_of_line (str);
+}
+
+/* Parse and encode a VFP SP register list, storing the initial
+   register in position POS and returning the range as the result.  If
+   the string is invalid return FAIL (an invalid range).  */
+
+static long
+vfp_sp_reg_list (char ** str, enum vfp_sp_reg_pos pos)
+{
+  long range = 0;
+  int base_reg = 0;
+  int new_base;
+  long base_bits = 0;
+  int count = 0;
+  long tempinst;
+  unsigned long mask = 0;
+  int warned = 0;
+
+  if (**str != '{')
+    return FAIL;
+
+  (*str)++;
+  skip_whitespace (*str);
+
+  tempinst = inst.instruction;
+
+  do
+    {
+      inst.instruction = 0;
+
+      if ((new_base = vfp_sp_reg_required_here (str, pos)) == FAIL)
+       return FAIL;
+
+      if (count == 0 || base_reg > new_base)
+       {
+         base_reg = new_base;
+         base_bits = inst.instruction;
+       }
+
+      if (mask & (1 << new_base))
+       {
+         inst.error = _("invalid register list");
+         return FAIL;
+       }
+
+      if ((mask >> new_base) != 0 && ! warned)
+       {
+         as_tsktsk (_("register list not in ascending order"));
+         warned = 1;
+       }
+
+      mask |= 1 << new_base;
+      count++;
+
+      skip_whitespace (*str);
+
+      if (**str == '-') /* We have the start of a range expression */
+       {
+         int high_range;
+
+         (*str)++;
+
+         if ((high_range
+              = arm_reg_parse (str, all_reg_maps[REG_TYPE_SN].htab))
+             == FAIL)
+           {
+             inst.error = _(all_reg_maps[REG_TYPE_SN].expected);
+             return FAIL;
+           }
+
+         if (high_range <= new_base)
+           {
+             inst.error = _("register range not in ascending order");
+             return FAIL;
+           }
 
-static void
-do_vfp_sp_monadic (str)
-     char *str;
-{
-  skip_whitespace (str);
+         for (new_base++; new_base <= high_range; new_base++)
+           {
+             if (mask & (1 << new_base))
+               {
+                 inst.error = _("invalid register list");
+                 return FAIL;
+               }
 
-  if (vfp_sp_reg_required_here (&str, VFP_REG_Sd) == FAIL)
-    return;
+             mask |= 1 << new_base;
+             count++;
+           }
+       }
+    }
+  while (skip_past_comma (str) != FAIL);
 
-  if (skip_past_comma (&str) == FAIL
-      || vfp_sp_reg_required_here (&str, VFP_REG_Sm) == FAIL)
+  if (**str != '}')
     {
-      if (! inst.error)
-       inst.error = BAD_ARGS;
-      return;
+      inst.error = _("invalid register list");
+      return FAIL;
     }
 
-  end_of_line (str);
-  return;
-}
+  (*str)++;
 
-static void
-do_vfp_dp_monadic (str)
-     char *str;
-{
-  skip_whitespace (str);
+  range = count;
 
-  if (vfp_dp_reg_required_here (&str, VFP_REG_Dd) == FAIL)
-    return;
+  /* Sanity check -- should have raised a parse error above.  */
+  if (count == 0 || count > 32)
+    abort ();
 
-  if (skip_past_comma (&str) == FAIL
-      || vfp_dp_reg_required_here (&str, VFP_REG_Dm) == FAIL)
+  /* Final test -- the registers must be consecutive.  */
+  while (count--)
     {
-      if (! inst.error)
-       inst.error = BAD_ARGS;
-      return;
+      if ((mask & (1 << base_reg++)) == 0)
+       {
+         inst.error = _("non-contiguous register range");
+         return FAIL;
+       }
     }
 
-  end_of_line (str);
-  return;
+  inst.instruction = tempinst | base_bits;
+  return range;
 }
 
 static void
-do_vfp_sp_dyadic (str)
-     char *str;
+do_vfp_reg2_from_sp2 (char * str)
 {
   skip_whitespace (str);
 
-  if (vfp_sp_reg_required_here (&str, VFP_REG_Sd) == FAIL)
-    return;
-
-  if (skip_past_comma (&str) == FAIL
-      || vfp_sp_reg_required_here (&str, VFP_REG_Sn) == FAIL
+  if (reg_required_here (&str, 12) == FAIL
       || skip_past_comma (&str) == FAIL
-      || vfp_sp_reg_required_here (&str, VFP_REG_Sm) == FAIL)
+      || reg_required_here (&str, 16) == FAIL
+      || skip_past_comma (&str) == FAIL)
     {
       if (! inst.error)
        inst.error = BAD_ARGS;
       return;
     }
 
-  end_of_line (str);
-  return;
-}
-
-static void
-do_vfp_dp_dyadic (str)
-     char *str;
-{
-  skip_whitespace (str);
-
-  if (vfp_dp_reg_required_here (&str, VFP_REG_Dd) == FAIL)
-    return;
-
-  if (skip_past_comma (&str) == FAIL
-      || vfp_dp_reg_required_here (&str, VFP_REG_Dn) == FAIL
-      || skip_past_comma (&str) == FAIL
-      || vfp_dp_reg_required_here (&str, VFP_REG_Dm) == FAIL)
+  /* We require exactly two consecutive SP registers.  */
+  if (vfp_sp_reg_list (&str, VFP_REG_Sm) != 2)
     {
       if (! inst.error)
-       inst.error = BAD_ARGS;
-      return;
+       inst.error = _("only two consecutive VFP SP registers allowed here");
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
-do_vfp_reg_from_sp (str)
-     char *str;
+do_vfp_sp_from_reg (char * str)
 {
   skip_whitespace (str);
 
-  if (reg_required_here (&str, 12) == FAIL)
+  if (vfp_sp_reg_required_here (&str, VFP_REG_Sn) == FAIL)
     return;
 
   if (skip_past_comma (&str) == FAIL
-      || vfp_sp_reg_required_here (&str, VFP_REG_Sn) == FAIL)
+      || reg_required_here (&str, 12) == FAIL)
     {
       if (! inst.error)
        inst.error = BAD_ARGS;
@@ -6573,27 +7604,13 @@ do_vfp_reg_from_sp (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
-do_vfp_sp_reg2 (str)
-     char *str;
+do_vfp_sp2_from_reg2 (char * str)
 {
   skip_whitespace (str);
 
-  if (reg_required_here (&str, 12) == FAIL)
-    return;
-
-  if (skip_past_comma (&str) == FAIL
-      || reg_required_here (&str, 16) == FAIL
-      || skip_past_comma (&str) == FAIL)
-    {
-      if (! inst.error)
-       inst.error = BAD_ARGS;
-      return;
-    }
-
   /* We require exactly two consecutive SP registers.  */
   if (vfp_sp_reg_list (&str, VFP_REG_Sm) != 2)
     {
@@ -6601,21 +7618,10 @@ do_vfp_sp_reg2 (str)
        inst.error = _("only two consecutive VFP SP registers allowed here");
     }
 
-  end_of_line (str);
-  return;
-}
-
-static void
-do_vfp_sp_from_reg (str)
-     char *str;
-{
-  skip_whitespace (str);
-
-  if (vfp_sp_reg_required_here (&str, VFP_REG_Sn) == FAIL)
-    return;
-
   if (skip_past_comma (&str) == FAIL
-      || reg_required_here (&str, 12) == FAIL)
+      || reg_required_here (&str, 12) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || reg_required_here (&str, 16) == FAIL)
     {
       if (! inst.error)
        inst.error = BAD_ARGS;
@@ -6623,12 +7629,10 @@ do_vfp_sp_from_reg (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
-do_vfp_reg_from_dp (str)
-     char *str;
+do_vfp_reg_from_dp (char * str)
 {
   skip_whitespace (str);
 
@@ -6644,12 +7648,10 @@ do_vfp_reg_from_dp (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
-do_vfp_reg2_from_dp (str)
-     char *str;
+do_vfp_reg2_from_dp (char * str)
 {
   skip_whitespace (str);
 
@@ -6667,12 +7669,10 @@ do_vfp_reg2_from_dp (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
-do_vfp_dp_from_reg (str)
-     char *str;
+do_vfp_dp_from_reg (char * str)
 {
   skip_whitespace (str);
 
@@ -6688,12 +7688,10 @@ do_vfp_dp_from_reg (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
-do_vfp_dp_from_reg2 (str)
-     char *str;
+do_vfp_dp_from_reg2 (char * str)
 {
   skip_whitespace (str);
 
@@ -6703,7 +7701,7 @@ do_vfp_dp_from_reg2 (str)
   if (skip_past_comma (&str) == FAIL
       || reg_required_here (&str, 12) == FAIL
       || skip_past_comma (&str) == FAIL
-      || reg_required_here (&str, 16))
+      || reg_required_here (&str, 16) == FAIL)
     {
       if (! inst.error)
        inst.error = BAD_ARGS;
@@ -6711,12 +7709,10 @@ do_vfp_dp_from_reg2 (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static const struct vfp_reg *
-vfp_psr_parse (str)
-     char **str;
+vfp_psr_parse (char ** str)
 {
   char *start = *str;
   char  c;
@@ -6739,7 +7735,7 @@ vfp_psr_parse (str)
        vreg < vfp_regs + sizeof (vfp_regs) / sizeof (struct vfp_reg);
        vreg++)
     {
-      if (strcmp (start, vreg->name) == 0)
+      if (streq (start, vreg->name))
        {
          *p = c;
          *str = p;
@@ -6752,8 +7748,7 @@ vfp_psr_parse (str)
 }
 
 static int
-vfp_psr_required_here (str)
-     char **str;
+vfp_psr_required_here (char ** str)
 {
   char *start = *str;
   const struct vfp_reg *vreg;
@@ -6773,8 +7768,7 @@ vfp_psr_required_here (str)
 }
 
 static void
-do_vfp_reg_from_ctrl (str)
-     char *str;
+do_vfp_reg_from_ctrl (char * str)
 {
   skip_whitespace (str);
 
@@ -6790,12 +7784,10 @@ do_vfp_reg_from_ctrl (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
-do_vfp_ctrl_from_reg (str)
-     char *str;
+do_vfp_ctrl_from_reg (char * str)
 {
   skip_whitespace (str);
 
@@ -6806,185 +7798,61 @@ do_vfp_ctrl_from_reg (str)
       || reg_required_here (&str, 12) == FAIL)
     {
       if (! inst.error)
-       inst.error = BAD_ARGS;
-      return;
-    }
-
-  end_of_line (str);
-  return;
-}
-
-static void
-do_vfp_sp_ldst (str)
-     char *str;
-{
-  skip_whitespace (str);
-
-  if (vfp_sp_reg_required_here (&str, VFP_REG_Sd) == FAIL)
-    {
-      if (!inst.error)
-       inst.error = BAD_ARGS;
-      return;
-    }
-
-  if (skip_past_comma (&str) == FAIL
-      || cp_address_required_here (&str, CP_NO_WB) == FAIL)
-    {
-      if (!inst.error)
-       inst.error = BAD_ARGS;
-      return;
-    }
-
-  end_of_line (str);
-  return;
-}
-
-static void
-do_vfp_dp_ldst (str)
-     char *str;
-{
-  skip_whitespace (str);
-
-  if (vfp_dp_reg_required_here (&str, VFP_REG_Dd) == FAIL)
-    {
-      if (!inst.error)
-       inst.error = BAD_ARGS;
-      return;
-    }
-
-  if (skip_past_comma (&str) == FAIL
-      || cp_address_required_here (&str, CP_NO_WB) == FAIL)
-    {
-      if (!inst.error)
-       inst.error = BAD_ARGS;
-      return;
-    }
-
-  end_of_line (str);
-  return;
-}
-
-/* Parse and encode a VFP SP register list, storing the initial
-   register in position POS and returning the range as the result.  If
-   the string is invalid return FAIL (an invalid range).  */
-static long
-vfp_sp_reg_list (str, pos)
-     char **str;
-     enum vfp_sp_reg_pos pos;
-{
-  long range = 0;
-  int base_reg = 0;
-  int new_base;
-  long base_bits = 0;
-  int count = 0;
-  long tempinst;
-  unsigned long mask = 0;
-  int warned = 0;
-
-  if (**str != '{')
-    return FAIL;
-
-  (*str)++;
-  skip_whitespace (*str);
-
-  tempinst = inst.instruction;
-
-  do
-    {
-      inst.instruction = 0;
-
-      if ((new_base = vfp_sp_reg_required_here (str, pos)) == FAIL)
-       return FAIL;
-
-      if (count == 0 || base_reg > new_base)
-       {
-         base_reg = new_base;
-         base_bits = inst.instruction;
-       }
-
-      if (mask & (1 << new_base))
-       {
-         inst.error = _("invalid register list");
-         return FAIL;
-       }
-
-      if ((mask >> new_base) != 0 && ! warned)
-       {
-         as_tsktsk (_("register list not in ascending order"));
-         warned = 1;
-       }
-
-      mask |= 1 << new_base;
-      count++;
-
-      skip_whitespace (*str);
-
-      if (**str == '-') /* We have the start of a range expression */
-       {
-         int high_range;
-
-         (*str)++;
-
-         if ((high_range
-              = arm_reg_parse (str, all_reg_maps[REG_TYPE_SN].htab))
-             == FAIL)
-           {
-             inst.error = _(all_reg_maps[REG_TYPE_SN].expected);
-             return FAIL;
-           }
+       inst.error = BAD_ARGS;
+      return;
+    }
 
-         if (high_range <= new_base)
-           {
-             inst.error = _("register range not in ascending order");
-             return FAIL;
-           }
+  end_of_line (str);
+}
 
-         for (new_base++; new_base <= high_range; new_base++)
-           {
-             if (mask & (1 << new_base))
-               {
-                 inst.error = _("invalid register list");
-                 return FAIL;
-               }
+static void
+do_vfp_sp_ldst (char * str)
+{
+  skip_whitespace (str);
 
-             mask |= 1 << new_base;
-             count++;
-           }
-       }
+  if (vfp_sp_reg_required_here (&str, VFP_REG_Sd) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
     }
-  while (skip_past_comma (str) != FAIL);
 
-  if (**str != '}')
+  if (skip_past_comma (&str) == FAIL
+      || cp_address_required_here (&str, CP_NO_WB) == FAIL)
     {
-      inst.error = _("invalid register list");
-      return FAIL;
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
     }
 
-  (*str)++;
+  end_of_line (str);
+}
 
-  range = count;
+static void
+do_vfp_dp_ldst (char * str)
+{
+  skip_whitespace (str);
 
-  /* Sanity check -- should have raised a parse error above.  */
-  if (count == 0 || count > 32)
-    abort ();
+  if (vfp_dp_reg_required_here (&str, VFP_REG_Dd) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
 
-  /* Final test -- the registers must be consecutive.  */
-  while (count--)
+  if (skip_past_comma (&str) == FAIL
+      || cp_address_required_here (&str, CP_NO_WB) == FAIL)
     {
-      if ((mask & (1 << base_reg++)) == 0)
-       {
-         inst.error = _("non-contiguous register range");
-         return FAIL;
-       }
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
     }
 
-  inst.instruction = tempinst | base_bits;
-  return range;
+  end_of_line (str);
 }
 
 static long
-vfp_dp_reg_list (str)
-     char **str;
+vfp_dp_reg_list (char ** str)
 {
   long range = 0;
   int base_reg = 0;
@@ -7096,9 +7964,7 @@ vfp_dp_reg_list (str)
 }
 
 static void
-vfp_sp_ldstm (str, ldstm_type)
-     char *str;
-     enum vfp_ldstm_type ldstm_type;
+vfp_sp_ldstm (char * str, enum vfp_ldstm_type ldstm_type)
 {
   long range;
 
@@ -7133,9 +7999,7 @@ vfp_sp_ldstm (str, ldstm_type)
 }
 
 static void
-vfp_dp_ldstm (str, ldstm_type)
-     char *str;
-     enum vfp_ldstm_type ldstm_type;
+vfp_dp_ldstm (char * str, enum vfp_ldstm_type ldstm_type)
 {
   long range;
 
@@ -7173,50 +8037,43 @@ vfp_dp_ldstm (str, ldstm_type)
 }
 
 static void
-do_vfp_sp_ldstmia (str)
-     char *str;
+do_vfp_sp_ldstmia (char * str)
 {
   vfp_sp_ldstm (str, VFP_LDSTMIA);
 }
 
 static void
-do_vfp_sp_ldstmdb (str)
-     char *str;
+do_vfp_sp_ldstmdb (char * str)
 {
   vfp_sp_ldstm (str, VFP_LDSTMDB);
 }
 
 static void
-do_vfp_dp_ldstmia (str)
-     char *str;
+do_vfp_dp_ldstmia (char * str)
 {
   vfp_dp_ldstm (str, VFP_LDSTMIA);
 }
 
 static void
-do_vfp_dp_ldstmdb (str)
-     char *str;
+do_vfp_dp_ldstmdb (char * str)
 {
   vfp_dp_ldstm (str, VFP_LDSTMDB);
 }
 
 static void
-do_vfp_xp_ldstmia (str)
-     char *str;
+do_vfp_xp_ldstmia (char *str)
 {
   vfp_dp_ldstm (str, VFP_LDSTMIAX);
 }
 
 static void
-do_vfp_xp_ldstmdb (str)
-     char *str;
+do_vfp_xp_ldstmdb (char * str)
 {
   vfp_dp_ldstm (str, VFP_LDSTMDBX);
 }
 
 static void
-do_vfp_sp_compare_z (str)
-     char *str;
+do_vfp_sp_compare_z (char * str)
 {
   skip_whitespace (str);
 
@@ -7228,12 +8085,10 @@ do_vfp_sp_compare_z (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
-do_vfp_dp_compare_z (str)
-     char *str;
+do_vfp_dp_compare_z (char * str)
 {
   skip_whitespace (str);
 
@@ -7245,12 +8100,10 @@ do_vfp_dp_compare_z (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
-do_vfp_dp_sp_cvt (str)
-     char *str;
+do_vfp_dp_sp_cvt (char * str)
 {
   skip_whitespace (str);
 
@@ -7266,86 +8119,315 @@ do_vfp_dp_sp_cvt (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
-do_vfp_sp_dp_cvt (str)
-     char *str;
+do_vfp_sp_dp_cvt (char * str)
+{
+  skip_whitespace (str);
+
+  if (vfp_sp_reg_required_here (&str, VFP_REG_Sd) == FAIL)
+    return;
+
+  if (skip_past_comma (&str) == FAIL
+      || vfp_dp_reg_required_here (&str, VFP_REG_Dm) == FAIL)
+    {
+      if (! inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  end_of_line (str);
+}
+
+/* Thumb specific routines.  */
+
+/* Parse an add or subtract instruction, SUBTRACT is non-zero if the opcode
+   was SUB.  */
+
+static void
+thumb_add_sub (char * str, int subtract)
+{
+  int Rd, Rs, Rn = FAIL;
+
+  skip_whitespace (str);
+
+  if ((Rd = thumb_reg (&str, THUMB_REG_ANY)) == FAIL
+      || skip_past_comma (&str) == FAIL)
+    {
+      if (! inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  if (is_immediate_prefix (*str))
+    {
+      Rs = Rd;
+      str++;
+      if (my_get_expression (&inst.reloc.exp, &str))
+       return;
+    }
+  else
+    {
+      if ((Rs = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
+       return;
+
+      if (skip_past_comma (&str) == FAIL)
+       {
+         /* Two operand format, shuffle the registers
+            and pretend there are 3.  */
+         Rn = Rs;
+         Rs = Rd;
+       }
+      else if (is_immediate_prefix (*str))
+       {
+         str++;
+         if (my_get_expression (&inst.reloc.exp, &str))
+           return;
+       }
+      else if ((Rn = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
+       return;
+    }
+
+  /* We now have Rd and Rs set to registers, and Rn set to a register or FAIL;
+     for the latter case, EXPR contains the immediate that was found.  */
+  if (Rn != FAIL)
+    {
+      /* All register format.  */
+      if (Rd > 7 || Rs > 7 || Rn > 7)
+       {
+         if (Rs != Rd)
+           {
+             inst.error = _("dest and source1 must be the same register");
+             return;
+           }
+
+         /* Can't do this for SUB.  */
+         if (subtract)
+           {
+             inst.error = _("subtract valid only on lo regs");
+             return;
+           }
+
+         inst.instruction = (T_OPCODE_ADD_HI
+                             | (Rd > 7 ? THUMB_H1 : 0)
+                             | (Rn > 7 ? THUMB_H2 : 0));
+         inst.instruction |= (Rd & 7) | ((Rn & 7) << 3);
+       }
+      else
+       {
+         inst.instruction = subtract ? T_OPCODE_SUB_R3 : T_OPCODE_ADD_R3;
+         inst.instruction |= Rd | (Rs << 3) | (Rn << 6);
+       }
+    }
+  else
+    {
+      /* Immediate expression, now things start to get nasty.  */
+
+      /* First deal with HI regs, only very restricted cases allowed:
+        Adjusting SP, and using PC or SP to get an address.  */
+      if ((Rd > 7 && (Rd != REG_SP || Rs != REG_SP))
+         || (Rs > 7 && Rs != REG_SP && Rs != REG_PC))
+       {
+         inst.error = _("invalid Hi register with immediate");
+         return;
+       }
+
+      if (inst.reloc.exp.X_op != O_constant)
+       {
+         /* Value isn't known yet, all we can do is store all the fragments
+            we know about in the instruction and let the reloc hacking
+            work it all out.  */
+         inst.instruction = (subtract ? 0x8000 : 0) | (Rd << 4) | Rs;
+         inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
+       }
+      else
+       {
+         int offset = inst.reloc.exp.X_add_number;
+
+         if (subtract)
+           offset = - offset;
+
+         if (offset < 0)
+           {
+             offset = - offset;
+             subtract = 1;
+
+             /* Quick check, in case offset is MIN_INT.  */
+             if (offset < 0)
+               {
+                 inst.error = _("immediate value out of range");
+                 return;
+               }
+           }
+         /* Note - you cannot convert a subtract of 0 into an
+            add of 0 because the carry flag is set differently.  */
+         else if (offset > 0)
+           subtract = 0;
+
+         if (Rd == REG_SP)
+           {
+             if (offset & ~0x1fc)
+               {
+                 inst.error = _("invalid immediate value for stack adjust");
+                 return;
+               }
+             inst.instruction = subtract ? T_OPCODE_SUB_ST : T_OPCODE_ADD_ST;
+             inst.instruction |= offset >> 2;
+           }
+         else if (Rs == REG_PC || Rs == REG_SP)
+           {
+             if (subtract
+                 || (offset & ~0x3fc))
+               {
+                 inst.error = _("invalid immediate for address calculation");
+                 return;
+               }
+             inst.instruction = (Rs == REG_PC ? T_OPCODE_ADD_PC
+                                 : T_OPCODE_ADD_SP);
+             inst.instruction |= (Rd << 8) | (offset >> 2);
+           }
+         else if (Rs == Rd)
+           {
+             if (offset & ~0xff)
+               {
+                 inst.error = _("immediate value out of range");
+                 return;
+               }
+             inst.instruction = subtract ? T_OPCODE_SUB_I8 : T_OPCODE_ADD_I8;
+             inst.instruction |= (Rd << 8) | offset;
+           }
+         else
+           {
+             if (offset & ~0x7)
+               {
+                 inst.error = _("immediate value out of range");
+                 return;
+               }
+             inst.instruction = subtract ? T_OPCODE_SUB_I3 : T_OPCODE_ADD_I3;
+             inst.instruction |= Rd | (Rs << 3) | (offset << 6);
+           }
+       }
+    }
+
+  end_of_line (str);
+}
+
+static void
+thumb_shift (char * str, int shift)
 {
-  skip_whitespace (str);
+  int Rd, Rs, Rn = FAIL;
 
-  if (vfp_sp_reg_required_here (&str, VFP_REG_Sd) == FAIL)
-    return;
+  skip_whitespace (str);
 
-  if (skip_past_comma (&str) == FAIL
-      || vfp_dp_reg_required_here (&str, VFP_REG_Dm) == FAIL)
+  if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL
+      || skip_past_comma (&str) == FAIL)
     {
       if (! inst.error)
        inst.error = BAD_ARGS;
       return;
     }
 
-  end_of_line (str);
-  return;
-}
+  if (is_immediate_prefix (*str))
+    {
+      /* Two operand immediate format, set Rs to Rd.  */
+      Rs = Rd;
+      str ++;
+      if (my_get_expression (&inst.reloc.exp, &str))
+       return;
+    }
+  else
+    {
+      if ((Rs = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
+       return;
 
-/* Thumb specific routines.  */
+      if (skip_past_comma (&str) == FAIL)
+       {
+         /* Two operand format, shuffle the registers
+            and pretend there are 3.  */
+         Rn = Rs;
+         Rs = Rd;
+       }
+      else if (is_immediate_prefix (*str))
+       {
+         str++;
+         if (my_get_expression (&inst.reloc.exp, &str))
+           return;
+       }
+      else if ((Rn = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
+       return;
+    }
 
-/* Parse and validate that a register is of the right form, this saves
-   repeated checking of this information in many similar cases.
-   Unlike the 32-bit case we do not insert the register into the opcode
-   here, since the position is often unknown until the full instruction
-   has been parsed.  */
+  /* We now have Rd and Rs set to registers, and Rn set to a register or FAIL;
+     for the latter case, EXPR contains the immediate that was found.  */
 
-static int
-thumb_reg (strp, hi_lo)
-     char ** strp;
-     int     hi_lo;
-{
-  int reg;
+  if (Rn != FAIL)
+    {
+      if (Rs != Rd)
+       {
+         inst.error = _("source1 and dest must be same register");
+         return;
+       }
 
-  if ((reg = reg_required_here (strp, -1)) == FAIL)
-    return FAIL;
+      switch (shift)
+       {
+       case THUMB_ASR: inst.instruction = T_OPCODE_ASR_R; break;
+       case THUMB_LSL: inst.instruction = T_OPCODE_LSL_R; break;
+       case THUMB_LSR: inst.instruction = T_OPCODE_LSR_R; break;
+       }
 
-  switch (hi_lo)
+      inst.instruction |= Rd | (Rn << 3);
+    }
+  else
     {
-    case THUMB_REG_LO:
-      if (reg > 7)
+      switch (shift)
        {
-         inst.error = _("lo register required");
-         return FAIL;
+       case THUMB_ASR: inst.instruction = T_OPCODE_ASR_I; break;
+       case THUMB_LSL: inst.instruction = T_OPCODE_LSL_I; break;
+       case THUMB_LSR: inst.instruction = T_OPCODE_LSR_I; break;
        }
-      break;
 
-    case THUMB_REG_HI:
-      if (reg < 8)
+      if (inst.reloc.exp.X_op != O_constant)
        {
-         inst.error = _("hi register required");
-         return FAIL;
+         /* Value isn't known yet, create a dummy reloc and let reloc
+            hacking fix it up.  */
+         inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT;
        }
-      break;
+      else
+       {
+         unsigned shift_value = inst.reloc.exp.X_add_number;
 
-    default:
-      break;
+         if (shift_value > 32 || (shift_value == 32 && shift == THUMB_LSL))
+           {
+             inst.error = _("invalid immediate for shift");
+             return;
+           }
+
+         /* Shifts of zero are handled by converting to LSL.  */
+         if (shift_value == 0)
+           inst.instruction = T_OPCODE_LSL_I;
+
+         /* Shifts of 32 are encoded as a shift of zero.  */
+         if (shift_value == 32)
+           shift_value = 0;
+
+         inst.instruction |= shift_value << 6;
+       }
+
+      inst.instruction |= Rd | (Rs << 3);
     }
 
-  return reg;
+  end_of_line (str);
 }
 
-/* Parse an add or subtract instruction, SUBTRACT is non-zero if the opcode
-   was SUB.  */
-
 static void
-thumb_add_sub (str, subtract)
-     char * str;
-     int    subtract;
+thumb_load_store (char * str, int load_store, int size)
 {
-  int Rd, Rs, Rn = FAIL;
+  int Rd, Rb, Ro = FAIL;
 
   skip_whitespace (str);
 
-  if ((Rd = thumb_reg (&str, THUMB_REG_ANY)) == FAIL
+  if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL
       || skip_past_comma (&str) == FAIL)
     {
       if (! inst.error)
@@ -7353,1768 +8435,2459 @@ thumb_add_sub (str, subtract)
       return;
     }
 
-  if (is_immediate_prefix (*str))
+  if (*str == '[')
     {
-      Rs = Rd;
       str++;
-      if (my_get_expression (&inst.reloc.exp, &str))
+      if ((Rb = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
        return;
+
+      if (skip_past_comma (&str) != FAIL)
+       {
+         if (is_immediate_prefix (*str))
+           {
+             str++;
+             if (my_get_expression (&inst.reloc.exp, &str))
+               return;
+           }
+         else if ((Ro = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
+           return;
+       }
+      else
+       {
+         inst.reloc.exp.X_op = O_constant;
+         inst.reloc.exp.X_add_number = 0;
+       }
+
+      if (*str != ']')
+       {
+         inst.error = _("expected ']'");
+         return;
+       }
+      str++;
     }
-  else
+  else if (*str == '=')
     {
-      if ((Rs = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
+      if (load_store != THUMB_LOAD)
+       {
+         inst.error = _("invalid pseudo operation");
+         return;
+       }
+
+      /* Parse an "ldr Rd, =expr" instruction; this is another pseudo op.  */
+      str++;
+
+      skip_whitespace (str);
+
+      if (my_get_expression (& inst.reloc.exp, & str))
        return;
 
-      if (skip_past_comma (&str) == FAIL)
+      end_of_line (str);
+
+      if (   inst.reloc.exp.X_op != O_constant
+         && inst.reloc.exp.X_op != O_symbol)
        {
-         /* Two operand format, shuffle the registers
-            and pretend there are 3.  */
-         Rn = Rs;
-         Rs = Rd;
+         inst.error = "Constant expression expected";
+         return;
        }
-      else if (is_immediate_prefix (*str))
+
+      if (inst.reloc.exp.X_op == O_constant
+         && ((inst.reloc.exp.X_add_number & ~0xFF) == 0))
        {
-         str++;
-         if (my_get_expression (&inst.reloc.exp, &str))
-           return;
+         /* This can be done with a mov instruction.  */
+
+         inst.instruction  = T_OPCODE_MOV_I8 | (Rd << 8);
+         inst.instruction |= inst.reloc.exp.X_add_number;
+         return;
        }
-      else if ((Rn = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
+
+      /* Insert into literal pool.  */
+      if (add_to_lit_pool () == FAIL)
+       {
+         if (!inst.error)
+           inst.error = "literal pool insertion failed";
+         return;
+       }
+
+      inst.reloc.type   = BFD_RELOC_ARM_THUMB_OFFSET;
+      inst.reloc.pc_rel = 1;
+      inst.instruction  = T_OPCODE_LDR_PC | (Rd << 8);
+      /* Adjust ARM pipeline offset to Thumb.  */
+      inst.reloc.exp.X_add_number += 4;
+
+      return;
+    }
+  else
+    {
+      if (my_get_expression (&inst.reloc.exp, &str))
        return;
+
+      inst.instruction = T_OPCODE_LDR_PC | (Rd << 8);
+      inst.reloc.pc_rel = 1;
+      inst.reloc.exp.X_add_number -= 4; /* Pipeline offset.  */
+      inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
+      end_of_line (str);
+      return;
     }
 
-  /* We now have Rd and Rs set to registers, and Rn set to a register or FAIL;
-     for the latter case, EXPR contains the immediate that was found.  */
-  if (Rn != FAIL)
+  if (Rb == REG_PC || Rb == REG_SP)
     {
-      /* All register format.  */
-      if (Rd > 7 || Rs > 7 || Rn > 7)
+      if (size != THUMB_WORD)
        {
-         if (Rs != Rd)
-           {
-             inst.error = _("dest and source1 must be the same register");
-             return;
-           }
+         inst.error = _("byte or halfword not valid for base register");
+         return;
+       }
+      else if (Rb == REG_PC && load_store != THUMB_LOAD)
+       {
+         inst.error = _("r15 based store not allowed");
+         return;
+       }
+      else if (Ro != FAIL)
+       {
+         inst.error = _("invalid base register for register offset");
+         return;
+       }
+
+      if (Rb == REG_PC)
+       inst.instruction = T_OPCODE_LDR_PC;
+      else if (load_store == THUMB_LOAD)
+       inst.instruction = T_OPCODE_LDR_SP;
+      else
+       inst.instruction = T_OPCODE_STR_SP;
+
+      inst.instruction |= Rd << 8;
+      if (inst.reloc.exp.X_op == O_constant)
+       {
+         unsigned offset = inst.reloc.exp.X_add_number;
 
-         /* Can't do this for SUB.  */
-         if (subtract)
+         if (offset & ~0x3fc)
            {
-             inst.error = _("subtract valid only on lo regs");
+             inst.error = _("invalid offset");
              return;
            }
 
-         inst.instruction = (T_OPCODE_ADD_HI
-                             | (Rd > 7 ? THUMB_H1 : 0)
-                             | (Rn > 7 ? THUMB_H2 : 0));
-         inst.instruction |= (Rd & 7) | ((Rn & 7) << 3);
+         inst.instruction |= offset >> 2;
        }
       else
-       {
-         inst.instruction = subtract ? T_OPCODE_SUB_R3 : T_OPCODE_ADD_R3;
-         inst.instruction |= Rd | (Rs << 3) | (Rn << 6);
-       }
+       inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
     }
-  else
+  else if (Rb > 7)
     {
-      /* Immediate expression, now things start to get nasty.  */
+      inst.error = _("invalid base register in load/store");
+      return;
+    }
+  else if (Ro == FAIL)
+    {
+      /* Immediate offset.  */
+      if (size == THUMB_WORD)
+       inst.instruction = (load_store == THUMB_LOAD
+                           ? T_OPCODE_LDR_IW : T_OPCODE_STR_IW);
+      else if (size == THUMB_HALFWORD)
+       inst.instruction = (load_store == THUMB_LOAD
+                           ? T_OPCODE_LDR_IH : T_OPCODE_STR_IH);
+      else
+       inst.instruction = (load_store == THUMB_LOAD
+                           ? T_OPCODE_LDR_IB : T_OPCODE_STR_IB);
 
-      /* First deal with HI regs, only very restricted cases allowed:
-        Adjusting SP, and using PC or SP to get an address.  */
-      if ((Rd > 7 && (Rd != REG_SP || Rs != REG_SP))
-         || (Rs > 7 && Rs != REG_SP && Rs != REG_PC))
-       {
-         inst.error = _("invalid Hi register with immediate");
-         return;
-       }
+      inst.instruction |= Rd | (Rb << 3);
 
-      if (inst.reloc.exp.X_op != O_constant)
+      if (inst.reloc.exp.X_op == O_constant)
        {
-         /* Value isn't known yet, all we can do is store all the fragments
-            we know about in the instruction and let the reloc hacking
-            work it all out.  */
-         inst.instruction = (subtract ? 0x8000 : 0) | (Rd << 4) | Rs;
-         inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
+         unsigned offset = inst.reloc.exp.X_add_number;
+
+         if (offset & ~(0x1f << size))
+           {
+             inst.error = _("invalid offset");
+             return;
+           }
+         inst.instruction |= (offset >> size) << 6;
        }
       else
-       {
-         int offset = inst.reloc.exp.X_add_number;
+       inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
+    }
+  else
+    {
+      /* Register offset.  */
+      if (size == THUMB_WORD)
+       inst.instruction = (load_store == THUMB_LOAD
+                           ? T_OPCODE_LDR_RW : T_OPCODE_STR_RW);
+      else if (size == THUMB_HALFWORD)
+       inst.instruction = (load_store == THUMB_LOAD
+                           ? T_OPCODE_LDR_RH : T_OPCODE_STR_RH);
+      else
+       inst.instruction = (load_store == THUMB_LOAD
+                           ? T_OPCODE_LDR_RB : T_OPCODE_STR_RB);
 
-         if (subtract)
-           offset = - offset;
+      inst.instruction |= Rd | (Rb << 3) | (Ro << 6);
+    }
 
-         if (offset < 0)
-           {
-             offset = - offset;
-             subtract = 1;
+  end_of_line (str);
+}
 
-             /* Quick check, in case offset is MIN_INT.  */
-             if (offset < 0)
-               {
-                 inst.error = _("immediate value out of range");
-                 return;
-               }
-           }
-         /* Note - you cannot convert a subtract of 0 into an
-            add of 0 because the carry flag is set differently.  */
-         else if (offset > 0)
-           subtract = 0;
+/* A register must be given at this point.
 
-         if (Rd == REG_SP)
-           {
-             if (offset & ~0x1fc)
-               {
-                 inst.error = _("invalid immediate value for stack adjust");
-                 return;
-               }
-             inst.instruction = subtract ? T_OPCODE_SUB_ST : T_OPCODE_ADD_ST;
-             inst.instruction |= offset >> 2;
-           }
-         else if (Rs == REG_PC || Rs == REG_SP)
-           {
-             if (subtract
-                 || (offset & ~0x3fc))
-               {
-                 inst.error = _("invalid immediate for address calculation");
-                 return;
-               }
-             inst.instruction = (Rs == REG_PC ? T_OPCODE_ADD_PC
-                                 : T_OPCODE_ADD_SP);
-             inst.instruction |= (Rd << 8) | (offset >> 2);
-           }
-         else if (Rs == Rd)
-           {
-             if (offset & ~0xff)
-               {
-                 inst.error = _("immediate value out of range");
-                 return;
-               }
-             inst.instruction = subtract ? T_OPCODE_SUB_I8 : T_OPCODE_ADD_I8;
-             inst.instruction |= (Rd << 8) | offset;
-           }
-         else
-           {
-             if (offset & ~0x7)
-               {
-                 inst.error = _("immediate value out of range");
-                 return;
-               }
-             inst.instruction = subtract ? T_OPCODE_SUB_I3 : T_OPCODE_ADD_I3;
-             inst.instruction |= Rd | (Rs << 3) | (offset << 6);
-           }
+   Shift is the place to put it in inst.instruction.
+
+   Restores input start point on err.
+   Returns the reg#, or FAIL.  */
+
+static int
+mav_reg_required_here (char ** str, int shift, enum arm_reg_type regtype)
+{
+  int   reg;
+  char *start = *str;
+
+  if ((reg = arm_reg_parse (str, all_reg_maps[regtype].htab)) != FAIL)
+    {
+      if (shift >= 0)
+       inst.instruction |= reg << shift;
+
+      return reg;
+    }
+
+  /* Restore the start point.  */
+  *str = start;
+
+  /* Try generic coprocessor name if applicable.  */
+  if (regtype == REG_TYPE_MVF ||
+      regtype == REG_TYPE_MVD ||
+      regtype == REG_TYPE_MVFX ||
+      regtype == REG_TYPE_MVDX)
+    {
+      if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_CN].htab)) != FAIL)
+       {
+         if (shift >= 0)
+           inst.instruction |= reg << shift;
+
+         return reg;
        }
+
+      /* Restore the start point.  */
+      *str = start;
     }
 
-  end_of_line (str);
+  /* In the few cases where we might be able to accept something else
+     this error can be overridden.  */
+  inst.error = _(all_reg_maps[regtype].expected);
+
+  return FAIL;
 }
 
+/* Cirrus Maverick Instructions.  */
+
+/* Isnsn like "foo X,Y".  */
+
 static void
-thumb_shift (str, shift)
-     char * str;
-     int    shift;
+do_mav_binops (char * str,
+              int mode,
+              enum arm_reg_type reg0,
+              enum arm_reg_type reg1)
 {
-  int Rd, Rs, Rn = FAIL;
+  int shift0, shift1;
+
+  shift0 = mode & 0xff;
+  shift1 = (mode >> 8) & 0xff;
 
   skip_whitespace (str);
 
-  if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL
-      || skip_past_comma (&str) == FAIL)
+  if (mav_reg_required_here (&str, shift0, reg0) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || mav_reg_required_here (&str, shift1, reg1) == FAIL)
     {
-      if (! inst.error)
+      if (!inst.error)
        inst.error = BAD_ARGS;
-      return;
-    }
-
-  if (is_immediate_prefix (*str))
-    {
-      /* Two operand immediate format, set Rs to Rd.  */
-      Rs = Rd;
-      str ++;
-      if (my_get_expression (&inst.reloc.exp, &str))
-       return;
     }
   else
-    {
-      if ((Rs = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
-       return;
+    end_of_line (str);
+}
 
-      if (skip_past_comma (&str) == FAIL)
-       {
-         /* Two operand format, shuffle the registers
-            and pretend there are 3.  */
-         Rn = Rs;
-         Rs = Rd;
-       }
-      else if (is_immediate_prefix (*str))
-       {
-         str++;
-         if (my_get_expression (&inst.reloc.exp, &str))
-           return;
-       }
-      else if ((Rn = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
-       return;
-    }
+/* Isnsn like "foo X,Y,Z".  */
 
-  /* We now have Rd and Rs set to registers, and Rn set to a register or FAIL;
-     for the latter case, EXPR contains the immediate that was found.  */
+static void
+do_mav_triple (char * str,
+              int mode,
+              enum arm_reg_type reg0,
+              enum arm_reg_type reg1,
+              enum arm_reg_type reg2)
+{
+  int shift0, shift1, shift2;
 
-  if (Rn != FAIL)
-    {
-      if (Rs != Rd)
-       {
-         inst.error = _("source1 and dest must be same register");
-         return;
-       }
+  shift0 = mode & 0xff;
+  shift1 = (mode >> 8) & 0xff;
+  shift2 = (mode >> 16) & 0xff;
 
-      switch (shift)
-       {
-       case THUMB_ASR: inst.instruction = T_OPCODE_ASR_R; break;
-       case THUMB_LSL: inst.instruction = T_OPCODE_LSL_R; break;
-       case THUMB_LSR: inst.instruction = T_OPCODE_LSR_R; break;
-       }
+  skip_whitespace (str);
 
-      inst.instruction |= Rd | (Rn << 3);
-    }
-  else
+  if (mav_reg_required_here (&str, shift0, reg0) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || mav_reg_required_here (&str, shift1, reg1) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || mav_reg_required_here (&str, shift2, reg2) == FAIL)
     {
-      switch (shift)
-       {
-       case THUMB_ASR: inst.instruction = T_OPCODE_ASR_I; break;
-       case THUMB_LSL: inst.instruction = T_OPCODE_LSL_I; break;
-       case THUMB_LSR: inst.instruction = T_OPCODE_LSR_I; break;
-       }
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+    }
+  else
+    end_of_line (str);
+}
 
-      if (inst.reloc.exp.X_op != O_constant)
-       {
-         /* Value isn't known yet, create a dummy reloc and let reloc
-            hacking fix it up.  */
-         inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT;
-       }
-      else
-       {
-         unsigned shift_value = inst.reloc.exp.X_add_number;
+/* Wrapper functions.  */
 
-         if (shift_value > 32 || (shift_value == 32 && shift == THUMB_LSL))
-           {
-             inst.error = _("invalid immediate for shift");
-             return;
-           }
+static void
+do_mav_binops_1a (char * str)
+{
+  do_mav_binops (str, MAV_MODE1, REG_TYPE_RN, REG_TYPE_MVF);
+}
 
-         /* Shifts of zero are handled by converting to LSL.  */
-         if (shift_value == 0)
-           inst.instruction = T_OPCODE_LSL_I;
+static void
+do_mav_binops_1b (char * str)
+{
+  do_mav_binops (str, MAV_MODE1, REG_TYPE_RN, REG_TYPE_MVD);
+}
 
-         /* Shifts of 32 are encoded as a shift of zero.  */
-         if (shift_value == 32)
-           shift_value = 0;
+static void
+do_mav_binops_1c (char * str)
+{
+  do_mav_binops (str, MAV_MODE1, REG_TYPE_RN, REG_TYPE_MVDX);
+}
 
-         inst.instruction |= shift_value << 6;
-       }
+static void
+do_mav_binops_1d (char * str)
+{
+  do_mav_binops (str, MAV_MODE1, REG_TYPE_MVF, REG_TYPE_MVF);
+}
 
-      inst.instruction |= Rd | (Rs << 3);
-    }
+static void
+do_mav_binops_1e (char * str)
+{
+  do_mav_binops (str, MAV_MODE1, REG_TYPE_MVD, REG_TYPE_MVD);
+}
 
-  end_of_line (str);
+static void
+do_mav_binops_1f (char * str)
+{
+  do_mav_binops (str, MAV_MODE1, REG_TYPE_MVD, REG_TYPE_MVF);
 }
 
 static void
-thumb_mov_compare (str, move)
-     char * str;
-     int    move;
+do_mav_binops_1g (char * str)
 {
-  int Rd, Rs = FAIL;
+  do_mav_binops (str, MAV_MODE1, REG_TYPE_MVF, REG_TYPE_MVD);
+}
 
-  skip_whitespace (str);
+static void
+do_mav_binops_1h (char * str)
+{
+  do_mav_binops (str, MAV_MODE1, REG_TYPE_MVF, REG_TYPE_MVFX);
+}
 
-  if ((Rd = thumb_reg (&str, THUMB_REG_ANY)) == FAIL
-      || skip_past_comma (&str) == FAIL)
-    {
-      if (! inst.error)
-       inst.error = BAD_ARGS;
-      return;
-    }
+static void
+do_mav_binops_1i (char * str)
+{
+  do_mav_binops (str, MAV_MODE1, REG_TYPE_MVD, REG_TYPE_MVFX);
+}
 
-  if (is_immediate_prefix (*str))
-    {
-      str++;
-      if (my_get_expression (&inst.reloc.exp, &str))
-       return;
-    }
-  else if ((Rs = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
-    return;
+static void
+do_mav_binops_1j (char * str)
+{
+  do_mav_binops (str, MAV_MODE1, REG_TYPE_MVF, REG_TYPE_MVDX);
+}
 
-  if (Rs != FAIL)
-    {
-      if (Rs < 8 && Rd < 8)
-       {
-         if (move == THUMB_MOVE)
-           /* A move of two lowregs is encoded as ADD Rd, Rs, #0
-              since a MOV instruction produces unpredictable results.  */
-           inst.instruction = T_OPCODE_ADD_I3;
-         else
-           inst.instruction = T_OPCODE_CMP_LR;
-         inst.instruction |= Rd | (Rs << 3);
-       }
-      else
-       {
-         if (move == THUMB_MOVE)
-           inst.instruction = T_OPCODE_MOV_HR;
-         else
-           inst.instruction = T_OPCODE_CMP_HR;
+static void
+do_mav_binops_1k (char * str)
+{
+  do_mav_binops (str, MAV_MODE1, REG_TYPE_MVD, REG_TYPE_MVDX);
+}
 
-         if (Rd > 7)
-           inst.instruction |= THUMB_H1;
+static void
+do_mav_binops_1l (char * str)
+{
+  do_mav_binops (str, MAV_MODE1, REG_TYPE_MVFX, REG_TYPE_MVF);
+}
 
-         if (Rs > 7)
-           inst.instruction |= THUMB_H2;
+static void
+do_mav_binops_1m (char * str)
+{
+  do_mav_binops (str, MAV_MODE1, REG_TYPE_MVFX, REG_TYPE_MVD);
+}
 
-         inst.instruction |= (Rd & 7) | ((Rs & 7) << 3);
-       }
-    }
-  else
-    {
-      if (Rd > 7)
-       {
-         inst.error = _("only lo regs allowed with immediate");
-         return;
-       }
+static void
+do_mav_binops_1n (char * str)
+{
+  do_mav_binops (str, MAV_MODE1, REG_TYPE_MVFX, REG_TYPE_MVFX);
+}
 
-      if (move == THUMB_MOVE)
-       inst.instruction = T_OPCODE_MOV_I8;
-      else
-       inst.instruction = T_OPCODE_CMP_I8;
+static void
+do_mav_binops_1o (char * str)
+{
+  do_mav_binops (str, MAV_MODE1, REG_TYPE_MVDX, REG_TYPE_MVDX);
+}
 
-      inst.instruction |= Rd << 8;
+static void
+do_mav_binops_2a (char * str)
+{
+  do_mav_binops (str, MAV_MODE2, REG_TYPE_MVF, REG_TYPE_RN);
+}
 
-      if (inst.reloc.exp.X_op != O_constant)
-       inst.reloc.type = BFD_RELOC_ARM_THUMB_IMM;
-      else
-       {
-         unsigned value = inst.reloc.exp.X_add_number;
+static void
+do_mav_binops_2b (char * str)
+{
+  do_mav_binops (str, MAV_MODE2, REG_TYPE_MVD, REG_TYPE_RN);
+}
 
-         if (value > 255)
-           {
-             inst.error = _("invalid immediate");
-             return;
-           }
+static void
+do_mav_binops_2c (char * str)
+{
+  do_mav_binops (str, MAV_MODE2, REG_TYPE_MVDX, REG_TYPE_RN);
+}
 
-         inst.instruction |= value;
-       }
-    }
+static void
+do_mav_binops_3a (char * str)
+{
+  do_mav_binops (str, MAV_MODE3, REG_TYPE_MVAX, REG_TYPE_MVFX);
+}
 
-  end_of_line (str);
+static void
+do_mav_binops_3b (char * str)
+{
+  do_mav_binops (str, MAV_MODE3, REG_TYPE_MVFX, REG_TYPE_MVAX);
 }
 
 static void
-thumb_load_store (str, load_store, size)
-     char * str;
-     int    load_store;
-     int    size;
+do_mav_binops_3c (char * str)
 {
-  int Rd, Rb, Ro = FAIL;
+  do_mav_binops (str, MAV_MODE3, REG_TYPE_MVAX, REG_TYPE_MVDX);
+}
 
-  skip_whitespace (str);
+static void
+do_mav_binops_3d (char * str)
+{
+  do_mav_binops (str, MAV_MODE3, REG_TYPE_MVDX, REG_TYPE_MVAX);
+}
 
-  if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL
-      || skip_past_comma (&str) == FAIL)
-    {
-      if (! inst.error)
-       inst.error = BAD_ARGS;
-      return;
-    }
+static void
+do_mav_triple_4a (char * str)
+{
+  do_mav_triple (str, MAV_MODE4, REG_TYPE_MVFX, REG_TYPE_MVFX, REG_TYPE_RN);
+}
 
-  if (*str == '[')
-    {
-      str++;
-      if ((Rb = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
-       return;
+static void
+do_mav_triple_4b (char * str)
+{
+  do_mav_triple (str, MAV_MODE4, REG_TYPE_MVDX, REG_TYPE_MVDX, REG_TYPE_RN);
+}
 
-      if (skip_past_comma (&str) != FAIL)
-       {
-         if (is_immediate_prefix (*str))
-           {
-             str++;
-             if (my_get_expression (&inst.reloc.exp, &str))
-               return;
-           }
-         else if ((Ro = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
-           return;
-       }
-      else
-       {
-         inst.reloc.exp.X_op = O_constant;
-         inst.reloc.exp.X_add_number = 0;
-       }
+static void
+do_mav_triple_5a (char * str)
+{
+  do_mav_triple (str, MAV_MODE5, REG_TYPE_RN, REG_TYPE_MVF, REG_TYPE_MVF);
+}
 
-      if (*str != ']')
-       {
-         inst.error = _("expected ']'");
-         return;
-       }
-      str++;
-    }
-  else if (*str == '=')
-    {
-      if (load_store != THUMB_LOAD)
-       {
-         inst.error = _("invalid pseudo operation");
-         return;
-       }
+static void
+do_mav_triple_5b (char * str)
+{
+  do_mav_triple (str, MAV_MODE5, REG_TYPE_RN, REG_TYPE_MVD, REG_TYPE_MVD);
+}
 
-      /* Parse an "ldr Rd, =expr" instruction; this is another pseudo op.  */
-      str++;
+static void
+do_mav_triple_5c (char * str)
+{
+  do_mav_triple (str, MAV_MODE5, REG_TYPE_RN, REG_TYPE_MVFX, REG_TYPE_MVFX);
+}
 
-      skip_whitespace (str);
+static void
+do_mav_triple_5d (char * str)
+{
+  do_mav_triple (str, MAV_MODE5, REG_TYPE_RN, REG_TYPE_MVDX, REG_TYPE_MVDX);
+}
+
+static void
+do_mav_triple_5e (char * str)
+{
+  do_mav_triple (str, MAV_MODE5, REG_TYPE_MVF, REG_TYPE_MVF, REG_TYPE_MVF);
+}
 
-      if (my_get_expression (& inst.reloc.exp, & str))
-       return;
+static void
+do_mav_triple_5f (char * str)
+{
+  do_mav_triple (str, MAV_MODE5, REG_TYPE_MVD, REG_TYPE_MVD, REG_TYPE_MVD);
+}
 
-      end_of_line (str);
+static void
+do_mav_triple_5g (char * str)
+{
+  do_mav_triple (str, MAV_MODE5, REG_TYPE_MVFX, REG_TYPE_MVFX, REG_TYPE_MVFX);
+}
 
-      if (   inst.reloc.exp.X_op != O_constant
-         && inst.reloc.exp.X_op != O_symbol)
-       {
-         inst.error = "Constant expression expected";
-         return;
-       }
+static void
+do_mav_triple_5h (char * str)
+{
+  do_mav_triple (str, MAV_MODE5, REG_TYPE_MVDX, REG_TYPE_MVDX, REG_TYPE_MVDX);
+}
 
-      if (inst.reloc.exp.X_op == O_constant
-         && ((inst.reloc.exp.X_add_number & ~0xFF) == 0))
-       {
-         /* This can be done with a mov instruction.  */
+/* Isnsn like "foo W,X,Y,Z".
+    where W=MVAX[0:3] and X,Y,Z=MVFX[0:15].  */
 
-         inst.instruction  = T_OPCODE_MOV_I8 | (Rd << 8);
-         inst.instruction |= inst.reloc.exp.X_add_number;
-         return;
-       }
+static void
+do_mav_quad (char * str,
+            int mode,
+            enum arm_reg_type reg0,
+            enum arm_reg_type reg1,
+            enum arm_reg_type reg2,
+            enum arm_reg_type reg3)
+{
+  int shift0, shift1, shift2, shift3;
 
-      /* Insert into literal pool.  */
-      if (add_to_lit_pool () == FAIL)
-       {
-         if (!inst.error)
-           inst.error = "literal pool insertion failed";
-         return;
-       }
+  shift0= mode & 0xff;
+  shift1 = (mode >> 8) & 0xff;
+  shift2 = (mode >> 16) & 0xff;
+  shift3 = (mode >> 24) & 0xff;
 
-      inst.reloc.type   = BFD_RELOC_ARM_THUMB_OFFSET;
-      inst.reloc.pc_rel = 1;
-      inst.instruction  = T_OPCODE_LDR_PC | (Rd << 8);
-      /* Adjust ARM pipeline offset to Thumb.  */
-      inst.reloc.exp.X_add_number += 4;
+  skip_whitespace (str);
 
-      return;
-    }
-  else
+  if (mav_reg_required_here (&str, shift0, reg0) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || mav_reg_required_here (&str, shift1, reg1) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || mav_reg_required_here (&str, shift2, reg2) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || mav_reg_required_here (&str, shift3, reg3) == FAIL)
     {
-      if (my_get_expression (&inst.reloc.exp, &str))
-       return;
-
-      inst.instruction = T_OPCODE_LDR_PC | (Rd << 8);
-      inst.reloc.pc_rel = 1;
-      inst.reloc.exp.X_add_number -= 4; /* Pipeline offset.  */
-      inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
-      end_of_line (str);
-      return;
+      if (!inst.error)
+       inst.error = BAD_ARGS;
     }
+  else
+    end_of_line (str);
+}
 
-  if (Rb == REG_PC || Rb == REG_SP)
-    {
-      if (size != THUMB_WORD)
-       {
-         inst.error = _("byte or halfword not valid for base register");
-         return;
-       }
-      else if (Rb == REG_PC && load_store != THUMB_LOAD)
-       {
-         inst.error = _("r15 based store not allowed");
-         return;
-       }
-      else if (Ro != FAIL)
-       {
-         inst.error = _("invalid base register for register offset");
-         return;
-       }
-
-      if (Rb == REG_PC)
-       inst.instruction = T_OPCODE_LDR_PC;
-      else if (load_store == THUMB_LOAD)
-       inst.instruction = T_OPCODE_LDR_SP;
-      else
-       inst.instruction = T_OPCODE_STR_SP;
+static void
+do_mav_quad_6a (char * str)
+{
+  do_mav_quad (str, MAV_MODE6, REG_TYPE_MVAX, REG_TYPE_MVFX, REG_TYPE_MVFX,
+              REG_TYPE_MVFX);
+}
 
-      inst.instruction |= Rd << 8;
-      if (inst.reloc.exp.X_op == O_constant)
-       {
-         unsigned offset = inst.reloc.exp.X_add_number;
+static void
+do_mav_quad_6b (char * str)
+{
+  do_mav_quad (str, MAV_MODE6, REG_TYPE_MVAX, REG_TYPE_MVAX, REG_TYPE_MVFX,
+              REG_TYPE_MVFX);
+}
 
-         if (offset & ~0x3fc)
-           {
-             inst.error = _("invalid offset");
-             return;
-           }
+/* cfmvsc32<cond> DSPSC,MVDX[15:0].  */
+static void
+do_mav_dspsc_1 (char * str)
+{
+  skip_whitespace (str);
 
-         inst.instruction |= offset >> 2;
-       }
-      else
-       inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
-    }
-  else if (Rb > 7)
+  /* cfmvsc32.  */
+  if (mav_reg_required_here (&str, -1, REG_TYPE_DSPSC) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || mav_reg_required_here (&str, 12, REG_TYPE_MVDX) == FAIL)
     {
-      inst.error = _("invalid base register in load/store");
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+
       return;
     }
-  else if (Ro == FAIL)
-    {
-      /* Immediate offset.  */
-      if (size == THUMB_WORD)
-       inst.instruction = (load_store == THUMB_LOAD
-                           ? T_OPCODE_LDR_IW : T_OPCODE_STR_IW);
-      else if (size == THUMB_HALFWORD)
-       inst.instruction = (load_store == THUMB_LOAD
-                           ? T_OPCODE_LDR_IH : T_OPCODE_STR_IH);
-      else
-       inst.instruction = (load_store == THUMB_LOAD
-                           ? T_OPCODE_LDR_IB : T_OPCODE_STR_IB);
 
-      inst.instruction |= Rd | (Rb << 3);
+  end_of_line (str);
+}
 
-      if (inst.reloc.exp.X_op == O_constant)
-       {
-         unsigned offset = inst.reloc.exp.X_add_number;
+/* cfmv32sc<cond> MVDX[15:0],DSPSC.  */
+static void
+do_mav_dspsc_2 (char * str)
+{
+  skip_whitespace (str);
 
-         if (offset & ~(0x1f << size))
-           {
-             inst.error = _("invalid offset");
-             return;
-           }
-         inst.instruction |= (offset >> size) << 6;
-       }
-      else
-       inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
-    }
-  else
+  /* cfmv32sc.  */
+  if (mav_reg_required_here (&str, 12, REG_TYPE_MVDX) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || mav_reg_required_here (&str, -1, REG_TYPE_DSPSC) == FAIL)
     {
-      /* Register offset.  */
-      if (size == THUMB_WORD)
-       inst.instruction = (load_store == THUMB_LOAD
-                           ? T_OPCODE_LDR_RW : T_OPCODE_STR_RW);
-      else if (size == THUMB_HALFWORD)
-       inst.instruction = (load_store == THUMB_LOAD
-                           ? T_OPCODE_LDR_RH : T_OPCODE_STR_RH);
-      else
-       inst.instruction = (load_store == THUMB_LOAD
-                           ? T_OPCODE_LDR_RB : T_OPCODE_STR_RB);
+      if (!inst.error)
+       inst.error = BAD_ARGS;
 
-      inst.instruction |= Rd | (Rb << 3) | (Ro << 6);
+      return;
     }
 
   end_of_line (str);
 }
 
-/* A register must be given at this point.
+/* Maverick 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].  */
 
-   Shift is the place to put it in inst.instruction.
+static void
+do_mav_shift (char * str,
+             enum arm_reg_type reg0,
+             enum arm_reg_type reg1)
+{
+  int error;
+  int imm, neg = 0;
 
-   Restores input start point on err.
-   Returns the reg#, or FAIL.  */
+  skip_whitespace (str);
 
-static int
-mav_reg_required_here (str, shift, regtype)
-     char ** str;
-     int shift;
-     enum arm_reg_type regtype;
-{
-  int   reg;
-  char *start = *str;
+  error = 0;
 
-  if ((reg = arm_reg_parse (str, all_reg_maps[regtype].htab)) != FAIL)
+  if (mav_reg_required_here (&str, 12, reg0) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || mav_reg_required_here (&str, 16, reg1) == FAIL
+      || skip_past_comma  (&str) == FAIL)
     {
-      if (shift >= 0)
-       inst.instruction |= reg << shift;
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
 
-      return reg;
+  /* 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;
     }
 
-  /* Restore the start point.  */
-  *str = start;
+  if (*str == '-')
+    {
+      neg = 1;
+      ++str;
+    }
 
-  /* In the few cases where we might be able to accept something else
-     this error can be overridden.  */
-  inst.error = _(all_reg_maps[regtype].expected);
+  for (imm = 0; *str && ISDIGIT (*str); ++str)
+    imm = imm * 10 + *str - '0';
 
-  return FAIL;
-}
+  if (imm > 64)
+    {
+      inst.error = _("immediate out of range");
+      return;
+    }
 
-/* Cirrus Maverick Instructions.  */
+  /* Make negative imm's into 7bit signed numbers.  */
+  if (neg)
+    {
+      imm = -imm;
+      imm &= 0x0000007f;
+    }
 
-/* Wrapper functions.  */
+  /* 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);
 
-static void
-do_mav_binops_1a (str)
-     char * str;
-{
-  do_mav_binops (str, MAV_MODE1, REG_TYPE_RN, REG_TYPE_MVF);
+  inst.instruction |= imm;
+  end_of_line (str);
 }
 
 static void
-do_mav_binops_1b (str)
-     char * str;
+do_mav_shift_1 (char * str)
 {
-  do_mav_binops (str, MAV_MODE1, REG_TYPE_RN, REG_TYPE_MVD);
+  do_mav_shift (str, REG_TYPE_MVFX, REG_TYPE_MVFX);
 }
 
 static void
-do_mav_binops_1c (str)
-     char * str;
+do_mav_shift_2 (char * str)
 {
-  do_mav_binops (str, MAV_MODE1, REG_TYPE_RN, REG_TYPE_MVDX);
+  do_mav_shift (str, REG_TYPE_MVDX, REG_TYPE_MVDX);
 }
 
-static void
-do_mav_binops_1d (str)
-     char * str;
+static int
+mav_parse_offset (char ** str, int * negative)
 {
-  do_mav_binops (str, MAV_MODE1, REG_TYPE_MVF, REG_TYPE_MVF);
-}
+  char * p = *str;
+  int offset;
 
-static void
-do_mav_binops_1e (str)
-     char * str;
-{
-  do_mav_binops (str, MAV_MODE1, REG_TYPE_MVD, REG_TYPE_MVD);
-}
+  *negative = 0;
 
-static void
-do_mav_binops_1f (str)
-     char * str;
-{
-  do_mav_binops (str, MAV_MODE1, REG_TYPE_MVD, REG_TYPE_MVF);
-}
+  skip_whitespace (p);
 
-static void
-do_mav_binops_1g (str)
-     char * str;
-{
-  do_mav_binops (str, MAV_MODE1, REG_TYPE_MVF, REG_TYPE_MVD);
-}
+  if (*p == '#')
+    ++p;
 
-static void
-do_mav_binops_1h (str)
-     char * str;
-{
-  do_mav_binops (str, MAV_MODE1, REG_TYPE_MVF, REG_TYPE_MVFX);
-}
+  if (*p == '-')
+    {
+      *negative = 1;
+      ++p;
+    }
 
-static void
-do_mav_binops_1i (str)
-     char * str;
-{
-  do_mav_binops (str, MAV_MODE1, REG_TYPE_MVD, REG_TYPE_MVFX);
-}
+  if (!ISDIGIT (*p))
+    {
+      inst.error = _("offset expected");
+      return 0;
+    }
 
-static void
-do_mav_binops_1j (str)
-     char * str;
-{
-  do_mav_binops (str, MAV_MODE1, REG_TYPE_MVF, REG_TYPE_MVDX);
-}
+  for (offset = 0; *p && ISDIGIT (*p); ++p)
+    offset = offset * 10 + *p - '0';
 
-static void
-do_mav_binops_1k (str)
-     char * str;
-{
-  do_mav_binops (str, MAV_MODE1, REG_TYPE_MVD, REG_TYPE_MVDX);
-}
+  if (offset > 0x3fc)
+    {
+      inst.error = _("offset out of range");
+      return 0;
+    }
+  if (offset & 0x3)
+    {
+      inst.error = _("offset not a multiple of 4");
+      return 0;
+    }
 
-static void
-do_mav_binops_1l (str)
-     char * str;
-{
-  do_mav_binops (str, MAV_MODE1, REG_TYPE_MVFX, REG_TYPE_MVF);
-}
+  *str = p;
 
-static void
-do_mav_binops_1m (str)
-     char * str;
-{
-  do_mav_binops (str, MAV_MODE1, REG_TYPE_MVFX, REG_TYPE_MVD);
+  return *negative ? -offset : offset;
 }
 
-static void
-do_mav_binops_1n (str)
-     char * str;
-{
-  do_mav_binops (str, MAV_MODE1, REG_TYPE_MVFX, REG_TYPE_MVFX);
-}
+/* Maverick load/store instructions.
+  <insn><cond> CRd,[Rn,<offset>]{!}.
+  <insn><cond> CRd,[Rn],<offset>.  */
 
 static void
-do_mav_binops_1o (str)
-     char * str;
+do_mav_ldst (char * str, enum arm_reg_type reg0)
 {
-  do_mav_binops (str, MAV_MODE1, REG_TYPE_MVDX, REG_TYPE_MVDX);
-}
+  int offset, negative;
 
-static void
-do_mav_binops_2a (str)
-     char * str;
-{
-  do_mav_binops (str, MAV_MODE2, REG_TYPE_MVF, REG_TYPE_RN);
-}
+  skip_whitespace (str);
 
-static void
-do_mav_binops_2b (str)
-     char * str;
-{
-  do_mav_binops (str, MAV_MODE2, REG_TYPE_MVD, REG_TYPE_RN);
-}
+  if (mav_reg_required_here (&str, 12, reg0) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || *str++ != '['
+      || reg_required_here (&str, 16) == FAIL)
+    goto fail_ldst;
 
-static void
-do_mav_binops_2c (str)
-     char * str;
-{
-  do_mav_binops (str, MAV_MODE2, REG_TYPE_MVDX, REG_TYPE_RN);
-}
+  if (skip_past_comma (&str) == SUCCESS)
+    {
+      /* You are here: "<offset>]{!}".  */
+      inst.instruction |= PRE_INDEX;
 
-static void
-do_mav_binops_3a (str)
-     char * str;
-{
-  do_mav_binops (str, MAV_MODE3, REG_TYPE_MVAX, REG_TYPE_MVFX);
-}
+      offset = mav_parse_offset (&str, &negative);
 
-static void
-do_mav_binops_3b (str)
-     char * str;
-{
-  do_mav_binops (str, MAV_MODE3, REG_TYPE_MVFX, REG_TYPE_MVAX);
-}
+      if (inst.error)
+       return;
 
-static void
-do_mav_binops_3c (str)
-     char * str;
-{
-  do_mav_binops (str, MAV_MODE3, REG_TYPE_MVAX, REG_TYPE_MVDX);
-}
+      if (*str++ != ']')
+       {
+         inst.error = _("missing ]");
+         return;
+       }
 
-static void
-do_mav_binops_3d (str)
-     char * str;
-{
-  do_mav_binops (str, MAV_MODE3, REG_TYPE_MVDX, REG_TYPE_MVAX);
-}
+      if (*str == '!')
+       {
+         inst.instruction |= WRITE_BACK;
+         ++str;
+       }
+    }
+  else
+    {
+      /* You are here: "], <offset>".  */
+      if (*str++ != ']')
+       {
+         inst.error = _("missing ]");
+         return;
+       }
 
-static void
-do_mav_triple_4a (str)
-     char * str;
-{
-  do_mav_triple (str, MAV_MODE4, REG_TYPE_MVFX, REG_TYPE_MVFX, REG_TYPE_RN);
-}
+      if (skip_past_comma (&str) == FAIL
+         || (offset = mav_parse_offset (&str, &negative), inst.error))
+       goto fail_ldst;
 
-static void
-do_mav_triple_4b (str)
-     char * str;
-{
-  do_mav_triple (str, MAV_MODE4, REG_TYPE_MVDX, REG_TYPE_MVDX, REG_TYPE_RN);
-}
+      inst.instruction |= CP_T_WB; /* Post indexed, set bit W.  */
+    }
 
-static void
-do_mav_triple_5a (str)
-     char * str;
-{
-  do_mav_triple (str, MAV_MODE5, REG_TYPE_RN, REG_TYPE_MVF, REG_TYPE_MVF);
-}
+  if (negative)
+    offset = -offset;
+  else
+    inst.instruction |= CP_T_UD; /* Positive, so set bit U.  */
 
-static void
-do_mav_triple_5b (str)
-     char * str;
-{
-  do_mav_triple (str, MAV_MODE5, REG_TYPE_RN, REG_TYPE_MVD, REG_TYPE_MVD);
-}
+  inst.instruction |= offset >> 2;
+  end_of_line (str);
+  return;
 
-static void
-do_mav_triple_5c (str)
-     char * str;
-{
-  do_mav_triple (str, MAV_MODE5, REG_TYPE_RN, REG_TYPE_MVFX, REG_TYPE_MVFX);
+fail_ldst:
+  if (!inst.error)
+     inst.error = BAD_ARGS;
 }
 
 static void
-do_mav_triple_5d (str)
-     char * str;
+do_mav_ldst_1 (char * str)
 {
-  do_mav_triple (str, MAV_MODE5, REG_TYPE_RN, REG_TYPE_MVDX, REG_TYPE_MVDX);
+  do_mav_ldst (str, REG_TYPE_MVF);
 }
 
 static void
-do_mav_triple_5e (str)
-     char * str;
+do_mav_ldst_2 (char * str)
 {
-  do_mav_triple (str, MAV_MODE5, REG_TYPE_MVF, REG_TYPE_MVF, REG_TYPE_MVF);
+  do_mav_ldst (str, REG_TYPE_MVD);
 }
 
 static void
-do_mav_triple_5f (str)
-     char * str;
+do_mav_ldst_3 (char * str)
 {
-  do_mav_triple (str, MAV_MODE5, REG_TYPE_MVD, REG_TYPE_MVD, REG_TYPE_MVD);
+  do_mav_ldst (str, REG_TYPE_MVFX);
 }
 
 static void
-do_mav_triple_5g (str)
-     char * str;
+do_mav_ldst_4 (char * str)
 {
-  do_mav_triple (str, MAV_MODE5, REG_TYPE_MVFX, REG_TYPE_MVFX, REG_TYPE_MVFX);
+  do_mav_ldst (str, REG_TYPE_MVDX);
 }
 
 static void
-do_mav_triple_5h (str)
-     char * str;
+do_t_nop (char * str)
 {
-  do_mav_triple (str, MAV_MODE5, REG_TYPE_MVDX, REG_TYPE_MVDX, REG_TYPE_MVDX);
+  /* Do nothing.  */
+  end_of_line (str);
 }
 
-static void
-do_mav_quad_6a (str)
-     char * str;
-{
-  do_mav_quad (str, MAV_MODE6, REG_TYPE_MVAX, REG_TYPE_MVFX, REG_TYPE_MVFX,
-            REG_TYPE_MVFX);
-}
+/* 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_mav_quad_6b (str)
-     char * str;
+do_t_arit (char * str)
 {
-  do_mav_quad (str, MAV_MODE6, REG_TYPE_MVAX, REG_TYPE_MVAX, REG_TYPE_MVFX,
-            REG_TYPE_MVFX);
-}
+  int Rd, Rs, Rn;
 
-/* cfmvsc32<cond> DSPSC,MVFX[15:0].  */
-static void
-do_mav_dspsc_1 (str)
-     char * str;
-{
   skip_whitespace (str);
 
-  /* cfmvsc32.  */
-  if (mav_reg_required_here (&str, -1, REG_TYPE_DSPSC) == FAIL
+  if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL
       || skip_past_comma (&str) == FAIL
-      || mav_reg_required_here (&str, 16, REG_TYPE_MVFX) == FAIL)
+      || (Rs = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
     {
-      if (!inst.error)
-       inst.error = BAD_ARGS;
-
+      inst.error = BAD_ARGS;
       return;
     }
 
-  end_of_line (str);
-}
-
-/* cfmv32sc<cond> MVFX[15:0],DSPSC.  */
-static void
-do_mav_dspsc_2 (str)
-     char * str;
-{
-  skip_whitespace (str);
-
-  /* cfmv32sc.  */
-  if (mav_reg_required_here (&str, 0, REG_TYPE_MVFX) == FAIL
-      || skip_past_comma (&str) == FAIL
-      || mav_reg_required_here (&str, -1, REG_TYPE_DSPSC) == FAIL)
+  if (skip_past_comma (&str) != FAIL)
     {
-      if (!inst.error)
-       inst.error = BAD_ARGS;
+      /* 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;
+       }
 
-      return;
-    }
+      if ((Rn = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
+       return;
 
-  end_of_line (str);
-}
+      if (Rs != Rd)
+       {
+         inst.error = _("dest and source1 must be the same register");
+         return;
+       }
+      Rs = Rn;
+    }
 
-static void
-do_mav_shift_1 (str)
-     char * str;
-{
-  do_mav_shift (str, REG_TYPE_MVFX, REG_TYPE_MVFX);
-}
+  if (inst.instruction == T_OPCODE_MUL
+      && Rs == Rd)
+    as_tsktsk (_("Rs and Rd must be different in MUL"));
 
-static void
-do_mav_shift_2 (str)
-     char * str;
-{
-  do_mav_shift (str, REG_TYPE_MVDX, REG_TYPE_MVDX);
+  inst.instruction |= Rd | (Rs << 3);
+  end_of_line (str);
 }
 
 static void
-do_mav_ldst_1 (str)
-     char * str;
+do_t_add (char * str)
 {
-  do_mav_ldst (str, REG_TYPE_MVF);
+  thumb_add_sub (str, 0);
 }
 
 static void
-do_mav_ldst_2 (str)
-     char * str;
+do_t_asr (char * str)
 {
-  do_mav_ldst (str, REG_TYPE_MVD);
+  thumb_shift (str, THUMB_ASR);
 }
 
 static void
-do_mav_ldst_3 (str)
-     char * str;
+do_t_branch9 (char * str)
 {
-  do_mav_ldst (str, REG_TYPE_MVFX);
+  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_mav_ldst_4 (str)
-     char * str;
+do_t_branch12 (char * str)
 {
-  do_mav_ldst (str, REG_TYPE_MVDX);
+  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);
 }
 
-/* Isnsn like "foo X,Y".  */
+/* Find the real, Thumb encoded start of a Thumb function.  */
 
-static void
-do_mav_binops (str, mode, reg0, reg1)
-     char * str;
-     int mode;
-     enum arm_reg_type reg0;
-     enum arm_reg_type reg1;
+static symbolS *
+find_real_start (symbolS * symbolP)
 {
-  int shift0, shift1;
+  char *       real_start;
+  const char * name = S_GET_NAME (symbolP);
+  symbolS *    new_target;
 
-  shift0 = mode & 0xff;
-  shift1 = (mode >> 8) & 0xff;
+  /* This definition must agree with the one in gcc/config/arm/thumb.c.  */
+#define STUB_NAME ".real_start_of"
 
-  skip_whitespace (str);
+  if (name == NULL)
+    abort ();
 
-  if (mav_reg_required_here (&str, shift0, reg0) == FAIL
-      || skip_past_comma (&str) == FAIL
-      || mav_reg_required_here (&str, shift1, reg1) == FAIL)
+  /* Names that start with '.' are local labels, not function entry points.
+     The compiler may generate BL instructions to these labels because it
+     needs to perform a branch to a far away location.  */
+  if (name[0] == '.')
+    return symbolP;
+
+  real_start = malloc (strlen (name) + strlen (STUB_NAME) + 1);
+  sprintf (real_start, "%s%s", STUB_NAME, name);
+
+  new_target = symbol_find (real_start);
+
+  if (new_target == NULL)
     {
-      if (!inst.error)
-       inst.error = BAD_ARGS;
+      as_warn ("Failed to find real start of function: %s\n", name);
+      new_target = symbolP;
     }
-  else
-    end_of_line (str);
-}
 
-/* Isnsn like "foo X,Y,Z".  */
+  free (real_start);
+
+  return new_target;
+}
 
 static void
-do_mav_triple (str, mode, reg0, reg1, reg2)
-     char * str;
-     int mode;
-     enum arm_reg_type reg0;
-     enum arm_reg_type reg1;
-     enum arm_reg_type reg2;
+do_t_branch23 (char * str)
 {
-  int shift0, shift1, shift2;
-
-  shift0 = mode & 0xff;
-  shift1 = (mode >> 8) & 0xff;
-  shift2 = (mode >> 16) & 0xff;
+  if (my_get_expression (& inst.reloc.exp, & str))
+    return;
 
-  skip_whitespace (str);
+  inst.reloc.type   = BFD_RELOC_THUMB_PCREL_BRANCH23;
+  inst.reloc.pc_rel = 1;
+  end_of_line (str);
 
-  if (mav_reg_required_here (&str, shift0, reg0) == FAIL
-      || skip_past_comma (&str) == FAIL
-      || mav_reg_required_here (&str, shift1, reg1) == FAIL
-      || skip_past_comma (&str) == FAIL
-      || mav_reg_required_here (&str, shift2, reg2) == FAIL)
-    {
-      if (!inst.error)
-       inst.error = BAD_ARGS;
-    }
-  else
-    end_of_line (str);
+  /* If the destination of the branch is a defined symbol which does not have
+     the THUMB_FUNC attribute, then we must be calling a function which has
+     the (interfacearm) attribute.  We look for the Thumb entry point to that
+     function and change the branch to refer to that function instead.  */
+  if (   inst.reloc.exp.X_op == O_symbol
+      && inst.reloc.exp.X_add_symbol != NULL
+      && S_IS_DEFINED (inst.reloc.exp.X_add_symbol)
+      && ! THUMB_IS_FUNC (inst.reloc.exp.X_add_symbol))
+    inst.reloc.exp.X_add_symbol =
+      find_real_start (inst.reloc.exp.X_add_symbol);
 }
 
-/* Isnsn like "foo W,X,Y,Z".
-    where W=MVAX[0:3] and X,Y,Z=MVFX[0:15].  */
-
 static void
-do_mav_quad (str, mode, reg0, reg1, reg2, reg3)
-     char * str;
-     int mode;
-     enum arm_reg_type reg0;
-     enum arm_reg_type reg1;
-     enum arm_reg_type reg2;
-     enum arm_reg_type reg3;
+do_t_bx (char * str)
 {
-  int shift0, shift1, shift2, shift3;
-
-  shift0= mode & 0xff;
-  shift1 = (mode >> 8) & 0xff;
-  shift2 = (mode >> 16) & 0xff;
-  shift3 = (mode >> 24) & 0xff;
+  int reg;
 
   skip_whitespace (str);
 
-  if (mav_reg_required_here (&str, shift0, reg0) == FAIL
-      || skip_past_comma (&str) == FAIL
-      || mav_reg_required_here (&str, shift1, reg1) == FAIL
-      || skip_past_comma (&str) == FAIL
-      || mav_reg_required_here (&str, shift2, reg2) == FAIL
-      || skip_past_comma (&str) == FAIL
-      || mav_reg_required_here (&str, shift3, reg3) == FAIL)
-    {
-      if (!inst.error)
-       inst.error = BAD_ARGS;
-    }
-  else
-    end_of_line (str);
+  if ((reg = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
+    return;
+
+  /* This sets THUMB_H2 from the top bit of reg.  */
+  inst.instruction |= reg << 3;
+
+  /* ??? FIXME: Should add a hacky reloc here if reg is REG_PC.  The reloc
+     should cause the alignment to be checked once it is known.  This is
+     because BX PC only works if the instruction is word aligned.  */
+
+  end_of_line (str);
 }
 
-/* Maverick 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_t_compare (char * str)
+{
+  thumb_mov_compare (str, THUMB_COMPARE);
+}
 
 static void
-do_mav_shift (str, reg0, reg1)
-     char * str;
-     enum arm_reg_type reg0;
-     enum arm_reg_type reg1;
+do_t_ldmstm (char * str)
 {
-  int error;
-  int imm, neg = 0;
+  int Rb;
+  long range;
 
   skip_whitespace (str);
 
-  error = 0;
+  if ((Rb = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
+    return;
 
-  if (mav_reg_required_here (&str, 12, reg0) == FAIL
-      || skip_past_comma (&str) == FAIL
-      || mav_reg_required_here (&str, 16, reg1) == FAIL
-      || skip_past_comma  (&str) == FAIL)
+  if (*str != '!')
+    as_warn (_("inserted missing '!': load/store multiple always writes back base register"));
+  else
+    str++;
+
+  if (skip_past_comma (&str) == FAIL
+      || (range = reg_list (&str)) == FAIL)
     {
-      if (!inst.error)
+      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 != '-')
+  if (inst.reloc.type != BFD_RELOC_NONE)
     {
-      inst.error = _("expecting immediate, 7bit operand");
+      /* This really doesn't seem worth it.  */
+      inst.reloc.type = BFD_RELOC_NONE;
+      inst.error = _("expression too complex");
       return;
     }
 
-  if (*str == '-')
-    {
-      neg = 1;
-      ++str;
-    }
-
-  for (imm = 0; *str && ISDIGIT (*str); ++str)
-    imm = imm * 10 + *str - '0';
-
-  if (imm > 64)
+  if (range & ~0xff)
     {
-      inst.error = _("immediate out of range");
+      inst.error = _("only lo-regs valid in load/store multiple");
       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 |= (Rb << 8) | range;
   end_of_line (str);
 }
 
-static int
-mav_parse_offset (str, negative)
-     char ** str;
-     int *negative;
+static void
+do_t_ldr (char * str)
 {
-  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;
+  thumb_load_store (str, THUMB_LOAD, THUMB_WORD);
 }
 
-/* Maverick load/store instructions.
-  <insn><cond> CRd,[Rn,<offset>]{!}.
-  <insn><cond> CRd,[Rn],<offset>.  */
-
 static void
-do_mav_ldst (str, reg0)
-     char * str;
-     enum arm_reg_type reg0;
+do_t_ldrb (char * str)
 {
-  int offset, negative;
-
-  skip_whitespace (str);
-
-  if (mav_reg_required_here (&str, 12, reg0) == 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 = mav_parse_offset (&str, &negative);
-
-      if (inst.error)
-       return;
+  thumb_load_store (str, THUMB_LOAD, THUMB_BYTE);
+}
 
-      if (*str++ != ']')
-       {
-         inst.error = _("missing ]");
-         return;
-       }
+static void
+do_t_ldrh (char * str)
+{
+  thumb_load_store (str, THUMB_LOAD, THUMB_HALFWORD);
+}
 
-      if (*str == '!')
-       {
-         inst.instruction |= WRITE_BACK;
-         ++str;
-       }
-    }
-  else
-    {
-      /* You are here: "], <offset>".  */
-      if (*str++ != ']')
-       {
-         inst.error = _("missing ]");
-         return;
-       }
+static void
+do_t_lds (char * str)
+{
+  int Rd, Rb, Ro;
 
-      if (skip_past_comma (&str) == FAIL
-         || (offset = mav_parse_offset (&str, &negative), inst.error))
-       goto fail_ldst;
+  skip_whitespace (str);
 
-      inst.instruction |= CP_T_WB; /* Post indexed, set bit W.  */
+  if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || *str++ != '['
+      || (Rb = thumb_reg (&str, THUMB_REG_LO)) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || (Ro = thumb_reg (&str, THUMB_REG_LO)) == FAIL
+      || *str++ != ']')
+    {
+      if (! inst.error)
+       inst.error = _("syntax: ldrs[b] Rd, [Rb, Ro]");
+      return;
     }
 
-  if (negative)
-    offset = -offset;
-  else
-    inst.instruction |= CP_T_UD; /* Postive, so set bit U.  */
-
-  inst.instruction |= offset >> 2;
+  inst.instruction |= Rd | (Rb << 3) | (Ro << 6);
   end_of_line (str);
-  return;
+}
 
-fail_ldst:
-  if (!inst.error)
-     inst.error = BAD_ARGS;
-  return;
+static void
+do_t_lsl (char * str)
+{
+  thumb_shift (str, THUMB_LSL);
 }
 
 static void
-do_t_nop (str)
-     char * str;
+do_t_lsr (char * str)
 {
-  /* Do nothing.  */
-  end_of_line (str);
-  return;
+  thumb_shift (str, THUMB_LSR);
 }
 
-/* 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_mov (char * str)
+{
+  thumb_mov_compare (str, THUMB_MOVE);
+}
 
 static void
-do_t_arit (str)
-     char * str;
+do_t_push_pop (char * str)
 {
-  int Rd, Rs, Rn;
+  long range;
 
   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)
+  if ((range = reg_list (&str)) == FAIL)
     {
-      inst.error = BAD_ARGS;
+      if (! inst.error)
+       inst.error = BAD_ARGS;
       return;
     }
 
-  if (skip_past_comma (&str) != FAIL)
+  if (inst.reloc.type != BFD_RELOC_NONE)
     {
-      /* 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)
+      /* This really doesn't seem worth it.  */
+      inst.reloc.type = BFD_RELOC_NONE;
+      inst.error = _("expression too complex");
+      return;
+    }
+
+  if (range & ~0xff)
+    {
+      if ((inst.instruction == T_OPCODE_PUSH
+          && (range & ~0xff) == 1 << REG_LR)
+         || (inst.instruction == T_OPCODE_POP
+             && (range & ~0xff) == 1 << REG_PC))
        {
-         inst.error = BAD_ARGS;
-         return;
+         inst.instruction |= THUMB_PP_PC_LR;
+         range &= 0xff;
        }
-
-      if ((Rn = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
-       return;
-
-      if (Rs != Rd)
+      else
        {
-         inst.error = _("dest and source1 must be the same register");
+         inst.error = _("invalid register list to push/pop instruction");
          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);
+  inst.instruction |= range;
   end_of_line (str);
 }
 
 static void
-do_t_add (str)
-     char * str;
+do_t_str (char * str)
 {
-  thumb_add_sub (str, 0);
+  thumb_load_store (str, THUMB_STORE, THUMB_WORD);
 }
 
 static void
-do_t_asr (str)
-     char * str;
+do_t_strb (char * str)
 {
-  thumb_shift (str, THUMB_ASR);
+  thumb_load_store (str, THUMB_STORE, THUMB_BYTE);
+}
+
+static void
+do_t_strh (char * str)
+{
+  thumb_load_store (str, THUMB_STORE, THUMB_HALFWORD);
+}
+
+static void
+do_t_sub (char * str)
+{
+  thumb_add_sub (str, 1);
 }
 
 static void
-do_t_branch9 (str)
-     char * str;
+do_t_swi (char * str)
 {
+  skip_whitespace (str);
+
   if (my_get_expression (&inst.reloc.exp, &str))
     return;
-  inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH9;
-  inst.reloc.pc_rel = 1;
+
+  inst.reloc.type = BFD_RELOC_ARM_SWI;
   end_of_line (str);
 }
 
 static void
-do_t_branch12 (str)
-     char * str;
+do_t_adr (char * str)
 {
-  if (my_get_expression (&inst.reloc.exp, &str))
-    return;
-  inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH12;
+  int reg;
+
+  /* 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-.-4".  */
+  skip_whitespace (str);
+
+  /* Store Rd in temporary location inside instruction.  */
+  if ((reg = reg_required_here (&str, 4)) == FAIL
+      || (reg > 7)  /* For Thumb reg must be r0..r7.  */
+      || skip_past_comma (&str) == FAIL
+      || my_get_expression (&inst.reloc.exp, &str))
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
+  inst.reloc.exp.X_add_number -= 4; /* PC relative adjust.  */
   inst.reloc.pc_rel = 1;
+  inst.instruction |= REG_PC; /* Rd is already placed into the instruction.  */
+
   end_of_line (str);
 }
 
-/* Find the real, Thumb encoded start of a Thumb function.  */
+static void
+insert_reg (const struct reg_entry * r,
+           struct hash_control * htab)
+{
+  int    len  = strlen (r->name) + 2;
+  char * buf  = xmalloc (len);
+  char * buf2 = xmalloc (len);
+  int    i    = 0;
 
-static symbolS *
-find_real_start (symbolP)
-     symbolS * symbolP;
+#ifdef REGISTER_PREFIX
+  buf[i++] = REGISTER_PREFIX;
+#endif
+
+  strcpy (buf + i, r->name);
+
+  for (i = 0; buf[i]; i++)
+    buf2[i] = TOUPPER (buf[i]);
+
+  buf2[i] = '\0';
+
+  hash_insert (htab, buf,  (PTR) r);
+  hash_insert (htab, buf2, (PTR) r);
+}
+
+static void
+build_reg_hsh (struct reg_map * map)
 {
-  char *       real_start;
-  const char * name = S_GET_NAME (symbolP);
-  symbolS *    new_target;
+  const struct reg_entry *r;
 
-  /* This definiton must agree with the one in gcc/config/arm/thumb.c.  */
-#define STUB_NAME ".real_start_of"
+  if ((map->htab = hash_new ()) == NULL)
+    as_fatal (_("virtual memory exhausted"));
 
-  if (name == NULL)
-    abort ();
+  for (r = map->names; r->name != NULL; r++)
+    insert_reg (r, map->htab);
+}
 
-  /* Names that start with '.' are local labels, not function entry points.
-     The compiler may generate BL instructions to these labels because it
-     needs to perform a branch to a far away location.  */
-  if (name[0] == '.')
-    return symbolP;
+static void
+insert_reg_alias (char * str,
+                 int regnum,
+                 struct hash_control *htab)
+{
+  const char * error;
+  struct reg_entry * new = xmalloc (sizeof (struct reg_entry));
+  const char * name = xmalloc (strlen (str) + 1);
 
-  real_start = malloc (strlen (name) + strlen (STUB_NAME) + 1);
-  sprintf (real_start, "%s%s", STUB_NAME, name);
+  strcpy ((char *) name, str);
+
+  new->name = name;
+  new->number = regnum;
+  new->builtin = FALSE;
+
+  error = hash_insert (htab, name, (PTR) new);
+  if (error)
+    {
+      as_bad (_("failed to create an alias for %s, reason: %s"),
+           str, error);
+      free ((char *) name);
+      free (new);
+    }
+}
+
+/* Look for the .req directive.  This is of the form:
+
+       new_register_name .req existing_register_name
+
+   If we find one, or if it looks sufficiently like one that we want to
+   handle any error here, return non-zero.  Otherwise return zero.  */
+
+static int
+create_register_alias (char * newname, char * p)
+{
+  char * q;
+  char c;
+
+  q = p;
+  skip_whitespace (q);
+
+  c = *p;
+  *p = '\0';
+
+  if (*q && !strncmp (q, ".req ", 5))
+    {
+      char *copy_of_str;
+      char *r;
+
+#ifndef IGNORE_OPCODE_CASE
+      newname = original_case_string;
+#endif
+      copy_of_str = newname;
+
+      q += 4;
+      skip_whitespace (q);
+
+      for (r = q; *r != '\0'; r++)
+       if (*r == ' ')
+         break;
+
+      if (r != q)
+       {
+         enum arm_reg_type new_type, old_type;
+         int old_regno;
+         char d = *r;
+
+         *r = '\0';
+         old_type = arm_reg_parse_any (q);
+         *r = d;
+
+         new_type = arm_reg_parse_any (newname);
+
+         if (new_type == REG_TYPE_MAX)
+           {
+             if (old_type != REG_TYPE_MAX)
+               {
+                 old_regno = arm_reg_parse (&q, all_reg_maps[old_type].htab);
+                 insert_reg_alias (newname, old_regno,
+                                   all_reg_maps[old_type].htab);
+               }
+             else
+               as_warn (_("register '%s' does not exist\n"), q);
+           }
+         else if (old_type == REG_TYPE_MAX)
+           {
+             as_warn (_("ignoring redefinition of register alias '%s' to non-existant register '%s'"),
+                      copy_of_str, q);
+           }
+         else
+           {
+             /* Do not warn about redefinitions to the same alias.  */
+             if (new_type != old_type
+                 || (arm_reg_parse (&q, all_reg_maps[old_type].htab)
+                     != arm_reg_parse (&q, all_reg_maps[new_type].htab)))
+               as_warn (_("ignoring redefinition of register alias '%s'"),
+                        copy_of_str);
 
-  new_target = symbol_find (real_start);
+           }
+       }
+      else
+       as_warn (_("ignoring incomplete .req pseuso op"));
 
-  if (new_target == NULL)
-    {
-      as_warn ("Failed to find real start of function: %s\n", name);
-      new_target = symbolP;
+      *p = c;
+      return 1;
     }
 
-  free (real_start);
-
-  return new_target;
+  *p = c;
+  return 0;
 }
 
 static void
-do_t_branch23 (str)
-     char * str;
+set_constant_flonums (void)
 {
-  if (my_get_expression (& inst.reloc.exp, & str))
-    return;
-
-  inst.reloc.type   = BFD_RELOC_THUMB_PCREL_BRANCH23;
-  inst.reloc.pc_rel = 1;
-  end_of_line (str);
+  int i;
 
-  /* If the destination of the branch is a defined symbol which does not have
-     the THUMB_FUNC attribute, then we must be calling a function which has
-     the (interfacearm) attribute.  We look for the Thumb entry point to that
-     function and change the branch to refer to that function instead.  */
-  if (   inst.reloc.exp.X_op == O_symbol
-      && inst.reloc.exp.X_add_symbol != NULL
-      && S_IS_DEFINED (inst.reloc.exp.X_add_symbol)
-      && ! THUMB_IS_FUNC (inst.reloc.exp.X_add_symbol))
-    inst.reloc.exp.X_add_symbol =
-      find_real_start (inst.reloc.exp.X_add_symbol);
+  for (i = 0; i < NUM_FLOAT_VALS; i++)
+    if (atof_ieee ((char *) fp_const[i], 'x', fp_values[i]) == NULL)
+      abort ();
 }
 
-static void
-do_t_bx (str)
-     char * str;
+\f
+static const struct asm_opcode insns[] =
 {
-  int reg;
+  /* Core ARM Instructions.  */
+  {"and",        0xe0000000, 3,  ARM_EXT_V1,       do_arit},
+  {"ands",       0xe0100000, 3,  ARM_EXT_V1,       do_arit},
+  {"eor",        0xe0200000, 3,  ARM_EXT_V1,       do_arit},
+  {"eors",       0xe0300000, 3,  ARM_EXT_V1,       do_arit},
+  {"sub",        0xe0400000, 3,  ARM_EXT_V1,       do_arit},
+  {"subs",       0xe0500000, 3,  ARM_EXT_V1,       do_arit},
+  {"rsb",        0xe0600000, 3,  ARM_EXT_V1,       do_arit},
+  {"rsbs",       0xe0700000, 3,  ARM_EXT_V1,       do_arit},
+  {"add",        0xe0800000, 3,  ARM_EXT_V1,       do_arit},
+  {"adds",       0xe0900000, 3,  ARM_EXT_V1,       do_arit},
+  {"adc",        0xe0a00000, 3,  ARM_EXT_V1,       do_arit},
+  {"adcs",       0xe0b00000, 3,  ARM_EXT_V1,       do_arit},
+  {"sbc",        0xe0c00000, 3,  ARM_EXT_V1,       do_arit},
+  {"sbcs",       0xe0d00000, 3,  ARM_EXT_V1,       do_arit},
+  {"rsc",        0xe0e00000, 3,  ARM_EXT_V1,       do_arit},
+  {"rscs",       0xe0f00000, 3,  ARM_EXT_V1,       do_arit},
+  {"orr",        0xe1800000, 3,  ARM_EXT_V1,       do_arit},
+  {"orrs",       0xe1900000, 3,  ARM_EXT_V1,       do_arit},
+  {"bic",        0xe1c00000, 3,  ARM_EXT_V1,       do_arit},
+  {"bics",       0xe1d00000, 3,  ARM_EXT_V1,       do_arit},
 
-  skip_whitespace (str);
+  {"tst",        0xe1100000, 3,  ARM_EXT_V1,       do_cmp},
+  {"tsts",       0xe1100000, 3,  ARM_EXT_V1,       do_cmp},
+  {"tstp",       0xe110f000, 3,  ARM_EXT_V1,       do_cmp},
+  {"teq",        0xe1300000, 3,  ARM_EXT_V1,       do_cmp},
+  {"teqs",       0xe1300000, 3,  ARM_EXT_V1,       do_cmp},
+  {"teqp",       0xe130f000, 3,  ARM_EXT_V1,       do_cmp},
+  {"cmp",        0xe1500000, 3,  ARM_EXT_V1,       do_cmp},
+  {"cmps",       0xe1500000, 3,  ARM_EXT_V1,       do_cmp},
+  {"cmpp",       0xe150f000, 3,  ARM_EXT_V1,       do_cmp},
+  {"cmn",        0xe1700000, 3,  ARM_EXT_V1,       do_cmp},
+  {"cmns",       0xe1700000, 3,  ARM_EXT_V1,       do_cmp},
+  {"cmnp",       0xe170f000, 3,  ARM_EXT_V1,       do_cmp},
 
-  if ((reg = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
-    return;
+  {"mov",        0xe1a00000, 3,  ARM_EXT_V1,       do_mov},
+  {"movs",       0xe1b00000, 3,  ARM_EXT_V1,       do_mov},
+  {"mvn",        0xe1e00000, 3,  ARM_EXT_V1,       do_mov},
+  {"mvns",       0xe1f00000, 3,  ARM_EXT_V1,       do_mov},
 
-  /* This sets THUMB_H2 from the top bit of reg.  */
-  inst.instruction |= reg << 3;
+  {"ldr",        0xe4100000, 3,  ARM_EXT_V1,       do_ldst},
+  {"ldrb",       0xe4500000, 3,  ARM_EXT_V1,       do_ldst},
+  {"ldrt",       0xe4300000, 3,  ARM_EXT_V1,       do_ldstt},
+  {"ldrbt",      0xe4700000, 3,  ARM_EXT_V1,       do_ldstt},
+  {"str",        0xe4000000, 3,  ARM_EXT_V1,       do_ldst},
+  {"strb",       0xe4400000, 3,  ARM_EXT_V1,       do_ldst},
+  {"strt",       0xe4200000, 3,  ARM_EXT_V1,       do_ldstt},
+  {"strbt",      0xe4600000, 3,  ARM_EXT_V1,       do_ldstt},
 
-  /* ??? FIXME: Should add a hacky reloc here if reg is REG_PC.  The reloc
-     should cause the alignment to be checked once it is known.  This is
-     because BX PC only works if the instruction is word aligned.  */
+  {"stmia",      0xe8800000, 3,  ARM_EXT_V1,       do_ldmstm},
+  {"stmib",      0xe9800000, 3,  ARM_EXT_V1,       do_ldmstm},
+  {"stmda",      0xe8000000, 3,  ARM_EXT_V1,       do_ldmstm},
+  {"stmdb",      0xe9000000, 3,  ARM_EXT_V1,       do_ldmstm},
+  {"stmfd",      0xe9000000, 3,  ARM_EXT_V1,       do_ldmstm},
+  {"stmfa",      0xe9800000, 3,  ARM_EXT_V1,       do_ldmstm},
+  {"stmea",      0xe8800000, 3,  ARM_EXT_V1,       do_ldmstm},
+  {"stmed",      0xe8000000, 3,  ARM_EXT_V1,       do_ldmstm},
 
-  end_of_line (str);
-}
+  {"ldmia",      0xe8900000, 3,  ARM_EXT_V1,       do_ldmstm},
+  {"ldmib",      0xe9900000, 3,  ARM_EXT_V1,       do_ldmstm},
+  {"ldmda",      0xe8100000, 3,  ARM_EXT_V1,       do_ldmstm},
+  {"ldmdb",      0xe9100000, 3,  ARM_EXT_V1,       do_ldmstm},
+  {"ldmfd",      0xe8900000, 3,  ARM_EXT_V1,       do_ldmstm},
+  {"ldmfa",      0xe8100000, 3,  ARM_EXT_V1,       do_ldmstm},
+  {"ldmea",      0xe9100000, 3,  ARM_EXT_V1,       do_ldmstm},
+  {"ldmed",      0xe9900000, 3,  ARM_EXT_V1,       do_ldmstm},
 
-static void
-do_t_compare (str)
-     char * str;
-{
-  thumb_mov_compare (str, THUMB_COMPARE);
-}
+  {"swi",        0xef000000, 3,  ARM_EXT_V1,       do_swi},
+#ifdef TE_WINCE
+  /* XXX This is the wrong place to do this.  Think multi-arch.  */
+  {"bl",         0xeb000000, 2,  ARM_EXT_V1,       do_branch},
+  {"b",          0xea000000, 1,  ARM_EXT_V1,       do_branch},
+#else
+  {"bl",         0xebfffffe, 2,  ARM_EXT_V1,       do_branch},
+  {"b",          0xeafffffe, 1,  ARM_EXT_V1,       do_branch},
+#endif
 
-static void
-do_t_ldmstm (str)
-     char * str;
-{
-  int Rb;
-  long range;
+  /* Pseudo ops.  */
+  {"adr",        0xe28f0000, 3,  ARM_EXT_V1,       do_adr},
+  {"adrl",       0xe28f0000, 3,  ARM_EXT_V1,       do_adrl},
+  {"nop",        0xe1a00000, 3,  ARM_EXT_V1,       do_nop},
 
-  skip_whitespace (str);
+  /* ARM 2 multiplies.  */
+  {"mul",        0xe0000090, 3,  ARM_EXT_V2,       do_mul},
+  {"muls",       0xe0100090, 3,  ARM_EXT_V2,       do_mul},
+  {"mla",        0xe0200090, 3,  ARM_EXT_V2,       do_mla},
+  {"mlas",       0xe0300090, 3,  ARM_EXT_V2,       do_mla},
 
-  if ((Rb = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
-    return;
+  /* Generic coprocessor instructions.  */
+  {"cdp",        0xee000000, 3,  ARM_EXT_V2,       do_cdp},
+  {"ldc",        0xec100000, 3,  ARM_EXT_V2,       do_lstc},
+  {"ldcl",       0xec500000, 3,  ARM_EXT_V2,       do_lstc},
+  {"stc",        0xec000000, 3,  ARM_EXT_V2,       do_lstc},
+  {"stcl",       0xec400000, 3,  ARM_EXT_V2,       do_lstc},
+  {"mcr",        0xee000010, 3,  ARM_EXT_V2,       do_co_reg},
+  {"mrc",        0xee100010, 3,  ARM_EXT_V2,       do_co_reg},
 
-  if (*str != '!')
-    as_warn (_("inserted missing '!': load/store multiple always writes back base register"));
-  else
-    str++;
+  /* ARM 3 - swp instructions.  */
+  {"swp",        0xe1000090, 3,  ARM_EXT_V2S,      do_swap},
+  {"swpb",       0xe1400090, 3,  ARM_EXT_V2S,      do_swap},
 
-  if (skip_past_comma (&str) == FAIL
-      || (range = reg_list (&str)) == FAIL)
-    {
-      if (! inst.error)
-       inst.error = BAD_ARGS;
-      return;
-    }
+  /* ARM 6 Status register instructions.  */
+  {"mrs",        0xe10f0000, 3,  ARM_EXT_V3,       do_mrs},
+  {"msr",        0xe120f000, 3,  ARM_EXT_V3,       do_msr},
+  /* ScottB: our code uses     0xe128f000 for msr.
+     NickC:  but this is wrong because the bits 16 through 19 are
+             handled by the PSR_xxx defines above.  */
 
-  if (inst.reloc.type != BFD_RELOC_NONE)
-    {
-      /* This really doesn't seem worth it.  */
-      inst.reloc.type = BFD_RELOC_NONE;
-      inst.error = _("expression too complex");
-      return;
-    }
+  /* ARM 7M long multiplies.  */
+  {"smull",      0xe0c00090, 5,  ARM_EXT_V3M,      do_mull},
+  {"smulls",     0xe0d00090, 5,  ARM_EXT_V3M,      do_mull},
+  {"umull",      0xe0800090, 5,  ARM_EXT_V3M,      do_mull},
+  {"umulls",     0xe0900090, 5,  ARM_EXT_V3M,      do_mull},
+  {"smlal",      0xe0e00090, 5,  ARM_EXT_V3M,      do_mull},
+  {"smlals",     0xe0f00090, 5,  ARM_EXT_V3M,      do_mull},
+  {"umlal",      0xe0a00090, 5,  ARM_EXT_V3M,      do_mull},
+  {"umlals",     0xe0b00090, 5,  ARM_EXT_V3M,      do_mull},
 
-  if (range & ~0xff)
-    {
-      inst.error = _("only lo-regs valid in load/store multiple");
-      return;
-    }
+  /* ARM Architecture 4.  */
+  {"ldrh",       0xe01000b0, 3,  ARM_EXT_V4,       do_ldstv4},
+  {"ldrsh",      0xe01000f0, 3,  ARM_EXT_V4,       do_ldstv4},
+  {"ldrsb",      0xe01000d0, 3,  ARM_EXT_V4,       do_ldstv4},
+  {"strh",       0xe00000b0, 3,  ARM_EXT_V4,       do_ldstv4},
 
-  inst.instruction |= (Rb << 8) | range;
-  end_of_line (str);
-}
+  /* ARM Architecture 4T.  */
+  /* Note: bx (and blx) are required on V5, even if the processor does
+     not support Thumb.  */
+  {"bx",         0xe12fff10, 2,  ARM_EXT_V4T | ARM_EXT_V5, do_bx},
 
-static void
-do_t_ldr (str)
-     char * str;
-{
-  thumb_load_store (str, THUMB_LOAD, THUMB_WORD);
-}
+  /*  ARM Architecture 5T.  */
+  /* Note: blx has 2 variants, so the .value is set dynamically.
+     Only one of the variants has conditional execution.  */
+  {"blx",        0xe0000000, 3,  ARM_EXT_V5,       do_blx},
+  {"clz",        0xe16f0f10, 3,  ARM_EXT_V5,       do_clz},
+  {"bkpt",       0xe1200070, 0,  ARM_EXT_V5,       do_bkpt},
+  {"ldc2",       0xfc100000, 0,  ARM_EXT_V5,       do_lstc2},
+  {"ldc2l",      0xfc500000, 0,  ARM_EXT_V5,       do_lstc2},
+  {"stc2",       0xfc000000, 0,  ARM_EXT_V5,       do_lstc2},
+  {"stc2l",      0xfc400000, 0,  ARM_EXT_V5,       do_lstc2},
+  {"cdp2",       0xfe000000, 0,  ARM_EXT_V5,       do_cdp2},
+  {"mcr2",       0xfe000010, 0,  ARM_EXT_V5,       do_co_reg2},
+  {"mrc2",       0xfe100010, 0,  ARM_EXT_V5,       do_co_reg2},
 
-static void
-do_t_ldrb (str)
-     char * str;
-{
-  thumb_load_store (str, THUMB_LOAD, THUMB_BYTE);
-}
+  /*  ARM Architecture 5TExP.  */
+  {"smlabb",     0xe1000080, 6,  ARM_EXT_V5ExP,    do_smla},
+  {"smlatb",     0xe10000a0, 6,  ARM_EXT_V5ExP,    do_smla},
+  {"smlabt",     0xe10000c0, 6,  ARM_EXT_V5ExP,    do_smla},
+  {"smlatt",     0xe10000e0, 6,  ARM_EXT_V5ExP,    do_smla},
+
+  {"smlawb",     0xe1200080, 6,  ARM_EXT_V5ExP,    do_smla},
+  {"smlawt",     0xe12000c0, 6,  ARM_EXT_V5ExP,    do_smla},
+
+  {"smlalbb",    0xe1400080, 7,  ARM_EXT_V5ExP,    do_smlal},
+  {"smlaltb",    0xe14000a0, 7,  ARM_EXT_V5ExP,    do_smlal},
+  {"smlalbt",    0xe14000c0, 7,  ARM_EXT_V5ExP,    do_smlal},
+  {"smlaltt",    0xe14000e0, 7,  ARM_EXT_V5ExP,    do_smlal},
+
+  {"smulbb",     0xe1600080, 6,  ARM_EXT_V5ExP,    do_smul},
+  {"smultb",     0xe16000a0, 6,  ARM_EXT_V5ExP,    do_smul},
+  {"smulbt",     0xe16000c0, 6,  ARM_EXT_V5ExP,    do_smul},
+  {"smultt",     0xe16000e0, 6,  ARM_EXT_V5ExP,    do_smul},
+
+  {"smulwb",     0xe12000a0, 6,  ARM_EXT_V5ExP,    do_smul},
+  {"smulwt",     0xe12000e0, 6,  ARM_EXT_V5ExP,    do_smul},
 
-static void
-do_t_ldrh (str)
-     char * str;
-{
-  thumb_load_store (str, THUMB_LOAD, THUMB_HALFWORD);
-}
+  {"qadd",       0xe1000050, 4,  ARM_EXT_V5ExP,    do_qadd},
+  {"qdadd",      0xe1400050, 5,  ARM_EXT_V5ExP,    do_qadd},
+  {"qsub",       0xe1200050, 4,  ARM_EXT_V5ExP,    do_qadd},
+  {"qdsub",      0xe1600050, 5,  ARM_EXT_V5ExP,    do_qadd},
 
-static void
-do_t_lds (str)
-     char * str;
-{
-  int Rd, Rb, Ro;
+  /*  ARM Architecture 5TE.  */
+  {"pld",        0xf450f000, 0,  ARM_EXT_V5E,      do_pld},
+  {"ldrd",       0xe00000d0, 3,  ARM_EXT_V5E,      do_ldrd},
+  {"strd",       0xe00000f0, 3,  ARM_EXT_V5E,      do_ldrd},
 
-  skip_whitespace (str);
+  {"mcrr",       0xec400000, 4,  ARM_EXT_V5E,      do_co_reg2c},
+  {"mrrc",       0xec500000, 4,  ARM_EXT_V5E,      do_co_reg2c},
 
-  if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL
-      || skip_past_comma (&str) == FAIL
-      || *str++ != '['
-      || (Rb = thumb_reg (&str, THUMB_REG_LO)) == FAIL
-      || skip_past_comma (&str) == FAIL
-      || (Ro = thumb_reg (&str, THUMB_REG_LO)) == FAIL
-      || *str++ != ']')
-    {
-      if (! inst.error)
-       inst.error = _("syntax: ldrs[b] Rd, [Rb, Ro]");
-      return;
-    }
+  /*  ARM Architecture 5TEJ.  */
+  {"bxj",       0xe12fff20, 3,  ARM_EXT_V5J,      do_bxj},
 
-  inst.instruction |= Rd | (Rb << 3) | (Ro << 6);
-  end_of_line (str);
-}
+  /*  ARM V6.  */
+  { "cps",       0xf1020000, 0,  ARM_EXT_V6,       do_cps},
+  { "cpsie",     0xf1080000, 0,  ARM_EXT_V6,       do_cpsi},
+  { "cpsid",     0xf10C0000, 0,  ARM_EXT_V6,       do_cpsi},
+  { "ldrex",     0xe1900f9f, 5,  ARM_EXT_V6,       do_ldrex},
+  { "mcrr2",     0xfc400000, 0,  ARM_EXT_V6,       do_co_reg2c},
+  { "mrrc2",     0xfc500000, 0,  ARM_EXT_V6,       do_co_reg2c},
+  { "pkhbt",     0xe6800010, 5,  ARM_EXT_V6,       do_pkhbt},
+  { "pkhtb",     0xe6800050, 5,  ARM_EXT_V6,       do_pkhtb},
+  { "qadd16",    0xe6200f10, 6,  ARM_EXT_V6,       do_qadd16},
+  { "qadd8",     0xe6200f90, 5,  ARM_EXT_V6,       do_qadd16},
+  { "qaddsubx",  0xe6200f30, 8,  ARM_EXT_V6,       do_qadd16},
+  { "qsub16",    0xe6200f70, 6,  ARM_EXT_V6,       do_qadd16},
+  { "qsub8",     0xe6200ff0, 5,  ARM_EXT_V6,       do_qadd16},
+  { "qsubaddx",  0xe6200f50, 8,  ARM_EXT_V6,       do_qadd16},
+  { "sadd16",    0xe6100f10, 6,  ARM_EXT_V6,       do_qadd16},
+  { "sadd8",     0xe6100f90, 5,  ARM_EXT_V6,       do_qadd16},
+  { "saddsubx",  0xe6100f30, 8,  ARM_EXT_V6,       do_qadd16},
+  { "shadd16",   0xe6300f10, 7,  ARM_EXT_V6,       do_qadd16},
+  { "shadd8",    0xe6300f90, 6,  ARM_EXT_V6,       do_qadd16},
+  { "shaddsubx", 0xe6300f30, 9,  ARM_EXT_V6,       do_qadd16},
+  { "shsub16",   0xe6300f70, 7,  ARM_EXT_V6,       do_qadd16},
+  { "shsub8",    0xe6300ff0, 6,  ARM_EXT_V6,       do_qadd16},
+  { "shsubaddx", 0xe6300f50, 9,  ARM_EXT_V6,       do_qadd16},
+  { "ssub16",    0xe6100f70, 6,  ARM_EXT_V6,       do_qadd16},
+  { "ssub8",     0xe6100ff0, 5,  ARM_EXT_V6,       do_qadd16},
+  { "ssubaddx",  0xe6100f50, 8,  ARM_EXT_V6,       do_qadd16},
+  { "uadd16",    0xe6500f10, 6,  ARM_EXT_V6,       do_qadd16},
+  { "uadd8",     0xe6500f90, 5,  ARM_EXT_V6,       do_qadd16},
+  { "uaddsubx",  0xe6500f30, 8,  ARM_EXT_V6,       do_qadd16},
+  { "uhadd16",   0xe6700f10, 7,  ARM_EXT_V6,       do_qadd16},
+  { "uhadd8",    0xe6700f90, 6,  ARM_EXT_V6,       do_qadd16},
+  { "uhaddsubx", 0xe6700f30, 9,  ARM_EXT_V6,       do_qadd16},
+  { "uhsub16",   0xe6700f70, 7,  ARM_EXT_V6,       do_qadd16},
+  { "uhsub8",    0xe6700ff0, 6,  ARM_EXT_V6,       do_qadd16},
+  { "uhsubaddx", 0xe6700f50, 9,  ARM_EXT_V6,       do_qadd16},
+  { "uqadd16",   0xe6600f10, 7,  ARM_EXT_V6,       do_qadd16},
+  { "uqadd8",    0xe6600f90, 6,  ARM_EXT_V6,       do_qadd16},
+  { "uqaddsubx", 0xe6600f30, 9,  ARM_EXT_V6,       do_qadd16},
+  { "uqsub16",   0xe6600f70, 7,  ARM_EXT_V6,       do_qadd16},
+  { "uqsub8",    0xe6600ff0, 6,  ARM_EXT_V6,       do_qadd16},
+  { "uqsubaddx", 0xe6600f50, 9,  ARM_EXT_V6,       do_qadd16},
+  { "usub16",    0xe6500f70, 6,  ARM_EXT_V6,       do_qadd16},
+  { "usub8",     0xe6500ff0, 5,  ARM_EXT_V6,       do_qadd16},
+  { "usubaddx",  0xe6500f50, 8,  ARM_EXT_V6,       do_qadd16},
+  { "rev",       0xe6bf0f30, 3,  ARM_EXT_V6,       do_rev},
+  { "rev16",     0xe6bf0fb0, 5,  ARM_EXT_V6,       do_rev},
+  { "revsh",     0xe6ff0fb0, 5,  ARM_EXT_V6,       do_rev},
+  { "rfeia",     0xf8900a00, 0,  ARM_EXT_V6,       do_rfe},
+  { "rfeib",     0xf9900a00, 0,  ARM_EXT_V6,       do_rfe},
+  { "rfeda",     0xf8100a00, 0,  ARM_EXT_V6,       do_rfe},
+  { "rfedb",     0xf9100a00, 0,  ARM_EXT_V6,       do_rfe},
+  { "rfefd",     0xf8900a00, 0,  ARM_EXT_V6,       do_rfe},
+  { "rfefa",     0xf9900a00, 0,  ARM_EXT_V6,       do_rfe},
+  { "rfeea",     0xf8100a00, 0,  ARM_EXT_V6,       do_rfe},
+  { "rfeed",     0xf9100a00, 0,  ARM_EXT_V6,       do_rfe},
+  { "sxtah",     0xe6b00070, 5,  ARM_EXT_V6,       do_sxtah},
+  { "sxtab16",   0xe6800070, 7,  ARM_EXT_V6,       do_sxtah},
+  { "sxtab",     0xe6a00070, 5,  ARM_EXT_V6,       do_sxtah},
+  { "sxth",      0xe6bf0070, 4,  ARM_EXT_V6,       do_sxth},
+  { "sxtb16",    0xe68f0070, 6,  ARM_EXT_V6,       do_sxth},
+  { "sxtb",      0xe6af0070, 4,  ARM_EXT_V6,       do_sxth},
+  { "uxtah",     0xe6f00070, 5,  ARM_EXT_V6,       do_sxtah},
+  { "uxtab16",   0xe6c00070, 7,  ARM_EXT_V6,       do_sxtah},
+  { "uxtab",     0xe6e00070, 5,  ARM_EXT_V6,       do_sxtah},
+  { "uxth",      0xe6ff0070, 4,  ARM_EXT_V6,       do_sxth},
+  { "uxtb16",    0xe6cf0070, 6,  ARM_EXT_V6,       do_sxth},
+  { "uxtb",      0xe6ef0070, 4,  ARM_EXT_V6,       do_sxth},
+  { "sel",       0xe68000b0, 3,  ARM_EXT_V6,       do_qadd16},
+  { "setend",    0xf1010000, 0,  ARM_EXT_V6,       do_setend},
+  { "smlad",     0xe7000010, 5,  ARM_EXT_V6,       do_smlad},
+  { "smladx",    0xe7000030, 6,  ARM_EXT_V6,       do_smlad},
+  { "smlald",    0xe7400010, 6,  ARM_EXT_V6,       do_smlald},
+  { "smlaldx",   0xe7400030, 7,  ARM_EXT_V6,       do_smlald},
+  { "smlsd",     0xe7000050, 5,  ARM_EXT_V6,       do_smlad},
+  { "smlsdx",    0xe7000070, 6,  ARM_EXT_V6,       do_smlad},
+  { "smlsld",    0xe7400050, 6,  ARM_EXT_V6,       do_smlald},
+  { "smlsldx",   0xe7400070, 7,  ARM_EXT_V6,       do_smlald},
+  { "smmla",     0xe7500010, 5,  ARM_EXT_V6,       do_smlad},
+  { "smmlar",    0xe7500030, 6,  ARM_EXT_V6,       do_smlad},
+  { "smmls",     0xe75000d0, 5,  ARM_EXT_V6,       do_smlad},
+  { "smmlsr",    0xe75000f0, 6,  ARM_EXT_V6,       do_smlad},
+  { "smmul",     0xe750f010, 5,  ARM_EXT_V6,       do_smmul},
+  { "smmulr",    0xe750f030, 6,  ARM_EXT_V6,       do_smmul},
+  { "smuad",     0xe700f010, 5,  ARM_EXT_V6,       do_smmul},
+  { "smuadx",    0xe700f030, 6,  ARM_EXT_V6,       do_smmul},
+  { "smusd",     0xe700f050, 5,  ARM_EXT_V6,       do_smmul},
+  { "smusdx",    0xe700f070, 6,  ARM_EXT_V6,       do_smmul},
+  { "srsia",     0xf8cd0500, 0,  ARM_EXT_V6,       do_srs},
+  { "srsib",     0xf9cd0500, 0,  ARM_EXT_V6,       do_srs},
+  { "srsda",     0xf84d0500, 0,  ARM_EXT_V6,       do_srs},
+  { "srsdb",     0xf94d0500, 0,  ARM_EXT_V6,       do_srs},
+  { "ssat",      0xe6a00010, 4,  ARM_EXT_V6,       do_ssat},
+  { "ssat16",    0xe6a00f30, 6,  ARM_EXT_V6,       do_ssat16},
+  { "strex",     0xe1800f90, 5,  ARM_EXT_V6,       do_strex},
+  { "umaal",     0xe0400090, 5,  ARM_EXT_V6,       do_umaal},
+  { "usad8",     0xe780f010, 5,  ARM_EXT_V6,       do_smmul},
+  { "usada8",    0xe7800010, 6,  ARM_EXT_V6,       do_smlad},
+  { "usat",      0xe6e00010, 4,  ARM_EXT_V6,       do_usat},
+  { "usat16",    0xe6e00f30, 6,  ARM_EXT_V6,       do_usat16},
+
+  /*  ARM V6K.  */
+  { "clrex",     0xf57ff01f, 0,  ARM_EXT_V6K,      do_empty},
+  { "ldrexb",    0xe1d00f9f, 6,  ARM_EXT_V6K,      do_ldrex},
+  { "ldrexd",    0xe1b00f9f, 6,  ARM_EXT_V6K,      do_ldrex},
+  { "ldrexh",    0xe1f00f9f, 6,  ARM_EXT_V6K,      do_ldrex},
+  { "sev",       0xe320f004, 3,  ARM_EXT_V6K,      do_empty},
+  { "strexb",    0xe1c00f90, 6,  ARM_EXT_V6K,      do_strex},
+  { "strexd",    0xe1a00f90, 6,  ARM_EXT_V6K,      do_strex},
+  { "strexh",    0xe1e00f90, 6,  ARM_EXT_V6K,      do_strex},
+  { "wfe",       0xe320f002, 3,  ARM_EXT_V6K,      do_empty},
+  { "wfi",       0xe320f003, 3,  ARM_EXT_V6K,      do_empty},
+  { "yield",     0xe320f001, 5,  ARM_EXT_V6K,      do_empty},
+  
+  /*  ARM V6Z.  */
+  { "smi",       0xe1600070, 3,  ARM_EXT_V6Z,      do_smi},
 
-static void
-do_t_lsl (str)
-     char * str;
-{
-  thumb_shift (str, THUMB_LSL);
-}
+  /* Core FPA instruction set (V1).  */
+  {"wfs",        0xee200110, 3,  FPU_FPA_EXT_V1,   do_fpa_ctrl},
+  {"rfs",        0xee300110, 3,  FPU_FPA_EXT_V1,   do_fpa_ctrl},
+  {"wfc",        0xee400110, 3,  FPU_FPA_EXT_V1,   do_fpa_ctrl},
+  {"rfc",        0xee500110, 3,  FPU_FPA_EXT_V1,   do_fpa_ctrl},
 
-static void
-do_t_lsr (str)
-     char * str;
-{
-  thumb_shift (str, THUMB_LSR);
-}
+  {"ldfs",       0xec100100, 3,  FPU_FPA_EXT_V1,   do_fpa_ldst},
+  {"ldfd",       0xec108100, 3,  FPU_FPA_EXT_V1,   do_fpa_ldst},
+  {"ldfe",       0xec500100, 3,  FPU_FPA_EXT_V1,   do_fpa_ldst},
+  {"ldfp",       0xec508100, 3,  FPU_FPA_EXT_V1,   do_fpa_ldst},
 
-static void
-do_t_mov (str)
-     char * str;
-{
-  thumb_mov_compare (str, THUMB_MOVE);
-}
+  {"stfs",       0xec000100, 3,  FPU_FPA_EXT_V1,   do_fpa_ldst},
+  {"stfd",       0xec008100, 3,  FPU_FPA_EXT_V1,   do_fpa_ldst},
+  {"stfe",       0xec400100, 3,  FPU_FPA_EXT_V1,   do_fpa_ldst},
+  {"stfp",       0xec408100, 3,  FPU_FPA_EXT_V1,   do_fpa_ldst},
 
-static void
-do_t_push_pop (str)
-     char * str;
-{
-  long range;
+  {"mvfs",       0xee008100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"mvfsp",      0xee008120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"mvfsm",      0xee008140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"mvfsz",      0xee008160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"mvfd",       0xee008180, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"mvfdp",      0xee0081a0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"mvfdm",      0xee0081c0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"mvfdz",      0xee0081e0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"mvfe",       0xee088100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"mvfep",      0xee088120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"mvfem",      0xee088140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"mvfez",      0xee088160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
 
-  skip_whitespace (str);
+  {"mnfs",       0xee108100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"mnfsp",      0xee108120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"mnfsm",      0xee108140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"mnfsz",      0xee108160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"mnfd",       0xee108180, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"mnfdp",      0xee1081a0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"mnfdm",      0xee1081c0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"mnfdz",      0xee1081e0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"mnfe",       0xee188100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"mnfep",      0xee188120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"mnfem",      0xee188140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"mnfez",      0xee188160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
 
-  if ((range = reg_list (&str)) == FAIL)
-    {
-      if (! inst.error)
-       inst.error = BAD_ARGS;
-      return;
-    }
+  {"abss",       0xee208100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"abssp",      0xee208120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"abssm",      0xee208140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"abssz",      0xee208160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"absd",       0xee208180, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"absdp",      0xee2081a0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"absdm",      0xee2081c0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"absdz",      0xee2081e0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"abse",       0xee288100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"absep",      0xee288120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"absem",      0xee288140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"absez",      0xee288160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
 
-  if (inst.reloc.type != BFD_RELOC_NONE)
-    {
-      /* This really doesn't seem worth it.  */
-      inst.reloc.type = BFD_RELOC_NONE;
-      inst.error = _("expression too complex");
-      return;
-    }
+  {"rnds",       0xee308100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"rndsp",      0xee308120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"rndsm",      0xee308140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"rndsz",      0xee308160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"rndd",       0xee308180, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"rnddp",      0xee3081a0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"rnddm",      0xee3081c0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"rnddz",      0xee3081e0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"rnde",       0xee388100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"rndep",      0xee388120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"rndem",      0xee388140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"rndez",      0xee388160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
 
-  if (range & ~0xff)
-    {
-      if ((inst.instruction == T_OPCODE_PUSH
-          && (range & ~0xff) == 1 << REG_LR)
-         || (inst.instruction == T_OPCODE_POP
-             && (range & ~0xff) == 1 << REG_PC))
-       {
-         inst.instruction |= THUMB_PP_PC_LR;
-         range &= 0xff;
-       }
-      else
-       {
-         inst.error = _("invalid register list to push/pop instruction");
-         return;
-       }
-    }
+  {"sqts",       0xee408100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"sqtsp",      0xee408120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"sqtsm",      0xee408140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"sqtsz",      0xee408160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"sqtd",       0xee408180, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"sqtdp",      0xee4081a0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"sqtdm",      0xee4081c0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"sqtdz",      0xee4081e0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"sqte",       0xee488100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"sqtep",      0xee488120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"sqtem",      0xee488140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"sqtez",      0xee488160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
 
-  inst.instruction |= range;
-  end_of_line (str);
-}
+  {"logs",       0xee508100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"logsp",      0xee508120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"logsm",      0xee508140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"logsz",      0xee508160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"logd",       0xee508180, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"logdp",      0xee5081a0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"logdm",      0xee5081c0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"logdz",      0xee5081e0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"loge",       0xee588100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"logep",      0xee588120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"logem",      0xee588140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"logez",      0xee588160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
 
-static void
-do_t_str (str)
-     char * str;
-{
-  thumb_load_store (str, THUMB_STORE, THUMB_WORD);
-}
+  {"lgns",       0xee608100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"lgnsp",      0xee608120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"lgnsm",      0xee608140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"lgnsz",      0xee608160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"lgnd",       0xee608180, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"lgndp",      0xee6081a0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"lgndm",      0xee6081c0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"lgndz",      0xee6081e0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"lgne",       0xee688100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"lgnep",      0xee688120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"lgnem",      0xee688140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"lgnez",      0xee688160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
 
-static void
-do_t_strb (str)
-     char * str;
-{
-  thumb_load_store (str, THUMB_STORE, THUMB_BYTE);
-}
+  {"exps",       0xee708100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"expsp",      0xee708120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"expsm",      0xee708140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"expsz",      0xee708160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"expd",       0xee708180, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"expdp",      0xee7081a0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"expdm",      0xee7081c0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"expdz",      0xee7081e0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"expe",       0xee788100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"expep",      0xee788120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"expem",      0xee788140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"expdz",      0xee788160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
 
-static void
-do_t_strh (str)
-     char * str;
-{
-  thumb_load_store (str, THUMB_STORE, THUMB_HALFWORD);
-}
+  {"sins",       0xee808100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"sinsp",      0xee808120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"sinsm",      0xee808140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"sinsz",      0xee808160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"sind",       0xee808180, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"sindp",      0xee8081a0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"sindm",      0xee8081c0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"sindz",      0xee8081e0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"sine",       0xee888100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"sinep",      0xee888120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"sinem",      0xee888140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"sinez",      0xee888160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
 
-static void
-do_t_sub (str)
-     char * str;
-{
-  thumb_add_sub (str, 1);
-}
+  {"coss",       0xee908100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"cossp",      0xee908120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"cossm",      0xee908140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"cossz",      0xee908160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"cosd",       0xee908180, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"cosdp",      0xee9081a0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"cosdm",      0xee9081c0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"cosdz",      0xee9081e0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"cose",       0xee988100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"cosep",      0xee988120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"cosem",      0xee988140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"cosez",      0xee988160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
 
-static void
-do_t_swi (str)
-     char * str;
-{
-  skip_whitespace (str);
+  {"tans",       0xeea08100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"tansp",      0xeea08120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"tansm",      0xeea08140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"tansz",      0xeea08160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"tand",       0xeea08180, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"tandp",      0xeea081a0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"tandm",      0xeea081c0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"tandz",      0xeea081e0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"tane",       0xeea88100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"tanep",      0xeea88120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"tanem",      0xeea88140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"tanez",      0xeea88160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
 
-  if (my_get_expression (&inst.reloc.exp, &str))
-    return;
+  {"asns",       0xeeb08100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"asnsp",      0xeeb08120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"asnsm",      0xeeb08140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"asnsz",      0xeeb08160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"asnd",       0xeeb08180, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"asndp",      0xeeb081a0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"asndm",      0xeeb081c0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"asndz",      0xeeb081e0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"asne",       0xeeb88100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"asnep",      0xeeb88120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"asnem",      0xeeb88140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"asnez",      0xeeb88160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
 
-  inst.reloc.type = BFD_RELOC_ARM_SWI;
-  end_of_line (str);
-  return;
-}
+  {"acss",       0xeec08100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"acssp",      0xeec08120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"acssm",      0xeec08140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"acssz",      0xeec08160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"acsd",       0xeec08180, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"acsdp",      0xeec081a0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"acsdm",      0xeec081c0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"acsdz",      0xeec081e0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"acse",       0xeec88100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"acsep",      0xeec88120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"acsem",      0xeec88140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"acsez",      0xeec88160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
 
-static void
-do_t_adr (str)
-     char * str;
-{
-  int reg;
+  {"atns",       0xeed08100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"atnsp",      0xeed08120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"atnsm",      0xeed08140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"atnsz",      0xeed08160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"atnd",       0xeed08180, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"atndp",      0xeed081a0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"atndm",      0xeed081c0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"atndz",      0xeed081e0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"atne",       0xeed88100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"atnep",      0xeed88120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"atnem",      0xeed88140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"atnez",      0xeed88160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
 
-  /* 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-.-4".  */
-  skip_whitespace (str);
+  {"urds",       0xeee08100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"urdsp",      0xeee08120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"urdsm",      0xeee08140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"urdsz",      0xeee08160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"urdd",       0xeee08180, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"urddp",      0xeee081a0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"urddm",      0xeee081c0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"urddz",      0xeee081e0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"urde",       0xeee88100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"urdep",      0xeee88120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"urdem",      0xeee88140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"urdez",      0xeee88160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
 
-  /* Store Rd in temporary location inside instruction.  */
-  if ((reg = reg_required_here (&str, 4)) == FAIL
-      || (reg > 7)  /* For Thumb reg must be r0..r7.  */
-      || skip_past_comma (&str) == FAIL
-      || my_get_expression (&inst.reloc.exp, &str))
-    {
-      if (!inst.error)
-       inst.error = BAD_ARGS;
-      return;
-    }
+  {"nrms",       0xeef08100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"nrmsp",      0xeef08120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"nrmsm",      0xeef08140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"nrmsz",      0xeef08160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"nrmd",       0xeef08180, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"nrmdp",      0xeef081a0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"nrmdm",      0xeef081c0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"nrmdz",      0xeef081e0, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"nrme",       0xeef88100, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"nrmep",      0xeef88120, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"nrmem",      0xeef88140, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
+  {"nrmez",      0xeef88160, 3,  FPU_FPA_EXT_V1,   do_fpa_monadic},
 
-  inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
-  inst.reloc.exp.X_add_number -= 4; /* PC relative adjust.  */
-  inst.reloc.pc_rel = 1;
-  inst.instruction |= REG_PC; /* Rd is already placed into the instruction.  */
+  {"adfs",       0xee000100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"adfsp",      0xee000120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"adfsm",      0xee000140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"adfsz",      0xee000160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"adfd",       0xee000180, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"adfdp",      0xee0001a0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"adfdm",      0xee0001c0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"adfdz",      0xee0001e0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"adfe",       0xee080100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"adfep",      0xee080120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"adfem",      0xee080140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"adfez",      0xee080160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
 
-  end_of_line (str);
-}
+  {"sufs",       0xee200100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"sufsp",      0xee200120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"sufsm",      0xee200140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"sufsz",      0xee200160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"sufd",       0xee200180, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"sufdp",      0xee2001a0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"sufdm",      0xee2001c0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"sufdz",      0xee2001e0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"sufe",       0xee280100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"sufep",      0xee280120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"sufem",      0xee280140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"sufez",      0xee280160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
 
-static void
-insert_reg (r, htab)
-     const struct reg_entry *r;
-     struct hash_control *htab;
-{
-  int    len  = strlen (r->name) + 2;
-  char * buf  = (char *) xmalloc (len);
-  char * buf2 = (char *) xmalloc (len);
-  int    i    = 0;
+  {"rsfs",       0xee300100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rsfsp",      0xee300120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rsfsm",      0xee300140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rsfsz",      0xee300160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rsfd",       0xee300180, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rsfdp",      0xee3001a0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rsfdm",      0xee3001c0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rsfdz",      0xee3001e0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rsfe",       0xee380100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rsfep",      0xee380120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rsfem",      0xee380140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rsfez",      0xee380160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
 
-#ifdef REGISTER_PREFIX
-  buf[i++] = REGISTER_PREFIX;
-#endif
+  {"mufs",       0xee100100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"mufsp",      0xee100120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"mufsm",      0xee100140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"mufsz",      0xee100160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"mufd",       0xee100180, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"mufdp",      0xee1001a0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"mufdm",      0xee1001c0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"mufdz",      0xee1001e0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"mufe",       0xee180100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"mufep",      0xee180120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"mufem",      0xee180140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"mufez",      0xee180160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
 
-  strcpy (buf + i, r->name);
+  {"dvfs",       0xee400100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"dvfsp",      0xee400120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"dvfsm",      0xee400140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"dvfsz",      0xee400160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"dvfd",       0xee400180, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"dvfdp",      0xee4001a0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"dvfdm",      0xee4001c0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"dvfdz",      0xee4001e0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"dvfe",       0xee480100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"dvfep",      0xee480120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"dvfem",      0xee480140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"dvfez",      0xee480160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
 
-  for (i = 0; buf[i]; i++)
-    buf2[i] = TOUPPER (buf[i]);
+  {"rdfs",       0xee500100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rdfsp",      0xee500120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rdfsm",      0xee500140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rdfsz",      0xee500160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rdfd",       0xee500180, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rdfdp",      0xee5001a0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rdfdm",      0xee5001c0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rdfdz",      0xee5001e0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rdfe",       0xee580100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rdfep",      0xee580120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rdfem",      0xee580140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rdfez",      0xee580160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
 
-  buf2[i] = '\0';
+  {"pows",       0xee600100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"powsp",      0xee600120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"powsm",      0xee600140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"powsz",      0xee600160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"powd",       0xee600180, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"powdp",      0xee6001a0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"powdm",      0xee6001c0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"powdz",      0xee6001e0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"powe",       0xee680100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"powep",      0xee680120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"powem",      0xee680140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"powez",      0xee680160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
 
-  hash_insert (htab, buf,  (PTR) r);
-  hash_insert (htab, buf2, (PTR) r);
-}
+  {"rpws",       0xee700100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rpwsp",      0xee700120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rpwsm",      0xee700140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rpwsz",      0xee700160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rpwd",       0xee700180, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rpwdp",      0xee7001a0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rpwdm",      0xee7001c0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rpwdz",      0xee7001e0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rpwe",       0xee780100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rpwep",      0xee780120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rpwem",      0xee780140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rpwez",      0xee780160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
 
-static void
-build_reg_hsh (map)
-     struct reg_map *map;
-{
-  const struct reg_entry *r;
+  {"rmfs",       0xee800100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rmfsp",      0xee800120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rmfsm",      0xee800140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rmfsz",      0xee800160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rmfd",       0xee800180, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rmfdp",      0xee8001a0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rmfdm",      0xee8001c0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rmfdz",      0xee8001e0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rmfe",       0xee880100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rmfep",      0xee880120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rmfem",      0xee880140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"rmfez",      0xee880160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
 
-  if ((map->htab = hash_new ()) == NULL)
-    as_fatal (_("virtual memory exhausted"));
+  {"fmls",       0xee900100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"fmlsp",      0xee900120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"fmlsm",      0xee900140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"fmlsz",      0xee900160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"fmld",       0xee900180, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"fmldp",      0xee9001a0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"fmldm",      0xee9001c0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"fmldz",      0xee9001e0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"fmle",       0xee980100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"fmlep",      0xee980120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"fmlem",      0xee980140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"fmlez",      0xee980160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
 
-  for (r = map->names; r->name != NULL; r++)
-    insert_reg (r, map->htab);
-}
+  {"fdvs",       0xeea00100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"fdvsp",      0xeea00120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"fdvsm",      0xeea00140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"fdvsz",      0xeea00160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"fdvd",       0xeea00180, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"fdvdp",      0xeea001a0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"fdvdm",      0xeea001c0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"fdvdz",      0xeea001e0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"fdve",       0xeea80100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"fdvep",      0xeea80120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"fdvem",      0xeea80140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"fdvez",      0xeea80160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
 
-static void
-insert_reg_alias (str, regnum, htab)
-     char *str;
-     int regnum;
-     struct hash_control *htab;
-{
-  struct reg_entry *new =
-    (struct reg_entry *) xmalloc (sizeof (struct reg_entry));
-  char *name = xmalloc (strlen (str) + 1);
-  strcpy (name, str);
+  {"frds",       0xeeb00100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"frdsp",      0xeeb00120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"frdsm",      0xeeb00140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"frdsz",      0xeeb00160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"frdd",       0xeeb00180, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"frddp",      0xeeb001a0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"frddm",      0xeeb001c0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"frddz",      0xeeb001e0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"frde",       0xeeb80100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"frdep",      0xeeb80120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"frdem",      0xeeb80140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"frdez",      0xeeb80160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
 
-  new->name = name;
-  new->number = regnum;
+  {"pols",       0xeec00100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"polsp",      0xeec00120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"polsm",      0xeec00140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"polsz",      0xeec00160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"pold",       0xeec00180, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"poldp",      0xeec001a0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"poldm",      0xeec001c0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"poldz",      0xeec001e0, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"pole",       0xeec80100, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"polep",      0xeec80120, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"polem",      0xeec80140, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
+  {"polez",      0xeec80160, 3,  FPU_FPA_EXT_V1,   do_fpa_dyadic},
 
-  hash_insert (htab, name, (PTR) new);
-}
+  {"cmf",        0xee90f110, 3,  FPU_FPA_EXT_V1,   do_fpa_cmp},
+  {"cmfe",       0xeed0f110, 3,  FPU_FPA_EXT_V1,   do_fpa_cmp},
+  {"cnf",        0xeeb0f110, 3,  FPU_FPA_EXT_V1,   do_fpa_cmp},
+  {"cnfe",       0xeef0f110, 3,  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",       0xeed0f110, 4,  FPU_FPA_EXT_V1,   do_fpa_cmp},
+  {"cnfe",       0xeef0f110, 4,  FPU_FPA_EXT_V1,   do_fpa_cmp},
 
-/* Look for the .req directive.  This is of the form:
+  {"flts",       0xee000110, 3,  FPU_FPA_EXT_V1,   do_fpa_from_reg},
+  {"fltsp",      0xee000130, 3,  FPU_FPA_EXT_V1,   do_fpa_from_reg},
+  {"fltsm",      0xee000150, 3,  FPU_FPA_EXT_V1,   do_fpa_from_reg},
+  {"fltsz",      0xee000170, 3,  FPU_FPA_EXT_V1,   do_fpa_from_reg},
+  {"fltd",       0xee000190, 3,  FPU_FPA_EXT_V1,   do_fpa_from_reg},
+  {"fltdp",      0xee0001b0, 3,  FPU_FPA_EXT_V1,   do_fpa_from_reg},
+  {"fltdm",      0xee0001d0, 3,  FPU_FPA_EXT_V1,   do_fpa_from_reg},
+  {"fltdz",      0xee0001f0, 3,  FPU_FPA_EXT_V1,   do_fpa_from_reg},
+  {"flte",       0xee080110, 3,  FPU_FPA_EXT_V1,   do_fpa_from_reg},
+  {"fltep",      0xee080130, 3,  FPU_FPA_EXT_V1,   do_fpa_from_reg},
+  {"fltem",      0xee080150, 3,  FPU_FPA_EXT_V1,   do_fpa_from_reg},
+  {"fltez",      0xee080170, 3,  FPU_FPA_EXT_V1,   do_fpa_from_reg},
 
-       newname .req existing_name
+  /* The implementation of the FIX instruction is broken on some
+     assemblers, 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.  */
+  {"fix",        0xee100110, 3,  FPU_FPA_EXT_V1,   do_fpa_to_reg},
+  {"fixp",       0xee100130, 3,  FPU_FPA_EXT_V1,   do_fpa_to_reg},
+  {"fixm",       0xee100150, 3,  FPU_FPA_EXT_V1,   do_fpa_to_reg},
+  {"fixz",       0xee100170, 3,  FPU_FPA_EXT_V1,   do_fpa_to_reg},
+  {"fixsp",      0xee100130, 3,  FPU_FPA_EXT_V1,   do_fpa_to_reg},
+  {"fixsm",      0xee100150, 3,  FPU_FPA_EXT_V1,   do_fpa_to_reg},
+  {"fixsz",      0xee100170, 3,  FPU_FPA_EXT_V1,   do_fpa_to_reg},
+  {"fixdp",      0xee100130, 3,  FPU_FPA_EXT_V1,   do_fpa_to_reg},
+  {"fixdm",      0xee100150, 3,  FPU_FPA_EXT_V1,   do_fpa_to_reg},
+  {"fixdz",      0xee100170, 3,  FPU_FPA_EXT_V1,   do_fpa_to_reg},
+  {"fixep",      0xee100130, 3,  FPU_FPA_EXT_V1,   do_fpa_to_reg},
+  {"fixem",      0xee100150, 3,  FPU_FPA_EXT_V1,   do_fpa_to_reg},
+  {"fixez",      0xee100170, 3,  FPU_FPA_EXT_V1,   do_fpa_to_reg},
 
-   If we find one, or if it looks sufficiently like one that we want to
-   handle any error here, return non-zero.  Otherwise return zero.  */
-static int
-create_register_alias (newname, p)
-     char *newname;
-     char *p;
-{
-  char *q;
-  char c;
+  /* Instructions that were new with the real FPA, call them V2.  */
+  {"lfm",        0xec100200, 3,  FPU_FPA_EXT_V2,   do_fpa_ldmstm},
+  {"lfmfd",      0xec900200, 3,  FPU_FPA_EXT_V2,   do_fpa_ldmstm},
+  {"lfmea",      0xed100200, 3,  FPU_FPA_EXT_V2,   do_fpa_ldmstm},
+  {"sfm",        0xec000200, 3,  FPU_FPA_EXT_V2,   do_fpa_ldmstm},
+  {"sfmfd",      0xed000200, 3,  FPU_FPA_EXT_V2,   do_fpa_ldmstm},
+  {"sfmea",      0xec800200, 3,  FPU_FPA_EXT_V2,   do_fpa_ldmstm},
 
-  q = p;
-  skip_whitespace (q);
+  /* VFP V1xD (single precision).  */
+  /* Moves and type conversions.  */
+  {"fcpys",   0xeeb00a40, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
+  {"fmrs",    0xee100a10, 4, FPU_VFP_EXT_V1xD, do_vfp_reg_from_sp},
+  {"fmsr",    0xee000a10, 4, FPU_VFP_EXT_V1xD, do_vfp_sp_from_reg},
+  {"fmstat",  0xeef1fa10, 6, FPU_VFP_EXT_V1xD, do_empty},
+  {"fsitos",  0xeeb80ac0, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
+  {"fuitos",  0xeeb80a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
+  {"ftosis",  0xeebd0a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
+  {"ftosizs", 0xeebd0ac0, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
+  {"ftouis",  0xeebc0a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
+  {"ftouizs", 0xeebc0ac0, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
+  {"fmrx",    0xeef00a10, 4, FPU_VFP_EXT_V1xD, do_vfp_reg_from_ctrl},
+  {"fmxr",    0xeee00a10, 4, FPU_VFP_EXT_V1xD, do_vfp_ctrl_from_reg},
 
-  c = *p;
-  *p = '\0';
+  /* Memory operations.  */
+  {"flds",    0xed100a00, 4, FPU_VFP_EXT_V1xD, do_vfp_sp_ldst},
+  {"fsts",    0xed000a00, 4, FPU_VFP_EXT_V1xD, do_vfp_sp_ldst},
+  {"fldmias", 0xec900a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmia},
+  {"fldmfds", 0xec900a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmia},
+  {"fldmdbs", 0xed300a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmdb},
+  {"fldmeas", 0xed300a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmdb},
+  {"fldmiax", 0xec900b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmia},
+  {"fldmfdx", 0xec900b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmia},
+  {"fldmdbx", 0xed300b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmdb},
+  {"fldmeax", 0xed300b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmdb},
+  {"fstmias", 0xec800a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmia},
+  {"fstmeas", 0xec800a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmia},
+  {"fstmdbs", 0xed200a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmdb},
+  {"fstmfds", 0xed200a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmdb},
+  {"fstmiax", 0xec800b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmia},
+  {"fstmeax", 0xec800b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmia},
+  {"fstmdbx", 0xed200b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmdb},
+  {"fstmfdx", 0xed200b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmdb},
 
-  if (*q && !strncmp (q, ".req ", 5))
-    {
-      char *copy_of_str;
-      char *r;
+  /* Monadic operations.  */
+  {"fabss",   0xeeb00ac0, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
+  {"fnegs",   0xeeb10a40, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
+  {"fsqrts",  0xeeb10ac0, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
 
-#ifdef IGNORE_OPCODE_CASE
-      newname = original_case_string;
-#endif
-      copy_of_str = newname;
+  /* Dyadic operations.  */
+  {"fadds",   0xee300a00, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
+  {"fsubs",   0xee300a40, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
+  {"fmuls",   0xee200a00, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
+  {"fdivs",   0xee800a00, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
+  {"fmacs",   0xee000a00, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
+  {"fmscs",   0xee100a00, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
+  {"fnmuls",  0xee200a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
+  {"fnmacs",  0xee000a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
+  {"fnmscs",  0xee100a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
 
-      q += 4;
-      skip_whitespace (q);
+  /* Comparisons.  */
+  {"fcmps",   0xeeb40a40, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
+  {"fcmpzs",  0xeeb50a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_compare_z},
+  {"fcmpes",  0xeeb40ac0, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
+  {"fcmpezs", 0xeeb50ac0, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_compare_z},
 
-      for (r = q; *r != '\0'; r++)
-       if (*r == ' ')
-         break;
+  /* VFP V1 (Double precision).  */
+  /* Moves and type conversions.  */
+  {"fcpyd",   0xeeb00b40, 5, FPU_VFP_EXT_V1,   do_vfp_dp_monadic},
+  {"fcvtds",  0xeeb70ac0, 6, FPU_VFP_EXT_V1,   do_vfp_dp_sp_cvt},
+  {"fcvtsd",  0xeeb70bc0, 6, FPU_VFP_EXT_V1,   do_vfp_sp_dp_cvt},
+  {"fmdhr",   0xee200b10, 5, FPU_VFP_EXT_V1,   do_vfp_dp_from_reg},
+  {"fmdlr",   0xee000b10, 5, FPU_VFP_EXT_V1,   do_vfp_dp_from_reg},
+  {"fmrdh",   0xee300b10, 5, FPU_VFP_EXT_V1,   do_vfp_reg_from_dp},
+  {"fmrdl",   0xee100b10, 5, FPU_VFP_EXT_V1,   do_vfp_reg_from_dp},
+  {"fsitod",  0xeeb80bc0, 6, FPU_VFP_EXT_V1,   do_vfp_dp_sp_cvt},
+  {"fuitod",  0xeeb80b40, 6, FPU_VFP_EXT_V1,   do_vfp_dp_sp_cvt},
+  {"ftosid",  0xeebd0b40, 6, FPU_VFP_EXT_V1,   do_vfp_sp_dp_cvt},
+  {"ftosizd", 0xeebd0bc0, 7, FPU_VFP_EXT_V1,   do_vfp_sp_dp_cvt},
+  {"ftouid",  0xeebc0b40, 6, FPU_VFP_EXT_V1,   do_vfp_sp_dp_cvt},
+  {"ftouizd", 0xeebc0bc0, 7, FPU_VFP_EXT_V1,   do_vfp_sp_dp_cvt},
 
-      if (r != q)
-       {
-         enum arm_reg_type new_type, old_type;
-         int old_regno;
-         char d = *r;
+  /* Memory operations.  */
+  {"fldd",    0xed100b00, 4, FPU_VFP_EXT_V1,   do_vfp_dp_ldst},
+  {"fstd",    0xed000b00, 4, FPU_VFP_EXT_V1,   do_vfp_dp_ldst},
+  {"fldmiad", 0xec900b00, 7, FPU_VFP_EXT_V1,   do_vfp_dp_ldstmia},
+  {"fldmfdd", 0xec900b00, 7, FPU_VFP_EXT_V1,   do_vfp_dp_ldstmia},
+  {"fldmdbd", 0xed300b00, 7, FPU_VFP_EXT_V1,   do_vfp_dp_ldstmdb},
+  {"fldmead", 0xed300b00, 7, FPU_VFP_EXT_V1,   do_vfp_dp_ldstmdb},
+  {"fstmiad", 0xec800b00, 7, FPU_VFP_EXT_V1,   do_vfp_dp_ldstmia},
+  {"fstmead", 0xec800b00, 7, FPU_VFP_EXT_V1,   do_vfp_dp_ldstmia},
+  {"fstmdbd", 0xed200b00, 7, FPU_VFP_EXT_V1,   do_vfp_dp_ldstmdb},
+  {"fstmfdd", 0xed200b00, 7, FPU_VFP_EXT_V1,   do_vfp_dp_ldstmdb},
 
-         *r = '\0';
-         old_type = arm_reg_parse_any (q);
-         *r = d;
+  /* Monadic operations.  */
+  {"fabsd",   0xeeb00bc0, 5, FPU_VFP_EXT_V1,   do_vfp_dp_monadic},
+  {"fnegd",   0xeeb10b40, 5, FPU_VFP_EXT_V1,   do_vfp_dp_monadic},
+  {"fsqrtd",  0xeeb10bc0, 6, FPU_VFP_EXT_V1,   do_vfp_dp_monadic},
 
-         new_type = arm_reg_parse_any (newname);
+  /* Dyadic operations.  */
+  {"faddd",   0xee300b00, 5, FPU_VFP_EXT_V1,   do_vfp_dp_dyadic},
+  {"fsubd",   0xee300b40, 5, FPU_VFP_EXT_V1,   do_vfp_dp_dyadic},
+  {"fmuld",   0xee200b00, 5, FPU_VFP_EXT_V1,   do_vfp_dp_dyadic},
+  {"fdivd",   0xee800b00, 5, FPU_VFP_EXT_V1,   do_vfp_dp_dyadic},
+  {"fmacd",   0xee000b00, 5, FPU_VFP_EXT_V1,   do_vfp_dp_dyadic},
+  {"fmscd",   0xee100b00, 5, FPU_VFP_EXT_V1,   do_vfp_dp_dyadic},
+  {"fnmuld",  0xee200b40, 6, FPU_VFP_EXT_V1,   do_vfp_dp_dyadic},
+  {"fnmacd",  0xee000b40, 6, FPU_VFP_EXT_V1,   do_vfp_dp_dyadic},
+  {"fnmscd",  0xee100b40, 6, FPU_VFP_EXT_V1,   do_vfp_dp_dyadic},
 
-         if (new_type == REG_TYPE_MAX)
-           {
-             if (old_type != REG_TYPE_MAX)
-               {
-                 old_regno = arm_reg_parse (&q, all_reg_maps[old_type].htab);
-                 insert_reg_alias (newname, old_regno,
-                                   all_reg_maps[old_type].htab);
-               }
-             else
-               as_warn (_("register '%s' does not exist\n"), q);
-           }
-         else if (old_type == REG_TYPE_MAX)
-           {
-             as_warn (_("ignoring redefinition of register alias '%s' to non-existant register '%s'"),
-                      copy_of_str, q);
-           }
-         else
-           {
-             /* Do not warn about redefinitions to the same alias.  */
-             if (new_type != old_type
-                 || (arm_reg_parse (&q, all_reg_maps[old_type].htab)
-                     != arm_reg_parse (&q, all_reg_maps[new_type].htab)))
-               as_warn (_("ignoring redefinition of register alias '%s'"),
-                        copy_of_str);
+  /* Comparisons.  */
+  {"fcmpd",   0xeeb40b40, 5, FPU_VFP_EXT_V1,   do_vfp_dp_monadic},
+  {"fcmpzd",  0xeeb50b40, 6, FPU_VFP_EXT_V1,   do_vfp_dp_compare_z},
+  {"fcmped",  0xeeb40bc0, 6, FPU_VFP_EXT_V1,   do_vfp_dp_monadic},
+  {"fcmpezd", 0xeeb50bc0, 7, FPU_VFP_EXT_V1,   do_vfp_dp_compare_z},
 
-           }
-       }
-      else
-       as_warn (_("ignoring incomplete .req pseuso op"));
+  /* VFP V2.  */
+  {"fmsrr",   0xec400a10, 5, FPU_VFP_EXT_V2,   do_vfp_sp2_from_reg2},
+  {"fmrrs",   0xec500a10, 5, FPU_VFP_EXT_V2,   do_vfp_reg2_from_sp2},
+  {"fmdrr",   0xec400b10, 5, FPU_VFP_EXT_V2,   do_vfp_dp_from_reg2},
+  {"fmrrd",   0xec500b10, 5, FPU_VFP_EXT_V2,   do_vfp_reg2_from_dp},
 
-      *p = c;
-      return 1;
-    }
-  *p = c;
-  return 0;
-}
+  /* Intel XScale extensions to ARM V5 ISA.  (All use CP0).  */
+  {"mia",        0xee200010, 3,  ARM_CEXT_XSCALE,   do_xsc_mia},
+  {"miaph",      0xee280010, 5,  ARM_CEXT_XSCALE,   do_xsc_mia},
+  {"miabb",      0xee2c0010, 5,  ARM_CEXT_XSCALE,   do_xsc_mia},
+  {"miabt",      0xee2d0010, 5,  ARM_CEXT_XSCALE,   do_xsc_mia},
+  {"miatb",      0xee2e0010, 5,  ARM_CEXT_XSCALE,   do_xsc_mia},
+  {"miatt",      0xee2f0010, 5,  ARM_CEXT_XSCALE,   do_xsc_mia},
+  {"mar",        0xec400000, 3,  ARM_CEXT_XSCALE,   do_xsc_mar},
+  {"mra",        0xec500000, 3,  ARM_CEXT_XSCALE,   do_xsc_mra},
 
-static void
-set_constant_flonums ()
-{
-  int i;
+  /* Intel Wireless MMX technology instructions.  */
+  {"tandcb",     0xee130130, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tandc},
+  {"tandch",     0xee530130, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tandc},
+  {"tandcw",     0xee930130, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tandc},
+  {"tbcstb",     0xee400010, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tbcst},
+  {"tbcsth",     0xee400050, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tbcst},
+  {"tbcstw",     0xee400090, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tbcst},
+  {"textrcb",    0xee130170, 7, ARM_CEXT_IWMMXT, do_iwmmxt_textrc},
+  {"textrch",    0xee530170, 7, ARM_CEXT_IWMMXT, do_iwmmxt_textrc},
+  {"textrcw",    0xee930170, 7, ARM_CEXT_IWMMXT, do_iwmmxt_textrc},
+  {"textrmub",   0xee100070, 8, ARM_CEXT_IWMMXT, do_iwmmxt_textrm},
+  {"textrmuh",   0xee500070, 8, ARM_CEXT_IWMMXT, do_iwmmxt_textrm},
+  {"textrmuw",   0xee900070, 8, ARM_CEXT_IWMMXT, do_iwmmxt_textrm},
+  {"textrmsb",   0xee100078, 8, ARM_CEXT_IWMMXT, do_iwmmxt_textrm},
+  {"textrmsh",   0xee500078, 8, ARM_CEXT_IWMMXT, do_iwmmxt_textrm},
+  {"textrmsw",   0xee900078, 8, ARM_CEXT_IWMMXT, do_iwmmxt_textrm},
+  {"tinsrb",     0xee600010, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tinsr},
+  {"tinsrh",     0xee600050, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tinsr},
+  {"tinsrw",     0xee600090, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tinsr},
+  {"tmcr",       0xee000110, 4, ARM_CEXT_IWMMXT, do_iwmmxt_tmcr},
+  {"tmcrr",      0xec400000, 5, ARM_CEXT_IWMMXT, do_iwmmxt_tmcrr},
+  {"tmia",       0xee200010, 4, ARM_CEXT_IWMMXT, do_iwmmxt_tmia},
+  {"tmiaph",     0xee280010, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tmia},
+  {"tmiabb",     0xee2c0010, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tmia},
+  {"tmiabt",     0xee2d0010, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tmia},
+  {"tmiatb",     0xee2e0010, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tmia},
+  {"tmiatt",     0xee2f0010, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tmia},
+  {"tmovmskb",   0xee100030, 8, ARM_CEXT_IWMMXT, do_iwmmxt_tmovmsk},
+  {"tmovmskh",   0xee500030, 8, ARM_CEXT_IWMMXT, do_iwmmxt_tmovmsk},
+  {"tmovmskw",   0xee900030, 8, ARM_CEXT_IWMMXT, do_iwmmxt_tmovmsk},
+  {"tmrc",       0xee100110, 4, ARM_CEXT_IWMMXT, do_iwmmxt_tmrc},
+  {"tmrrc",      0xec500000, 5, ARM_CEXT_IWMMXT, do_iwmmxt_tmrrc},
+  {"torcb",      0xee130150, 5, ARM_CEXT_IWMMXT, do_iwmmxt_torc},
+  {"torch",      0xee530150, 5, ARM_CEXT_IWMMXT, do_iwmmxt_torc},
+  {"torcw",      0xee930150, 5, ARM_CEXT_IWMMXT, do_iwmmxt_torc},
+  {"waccb",      0xee0001c0, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
+  {"wacch",      0xee4001c0, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
+  {"waccw",      0xee8001c0, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
+  {"waddbss",    0xee300180, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"waddb",      0xee000180, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"waddbus",    0xee100180, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"waddhss",    0xee700180, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"waddh",      0xee400180, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"waddhus",    0xee500180, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"waddwss",    0xeeb00180, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"waddw",      0xee800180, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"waddwus",    0xee900180, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"waligni",    0xee000020, 7, ARM_CEXT_IWMMXT, do_iwmmxt_waligni},
+  {"walignr0",   0xee800020, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"walignr1",   0xee900020, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"walignr2",   0xeea00020, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"walignr3",   0xeeb00020, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wand",       0xee200000, 4, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wandn",      0xee300000, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wavg2b",     0xee800000, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wavg2br",    0xee900000, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wavg2h",     0xeec00000, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wavg2hr",    0xeed00000, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wcmpeqb",    0xee000060, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wcmpeqh",    0xee400060, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wcmpeqw",    0xee800060, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wcmpgtub",   0xee100060, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wcmpgtuh",   0xee500060, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wcmpgtuw",   0xee900060, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wcmpgtsb",   0xee300060, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wcmpgtsh",   0xee700060, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wcmpgtsw",   0xeeb00060, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wldrb",      0xec100000, 5, ARM_CEXT_IWMMXT, do_iwmmxt_byte_addr},
+  {"wldrh",      0xec100100, 5, ARM_CEXT_IWMMXT, do_iwmmxt_byte_addr},
+  {"wldrw",      0xec100200, 5, ARM_CEXT_IWMMXT, do_iwmmxt_word_addr},
+  {"wldrd",      0xec100300, 5, ARM_CEXT_IWMMXT, do_iwmmxt_word_addr},
+  {"wmacs",      0xee600100, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wmacsz",     0xee700100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wmacu",      0xee400100, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wmacuz",     0xee500100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wmadds",     0xeea00100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wmaddu",     0xee800100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wmaxsb",     0xee200160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wmaxsh",     0xee600160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wmaxsw",     0xeea00160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wmaxub",     0xee000160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wmaxuh",     0xee400160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wmaxuw",     0xee800160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wminsb",     0xee300160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wminsh",     0xee700160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wminsw",     0xeeb00160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wminub",     0xee100160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wminuh",     0xee500160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wminuw",     0xee900160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wmov",       0xee000000, 4, ARM_CEXT_IWMMXT, do_iwmmxt_wmov},
+  {"wmulsm",     0xee300100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wmulsl",     0xee200100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wmulum",     0xee100100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wmulul",     0xee000100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wor",        0xee000000, 3, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wpackhss",   0xee700080, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wpackhus",   0xee500080, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wpackwss",   0xeeb00080, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wpackwus",   0xee900080, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wpackdss",   0xeef00080, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wpackdus",   0xeed00080, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wrorh",      0xee700040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wrorhg",     0xee700148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
+  {"wrorw",      0xeeb00040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wrorwg",     0xeeb00148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
+  {"wrord",      0xeef00040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wrordg",     0xeef00148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
+  {"wsadb",      0xee000120, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wsadbz",     0xee100120, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wsadh",      0xee400120, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wsadhz",     0xee500120, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wshufh",     0xee0001e0, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wshufh},
+  {"wsllh",      0xee500040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wsllhg",     0xee500148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
+  {"wsllw",      0xee900040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wsllwg",     0xee900148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
+  {"wslld",      0xeed00040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wslldg",     0xeed00148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
+  {"wsrah",      0xee400040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wsrahg",     0xee400148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
+  {"wsraw",      0xee800040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wsrawg",     0xee800148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
+  {"wsrad",      0xeec00040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wsradg",     0xeec00148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
+  {"wsrlh",      0xee600040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wsrlhg",     0xee600148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
+  {"wsrlw",      0xeea00040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wsrlwg",     0xeea00148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
+  {"wsrld",      0xeee00040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wsrldg",     0xeee00148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
+  {"wstrb",      0xec000000, 5, ARM_CEXT_IWMMXT, do_iwmmxt_byte_addr},
+  {"wstrh",      0xec000100, 5, ARM_CEXT_IWMMXT, do_iwmmxt_byte_addr},
+  {"wstrw",      0xec000200, 5, ARM_CEXT_IWMMXT, do_iwmmxt_word_addr},
+  {"wstrd",      0xec000300, 5, ARM_CEXT_IWMMXT, do_iwmmxt_word_addr},
+  {"wsubbss",    0xee3001a0, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wsubb",      0xee0001a0, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wsubbus",    0xee1001a0, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wsubhss",    0xee7001a0, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wsubh",      0xee4001a0, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wsubhus",    0xee5001a0, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wsubwss",    0xeeb001a0, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wsubw",      0xee8001a0, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wsubwus",    0xee9001a0, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wunpckehub", 0xee0000c0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
+  {"wunpckehuh", 0xee4000c0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
+  {"wunpckehuw", 0xee8000c0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
+  {"wunpckehsb", 0xee2000c0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
+  {"wunpckehsh", 0xee6000c0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
+  {"wunpckehsw", 0xeea000c0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
+  {"wunpckihb",  0xee1000c0, 9, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wunpckihh",  0xee5000c0, 9, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wunpckihw",  0xee9000c0, 9, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wunpckelub", 0xee0000e0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
+  {"wunpckeluh", 0xee4000e0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
+  {"wunpckeluw", 0xee8000e0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
+  {"wunpckelsb", 0xee2000e0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
+  {"wunpckelsh", 0xee6000e0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
+  {"wunpckelsw", 0xeea000e0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
+  {"wunpckilb",  0xee1000e0, 9, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wunpckilh",  0xee5000e0, 9, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wunpckilw",  0xee9000e0, 9, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wxor",       0xee100000, 4, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
+  {"wzero",      0xee300000, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wzero},
 
-  for (i = 0; i < NUM_FLOAT_VALS; i++)
-    if (atof_ieee ((char *) fp_const[i], 'x', fp_values[i]) == NULL)
-      abort ();
-}
+  /* Cirrus Maverick instructions.  */
+  {"cfldrs",     0xec100400, 6,  ARM_CEXT_MAVERICK, do_mav_ldst_1},
+  {"cfldrd",     0xec500400, 6,  ARM_CEXT_MAVERICK, do_mav_ldst_2},
+  {"cfldr32",    0xec100500, 7,  ARM_CEXT_MAVERICK, do_mav_ldst_3},
+  {"cfldr64",    0xec500500, 7,  ARM_CEXT_MAVERICK, do_mav_ldst_4},
+  {"cfstrs",     0xec000400, 6,  ARM_CEXT_MAVERICK, do_mav_ldst_1},
+  {"cfstrd",     0xec400400, 6,  ARM_CEXT_MAVERICK, do_mav_ldst_2},
+  {"cfstr32",    0xec000500, 7,  ARM_CEXT_MAVERICK, do_mav_ldst_3},
+  {"cfstr64",    0xec400500, 7,  ARM_CEXT_MAVERICK, do_mav_ldst_4},
+  {"cfmvsr",     0xee000450, 6,  ARM_CEXT_MAVERICK, do_mav_binops_2a},
+  {"cfmvrs",     0xee100450, 6,  ARM_CEXT_MAVERICK, do_mav_binops_1a},
+  {"cfmvdlr",    0xee000410, 7,  ARM_CEXT_MAVERICK, do_mav_binops_2b},
+  {"cfmvrdl",    0xee100410, 7,  ARM_CEXT_MAVERICK, do_mav_binops_1b},
+  {"cfmvdhr",    0xee000430, 7,  ARM_CEXT_MAVERICK, do_mav_binops_2b},
+  {"cfmvrdh",    0xee100430, 7,  ARM_CEXT_MAVERICK, do_mav_binops_1b},
+  {"cfmv64lr",   0xee000510, 8,  ARM_CEXT_MAVERICK, do_mav_binops_2c},
+  {"cfmvr64l",   0xee100510, 8,  ARM_CEXT_MAVERICK, do_mav_binops_1c},
+  {"cfmv64hr",   0xee000530, 8,  ARM_CEXT_MAVERICK, do_mav_binops_2c},
+  {"cfmvr64h",   0xee100530, 8,  ARM_CEXT_MAVERICK, do_mav_binops_1c},
+  {"cfmval32",   0xee200440, 8,  ARM_CEXT_MAVERICK, do_mav_binops_3a},
+  {"cfmv32al",   0xee100440, 8,  ARM_CEXT_MAVERICK, do_mav_binops_3b},
+  {"cfmvam32",   0xee200460, 8,  ARM_CEXT_MAVERICK, do_mav_binops_3a},
+  {"cfmv32am",   0xee100460, 8,  ARM_CEXT_MAVERICK, do_mav_binops_3b},
+  {"cfmvah32",   0xee200480, 8,  ARM_CEXT_MAVERICK, do_mav_binops_3a},
+  {"cfmv32ah",   0xee100480, 8,  ARM_CEXT_MAVERICK, do_mav_binops_3b},
+  {"cfmva32",    0xee2004a0, 7,  ARM_CEXT_MAVERICK, do_mav_binops_3a},
+  {"cfmv32a",    0xee1004a0, 7,  ARM_CEXT_MAVERICK, do_mav_binops_3b},
+  {"cfmva64",    0xee2004c0, 7,  ARM_CEXT_MAVERICK, do_mav_binops_3c},
+  {"cfmv64a",    0xee1004c0, 7,  ARM_CEXT_MAVERICK, do_mav_binops_3d},
+  {"cfmvsc32",   0xee2004e0, 8,  ARM_CEXT_MAVERICK, do_mav_dspsc_1},
+  {"cfmv32sc",   0xee1004e0, 8,  ARM_CEXT_MAVERICK, do_mav_dspsc_2},
+  {"cfcpys",     0xee000400, 6,  ARM_CEXT_MAVERICK, do_mav_binops_1d},
+  {"cfcpyd",     0xee000420, 6,  ARM_CEXT_MAVERICK, do_mav_binops_1e},
+  {"cfcvtsd",    0xee000460, 7,  ARM_CEXT_MAVERICK, do_mav_binops_1f},
+  {"cfcvtds",    0xee000440, 7,  ARM_CEXT_MAVERICK, do_mav_binops_1g},
+  {"cfcvt32s",   0xee000480, 8,  ARM_CEXT_MAVERICK, do_mav_binops_1h},
+  {"cfcvt32d",   0xee0004a0, 8,  ARM_CEXT_MAVERICK, do_mav_binops_1i},
+  {"cfcvt64s",   0xee0004c0, 8,  ARM_CEXT_MAVERICK, do_mav_binops_1j},
+  {"cfcvt64d",   0xee0004e0, 8,  ARM_CEXT_MAVERICK, do_mav_binops_1k},
+  {"cfcvts32",   0xee100580, 8,  ARM_CEXT_MAVERICK, do_mav_binops_1l},
+  {"cfcvtd32",   0xee1005a0, 8,  ARM_CEXT_MAVERICK, do_mav_binops_1m},
+  {"cftruncs32", 0xee1005c0, 10, ARM_CEXT_MAVERICK, do_mav_binops_1l},
+  {"cftruncd32", 0xee1005e0, 10, ARM_CEXT_MAVERICK, do_mav_binops_1m},
+  {"cfrshl32",   0xee000550, 8,  ARM_CEXT_MAVERICK, do_mav_triple_4a},
+  {"cfrshl64",   0xee000570, 8,  ARM_CEXT_MAVERICK, do_mav_triple_4b},
+  {"cfsh32",     0xee000500, 6,  ARM_CEXT_MAVERICK, do_mav_shift_1},
+  {"cfsh64",     0xee200500, 6,  ARM_CEXT_MAVERICK, do_mav_shift_2},
+  {"cfcmps",     0xee100490, 6,  ARM_CEXT_MAVERICK, do_mav_triple_5a},
+  {"cfcmpd",     0xee1004b0, 6,  ARM_CEXT_MAVERICK, do_mav_triple_5b},
+  {"cfcmp32",    0xee100590, 7,  ARM_CEXT_MAVERICK, do_mav_triple_5c},
+  {"cfcmp64",    0xee1005b0, 7,  ARM_CEXT_MAVERICK, do_mav_triple_5d},
+  {"cfabss",     0xee300400, 6,  ARM_CEXT_MAVERICK, do_mav_binops_1d},
+  {"cfabsd",     0xee300420, 6,  ARM_CEXT_MAVERICK, do_mav_binops_1e},
+  {"cfnegs",     0xee300440, 6,  ARM_CEXT_MAVERICK, do_mav_binops_1d},
+  {"cfnegd",     0xee300460, 6,  ARM_CEXT_MAVERICK, do_mav_binops_1e},
+  {"cfadds",     0xee300480, 6,  ARM_CEXT_MAVERICK, do_mav_triple_5e},
+  {"cfaddd",     0xee3004a0, 6,  ARM_CEXT_MAVERICK, do_mav_triple_5f},
+  {"cfsubs",     0xee3004c0, 6,  ARM_CEXT_MAVERICK, do_mav_triple_5e},
+  {"cfsubd",     0xee3004e0, 6,  ARM_CEXT_MAVERICK, do_mav_triple_5f},
+  {"cfmuls",     0xee100400, 6,  ARM_CEXT_MAVERICK, do_mav_triple_5e},
+  {"cfmuld",     0xee100420, 6,  ARM_CEXT_MAVERICK, do_mav_triple_5f},
+  {"cfabs32",    0xee300500, 7,  ARM_CEXT_MAVERICK, do_mav_binops_1n},
+  {"cfabs64",    0xee300520, 7,  ARM_CEXT_MAVERICK, do_mav_binops_1o},
+  {"cfneg32",    0xee300540, 7,  ARM_CEXT_MAVERICK, do_mav_binops_1n},
+  {"cfneg64",    0xee300560, 7,  ARM_CEXT_MAVERICK, do_mav_binops_1o},
+  {"cfadd32",    0xee300580, 7,  ARM_CEXT_MAVERICK, do_mav_triple_5g},
+  {"cfadd64",    0xee3005a0, 7,  ARM_CEXT_MAVERICK, do_mav_triple_5h},
+  {"cfsub32",    0xee3005c0, 7,  ARM_CEXT_MAVERICK, do_mav_triple_5g},
+  {"cfsub64",    0xee3005e0, 7,  ARM_CEXT_MAVERICK, do_mav_triple_5h},
+  {"cfmul32",    0xee100500, 7,  ARM_CEXT_MAVERICK, do_mav_triple_5g},
+  {"cfmul64",    0xee100520, 7,  ARM_CEXT_MAVERICK, do_mav_triple_5h},
+  {"cfmac32",    0xee100540, 7,  ARM_CEXT_MAVERICK, do_mav_triple_5g},
+  {"cfmsc32",    0xee100560, 7,  ARM_CEXT_MAVERICK, do_mav_triple_5g},
+  {"cfmadd32",   0xee000600, 8,  ARM_CEXT_MAVERICK, do_mav_quad_6a},
+  {"cfmsub32",   0xee100600, 8,  ARM_CEXT_MAVERICK, do_mav_quad_6a},
+  {"cfmadda32",  0xee200600, 9,  ARM_CEXT_MAVERICK, do_mav_quad_6b},
+  {"cfmsuba32",  0xee300600, 9,  ARM_CEXT_MAVERICK, do_mav_quad_6b},
+};
 
 /* Iterate over the base tables to create the instruction patterns.  */
+
 static void
-build_arm_ops_hsh ()
+build_arm_ops_hsh (void)
 {
   unsigned int i;
   unsigned int j;
@@ -9160,8 +10933,137 @@ build_arm_ops_hsh ()
     }
 }
 
+#if 0 /* Suppressed - for now.  */
+#if defined OBJ_ELF || defined OBJ_COFF
+
+#ifdef OBJ_ELF
+#define arm_Note Elf_External_Note
+#else
+typedef struct
+{
+  unsigned char        namesz[4];      /* Size of entry's owner string.  */
+  unsigned char        descsz[4];      /* Size of the note descriptor.  */
+  unsigned char        type[4];        /* Interpretation of the descriptor.  */
+  char         name[1];        /* Start of the name+desc data.  */
+} arm_Note;
+#endif
+
+/* The description is kept to a fix sized in order to make updating
+   it and merging it easier.  */
+#define ARM_NOTE_DESCRIPTION_LENGTH    8
+
+static void
+arm_add_note (const char * name,
+             const char * description,
+             unsigned int type)
+{
+  arm_Note     note ATTRIBUTE_UNUSED;
+  char *       p;
+  unsigned int name_len;
+
+  name_len = (strlen (name) + 1 + 3) & ~3;
+
+  p = frag_more (sizeof (note.namesz));
+  md_number_to_chars (p, (valueT) name_len, sizeof (note.namesz));
+
+  p = frag_more (sizeof (note.descsz));
+  md_number_to_chars (p, (valueT) ARM_NOTE_DESCRIPTION_LENGTH, sizeof (note.descsz));
+
+  p = frag_more (sizeof (note.type));
+  md_number_to_chars (p, (valueT) type, sizeof (note.type));
+
+  p = frag_more (name_len);
+  strcpy (p, name);
+
+  p = frag_more (ARM_NOTE_DESCRIPTION_LENGTH);
+  strncpy (p, description, ARM_NOTE_DESCRIPTION_LENGTH);
+  frag_align (2, 0, 0);
+}
+#endif
+#endif
+
+\f
+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_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},
+
+  /* ARM V6.  */
+  {"cpsie",    0xb660,         2,      ARM_EXT_V6,  do_t_cps},
+  {"cpsid",     0xb670,                2,      ARM_EXT_V6,  do_t_cps},
+  {"cpy",      0x4600,         2,      ARM_EXT_V6,  do_t_cpy},
+  {"rev",      0xba00,         2,      ARM_EXT_V6,  do_t_arit},
+  {"rev16",    0xba40,         2,      ARM_EXT_V6,  do_t_arit},
+  {"revsh",    0xbac0,         2,      ARM_EXT_V6,  do_t_arit},
+  {"setend",   0xb650,         2,      ARM_EXT_V6,  do_t_setend},
+  {"sxth",     0xb200,         2,      ARM_EXT_V6,  do_t_arit},
+  {"sxtb",     0xb240,         2,      ARM_EXT_V6,  do_t_arit},
+  {"uxth",     0xb280,         2,      ARM_EXT_V6,  do_t_arit},
+  {"uxtb",     0xb2c0,         2,      ARM_EXT_V6,  do_t_arit},
+};
+
 void
-md_begin ()
+md_begin (void)
 {
   unsigned mach;
   unsigned int i;
@@ -9211,10 +11113,16 @@ md_begin ()
     }
   else if (mfpu_opt == -1)
     {
+#if !(defined (TE_LINUX) || defined (TE_NetBSD))
+      /* Some environments specify a default FPU.  If they don't, infer it
+        from the processor.  */
       if (mcpu_fpu_opt != -1)
        mfpu_opt = mcpu_fpu_opt;
       else
        mfpu_opt = march_fpu_opt;
+#else
+      mfpu_opt = FPU_DEFAULT;
+#endif
     }
 
   if (mfpu_opt == -1)
@@ -9232,22 +11140,57 @@ md_begin ()
 
   cpu_variant = mcpu_cpu_opt | mfpu_opt;
 
-#if defined OBJ_COFF || defined OBJ_ELF
   {
     unsigned int flags = 0;
 
-    /* Set the flags in the private structure.  */
-    if (uses_apcs_26)      flags |= F_APCS26;
-    if (support_interwork) flags |= F_INTERWORK;
-    if (uses_apcs_float)   flags |= F_APCS_FLOAT;
-    if (pic_code)          flags |= F_PIC;
-    if ((cpu_variant & FPU_ANY) == FPU_NONE
-       || (cpu_variant & FPU_ANY) == FPU_ARCH_VFP) /* VFP layout only.  */
-      flags |= F_SOFT_FLOAT;
-    /* Using VFP conventions (even if soft-float).  */
-    if (cpu_variant & FPU_VFP_EXT_NONE) flags |= F_VFP_FLOAT;
+#if defined OBJ_ELF
+    flags = meabi_flags;
+
+    switch (meabi_flags)
+      {
+      case EF_ARM_EABI_UNKNOWN:
+#endif
+#if defined OBJ_COFF || defined OBJ_ELF
+       /* Set the flags in the private structure.  */
+       if (uses_apcs_26)      flags |= F_APCS26;
+       if (support_interwork) flags |= F_INTERWORK;
+       if (uses_apcs_float)   flags |= F_APCS_FLOAT;
+       if (pic_code)          flags |= F_PIC;
+       if ((cpu_variant & FPU_ANY) == FPU_NONE
+            || (cpu_variant & FPU_ANY) == FPU_ARCH_VFP) /* VFP layout only.  */
+         flags |= F_SOFT_FLOAT;
+
+       switch (mfloat_abi_opt)
+         {
+         case ARM_FLOAT_ABI_SOFT:
+         case ARM_FLOAT_ABI_SOFTFP:
+           flags |= F_SOFT_FLOAT;
+           break;
+
+         case ARM_FLOAT_ABI_HARD:
+           if (flags & F_SOFT_FLOAT)
+             as_bad (_("hard-float conflicts with specified fpu"));
+           break;
+         }
+
+       /* Using VFP conventions (even if soft-float).  */
+       if (cpu_variant & FPU_VFP_EXT_NONE)
+         flags |= F_VFP_FLOAT;
+#endif
+#if defined OBJ_ELF
+       if (cpu_variant & FPU_ARCH_MAVERICK)
+           flags |= EF_ARM_MAVERICK_FLOAT;
+       break;
 
+      case EF_ARM_EABI_VER3:
+       /* No additional flags to set.  */
+       break;
 
+      default:
+       abort ();
+      }
+#endif
+#if defined OBJ_COFF || defined OBJ_ELF
     bfd_set_private_flags (stdoutput, flags);
 
     /* We have run out flags in the COFF header to encode the
@@ -9267,8 +11210,8 @@ md_begin ()
            bfd_set_section_contents (stdoutput, sec, NULL, 0, 0);
          }
       }
-  }
 #endif
+  }
 
   /* Record the CPU type as well.  */
   switch (cpu_variant & ARM_CPU_MASK)
@@ -9286,13 +11229,17 @@ md_begin ()
       break;
 
     default:
-      mach = bfd_mach_arm_4;
+      mach = bfd_mach_arm_unknown;
       break;
     }
 
   /* Catch special cases.  */
-  if (cpu_variant & ARM_CEXT_XSCALE)
+  if (cpu_variant & ARM_CEXT_IWMMXT)
+    mach = bfd_mach_arm_iWMMXt;
+  else if (cpu_variant & ARM_CEXT_XSCALE)
     mach = bfd_mach_arm_XScale;
+  else if (cpu_variant & ARM_CEXT_MAVERICK)
+    mach = bfd_mach_arm_ep9312;
   else if (cpu_variant & ARM_EXT_V5E)
     mach = bfd_mach_arm_5TE;
   else if (cpu_variant & ARM_EXT_V5)
@@ -9312,6 +11259,62 @@ md_begin ()
   else if (cpu_variant & ARM_EXT_V3M)
     mach = bfd_mach_arm_3M;
 
+#if 0 /* Suppressed - for now.  */
+#if defined (OBJ_ELF) || defined (OBJ_COFF)
+
+  /* Create a .note section to fully identify this arm binary.  */
+
+#define NOTE_ARCH_STRING       "arch: "
+
+#if defined OBJ_COFF && ! defined NT_VERSION
+#define NT_VERSION  1
+#define NT_ARCH     2
+#endif
+
+  {
+    segT current_seg = now_seg;
+    subsegT current_subseg = now_subseg;
+    asection * arm_arch;
+    const char * arch_string;
+
+    arm_arch = bfd_make_section_old_way (stdoutput, ARM_NOTE_SECTION);
+
+#ifdef OBJ_COFF
+    bfd_set_section_flags (stdoutput, arm_arch,
+                          SEC_DATA | SEC_ALLOC | SEC_LOAD | SEC_LINK_ONCE \
+                          | SEC_HAS_CONTENTS);
+#else
+    bfd_set_section_flags (stdoutput, arm_arch,
+                          SEC_READONLY | SEC_HAS_CONTENTS);
+#endif
+    arm_arch->output_section = arm_arch;
+    subseg_set (arm_arch, 0);
+
+    switch (mach)
+      {
+      default:
+      case bfd_mach_arm_unknown: arch_string = "unknown"; break;
+      case bfd_mach_arm_2:       arch_string = "armv2"; break;
+      case bfd_mach_arm_2a:      arch_string = "armv2a"; break;
+      case bfd_mach_arm_3:       arch_string = "armv3"; break;
+      case bfd_mach_arm_3M:      arch_string = "armv3M"; break;
+      case bfd_mach_arm_4:       arch_string = "armv4"; break;
+      case bfd_mach_arm_4T:      arch_string = "armv4t"; break;
+      case bfd_mach_arm_5:       arch_string = "armv5"; break;
+      case bfd_mach_arm_5T:      arch_string = "armv5t"; break;
+      case bfd_mach_arm_5TE:     arch_string = "armv5te"; break;
+      case bfd_mach_arm_XScale:  arch_string = "XScale"; break;
+      case bfd_mach_arm_ep9312:  arch_string = "ep9312"; break;
+      case bfd_mach_arm_iWMMXt:  arch_string = "iWMMXt"; break;
+      }
+
+    arm_add_note (NOTE_ARCH_STRING, arch_string, NT_ARCH);
+
+    subseg_set (current_seg, current_subseg);
+  }
+#endif
+#endif /* Suppressed code.  */
+
   bfd_set_arch_mach (stdoutput, TARGET_ARCH, mach);
 }
 
@@ -9323,10 +11326,7 @@ md_begin ()
    LITTLENUMS (shorts, here at least).  */
 
 void
-md_number_to_chars (buf, val, n)
-     char * buf;
-     valueT val;
-     int    n;
+md_number_to_chars (char * buf, valueT val, int n)
 {
   if (target_big_endian)
     number_to_chars_bigendian (buf, val, n);
@@ -9335,9 +11335,7 @@ md_number_to_chars (buf, val, n)
 }
 
 static valueT
-md_chars_to_number (buf, n)
-     char * buf;
-     int    n;
+md_chars_to_number (char * buf, int n)
 {
   valueT result = 0;
   unsigned char * where = (unsigned char *) buf;
@@ -9377,10 +11375,7 @@ md_chars_to_number (buf, n)
    ??? The format of 12 byte floats is uncertain according to gcc's arm.h.  */
 
 char *
-md_atof (type, litP, sizeP)
-     char   type;
-     char * litP;
-     int *  sizeP;
+md_atof (int type, char * litP, int * sizeP)
 {
   int prec;
   LITTLENUM_TYPE words[MAX_LITTLENUMS];
@@ -9457,8 +11452,7 @@ md_atof (type, litP, sizeP)
    themselves.  */
 
 long
-md_pcrel_from (fixP)
-     fixS * fixP;
+md_pcrel_from (fixS * fixP)
 {
   if (fixP->fx_addsy
       && S_GET_SEGMENT (fixP->fx_addsy) == undefined_section
@@ -9474,8 +11468,8 @@ md_pcrel_from (fixP)
     }
 
 #ifdef TE_WINCE
-  /* The pattern was adjusted to accomodate CE's off-by-one fixups,
-     so we un-adjust here to compensate for the accomodation.  */
+  /* The pattern was adjusted to accommodate CE's off-by-one fixups,
+     so we un-adjust here to compensate for the accommodation.  */
   return fixP->fx_where + fixP->fx_frag->fr_address + 8;
 #else
   return fixP->fx_where + fixP->fx_frag->fr_address;
@@ -9485,9 +11479,8 @@ md_pcrel_from (fixP)
 /* Round up a section size to the appropriate boundary.  */
 
 valueT
-md_section_align (segment, size)
-     segT   segment ATTRIBUTE_UNUSED;
-     valueT size;
+md_section_align (segT   segment ATTRIBUTE_UNUSED,
+                 valueT size)
 {
 #ifdef OBJ_ELF
   return size;
@@ -9501,8 +11494,7 @@ md_section_align (segment, size)
    Otherwise we have no need to default values of symbols.  */
 
 symbolS *
-md_undefined_symbol (name)
-     char * name ATTRIBUTE_UNUSED;
+md_undefined_symbol (char * name ATTRIBUTE_UNUSED)
 {
 #ifdef OBJ_ELF
   if (name[0] == '_' && name[1] == 'G'
@@ -9524,71 +11516,10 @@ md_undefined_symbol (name)
   return 0;
 }
 
-/* arm_reg_parse () := if it looks like a register, return its token and
-   advance the pointer.  */
-
-static int
-arm_reg_parse (ccp, htab)
-     register char ** ccp;
-     struct hash_control *htab;
-{
-  char * start = * ccp;
-  char   c;
-  char * p;
-  struct reg_entry * reg;
-
-#ifdef REGISTER_PREFIX
-  if (*start != REGISTER_PREFIX)
-    return FAIL;
-  p = start + 1;
-#else
-  p = start;
-#ifdef OPTIONAL_REGISTER_PREFIX
-  if (*p == OPTIONAL_REGISTER_PREFIX)
-    p++, start++;
-#endif
-#endif
-  if (!ISALPHA (*p) || !is_name_beginner (*p))
-    return FAIL;
-
-  c = *p++;
-  while (ISALPHA (c) || ISDIGIT (c) || c == '_')
-    c = *p++;
-
-  *--p = 0;
-  reg = (struct reg_entry *) hash_find (htab, start);
-  *p = c;
-
-  if (reg)
-    {
-      *ccp = p;
-      return reg->number;
-    }
-
-  return FAIL;
-}
-
-/* Search for the following register name in each of the possible reg name
-   tables.  Return the classification if found, or REG_TYPE_MAX if not
-   present.  */
-static enum arm_reg_type
-arm_reg_parse_any (cp)
-     char *cp;
-{
-  int i;
-
-  for (i = (int) REG_TYPE_FIRST; i < (int) REG_TYPE_MAX; i++)
-    if (arm_reg_parse (&cp, all_reg_maps[i].htab) != FAIL)
-      return (enum arm_reg_type) i;
-
-  return REG_TYPE_MAX;
-}
-
 void
-md_apply_fix3 (fixP, valP, seg)
-     fixS *   fixP;
-     valueT * valP;
-     segT     seg;
+md_apply_fix3 (fixS *   fixP,
+              valueT * valP,
+              segT     seg)
 {
   offsetT        value = * valP;
   offsetT        newval;
@@ -9636,6 +11567,20 @@ md_apply_fix3 (fixP, valP, seg)
   switch (fixP->fx_r_type)
     {
     case BFD_RELOC_ARM_IMMEDIATE:
+      /* We claim that this fixup has been processed here,
+        even if in fact we generate an error because we do
+        not have a reloc for it, so tc_gen_reloc will reject it.  */
+      fixP->fx_done = 1;
+
+      if (fixP->fx_addsy
+         && ! S_IS_DEFINED (fixP->fx_addsy))
+       {
+         as_bad_where (fixP->fx_file, fixP->fx_line,
+                       _("undefined symbol %s used as an immediate value"),
+                       S_GET_NAME (fixP->fx_addsy));
+         break;
+       }
+
       newimm = validate_immediate (value);
       temp = md_chars_to_number (buf, INSN_SIZE);
 
@@ -9658,6 +11603,7 @@ md_apply_fix3 (fixP, valP, seg)
       {
        unsigned int highpart = 0;
        unsigned int newinsn  = 0xe1a00000; /* nop.  */
+
        newimm = validate_immediate (value);
        temp = md_chars_to_number (buf, INSN_SIZE);
 
@@ -9786,6 +11732,15 @@ md_apply_fix3 (fixP, valP, seg)
       md_number_to_chars (buf, newval, INSN_SIZE);
       break;
 
+    case BFD_RELOC_ARM_SMI:
+      if (((unsigned long) value) > 0xffff)
+       as_bad_where (fixP->fx_file, fixP->fx_line,
+                     _("invalid smi expression"));
+      newval = md_chars_to_number (buf, INSN_SIZE) & 0xfff000f0;
+      newval |= (value & 0xf) | ((value & 0xfff0) << 4);
+      md_number_to_chars (buf, newval, INSN_SIZE);
+      break;
+
     case BFD_RELOC_ARM_SWI:
       if (arm_data->thumb_mode)
        {
@@ -9838,7 +11793,7 @@ md_apply_fix3 (fixP, valP, seg)
             the absolute address that is the destination of the branch in the
             24 bits of the branch instruction.  If however, we happen to know
             that the destination of the branch is in the same section as the
-            branch instruciton itself, then we can compute the relocation for
+            branch instruction itself, then we can compute the relocation for
             ourselves and not have to bother the linker with it.
 
             FIXME: The tests for OBJ_ELF and ! target_oabi are only here
@@ -9987,12 +11942,17 @@ md_apply_fix3 (fixP, valP, seg)
 #ifdef OBJ_ELF
     case BFD_RELOC_ARM_GOT32:
     case BFD_RELOC_ARM_GOTOFF:
+    case BFD_RELOC_ARM_TARGET2:
       md_number_to_chars (buf, 0, 4);
       break;
 #endif
 
     case BFD_RELOC_RVA:
     case BFD_RELOC_32:
+    case BFD_RELOC_ARM_TARGET1:
+    case BFD_RELOC_ARM_ROSEGREL32:
+    case BFD_RELOC_ARM_SBREL32:
+    case BFD_RELOC_32_PCREL:
       if (fixP->fx_done || fixP->fx_pcrel)
        md_number_to_chars (buf, value, 4);
 #ifdef OBJ_ELF
@@ -10005,25 +11965,47 @@ md_apply_fix3 (fixP, valP, seg)
       break;
 
 #ifdef OBJ_ELF
+    case BFD_RELOC_ARM_PREL31:
+      if (fixP->fx_done || fixP->fx_pcrel)
+       {
+         newval = md_chars_to_number (buf, 4) & 0x80000000;
+         if ((value ^ (value >> 1)) & 0x40000000)
+           {
+             as_bad_where (fixP->fx_file, fixP->fx_line,
+                           _("rel31 relocation overflow"));
+           }
+         newval |= value & 0x7fffffff;
+         md_number_to_chars (buf, newval, 4);
+       }
+      break;
+
     case BFD_RELOC_ARM_PLT32:
       /* It appears the instruction is fully prepared at this point.  */
       break;
 #endif
 
-    case BFD_RELOC_ARM_GOTPC:
-      md_number_to_chars (buf, value, 4);
-      break;
-
     case BFD_RELOC_ARM_CP_OFF_IMM:
       sign = value >= 0;
       if (value < -1023 || value > 1023 || (value & 3))
        as_bad_where (fixP->fx_file, fixP->fx_line,
                      _("illegal value for co-processor offset"));
       if (value < 0)
-       value = -value;
+       value = -value;
+      newval = md_chars_to_number (buf, INSN_SIZE) & 0xff7fff00;
+      newval |= (value >> 2) | (sign ? INDEX_UP : 0);
+      md_number_to_chars (buf, newval, INSN_SIZE);
+      break;
+
+    case BFD_RELOC_ARM_CP_OFF_IMM_S2:
+      sign = value >= 0;
+      if (value < -255 || value > 255)
+        as_bad_where (fixP->fx_file, fixP->fx_line,
+                      _("Illegal value for co-processor offset"));
+      if (value < 0)
+        value = -value;
       newval = md_chars_to_number (buf, INSN_SIZE) & 0xff7fff00;
-      newval |= (value >> 2) | (sign ? INDEX_UP : 0);
-      md_number_to_chars (buf, newval, INSN_SIZE);
+      newval |= value | (sign ?  INDEX_UP : 0);
+      md_number_to_chars (buf, newval , INSN_SIZE);
       break;
 
     case BFD_RELOC_ARM_THUMB_OFFSET:
@@ -10202,16 +12184,15 @@ md_apply_fix3 (fixP, valP, seg)
    format.  */
 
 arelent *
-tc_gen_reloc (section, fixp)
-     asection * section ATTRIBUTE_UNUSED;
-     fixS * fixp;
+tc_gen_reloc (asection * section ATTRIBUTE_UNUSED,
+             fixS *     fixp)
 {
   arelent * reloc;
   bfd_reloc_code_real_type code;
 
-  reloc = (arelent *) xmalloc (sizeof (arelent));
+  reloc = xmalloc (sizeof (arelent));
 
-  reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+  reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
   *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
   reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
 
@@ -10265,21 +12246,25 @@ tc_gen_reloc (section, fixp)
       /* If this is called then the a literal has
         been referenced across a section boundary.  */
       as_bad_where (fixp->fx_file, fixp->fx_line,
-                   _("literal referenced across section boundary"));   
+                   _("literal referenced across section boundary"));
       return NULL;
 
 #ifdef OBJ_ELF
     case BFD_RELOC_ARM_GOT32:
     case BFD_RELOC_ARM_GOTOFF:
     case BFD_RELOC_ARM_PLT32:
+    case BFD_RELOC_ARM_TARGET1:
+    case BFD_RELOC_ARM_ROSEGREL32:
+    case BFD_RELOC_ARM_SBREL32:
+    case BFD_RELOC_ARM_PREL31:
+    case BFD_RELOC_ARM_TARGET2:
       code = fixp->fx_r_type;
       break;
 #endif
 
     case BFD_RELOC_ARM_IMMEDIATE:
       as_bad_where (fixp->fx_file, fixp->fx_line,
-                   _("internal relocation (type %d) not fixed up (IMMEDIATE)"),
-                   fixp->fx_r_type);
+                   _("internal relocation (type: IMMEDIATE) not fixed up"));
       return NULL;
 
     case BFD_RELOC_ARM_ADRL_IMMEDIATE:
@@ -10288,9 +12273,18 @@ tc_gen_reloc (section, fixp)
       return NULL;
 
     case BFD_RELOC_ARM_OFFSET_IMM:
+      if (fixp->fx_addsy != NULL
+         && !S_IS_DEFINED (fixp->fx_addsy)
+         && S_IS_LOCAL (fixp->fx_addsy))
+       {
+         as_bad_where (fixp->fx_file, fixp->fx_line,
+                       _("undefined local label `%s'"),
+                       S_GET_NAME (fixp->fx_addsy));
+         return NULL;
+       }
+
       as_bad_where (fixp->fx_file, fixp->fx_line,
-                   _("internal_relocation (type %d) not fixed up (OFFSET_IMM)"),
-                   fixp->fx_r_type);
+                   _("internal_relocation (type: OFFSET_IMM) not fixed up"));
       return NULL;
 
     default:
@@ -10299,10 +12293,9 @@ tc_gen_reloc (section, fixp)
 
        switch (fixp->fx_r_type)
          {
-         case BFD_RELOC_ARM_IMMEDIATE:    type = "IMMEDIATE";    break;
-         case BFD_RELOC_ARM_OFFSET_IMM:   type = "OFFSET_IMM";   break;
          case BFD_RELOC_ARM_OFFSET_IMM8:  type = "OFFSET_IMM8";  break;
          case BFD_RELOC_ARM_SHIFT_IMM:    type = "SHIFT_IMM";    break;
+         case BFD_RELOC_ARM_SMI:          type = "SMI";          break;
          case BFD_RELOC_ARM_SWI:          type = "SWI";          break;
          case BFD_RELOC_ARM_MULTI:        type = "MULTI";        break;
          case BFD_RELOC_ARM_CP_OFF_IMM:   type = "CP_OFF_IMM";   break;
@@ -10320,7 +12313,7 @@ tc_gen_reloc (section, fixp)
     }
 
 #ifdef OBJ_ELF
-  if (code == BFD_RELOC_32_PCREL
+  if ((code == BFD_RELOC_32_PCREL || code == BFD_RELOC_32)
       && GOT_symbol
       && fixp->fx_addsy == GOT_symbol)
     {
@@ -10348,17 +12341,55 @@ tc_gen_reloc (section, fixp)
 }
 
 int
-md_estimate_size_before_relax (fragP, segtype)
-     fragS * fragP ATTRIBUTE_UNUSED;
-     segT    segtype ATTRIBUTE_UNUSED;
+md_estimate_size_before_relax (fragS * fragP ATTRIBUTE_UNUSED,
+                              segT    segtype ATTRIBUTE_UNUSED)
 {
   as_fatal (_("md_estimate_size_before_relax\n"));
   return 1;
 }
 
+/* We need to be able to fix up arbitrary expressions in some statements.
+   This is so that we can handle symbols that are an arbitrary distance from
+   the pc.  The most common cases are of the form ((+/-sym -/+ . - 8) & mask),
+   which returns part of an address in a form which will be valid for
+   a data instruction.  We do this by pushing the expression into a symbol
+   in the expr_section, and creating a fix for that.  */
+
+static void
+fix_new_arm (fragS *       frag,
+            int           where,
+            short int     size,
+            expressionS * exp,
+            int           pc_rel,
+            int           reloc)
+{
+  fixS *           new_fix;
+  arm_fix_data *   arm_data;
+
+  switch (exp->X_op)
+    {
+    case O_constant:
+    case O_symbol:
+    case O_add:
+    case O_subtract:
+      new_fix = fix_new_exp (frag, where, size, exp, pc_rel, reloc);
+      break;
+
+    default:
+      new_fix = fix_new (frag, where, size, make_expr_symbol (exp), 0,
+                        pc_rel, reloc);
+      break;
+    }
+
+  /* Mark whether the fix is to a THUMB instruction, or an ARM
+     instruction.  */
+  arm_data = obstack_alloc (& notes, sizeof (arm_fix_data));
+  new_fix->tc_fix_data = (PTR) arm_data;
+  arm_data->thumb_mode = thumb_mode;
+}
+
 static void
-output_inst (str)
-     const char *str;
+output_inst (const char * str)
 {
   char * to = NULL;
 
@@ -10396,8 +12427,7 @@ output_inst (str)
 }
 
 void
-md_assemble (str)
-     char * str;
+md_assemble (char * str)
 {
   char  c;
   char *p;
@@ -10452,9 +12482,10 @@ md_assemble (str)
              return;
            }
 
+         mapping_state (MAP_THUMB);
          inst.instruction = opcode->value;
          inst.size = opcode->size;
-         (*opcode->parms) (p);
+         opcode->parms (p);
          output_inst (str);
          return;
        }
@@ -10477,9 +12508,10 @@ md_assemble (str)
              return;
            }
 
+          mapping_state (MAP_ARM);
          inst.instruction = opcode->value;
          inst.size = INSN_SIZE;
-         (*opcode->parms) (p);
+         opcode->parms (p);
          output_inst (str);
          return;
        }
@@ -10688,6 +12720,7 @@ struct arm_option_table arm_opts[] =
   {"mstrongarm1110", NULL, &legacy_cpu, ARM_ARCH_V4,
    N_("use -mcpu=strongarm1110")},
   {"mxscale",   NULL, &legacy_cpu, ARM_ARCH_XSCALE, N_("use -mcpu=xscale")},
+  {"miwmmxt",   NULL, &legacy_cpu, ARM_ARCH_IWMMXT, N_("use -mcpu=iwmmxt")},
   {"mall",      NULL, &legacy_cpu, ARM_ANY,      N_("use -mcpu=all")},
 
   /* Architecture variants -- don't add any more to this list either.  */
@@ -10763,6 +12796,7 @@ static struct arm_cpu_option_table arm_cpus[] =
   {"arm7500fe",                ARM_ARCH_V3,     FPU_ARCH_FPA},
   {"arm7t",            ARM_ARCH_V4T,    FPU_ARCH_FPA},
   {"arm7tdmi",         ARM_ARCH_V4T,    FPU_ARCH_FPA},
+  {"arm7tdmi-s",       ARM_ARCH_V4T,    FPU_ARCH_FPA},
   {"arm8",             ARM_ARCH_V4,     FPU_ARCH_FPA},
   {"arm810",           ARM_ARCH_V4,     FPU_ARCH_FPA},
   {"strongarm",                ARM_ARCH_V4,     FPU_ARCH_FPA},
@@ -10781,6 +12815,8 @@ static struct arm_cpu_option_table arm_cpus[] =
   {"arm9e-r0",         ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2},
   {"arm9e",            ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2},
   {"arm926ej",         ARM_ARCH_V5TEJ,  FPU_ARCH_VFP_V2},
+  {"arm926ejs",                ARM_ARCH_V5TEJ,  FPU_ARCH_VFP_V2},
+  {"arm926ej-s",       ARM_ARCH_V5TEJ,  FPU_ARCH_VFP_V2},
   {"arm946e-r0",       ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2},
   {"arm946e",          ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2},
   {"arm966e-r0",       ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2},
@@ -10790,11 +12826,23 @@ static struct arm_cpu_option_table arm_cpus[] =
   {"arm1020",          ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2},
   {"arm1020t",         ARM_ARCH_V5T,    FPU_ARCH_VFP_V1},
   {"arm1020e",         ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2},
+  {"arm1026ejs",       ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2},
+  {"arm1026ej-s",      ARM_ARCH_V5TE,   FPU_ARCH_VFP_V2},
+  {"arm1136js",                ARM_ARCH_V6,     FPU_NONE},
+  {"arm1136j-s",       ARM_ARCH_V6,     FPU_NONE},
+  {"arm1136jfs",       ARM_ARCH_V6,     FPU_ARCH_VFP_V2},
+  {"arm1136jf-s",      ARM_ARCH_V6,     FPU_ARCH_VFP_V2},
+  {"mpcore",           ARM_ARCH_V6K,    FPU_ARCH_VFP_V2},
+  {"mpcorenovfp",      ARM_ARCH_V6K,    FPU_NONE},
+  {"arm1176jz-s",      ARM_ARCH_V6ZK,   FPU_NONE},
+  {"arm1176jzf-s",     ARM_ARCH_V6ZK,   FPU_ARCH_VFP_V2},
   /* ??? XSCALE is really an architecture.  */
   {"xscale",           ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2},
+  /* ??? iwmmxt is not a processor.  */
+  {"iwmmxt",           ARM_ARCH_IWMMXT, FPU_ARCH_VFP_V2},
   {"i80200",           ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2},
   /* Maverick */
-  {"ep9312",           ARM_ARCH_V4T | ARM_CEXT_MAVERICK, FPU_NONE},
+  {"ep9312",           ARM_ARCH_V4T | ARM_CEXT_MAVERICK, FPU_ARCH_MAVERICK},
   {NULL, 0, 0}
 };
 
@@ -10826,7 +12874,13 @@ static struct arm_arch_option_table arm_archs[] =
   {"armv5te",          ARM_ARCH_V5TE,   FPU_ARCH_VFP},
   {"armv5texp",                ARM_ARCH_V5TExP, FPU_ARCH_VFP},
   {"armv5tej",         ARM_ARCH_V5TEJ,  FPU_ARCH_VFP},
+  {"armv6",             ARM_ARCH_V6,     FPU_ARCH_VFP},
+  {"armv6j",            ARM_ARCH_V6,     FPU_ARCH_VFP},
+  {"armv6k",            ARM_ARCH_V6K,    FPU_ARCH_VFP},
+  {"armv6z",            ARM_ARCH_V6Z,    FPU_ARCH_VFP},
+  {"armv6zk",           ARM_ARCH_V6ZK,   FPU_ARCH_VFP},
   {"xscale",           ARM_ARCH_XSCALE, FPU_ARCH_VFP},
+  {"iwmmxt",           ARM_ARCH_IWMMXT, FPU_ARCH_VFP},
   {NULL, 0, 0}
 };
 
@@ -10841,6 +12895,7 @@ static struct arm_arch_extension_table arm_extensions[] =
 {
   {"maverick",         ARM_CEXT_MAVERICK},
   {"xscale",           ARM_CEXT_XSCALE},
+  {"iwmmxt",           ARM_CEXT_IWMMXT},
   {NULL,               0}
 };
 
@@ -10871,26 +12926,57 @@ static struct arm_fpu_option_table arm_fpus[] =
   {"vfpxd",            FPU_ARCH_VFP_V1xD},
   {"arm1020t",         FPU_ARCH_VFP_V1},
   {"arm1020e",         FPU_ARCH_VFP_V2},
+  {"arm1136jfs",       FPU_ARCH_VFP_V2},
+  {"arm1136jf-s",      FPU_ARCH_VFP_V2},
+  {"maverick",         FPU_ARCH_MAVERICK},
+  {NULL, 0}
+};
+
+struct arm_float_abi_option_table
+{
+  char *name;
+  int value;
+};
+
+static struct arm_float_abi_option_table arm_float_abis[] =
+{
+  {"hard",     ARM_FLOAT_ABI_HARD},
+  {"softfp",   ARM_FLOAT_ABI_SOFTFP},
+  {"soft",     ARM_FLOAT_ABI_SOFT},
+  {NULL, 0}
+};
+
+struct arm_eabi_option_table
+{
+  char *name;
+  unsigned int value;
+};
+
+#ifdef OBJ_ELF
+/* We only know hot to output GNU and ver 3 (AAELF) formats.  */
+static struct arm_eabi_option_table arm_eabis[] =
+{
+  {"gnu",      EF_ARM_EABI_UNKNOWN},
+  {"3",                EF_ARM_EABI_VER3},
   {NULL, 0}
 };
+#endif
 
 struct arm_long_option_table
 {
-  char *option;                /* Substring to match.  */
-  char *help;          /* Help information.  */
-  int (*func) PARAMS ((char *subopt)); /* Function to decode sub-option.  */
-  char *deprecated;    /* If non-null, print this message.  */
+  char * option;               /* Substring to match.  */
+  char * help;                 /* Help information.  */
+  int (* func) (char * subopt);        /* Function to decode sub-option.  */
+  char * deprecated;           /* If non-null, print this message.  */
 };
 
 static int
-arm_parse_extension (str, opt_p)
-     char *str;
-     int *opt_p;
+arm_parse_extension (char * str, int * opt_p)
 {
   while (str != NULL && *str != 0)
     {
-      struct arm_arch_extension_table *opt;
-      char *ext;
+      struct arm_arch_extension_table * opt;
+      char * ext;
       int optlen;
 
       if (*str != '+')
@@ -10933,11 +13019,10 @@ arm_parse_extension (str, opt_p)
 }
 
 static int
-arm_parse_cpu (str)
-     char *str;
+arm_parse_cpu (char * str)
 {
-  struct arm_cpu_option_table *opt;
-  char *ext = strchr (str, '+');
+  struct arm_cpu_option_table * opt;
+  char * ext = strchr (str, '+');
   int optlen;
 
   if (ext != NULL)
@@ -10968,8 +13053,7 @@ arm_parse_cpu (str)
 }
 
 static int
-arm_parse_arch (str)
-     char *str;
+arm_parse_arch (char * str)
 {
   struct arm_arch_option_table *opt;
   char *ext = strchr (str, '+');
@@ -10988,7 +13072,7 @@ arm_parse_arch (str)
 
 
   for (opt = arm_archs; opt->name != NULL; opt++)
-    if (strcmp (opt->name, str) == 0)
+    if (streq (opt->name, str))
       {
        march_cpu_opt = opt->value;
        march_fpu_opt = opt->default_fpu;
@@ -11004,13 +13088,12 @@ arm_parse_arch (str)
 }
 
 static int
-arm_parse_fpu (str)
-     char *str;
+arm_parse_fpu (char * str)
 {
-  struct arm_fpu_option_table *opt;
+  struct arm_fpu_option_table * opt;
 
   for (opt = arm_fpus; opt->name != NULL; opt++)
-    if (strcmp (opt->name, str) == 0)
+    if (streq (opt->name, str))
       {
        mfpu_opt = opt->value;
        return 1;
@@ -11020,6 +13103,39 @@ arm_parse_fpu (str)
   return 0;
 }
 
+static int
+arm_parse_float_abi (char * str)
+{
+  struct arm_float_abi_option_table * opt;
+
+  for (opt = arm_float_abis; opt->name != NULL; opt++)
+    if (streq (opt->name, str))
+      {
+       mfloat_abi_opt = opt->value;
+       return 1;
+      }
+
+  as_bad (_("unknown floating point abi `%s'\n"), str);
+  return 0;
+}
+
+#ifdef OBJ_ELF
+static int
+arm_parse_eabi (char * str)
+{
+  struct arm_eabi_option_table *opt;
+
+  for (opt = arm_eabis; opt->name != NULL; opt++)
+    if (streq (opt->name, str))
+      {
+       meabi_flags = opt->value;
+       return 1;
+      }
+  as_bad (_("unknown EABI `%s'\n"), str);
+  return 0;
+}
+#endif
+
 struct arm_long_option_table arm_long_opts[] =
 {
   {"mcpu=", N_("<cpu name>\t  assemble for CPU <cpu name>"),
@@ -11028,13 +13144,17 @@ struct arm_long_option_table arm_long_opts[] =
    arm_parse_arch, NULL},
   {"mfpu=", N_("<fpu name>\t  assemble for FPU architecture <fpu name>"),
    arm_parse_fpu, NULL},
+  {"mfloat-abi=", N_("<abi>\t  assemble for floating point ABI <abi>"),
+   arm_parse_float_abi, NULL},
+#ifdef OBJ_ELF
+  {"meabi=", N_("<ver>\t  assemble for eabi version <ver>"),
+   arm_parse_eabi, NULL},
+#endif
   {NULL, NULL, 0, NULL}
 };
 
 int
-md_parse_option (c, arg)
-     int    c;
-     char * arg;
+md_parse_option (int c, char * arg)
 {
   struct arm_option_table *opt;
   struct arm_long_option_table *lopt;
@@ -11063,7 +13183,7 @@ md_parse_option (c, arg)
        {
          if (c == opt->option[0]
              && ((arg == NULL && opt->option[1] == 0)
-                 || strcmp (arg, opt->option + 1) == 0))
+                 || streq (arg, opt->option + 1)))
            {
 #if WARN_DEPRECATED
              /* If the option is deprecated, tell the user.  */
@@ -11095,11 +13215,10 @@ md_parse_option (c, arg)
 #endif
 
              /* Call the sup-option parser.  */
-             return (*lopt->func)(arg + strlen (lopt->option) - 1);
+             return lopt->func (arg + strlen (lopt->option) - 1);
            }
        }
 
-      as_bad (_("unrecognized option `-%c%s'"), c, arg ? arg : "");
       return 0;
     }
 
@@ -11107,8 +13226,7 @@ md_parse_option (c, arg)
 }
 
 void
-md_show_usage (fp)
-     FILE * fp;
+md_show_usage (FILE * fp)
 {
   struct arm_option_table *opt;
   struct arm_long_option_table *lopt;
@@ -11134,57 +13252,13 @@ md_show_usage (fp)
 #endif
 }
 
-/* We need to be able to fix up arbitrary expressions in some statements.
-   This is so that we can handle symbols that are an arbitrary distance from
-   the pc.  The most common cases are of the form ((+/-sym -/+ . - 8) & mask),
-   which returns part of an address in a form which will be valid for
-   a data instruction.  We do this by pushing the expression into a symbol
-   in the expr_section, and creating a fix for that.  */
-
-static void
-fix_new_arm (frag, where, size, exp, pc_rel, reloc)
-     fragS *       frag;
-     int           where;
-     short int     size;
-     expressionS * exp;
-     int           pc_rel;
-     int           reloc;
-{
-  fixS *           new_fix;
-  arm_fix_data *   arm_data;
-
-  switch (exp->X_op)
-    {
-    case O_constant:
-    case O_symbol:
-    case O_add:
-    case O_subtract:
-      new_fix = fix_new_exp (frag, where, size, exp, pc_rel, reloc);
-      break;
-
-    default:
-      new_fix = fix_new (frag, where, size, make_expr_symbol (exp), 0,
-                        pc_rel, reloc);
-      break;
-    }
-
-  /* Mark whether the fix is to a THUMB instruction, or an ARM
-     instruction.  */
-  arm_data = (arm_fix_data *) obstack_alloc (& notes, sizeof (arm_fix_data));
-  new_fix->tc_fix_data = (PTR) arm_data;
-  arm_data->thumb_mode = thumb_mode;
-
-  return;
-}
-
 /* This fix_new is called by cons via TC_CONS_FIX_NEW.  */
 
 void
-cons_fix_new_arm (frag, where, size, exp)
-     fragS *       frag;
-     int           where;
-     int           size;
-     expressionS * exp;
+cons_fix_new_arm (fragS *       frag,
+                 int           where,
+                 int           size,
+                 expressionS * exp)
 {
   bfd_reloc_code_real_type type;
   int pcrel = 0;
@@ -11216,7 +13290,7 @@ cons_fix_new_arm (frag, where, size, exp)
    references are made to a null symbol pointer.  */
 
 void
-arm_cleanup ()
+arm_cleanup (void)
 {
   literal_pool * pool;
 
@@ -11224,19 +13298,21 @@ arm_cleanup ()
     {
       /* Put it at the end of the relevent section.  */
       subseg_set (pool->section, pool->sub_section);
+#ifdef OBJ_ELF
+      arm_elf_change_section ();
+#endif
       s_ltorg (0);
     }
 }
 
 void
-arm_start_line_hook ()
+arm_start_line_hook (void)
 {
   last_label_seen = NULL;
 }
 
 void
-arm_frob_label (sym)
-     symbolS * sym;
+arm_frob_label (symbolS * sym)
 {
   last_label_seen = sym;
 
@@ -11286,7 +13362,7 @@ arm_frob_label (sym)
 
       THUMB_SET_FUNC (sym, 1);
 
-      label_is_thumb_function_name = false;
+      label_is_thumb_function_name = FALSE;
     }
 }
 
@@ -11294,7 +13370,7 @@ arm_frob_label (sym)
    ARM ones.  */
 
 void
-arm_adjust_symtab ()
+arm_adjust_symtab (void)
 {
 #ifdef OBJ_COFF
   symbolS * sym;
@@ -11364,7 +13440,7 @@ arm_adjust_symtab ()
 }
 
 int
-arm_data_in_code ()
+arm_data_in_code (void)
 {
   if (thumb_mode && ! strncmp (input_line_pointer + 1, "data:", 5))
     {
@@ -11378,8 +13454,7 @@ arm_data_in_code ()
 }
 
 char *
-arm_canonicalize_symbol_name (name)
-     char * name;
+arm_canonicalize_symbol_name (char * name)
 {
   int len;
 
@@ -11390,9 +13465,9 @@ arm_canonicalize_symbol_name (name)
   return name;
 }
 
-boolean
-arm_validate_fix (fixP)
-     fixS * fixP;
+#if defined OBJ_COFF || defined OBJ_ELF
+void
+arm_validate_fix (fixS * fixP)
 {
   /* If the destination of the branch is a defined symbol which does not have
      the THUMB_FUNC attribute, then we must be calling a function which has
@@ -11404,10 +13479,32 @@ arm_validate_fix (fixP)
       && ! THUMB_IS_FUNC (fixP->fx_addsy))
     {
       fixP->fx_addsy = find_real_start (fixP->fx_addsy);
-      return true;
     }
+}
+#endif
+
+int
+arm_force_relocation (struct fix * fixp)
+{
+#if defined (OBJ_COFF) && defined (TE_PE)
+  if (fixp->fx_r_type == BFD_RELOC_RVA)
+    return 1;
+#endif
+#ifdef OBJ_ELF
+  if (fixp->fx_r_type == BFD_RELOC_ARM_PCREL_BRANCH
+      || fixp->fx_r_type == BFD_RELOC_ARM_PCREL_BLX
+      || fixp->fx_r_type == BFD_RELOC_THUMB_PCREL_BLX
+      || fixp->fx_r_type == BFD_RELOC_THUMB_PCREL_BRANCH23)
+    return 1;
+#endif
+
+  /* Resolve these relocations even if the symbol is extern or weak.  */
+  if (fixp->fx_r_type == BFD_RELOC_ARM_IMMEDIATE
+      || fixp->fx_r_type == BFD_RELOC_ARM_OFFSET_IMM
+      || fixp->fx_r_type == BFD_RELOC_ARM_ADRL_IMMEDIATE)
+    return 0;
 
-  return false;
+  return generic_force_reloc (fixp);
 }
 
 #ifdef OBJ_COFF
@@ -11417,15 +13514,15 @@ arm_validate_fix (fixP)
    be resolved before the binbary is emitted, so it is safe to say that
    it is adjustable.  */
 
-boolean
-arm_fix_adjustable (fixP)
-   fixS * fixP;
+bfd_boolean
+arm_fix_adjustable (fixS * fixP)
 {
   if (fixP->fx_r_type == BFD_RELOC_ARM_ADRL_IMMEDIATE)
     return 1;
   return 0;
 }
 #endif
+
 #ifdef OBJ_ELF
 /* Relocations against Thumb function names must be left unadjusted,
    so that the linker can use this information to correctly set the
@@ -11440,20 +13537,12 @@ arm_fix_adjustable (fixP)
    addresses also ought to have their bottom bit set (assuming that
    they reside in Thumb code), but at the moment they will not.  */
 
-boolean
-arm_fix_adjustable (fixP)
-   fixS * fixP;
+bfd_boolean
+arm_fix_adjustable (fixS * fixP)
 {
   if (fixP->fx_addsy == NULL)
     return 1;
 
-  /* Prevent all adjustments to global symbols.  */
-  if (S_IS_EXTERN (fixP->fx_addsy))
-    return 0;
-
-  if (S_IS_WEAK (fixP->fx_addsy))
-    return 0;
-
   if (THUMB_IS_FUNC (fixP->fx_addsy)
       && fixP->fx_subsy == NULL)
     return 0;
@@ -11463,12 +13552,24 @@ arm_fix_adjustable (fixP)
       || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
     return 0;
 
+  /* Don't allow symbols to be discarded on GOT related relocs.  */
+  if (fixP->fx_r_type == BFD_RELOC_ARM_PLT32
+      || fixP->fx_r_type == BFD_RELOC_ARM_GOT32
+      || fixP->fx_r_type == BFD_RELOC_ARM_GOTOFF
+      || fixP->fx_r_type == BFD_RELOC_ARM_TARGET2)
+    return 0;
+
   return 1;
 }
 
 const char *
-elf32_arm_target_format ()
+elf32_arm_target_format (void)
 {
+#ifdef TE_SYMBIAN
+  return (target_big_endian
+         ? "elf32-bigarm-symbian"
+         : "elf32-littlearm-symbian");
+#else
   if (target_big_endian)
     {
       if (target_oabi)
@@ -11483,72 +13584,18 @@ elf32_arm_target_format ()
       else
        return "elf32-littlearm";
     }
+#endif
 }
 
 void
-armelf_frob_symbol (symp, puntp)
-     symbolS * symp;
-     int *     puntp;
+armelf_frob_symbol (symbolS * symp,
+                   int *     puntp)
 {
   elf_frob_symbol (symp, puntp);
 }
 
-int
-arm_force_relocation (fixp)
-     struct fix * fixp;
-{
-  if (   fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
-      || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY
-      || fixp->fx_r_type == BFD_RELOC_ARM_PCREL_BRANCH
-      || fixp->fx_r_type == BFD_RELOC_ARM_PCREL_BLX
-      || fixp->fx_r_type == BFD_RELOC_THUMB_PCREL_BLX
-      || fixp->fx_r_type == BFD_RELOC_THUMB_PCREL_BRANCH23)
-    return 1;
-
-  return 0;
-}
-
-static bfd_reloc_code_real_type
-arm_parse_reloc ()
-{
-  char         id [16];
-  char *       ip;
-  unsigned int i;
-  static struct
-  {
-    char * str;
-    int    len;
-    bfd_reloc_code_real_type reloc;
-  }
-  reloc_map[] =
-  {
-#define MAP(str,reloc) { str, sizeof (str) - 1, reloc }
-    MAP ("(got)",    BFD_RELOC_ARM_GOT32),
-    MAP ("(gotoff)", BFD_RELOC_ARM_GOTOFF),
-    /* ScottB: Jan 30, 1998 - Added support for parsing "var(PLT)"
-       branch instructions generated by GCC for PLT relocs.  */
-    MAP ("(plt)",    BFD_RELOC_ARM_PLT32),
-    { NULL, 0,         BFD_RELOC_UNUSED }
-#undef MAP
-  };
-
-  for (i = 0, ip = input_line_pointer;
-       i < sizeof (id) && (ISALNUM (*ip) || ISPUNCT (*ip));
-       i++, 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)
-      break;
-
-  input_line_pointer += reloc_map[i].len;
-
-  return reloc_map[i].reloc;
-}
-
 static void
-s_arm_elf_cons (nbytes)
-     int nbytes;
+s_arm_elf_cons (int nbytes)
 {
   expressionS exp;
 
@@ -11566,6 +13613,7 @@ s_arm_elf_cons (nbytes)
   md_cons_align (nbytes);
 #endif
 
+  mapping_state (MAP_DATA);
   do
     {
       bfd_reloc_code_real_type reloc;
@@ -11584,7 +13632,7 @@ s_arm_elf_cons (nbytes)
                    howto->name, nbytes);
          else
            {
-             register char *p = frag_more ((int) nbytes);
+             char *p = frag_more ((int) nbytes);
              int offset = nbytes - size;
 
              fix_new_exp (frag_now, p - frag_now->fr_literal + offset, size,
@@ -11601,14 +13649,57 @@ s_arm_elf_cons (nbytes)
   demand_empty_rest_of_line ();
 }
 
+
+/* Parse a .rel31 directive.  */
+
+static void
+s_arm_rel31 (int ignored ATTRIBUTE_UNUSED)
+{
+  expressionS exp;
+  char *p;
+  valueT highbit;
+
+  SKIP_WHITESPACE ();
+
+  highbit = 0;
+  if (*input_line_pointer == '1')
+    highbit = 0x80000000;
+  else if (*input_line_pointer != '0')
+    as_bad (_("expected 0 or 1"));
+
+  input_line_pointer++;
+  SKIP_WHITESPACE ();
+  if (*input_line_pointer != ',')
+    as_bad (_("missing comma"));
+  input_line_pointer++;
+
+#ifdef md_flush_pending_output
+  md_flush_pending_output ();
+#endif
+
+#ifdef md_cons_align
+  md_cons_align (4);
+#endif
+
+  mapping_state (MAP_DATA);
+
+  expression (&exp);
+
+  p = frag_more (4);
+  md_number_to_chars (p, highbit, 4);
+  fix_new_arm (frag_now, p - frag_now->fr_literal, 4, &exp, 1,
+              BFD_RELOC_ARM_PREL31);
+
+  demand_empty_rest_of_line ();
+}
+
 #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;
+arm_handle_align (fragS * fragP)
 {
   static char const arm_noop[4] = { 0x00, 0x00, 0xa0, 0xe1 };
   static char const thumb_noop[2] = { 0xc0, 0x46 };
@@ -11670,13 +13761,11 @@ arm_handle_align (fragP)
    frag in a code section.  */
 
 void
-arm_frag_align_code (n, max)
-     int n;
-     int max;
+arm_frag_align_code (int n, int max)
 {
   char * p;
 
-  /* We assume that there will never be a requirment
+  /* We assume that there will never be a requirement
      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."));
@@ -11689,15 +13778,48 @@ arm_frag_align_code (n, max)
                (offsetT) n,
                (char *) NULL);
   *p = 0;
-
 }
 
 /* Perform target specific initialisation of a frag.  */
 
 void
-arm_init_frag (fragP)
-     fragS *fragP;
+arm_init_frag (fragS * fragP)
 {
   /* Record whether this frag is in an ARM or a THUMB area.  */
   fragP->tc_frag_data = thumb_mode;
 }
+
+/* This table describes all the machine specific pseudo-ops the assembler
+   has to support.  The fields are:
+     pseudo-op name without dot
+     function to call to execute this pseudo-op
+     Integer arg to pass to the function.  */
+
+const pseudo_typeS md_pseudo_table[] =
+{
+  /* Never called because '.req' does not start a line.  */
+  { "req",         s_req,         0 },
+  { "unreq",       s_unreq,       0 },
+  { "bss",         s_bss,         0 },
+  { "align",       s_align,       0 },
+  { "arm",         s_arm,         0 },
+  { "thumb",       s_thumb,       0 },
+  { "code",        s_code,        0 },
+  { "force_thumb", s_force_thumb, 0 },
+  { "thumb_func",  s_thumb_func,  0 },
+  { "thumb_set",   s_thumb_set,   0 },
+  { "even",        s_even,        0 },
+  { "ltorg",       s_ltorg,       0 },
+  { "pool",        s_ltorg,       0 },
+#ifdef OBJ_ELF
+  { "word",        s_arm_elf_cons, 4 },
+  { "long",        s_arm_elf_cons, 4 },
+  { "rel31",       s_arm_rel31,   0 },
+#else
+  { "word",        cons, 4},
+#endif
+  { "extend",      float_cons, 'x' },
+  { "ldouble",     float_cons, 'x' },
+  { "packed",      float_cons, 'p' },
+  { 0, 0, 0 }
+};
This page took 0.278647 seconds and 4 git commands to generate.