Fix region length calculations when regions end with .align padding.
[deliverable/binutils-gdb.git] / gas / config / tc-arm.c
index 025dd1662ac6f1fa1eff3d199712bf70def1a132..aef76e7c0cecda6f38cf2c2d43752f96528b6052 100644 (file)
@@ -55,6 +55,7 @@
 #define ARM_EXT_V5ExP   0x00000200     /* DSP core set.           */
 #define ARM_EXT_V5E     0x00000400     /* DSP Double transfers.   */
 #define ARM_EXT_V5J     0x00000800     /* Jazelle extension.      */
+#define ARM_EXT_V6       0x00001000     /* ARM V6.                 */
 
 /* Co-processor space extensions.  */
 #define ARM_CEXT_XSCALE   0x00800000   /* Allow MIA etc.          */
@@ -82,6 +83,7 @@
 #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)
+#define ARM_ARCH_V6     (ARM_ARCH_V5TEJ | ARM_EXT_V6)
 
 /* Processors with specific extensions in the co-processor space.  */
 #define ARM_ARCH_XSCALE        (ARM_ARCH_V5TE  | ARM_CEXT_XSCALE)
 #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_MAVERICK    0x02000000     /* Cirrus Maverick.           */
 #define FPU_NONE        0
 
 #define FPU_ARCH_FPE    FPU_FPA_EXT_V1
 #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)
 
+#define FPU_ARCH_MAVERICK  FPU_MAVERICK
+
+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
 #define ARM_2          ARM_ARCH_V2
@@ -176,6 +188,7 @@ 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;
 
 /* This array holds the chars that always start a comment.  If the
    pre-processor is disabled, these aren't very useful.  */
@@ -288,8 +301,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
 
@@ -856,6 +877,36 @@ static void do_co_reg2c            PARAMS ((char *));
 /* ARM v5TEJ.  */
 static void do_bxj             PARAMS ((char *));
 
+/* ARM V6. */
+static void do_cps              PARAMS ((char *));
+static void do_cpsi             PARAMS ((char *));
+static void do_ldrex            PARAMS ((char *));
+static void do_pkhbt            PARAMS ((char *));
+static void do_pkhtb            PARAMS ((char *));
+static void do_qadd16           PARAMS ((char *));
+static void do_rev              PARAMS ((char *));
+static void do_rfe              PARAMS ((char *));
+static void do_sxtah            PARAMS ((char *));
+static void do_sxth             PARAMS ((char *));
+static void do_setend           PARAMS ((char *));
+static void do_smlad            PARAMS ((char *));
+static void do_smlald           PARAMS ((char *));
+static void do_smmul            PARAMS ((char *));
+static void do_ssat             PARAMS ((char *));
+static void do_usat             PARAMS ((char *));
+static void do_srs              PARAMS ((char *));
+static void do_ssat16           PARAMS ((char *));
+static void do_usat16           PARAMS ((char *));
+static void do_strex            PARAMS ((char *));
+static void do_umaal            PARAMS ((char *));
+
+static void do_cps_mode         PARAMS ((char **));
+static void do_cps_flags        PARAMS ((char **, int));
+static int do_endian_specifier  PARAMS ((char *));
+static void do_pkh_core         PARAMS ((char *, int));
+static void do_sat              PARAMS ((char **, int));
+static void do_sat16            PARAMS ((char **, int));
+
 /* Coprocessor Instructions.  */
 static void do_cdp             PARAMS ((char *));
 static void do_lstc            PARAMS ((char *));
@@ -878,7 +929,8 @@ 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_reg2_from_sp2 PARAMS ((char *));
+static void do_vfp_sp2_from_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 *));
@@ -1180,7 +1232,7 @@ static const struct asm_opcode insns[] =
   {"mla",        0xe0200090, 3,  ARM_EXT_V2,       do_mla},
   {"mlas",       0xe0300090, 3,  ARM_EXT_V2,       do_mla},
 
-  /* Generic copressor instructions.  */
+  /* 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},
@@ -1273,6 +1325,107 @@ static const struct asm_opcode insns[] =
   /*  ARM Architecture 5TEJ.  */
   {"bxj",       0xe12fff20, 3,  ARM_EXT_V5J,      do_bxj},
 
+  /*  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},
+
   /* 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},
@@ -1824,8 +1977,8 @@ static const struct asm_opcode insns[] =
   {"fcmpezd", 0xeeb50bc0, 7, FPU_VFP_EXT_V1,   do_vfp_dp_compare_z},
 
   /* VFP V2.  */
-  {"fmsrr",   0xec400a10, 5, FPU_VFP_EXT_V2,   do_vfp_sp_reg2},
-  {"fmrrs",   0xec500a10, 5, FPU_VFP_EXT_V2,   do_vfp_sp_reg2},
+  {"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},
 
@@ -2146,6 +2299,11 @@ static void do_t_adr             PARAMS ((char *));
 static void do_t_blx           PARAMS ((char *));
 static void do_t_bkpt          PARAMS ((char *));
 
+/* ARM V6.  */
+static void do_t_cps            PARAMS ((char *));
+static void do_t_cpy            PARAMS ((char *));
+static void do_t_setend         PARAMS ((char *));;
+
 #define T_OPCODE_MUL 0x4340
 #define T_OPCODE_TST 0x4200
 #define T_OPCODE_CMN 0x42c0
@@ -2214,6 +2372,7 @@ static int thumb_reg              PARAMS ((char ** str, int hi_lo));
 
 #define THUMB_MOVE 0
 #define THUMB_COMPARE 1
+#define THUMB_CPY 2
 
 #define THUMB_LOAD 0
 #define THUMB_STORE 1
@@ -2306,6 +2465,19 @@ static const struct thumb_opcode tinsns[] =
   /* 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},
 };
 
 #define BAD_ARGS       _("bad arguments to instruction")
@@ -2376,6 +2548,7 @@ 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 *));
+static int arm_parse_float_abi PARAMS ((char *));
 #if 0 /* Suppressed - for now.  */
 #if defined OBJ_COFF || defined OBJ_ELF
 static void arm_add_note PARAMS ((const char *, const char *, unsigned int));
@@ -2867,7 +3040,7 @@ s_unreq (int a ATTRIBUTE_UNUSED)
              if (!req_entry)
                as_bad (_("unreq: missing hash entry for \"%s\""), name);
              else if (req_entry->builtin)
-               /* FIXME: We are deleteing a built in register alias which
+               /* 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
@@ -2876,7 +3049,7 @@ s_unreq (int a ATTRIBUTE_UNUSED)
                ;
              else
                {
-                 /* Deleteing a user defined alias.  We need to free the
+                 /* 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);
@@ -3871,7 +4044,6 @@ do_empty (str)
 {
   /* Do nothing really.  */
   end_of_line (str);
-  return;
 }
 
 static void
@@ -4055,7 +4227,6 @@ do_mull (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
@@ -4109,7 +4280,6 @@ do_mul (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
@@ -4165,7 +4335,6 @@ do_mla (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 /* Expects *str -> the characters "acc0", possibly with leading blanks.
@@ -4611,94 +4780,1038 @@ do_cdp2 (str)
          return;
        }
     }
-
+
+  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.  */
+
+static void
+do_co_reg2 (str)
+     char *        str;
+{
+  skip_whitespace (str);
+
+  if (co_proc_number (& str) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  if (skip_past_comma (& str) == FAIL
+      || cp_opc_expr (& str, 21, 3) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  if (skip_past_comma (& str) == FAIL
+      || 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;
+    }
+
+  if (skip_past_comma (& str) == FAIL
+      || cp_reg_required_here (& str, 0) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  if (skip_past_comma (& str) == SUCCESS)
+    {
+      if (cp_opc_expr (& str, 5, 3) == FAIL)
+       {
+         if (!inst.error)
+           inst.error = BAD_ARGS;
+         return;
+       }
+    }
+
+  end_of_line (str);
+}
+
+/* ARM v5TEJ.  Jump to Jazelle code.  */
+static void
+do_bxj (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 "bxj pc".  Useless, but not illegal.  */
+  if (reg == REG_PC)
+    as_tsktsk (_("use of r15 in bxj is not really useful"));
+
+  end_of_line (str);
+}
+
+/* ARM V6 umaal (argument parse). */
+
+static void
+do_umaal (str)
+     char *str;
+{
+
+  int rdlo, rdhi, rm, rs;
+
+  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)
+    {
+      inst.error = BAD_ARGS;
+      return;      
+    }
+
+  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 
+do_strex (str)
+     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;
+    }
+
+  /* Skip past '['. */
+  if ((strlen (str) >= 1) 
+      && strncmp (str, "[", 1) == 0)
+    str+=1;
+  skip_whitespace (str);  
+
+  /* Parse Rn. */
+  if ((rn = reg_required_here (& str, 16)) == FAIL)
+    {
+      inst.error = BAD_ARGS;
+      return;
+    }
+  else if (rn == REG_PC)
+    {
+      inst.error = BAD_PC;
+      return;
+    }
+  if (rd == rn)
+    {
+      inst.error = _("Rd equal to Rm or Rn yields unpredictable results");
+      return;
+    }
+  skip_whitespace (str);  
+
+  /* Skip past ']'. */
+  if ((strlen (str) >= 1) 
+      && strncmp (str, "]", 1) == 0)
+    str+=1;
+  
+  end_of_line (str);
+}
+
+/* ARM V6 ssat (argument parse). */
+
+static void
+do_ssat (str)
+     char* str;
+{
+  do_sat (&str, /*bias=*/-1);
+  end_of_line (str);
+}
+
+/* ARM V6 usat (argument parse). */
+
+static void
+do_usat (str)
+     char* str;
+{
+  do_sat (&str, /*bias=*/0);
+  end_of_line (str);
+}
+
+static void
+do_sat (str, bias)
+     char **str;
+     int    bias;
+{
+  int rd, rm;
+  expressionS expr;
+
+  skip_whitespace (*str);
+  
+  /* Parse <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))
+    {
+      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;
+    }
+
+  /* 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;
+    }
+
+  if (skip_past_comma (str) == SUCCESS)
+    decode_shift (str, SHIFT_LSL_OR_ASR_IMMEDIATE);
+}
+
+/* ARM V6 ssat16 (argument parse). */
+
+static void
+do_ssat16 (str)
+     char *str;
+{
+  do_sat16 (&str, /*bias=*/-1);
+  end_of_line (str);
+}
+
+static void
+do_usat16 (str)
+     char *str;
+{
+  do_sat16 (&str, /*bias=*/0);
+  end_of_line (str);
+}
+
+static void
+do_sat16 (str, bias)
+     char **str;
+     int bias;
+{
+  int rd, rm;
+  expressionS expr;
+
+  skip_whitespace (*str);
+
+  /* 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))
+    {
+      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 > 15)
+    {
+      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;
+    }
+
+  /* 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;
+    }
+}
+
+/* ARM V6 srs (argument parse). */
+
+static void
+do_srs (str)
+     char* str;
+{
+  char *exclam;
+  skip_whitespace (str);
+  exclam = strchr (str, '!');
+  if (exclam)
+    *exclam = '\0';
+  do_cps_mode (&str);
+  if (exclam)
+    *exclam = '!';
+  if (*str == '!') 
+    {
+      inst.instruction |= WRITE_BACK;
+      str++;
+    }
+  end_of_line (str);
+}
+
+/* ARM V6 SMMUL (argument parse). */
+
+static void
+do_smmul (str)
+     char* str;
+{
+  int rd, rm, rs;
+  
+  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;
+    }
+
+  if (rd == REG_PC 
+      || rm == REG_PC
+      || rs == REG_PC)
+    {
+      inst.error = BAD_PC;
+      return;
+    }
+
+  end_of_line (str);
+  
+}
+
+/* ARM V6 SMLALD (argument parse). */
+
+static void
+do_smlald (str)
+    char* str;
+{
+  int rdlo, rdhi, rm, rs;
+  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)
+    {
+      inst.error = BAD_ARGS;
+      return;
+    }
+
+  if (rdlo == REG_PC 
+      || rdhi == REG_PC 
+      || rm == REG_PC
+      || rs == REG_PC)
+    {
+      inst.error = BAD_PC;
+      return;
+    }
+
+  end_of_line (str);
+}
+
+/* ARM V6 SMLAD (argument parse).  Signed multiply accumulate dual. 
+   smlad{x}{<cond>} Rd, Rm, Rs, Rn */
+
+static void 
+do_smlad (str)
+     char *str;
+{
+  int rd, rm, rs, rn;
+  
+  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
+      || skip_past_comma (&str) == FAIL
+      || (rn = reg_required_here (&str, 12)) == FAIL)
+    {
+      inst.error = BAD_ARGS;
+      return;
+    }
+  
+  if (rd == REG_PC 
+      || rn == REG_PC 
+      || rs == REG_PC
+      || rm == REG_PC)
+    {
+      inst.error = BAD_PC;
+      return;
+    }
+
+  end_of_line (str);
+} 
+
+/* 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_setend (str)
+     char *str;
+{
+  if (do_endian_specifier (str))
+    inst.instruction |= 0x200;
+}
+
+/* Returns true if the endian-specifier indicates big-endianness.  */
+
+static int
+do_endian_specifier (str)
+     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)
+    {
+      str += 2;
+      big_endian = 1;
+    }
+  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;
+}
+
+/* ARM V6 SXTH.
+
+   SXTH {<cond>} <Rd>, <Rm>{, <rotation>}
+   Condition defaults to COND_ALWAYS.
+   Error if any register uses R15. */
+
+static void 
+do_sxth (str)
+     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 = BAD_ARGS;
+      return;
+    }
+
+  else if (rd == REG_PC || rm == REG_PC)
+    {
+      inst.error = BAD_PC;
+      return;
+    }
+  
+  /* Zero out the rotation field. */
+  inst.instruction &= rotation_clear_mask;
+  
+  /* Check for lack of optional rotation field. */
+  if (skip_past_comma (&str) == FAIL)
+    {
+      end_of_line (str);
+      return;
+    }
+  
+  /* Move past 'ROR'. */
+  skip_whitespace (str);
+  if (strncasecmp (str, "ROR", 3) == 0)
+    str+=3;
+  else
+    {
+      inst.error = _("missing rotation field after comma");
+      return;
+    }
+  
+  /* Get the immediate constant. */
+  skip_whitespace (str);
+  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;
+    }
+  
+  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);
+  
+}
+
+/* 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_sxtah (str)
+     char *str;
+{
+  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;
+  
+  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;
+    }
+
+  else if (rd == REG_PC || rn == REG_PC || rm == REG_PC)
+    {
+      inst.error = BAD_PC;
+      return;
+    }
+  
+  /* Zero out the rotation field. */
+  inst.instruction &= rotation_clear_mask;
+  
+  /* Check for lack of optional rotation field. */
+  if (skip_past_comma (&str) == FAIL)
+    {
+      end_of_line (str);
+      return;
+    }
+  
+  /* Move past 'ROR'. */
+  skip_whitespace (str);
+  if (strncasecmp (str, "ROR", 3) == 0)
+    str+=3;
+  else
+    {
+      inst.error = _("missing rotation field after comma");
+      return;
+    }
+  
+  /* Get the immediate constant. */
+  skip_whitespace (str);
+  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;
+    }
+  
+  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);
+  
+}
+   
+
+/* 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_rfe (str)
+     char *str;
+{
+  int rn;
+
+  skip_whitespace (str);
+  
+  if ((rn = reg_required_here (&str, 16)) == FAIL)
+    return;
+
+  if (rn == REG_PC)
+    {
+      inst.error = BAD_PC;
+      return;
+    }
+
+  skip_whitespace (str);
+  
+  if (*str == '!')
+    {
+      inst.instruction |= WRITE_BACK;
+      str++;
+    }
+  end_of_line (str);
+}
+
+/* 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 (str)
+     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 (str) 
+     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);
+}
+
+/* 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_pkhbt (str)
+     char* str;
+{
+  do_pkh_core (str, SHIFT_LSL_IMMEDIATE);
+}
+
+/* ARM V6 PKHTB (Argument Parse). */
+
+static void 
+do_pkhtb (str)
+     char* str;
+{
+  do_pkh_core (str, SHIFT_ASR_IMMEDIATE);
+}
+
+static void
+do_pkh_core (str, shift)
+     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;
+    }
+
+  else if (rd == REG_PC || rn == REG_PC || rm == REG_PC)
+    {
+      inst.error = BAD_PC;
+      return;
+    }
+
+  /* Check for optional shift immediate constant. */
+  if (skip_past_comma (&str) == FAIL) 
+    {
+      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;
+    }
+
+  decode_shift (&str, shift);
+}
+
+/* ARM V6 Load Register Exclusive instruction (argument parse).
+   LDREX{<cond>} <Rd, [<Rn>]
+   Condition defaults to COND_ALWAYS.
+   Error if Rd or Rn are R15. 
+   See ARMARMv6 A4.1.27: LDREX. */
+
+
+static void
+do_ldrex (str)
+     char * str;
+{
+  int rd, rn;
+
+  skip_whitespace (str);
+
+  /* Parse Rd. */
+  if (((rd = reg_required_here (&str, 12)) == FAIL)
+      || (skip_past_comma (&str) == FAIL))
+    {
+      inst.error = BAD_ARGS;
+      return;
+    }
+  else if (rd == REG_PC)
+    {
+      inst.error = BAD_PC;
+      return;
+    }
+  skip_whitespace (str);  
+
+  /* Skip past '['. */
+  if ((strlen (str) >= 1) 
+      &&strncmp (str, "[", 1) == 0)
+    str+=1;
+  skip_whitespace (str);  
+
+  /* Parse Rn. */
+  if ((rn = reg_required_here (&str, 16)) == FAIL)
+    {
+      inst.error = BAD_ARGS;
+      return;
+    }
+  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);
+}
+
+/* ARM V6 change processor state instruction (argument parse)
+      CPS, CPSIE, CSPID . */
+
+static void
+do_cps (str)
+     char * str;
+{
+  do_cps_mode (&str);
+  end_of_line (str);
+}
+
+static void
+do_cpsi (str)
+     char * str;
+{
+  do_cps_flags (&str, /*thumb_p=*/0);
+
+  if (skip_past_comma (&str) == SUCCESS)
+    {
+      skip_whitespace (str);
+      do_cps_mode (&str);
+    }
   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.  */
-
 static void
-do_co_reg2 (str)
-     char *        str;
+do_cps_mode (str)
+     char **str;
 {
-  skip_whitespace (str);
+  expressionS expr;
 
-  if (co_proc_number (& str) == FAIL)
-    {
-      if (!inst.error)
-       inst.error = BAD_ARGS;
-      return;
-    }
+  skip_whitespace (*str);
 
-  if (skip_past_comma (& str) == FAIL
-      || cp_opc_expr (& str, 21, 3) == FAIL)
+  if (! is_immediate_prefix (**str))
     {
-      if (!inst.error)
-       inst.error = BAD_ARGS;
+      inst.error = _("immediate expression expected");
       return;
     }
 
-  if (skip_past_comma (& str) == FAIL
-      || reg_required_here (& str, 12) == FAIL)
+  (*str)++; /* Strip off the immediate signifier. */
+  if (my_get_expression (&expr, str))
     {
-      if (!inst.error)
-       inst.error = BAD_ARGS;
+      inst.error = _("bad expression");
       return;
     }
 
-  if (skip_past_comma (& str) == FAIL
-      || cp_reg_required_here (& str, 16) == FAIL)
+  if (expr.X_op != O_constant)
     {
-      if (!inst.error)
-       inst.error = BAD_ARGS;
+      inst.error = _("constant expression expected");
       return;
     }
-
-  if (skip_past_comma (& str) == FAIL
-      || cp_reg_required_here (& str, 0) == FAIL)
+  
+  /* 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)
     {
-      if (!inst.error)
-       inst.error = BAD_ARGS;
+      inst.error = _("invalid constant");
       return;
     }
-
-  if (skip_past_comma (& str) == SUCCESS)
-    {
-      if (cp_opc_expr (& str, 5, 3) == FAIL)
-       {
-         if (!inst.error)
-           inst.error = BAD_ARGS;
-         return;
-       }
-    }
-
-  end_of_line (str);
+  
+  inst.instruction |= expr.X_add_number;
 }
 
-/* ARM v5TEJ.  Jump to Jazelle code.  */
 static void
-do_bxj (str)
-     char * str;
+do_cps_flags (str, thumb_p)
+     char **str;
+     int    thumb_p;
 {
-  int reg;
+  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 }
+  };
 
-  skip_whitespace (str);
+  int saw_a_flag = 0;
 
-  if ((reg = reg_required_here (&str, 0)) == FAIL)
+  skip_whitespace (*str);
+
+  /* Get the a, f and i flags. */
+  while (**str && **str != ',')
     {
-      inst.error = BAD_ARGS;
-      return;
+      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)++;
     }
-
-  /* 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"));
-
-  end_of_line (str);
+  if (!saw_a_flag) 
+    inst.error = _("no 'a', 'i', or 'f' flags for 'cps'");
 }
 
 /* THUMB V5 breakpoint instruction (argument parse)
@@ -4930,6 +6043,35 @@ do_bkpt (str)
   end_of_line (str);
 }
 
+/* THUMB CPS instruction (argument parse).  */
+
+static void
+do_t_cps (str)
+     char *str;
+{
+  do_cps_flags (&str, /*thumb_p=*/1);
+  end_of_line (str);
+}
+
+/* THUMB CPY instruction (argument parse).  */
+
+static void
+do_t_cpy (str)
+     char *str;
+{
+  thumb_mov_compare (str, THUMB_CPY);
+}
+
+/* THUMB SETEND instruction (argument parse).  */
+
+static void
+do_t_setend (str)
+     char *str;
+{
+  if (do_endian_specifier (str))
+    inst.instruction |= 0x8;
+}
+
 static unsigned long check_iwmmxt_insn PARAMS ((char *, enum iwmmxt_insn_type, int));
 
 /* Parse INSN_TYPE insn STR having a possible IMMEDIATE_SIZE immediate.  */
@@ -5158,7 +6300,6 @@ do_iwmmxt_tandc (str)
 
   if (reg != REG_PC && !inst.error)
     inst.error = _("only r15 allowed here");
-  return;
 }
 
 static void
@@ -5166,8 +6307,6 @@ do_iwmmxt_tbcst (str)
      char * str;
 {
   check_iwmmxt_insn (str, check_tbcst, 0);
-
-  return;
 }
 
 static void
@@ -5180,7 +6319,6 @@ do_iwmmxt_textrc (str)
     return;
 
   inst.instruction |= number & 0x7;
-  return;
 }
 
 static void
@@ -5205,7 +6343,6 @@ do_iwmmxt_tinsr (str)
     return;
 
   inst.instruction |= number & 0x7;
-  return;
 }
 
 static void
@@ -5213,8 +6350,6 @@ do_iwmmxt_tmcr (str)
      char * str;
 {
   check_iwmmxt_insn (str, check_tmcr, 0);
-
-  return;
 }
 
 static void
@@ -5222,8 +6357,6 @@ do_iwmmxt_tmcrr (str)
      char * str;
 {
   check_iwmmxt_insn (str, check_tmcrr, 0);
-
-  return;
 }
 
 static void
@@ -5231,8 +6364,6 @@ do_iwmmxt_tmia (str)
      char * str;
 {
   check_iwmmxt_insn (str, check_tmia, 0);
-
-  return;
 }
 
 static void
@@ -5240,8 +6371,6 @@ do_iwmmxt_tmovmsk (str)
      char * str;
 {
   check_iwmmxt_insn (str, check_tmovmsk, 0);
-
-  return;
 }
 
 static void
@@ -5249,8 +6378,6 @@ do_iwmmxt_tmrc (str)
      char * str;
 {
   check_iwmmxt_insn (str, check_tmrc, 0);
-
-  return;
 }
 
 static void
@@ -5258,8 +6385,6 @@ do_iwmmxt_tmrrc (str)
      char * str;
 {
   check_iwmmxt_insn (str, check_tmrrc, 0);
-
-  return;
 }
 
 static void
@@ -5267,7 +6392,6 @@ do_iwmmxt_torc (str)
      char * str;
 {
   check_iwmmxt_insn (str, check_rd, 0);
-  return;
 }
 
 static void
@@ -5280,7 +6404,6 @@ do_iwmmxt_waligni (str)
     return;
 
   inst.instruction |= ((number & 0x7) << 20);
-  return;
 }
 
 static void
@@ -5291,7 +6414,6 @@ do_iwmmxt_wmov (str)
     return;
   
   inst.instruction |= ((inst.instruction >> 16) & 0xf);
-  return;
 }
 
 static void
@@ -5332,8 +6454,6 @@ do_iwmmxt_wrwr (str)
      char * str;
 {
   check_iwmmxt_insn (str, check_wrwr, 0);
-  
-  return;
 }
 
 static void
@@ -5341,8 +6461,6 @@ do_iwmmxt_wrwrwcg (str)
      char * str;
 {
   check_iwmmxt_insn (str, check_wrwrwcg, 0);
-
-  return;
 }
 
 static void
@@ -5350,8 +6468,6 @@ do_iwmmxt_wrwrwr (str)
      char * str;
 {
   check_iwmmxt_insn (str, check_wrwrwr, 0);
-
-  return;
 }
 
 static void
@@ -5364,7 +6480,6 @@ do_iwmmxt_wshufh (str)
     return;
 
   inst.instruction |= ((number & 0xf0) << 16) | (number & 0xf);
-  return;
 }
 
 static void
@@ -5375,7 +6490,6 @@ do_iwmmxt_wzero (str)
     return;
 
   inst.instruction |= ((inst.instruction & 0xf) << 12) | ((inst.instruction & 0xf) << 16);
-  return;
 }
 
 /* Xscale multiply-accumulate (argument parse)
@@ -5777,13 +6891,12 @@ md_operand (expr)
     }
 }
 
-/* UNRESTRICT should be one if <shift> <register> is permitted for this
-   instruction.  */
+/* KIND indicates what kind of shifts are accepted.  */
 
 static int
-decode_shift (str, unrestrict)
+decode_shift (str, kind)
      char ** str;
-     int     unrestrict;
+     int     kind;
 {
   const struct asm_shift_name * shift;
   char * p;
@@ -5813,6 +6926,26 @@ decode_shift (str, unrestrict)
 
   assert (shift->properties->index == shift_properties[shift->properties->index].index);
 
+  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;
+    }
+    
   if (shift->properties->index == SHIFT_RRX)
     {
       * str = p;
@@ -5822,7 +6955,7 @@ decode_shift (str, unrestrict)
 
   skip_whitespace (p);
 
-  if (unrestrict && reg_required_here (& p, 8) != FAIL)
+  if (kind == NO_SHIFT_RESTRICT && reg_required_here (& p, 8) != FAIL)
     {
       inst.instruction |= shift->properties->bit_field | SHIFT_BY_REG;
       * str = p;
@@ -5830,7 +6963,7 @@ decode_shift (str, unrestrict)
     }
   else if (! is_immediate_prefix (* p))
     {
-      inst.error = (unrestrict
+      inst.error = (NO_SHIFT_RESTRICT
                    ? _("shift requires register or #expression")
                    : _("shift requires #expression"));
       * str = p;
@@ -6145,7 +7278,6 @@ do_arit (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
@@ -6168,7 +7300,9 @@ 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);
@@ -6199,11 +7333,11 @@ 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
@@ -6228,7 +7362,6 @@ do_cmp (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
@@ -6253,7 +7386,6 @@ do_mov (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static int
@@ -6309,7 +7441,7 @@ ldst_extend (str)
 
       inst.instruction |= add | OFFSET_REG;
       if (skip_past_comma (str) == SUCCESS)
-       return decode_shift (str, SHIFT_RESTRICT);
+       return decode_shift (str, SHIFT_IMMEDIATE);
 
       return SUCCESS;
     }
@@ -6504,7 +7636,6 @@ do_ldst (str)
 
   inst.instruction |= (pre_inc ? PRE_INDEX : 0);
   end_of_line (str);
-  return;
 }
 
 static void
@@ -6583,7 +7714,6 @@ do_ldstt (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static int
@@ -6839,7 +7969,6 @@ do_ldstv4 (str)
 
   inst.instruction |= (pre_inc ? PRE_INDEX : 0);
   end_of_line (str);
-  return;
 }
 
 static long
@@ -7036,7 +8165,6 @@ do_ldmstm (str)
 
   inst.instruction |= range;
   end_of_line (str);
-  return;
 }
 
 static void
@@ -7055,8 +8183,6 @@ do_swi (str)
   inst.reloc.type = BFD_RELOC_ARM_SWI;
   inst.reloc.pc_rel = 0;
   end_of_line (str);
-
-  return;
 }
 
 static void
@@ -7117,7 +8243,6 @@ do_swap (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
@@ -7162,7 +8287,6 @@ do_branch (str)
 #endif /* OBJ_ELF  */
 
   end_of_line (str);
-  return;
 }
 
 static void
@@ -7244,7 +8368,6 @@ do_cdp (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
@@ -7280,7 +8403,6 @@ do_lstc (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
@@ -7342,7 +8464,6 @@ do_co_reg (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
@@ -7362,7 +8483,6 @@ do_fpa_ctrl (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
@@ -7558,7 +8678,6 @@ do_fpa_dyadic (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
@@ -7583,7 +8702,6 @@ do_fpa_monadic (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
@@ -7608,7 +8726,6 @@ do_fpa_cmp (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
@@ -7633,7 +8750,6 @@ do_fpa_from_reg (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
@@ -7654,7 +8770,6 @@ do_fpa_to_reg (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static int
@@ -7753,7 +8868,6 @@ do_vfp_sp_monadic (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
@@ -7774,7 +8888,6 @@ do_vfp_dp_monadic (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
@@ -7797,7 +8910,6 @@ do_vfp_sp_dyadic (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
@@ -7820,7 +8932,6 @@ do_vfp_dp_dyadic (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
@@ -7841,19 +8952,16 @@ do_vfp_reg_from_sp (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
-do_vfp_sp_reg2 (str)
+do_vfp_reg2_from_sp2 (str)
      char *str;
 {
   skip_whitespace (str);
 
-  if (reg_required_here (&str, 12) == FAIL)
-    return;
-
-  if (skip_past_comma (&str) == FAIL
+  if (reg_required_here (&str, 12) == FAIL
+      || skip_past_comma (&str) == FAIL
       || reg_required_here (&str, 16) == FAIL
       || skip_past_comma (&str) == FAIL)
     {
@@ -7870,7 +8978,6 @@ do_vfp_sp_reg2 (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
@@ -7891,7 +8998,32 @@ do_vfp_sp_from_reg (str)
     }
 
   end_of_line (str);
-  return;
+}
+
+static void
+do_vfp_sp2_from_reg2 (str)
+     char *str;
+{
+  skip_whitespace (str);
+
+  /* We require exactly two consecutive SP registers.  */
+  if (vfp_sp_reg_list (&str, VFP_REG_Sm) != 2)
+    {
+      if (! inst.error)
+       inst.error = _("only two consecutive VFP SP registers allowed here");
+    }
+
+  if (skip_past_comma (&str) == 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;
+      return;
+    }
+
+  end_of_line (str);
 }
 
 static void
@@ -7912,7 +9044,6 @@ do_vfp_reg_from_dp (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
@@ -7935,7 +9066,6 @@ do_vfp_reg2_from_dp (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
@@ -7956,7 +9086,6 @@ do_vfp_dp_from_reg (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
@@ -7971,7 +9100,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;
@@ -7979,7 +9108,6 @@ do_vfp_dp_from_reg2 (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static const struct vfp_reg *
@@ -8058,7 +9186,6 @@ do_vfp_reg_from_ctrl (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
@@ -8079,7 +9206,6 @@ do_vfp_ctrl_from_reg (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
@@ -8104,7 +9230,6 @@ do_vfp_sp_ldst (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
@@ -8129,7 +9254,6 @@ do_vfp_dp_ldst (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 /* Parse and encode a VFP SP register list, storing the initial
@@ -8496,7 +9620,6 @@ do_vfp_sp_compare_z (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
@@ -8513,7 +9636,6 @@ do_vfp_dp_compare_z (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
@@ -8534,7 +9656,6 @@ do_vfp_dp_sp_cvt (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 static void
@@ -8555,7 +9676,6 @@ do_vfp_sp_dp_cvt (str)
     }
 
   end_of_line (str);
-  return;
 }
 
 /* Thumb specific routines.  */
@@ -8900,7 +10020,7 @@ thumb_mov_compare (str, move)
       return;
     }
 
-  if (is_immediate_prefix (*str))
+  if (move != THUMB_CPY && is_immediate_prefix (*str))
     {
       str++;
       if (my_get_expression (&inst.reloc.exp, &str))
@@ -8911,7 +10031,7 @@ thumb_mov_compare (str, move)
 
   if (Rs != FAIL)
     {
-      if (Rs < 8 && Rd < 8)
+      if (move != THUMB_CPY && Rs < 8 && Rd < 8)
        {
          if (move == THUMB_MOVE)
            /* A move of two lowregs is encoded as ADD Rd, Rs, #0
@@ -8925,7 +10045,7 @@ thumb_mov_compare (str, move)
        {
          if (move == THUMB_MOVE)
            inst.instruction = T_OPCODE_MOV_HR;
-         else
+         else if (move != THUMB_CPY)
            inst.instruction = T_OPCODE_CMP_HR;
 
          if (Rd > 7)
@@ -9814,7 +10934,6 @@ do_mav_ldst (str, reg0)
 fail_ldst:
   if (!inst.error)
      inst.error = BAD_ARGS;
-  return;
 }
 
 static void
@@ -9823,7 +10942,6 @@ do_t_nop (str)
 {
   /* Do nothing.  */
   end_of_line (str);
-  return;
 }
 
 /* Handle the Format 4 instructions that do not have equivalents in other
@@ -10197,7 +11315,6 @@ do_t_swi (str)
 
   inst.reloc.type = BFD_RELOC_ARM_SWI;
   end_of_line (str);
-  return;
 }
 
 static void
@@ -10576,17 +11693,28 @@ md_begin ()
     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;
+        || (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;
 
 #if defined OBJ_ELF
-    if (cpu_variant & ARM_CEXT_MAVERICK)
-      {
-       flags &= ~ F_SOFT_FLOAT;
+    if (cpu_variant & FPU_ARCH_MAVERICK)
        flags |= EF_ARM_MAVERICK_FLOAT;
-      }
 #endif
 
     bfd_set_private_flags (stdoutput, flags);
@@ -11695,6 +12823,16 @@ 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: OFFSET_IMM) not fixed up"));
       return NULL;
@@ -12188,6 +13326,7 @@ 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},
   {"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},
@@ -12197,13 +13336,16 @@ 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},
+  {"arm1136js",                ARM_ARCH_V6,     FPU_NONE},
+  {"arm1136jfs",       ARM_ARCH_V6,     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}
 };
 
@@ -12235,6 +13377,8 @@ 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},
   {"xscale",           ARM_ARCH_XSCALE, FPU_ARCH_VFP},
   {"iwmmxt",           ARM_ARCH_IWMMXT, FPU_ARCH_VFP},
   {NULL, 0, 0}
@@ -12282,6 +13426,22 @@ 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},
+  {"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}
 };
 
@@ -12431,6 +13591,23 @@ arm_parse_fpu (str)
   return 0;
 }
 
+static int
+arm_parse_float_abi (str)
+     char * str;
+{
+  struct arm_float_abi_option_table *opt;
+
+  for (opt = arm_float_abis; opt->name != NULL; opt++)
+    if (strcmp (opt->name, str) == 0)
+      {
+       mfloat_abi_opt = opt->value;
+       return 1;
+      }
+
+  as_bad (_("unknown floating point abi `%s'\n"), str);
+  return 0;
+}
+
 struct arm_long_option_table arm_long_opts[] =
 {
   {"mcpu=", N_("<cpu name>\t  assemble for CPU <cpu name>"),
@@ -12439,6 +13616,8 @@ 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},
   {NULL, NULL, 0, NULL}
 };
 
@@ -12584,8 +13763,6 @@ fix_new_arm (frag, where, size, exp, pc_rel, reloc)
   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.  */
This page took 0.056377 seconds and 4 git commands to generate.