import gdb-2000-02-02 snapshot
[external/binutils.git] / gas / config / tc-arm.c
index 31b06e3..86e3600 100644 (file)
@@ -52,6 +52,7 @@
 #define ARM_HALFWORD    0x00000020     /* allow half word loads */
 #define ARM_THUMB       0x00000040     /* allow BX instruction  */
 #define ARM_EXT_V5     0x00000080      /* allow CLZ etc         */
+#define ARM_EXT_V5E     0x00000200     /* "El Segundo"          */
 
 /* Architectures are the sum of the base and extensions */
 #define ARM_ARCH_V4    (ARM_7 | ARM_LONGMUL | ARM_HALFWORD)
@@ -138,10 +139,11 @@ CONST char FLT_CHARS[] = "rRsSfFdDxXeEpP";
 symbolS * GOT_symbol;          /* Pre-defined "_GLOBAL_OFFSET_TABLE_" */
 #endif
 
-CONST int md_reloc_size = 8;           /* Size of relocation record */
-
-static int thumb_mode = 0;      /* non-zero if assembling thumb instructions */
+CONST int md_reloc_size = 8;   /* Size of relocation record */
 
+static int thumb_mode = 0;      /* 0: assemble for ARM, 1: assemble for Thumb,
+                                  2: assemble for Thumb even though target cpu
+                                  does not support thumb instructions */
 typedef struct arm_fix
 {
   int thumb_mode;
@@ -439,6 +441,7 @@ static void do_mrs          PARAMS ((char *, unsigned long));
 static void do_mull            PARAMS ((char *, unsigned long));
 /* ARM THUMB */                                                      
 static void do_bx               PARAMS ((char *, unsigned long));
+
                                                              
 /* Coprocessor Instructions */                               
 static void do_cdp             PARAMS ((char *, unsigned long));
@@ -504,11 +507,16 @@ static bfd_reloc_code_real_type   arm_parse_reloc PARAMS ((void));
 
 #define LONGEST_INST 5
 
+
 struct asm_opcode 
 {
   CONST char *           template;     /* Basic string to match */
   unsigned long          value;                /* Basic instruction code */
-  CONST char *           comp_suffix;  /* Compulsory suffix that must follow conds */
+
+  /* Compulsory suffix that must follow conds. If "", then the
+     instruction is not conditional and must have no suffix. */
+  CONST char *           comp_suffix;  
+
   CONST struct asm_flg * flags;                /* Bits to toggle if flag 'n' set */
   unsigned long          variants;     /* Which CPU variants this exists for */
   /* Function to call to parse args */
@@ -770,68 +778,69 @@ struct thumb_opcode
   CONST char *  template;      /* Basic string to match */
   unsigned long value;         /* Basic instruction code */
   int           size;
+  unsigned long          variants;    /* Which CPU variants this exists for */
   void (*       parms) PARAMS ((char *));  /* Function to call to parse args */
 };
 
 static CONST struct thumb_opcode tinsns[] =
 {
-  {"adc",      0x4140,         2,      do_t_arit},
-  {"add",      0x0000,         2,      do_t_add},
-  {"and",      0x4000,         2,      do_t_arit},
-  {"asr",      0x0000,         2,      do_t_asr},
-  {"b",                T_OPCODE_BRANCH, 2,     do_t_branch12},
-  {"beq",      0xd0fe,         2,      do_t_branch9},
-  {"bne",      0xd1fe,         2,      do_t_branch9},
-  {"bcs",      0xd2fe,         2,      do_t_branch9},
-  {"bhs",      0xd2fe,         2,      do_t_branch9},
-  {"bcc",      0xd3fe,         2,      do_t_branch9},
-  {"bul",      0xd3fe,         2,      do_t_branch9},
-  {"blo",      0xd3fe,         2,      do_t_branch9},
-  {"bmi",      0xd4fe,         2,      do_t_branch9},
-  {"bpl",      0xd5fe,         2,      do_t_branch9},
-  {"bvs",      0xd6fe,         2,      do_t_branch9},
-  {"bvc",      0xd7fe,         2,      do_t_branch9},
-  {"bhi",      0xd8fe,         2,      do_t_branch9},
-  {"bls",      0xd9fe,         2,      do_t_branch9},
-  {"bge",      0xdafe,         2,      do_t_branch9},
-  {"blt",      0xdbfe,         2,      do_t_branch9},
-  {"bgt",      0xdcfe,         2,      do_t_branch9},
-  {"ble",      0xddfe,         2,      do_t_branch9},
-  {"bic",      0x4380,         2,      do_t_arit},
-  {"bl",       0xf7fffffe,     4,      do_t_branch23},
-  {"bx",       0x4700,         2,      do_t_bx},
-  {"cmn",      T_OPCODE_CMN,   2,      do_t_arit},
-  {"cmp",      0x0000,         2,      do_t_compare},
-  {"eor",      0x4040,         2,      do_t_arit},
-  {"ldmia",    0xc800,         2,      do_t_ldmstm},
-  {"ldr",      0x0000,         2,      do_t_ldr},
-  {"ldrb",     0x0000,         2,      do_t_ldrb},
-  {"ldrh",     0x0000,         2,      do_t_ldrh},
-  {"ldrsb",    0x5600,         2,      do_t_lds},
-  {"ldrsh",    0x5e00,         2,      do_t_lds},
-  {"ldsb",     0x5600,         2,      do_t_lds},
-  {"ldsh",     0x5e00,         2,      do_t_lds},
-  {"lsl",      0x0000,         2,      do_t_lsl},
-  {"lsr",      0x0000,         2,      do_t_lsr},
-  {"mov",      0x0000,         2,      do_t_mov},
-  {"mul",      T_OPCODE_MUL,   2,      do_t_arit},
-  {"mvn",      T_OPCODE_MVN,   2,      do_t_arit},
-  {"neg",      T_OPCODE_NEG,   2,      do_t_arit},
-  {"orr",      0x4300,         2,      do_t_arit},
-  {"pop",      0xbc00,         2,      do_t_push_pop},
-  {"push",     0xb400,         2,      do_t_push_pop},
-  {"ror",      0x41c0,         2,      do_t_arit},
-  {"sbc",      0x4180,         2,      do_t_arit},
-  {"stmia",    0xc000,         2,      do_t_ldmstm},
-  {"str",      0x0000,         2,      do_t_str},
-  {"strb",     0x0000,         2,      do_t_strb},
-  {"strh",     0x0000,         2,      do_t_strh},
-  {"swi",      0xdf00,         2,      do_t_swi},
-  {"sub",      0x0000,         2,      do_t_sub},
-  {"tst",      T_OPCODE_TST,   2,      do_t_arit},
+  {"adc",      0x4140,         2,      ARM_THUMB, do_t_arit},
+  {"add",      0x0000,         2,      ARM_THUMB, do_t_add},
+  {"and",      0x4000,         2,      ARM_THUMB, do_t_arit},
+  {"asr",      0x0000,         2,      ARM_THUMB, do_t_asr},
+  {"b",                T_OPCODE_BRANCH, 2,     ARM_THUMB, do_t_branch12},
+  {"beq",      0xd0fe,         2,      ARM_THUMB, do_t_branch9},
+  {"bne",      0xd1fe,         2,      ARM_THUMB, do_t_branch9},
+  {"bcs",      0xd2fe,         2,      ARM_THUMB, do_t_branch9},
+  {"bhs",      0xd2fe,         2,      ARM_THUMB, do_t_branch9},
+  {"bcc",      0xd3fe,         2,      ARM_THUMB, do_t_branch9},
+  {"bul",      0xd3fe,         2,      ARM_THUMB, do_t_branch9},
+  {"blo",      0xd3fe,         2,      ARM_THUMB, do_t_branch9},
+  {"bmi",      0xd4fe,         2,      ARM_THUMB, do_t_branch9},
+  {"bpl",      0xd5fe,         2,      ARM_THUMB, do_t_branch9},
+  {"bvs",      0xd6fe,         2,      ARM_THUMB, do_t_branch9},
+  {"bvc",      0xd7fe,         2,      ARM_THUMB, do_t_branch9},
+  {"bhi",      0xd8fe,         2,      ARM_THUMB, do_t_branch9},
+  {"bls",      0xd9fe,         2,      ARM_THUMB, do_t_branch9},
+  {"bge",      0xdafe,         2,      ARM_THUMB, do_t_branch9},
+  {"blt",      0xdbfe,         2,      ARM_THUMB, do_t_branch9},
+  {"bgt",      0xdcfe,         2,      ARM_THUMB, do_t_branch9},
+  {"ble",      0xddfe,         2,      ARM_THUMB, do_t_branch9},
+  {"bic",      0x4380,         2,      ARM_THUMB, do_t_arit},
+  {"bl",       0xf7fffffe,     4,      ARM_THUMB, do_t_branch23},
+  {"bx",       0x4700,         2,      ARM_THUMB, do_t_bx},
+  {"cmn",      T_OPCODE_CMN,   2,      ARM_THUMB, do_t_arit},
+  {"cmp",      0x0000,         2,      ARM_THUMB, do_t_compare},
+  {"eor",      0x4040,         2,      ARM_THUMB, do_t_arit},
+  {"ldmia",    0xc800,         2,      ARM_THUMB, do_t_ldmstm},
+  {"ldr",      0x0000,         2,      ARM_THUMB, do_t_ldr},
+  {"ldrb",     0x0000,         2,      ARM_THUMB, do_t_ldrb},
+  {"ldrh",     0x0000,         2,      ARM_THUMB, do_t_ldrh},
+  {"ldrsb",    0x5600,         2,      ARM_THUMB, do_t_lds},
+  {"ldrsh",    0x5e00,         2,      ARM_THUMB, do_t_lds},
+  {"ldsb",     0x5600,         2,      ARM_THUMB, do_t_lds},
+  {"ldsh",     0x5e00,         2,      ARM_THUMB, do_t_lds},
+  {"lsl",      0x0000,         2,      ARM_THUMB, do_t_lsl},
+  {"lsr",      0x0000,         2,      ARM_THUMB, do_t_lsr},
+  {"mov",      0x0000,         2,      ARM_THUMB, do_t_mov},
+  {"mul",      T_OPCODE_MUL,   2,      ARM_THUMB, do_t_arit},
+  {"mvn",      T_OPCODE_MVN,   2,      ARM_THUMB, do_t_arit},
+  {"neg",      T_OPCODE_NEG,   2,      ARM_THUMB, do_t_arit},
+  {"orr",      0x4300,         2,      ARM_THUMB, do_t_arit},
+  {"pop",      0xbc00,         2,      ARM_THUMB, do_t_push_pop},
+  {"push",     0xb400,         2,      ARM_THUMB, do_t_push_pop},
+  {"ror",      0x41c0,         2,      ARM_THUMB, do_t_arit},
+  {"sbc",      0x4180,         2,      ARM_THUMB, do_t_arit},
+  {"stmia",    0xc000,         2,      ARM_THUMB, do_t_ldmstm},
+  {"str",      0x0000,         2,      ARM_THUMB, do_t_str},
+  {"strb",     0x0000,         2,      ARM_THUMB, do_t_strb},
+  {"strh",     0x0000,         2,      ARM_THUMB, do_t_strh},
+  {"swi",      0xdf00,         2,      ARM_THUMB, do_t_swi},
+  {"sub",      0x0000,         2,      ARM_THUMB, do_t_sub},
+  {"tst",      T_OPCODE_TST,   2,      ARM_THUMB, do_t_arit},
   /* Pseudo ops: */
-  {"adr",       0x0000,         2,      do_t_adr},
-  {"nop",       0x46C0,         2,      do_t_nop},      /* mov r8,r8 */
+  {"adr",       0x0000,         2,      ARM_THUMB, do_t_adr},
+  {"nop",       0x46C0,         2,      ARM_THUMB, do_t_nop},      /* mov r8,r8 */
 };
 
 struct reg_entry
@@ -848,20 +857,22 @@ struct reg_entry
 #define REG_LR  14
 #define REG_SP  13
 
-/* These are the standard names;  Users can add aliases with .req */
+/* These are the standard names.  Users can add aliases with .req */
 static CONST struct reg_entry reg_table[] =
 {
-  /* Processor Register Numbers */
+  /* Processor Register Numbers */
   {"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},
-  /* APCS conventions */
+  /* APCS conventions */
   {"a1", 0},   {"a2", 1},    {"a3", 2},     {"a4", 3},
   {"v1", 4},   {"v2", 5},    {"v3", 6},     {"v4", 7},     {"v5", 8},
   {"v6", 9},   {"sb", 9},    {"v7", 10},    {"sl", 10},
   {"fp", 11},  {"ip", 12},   {"sp", REG_SP},{"lr", REG_LR},{"pc", REG_PC},
-  /* FP Registers */
+  /* ATPCS additions to APCS conventions.  */
+  {"wr", 7},    {"v8", 11},
+  /* FP Registers.  */
   {"f0", 16},   {"f1", 17},   {"f2", 18},   {"f3", 19},
   {"f4", 20},   {"f5", 21},   {"f6", 22},   {"f7", 23},
   {"c0", 32},   {"c1", 33},   {"c2", 34},   {"c3", 35},
@@ -872,11 +883,20 @@ static CONST struct reg_entry reg_table[] =
   {"cr4", 36},  {"cr5", 37},  {"cr6", 38},  {"cr7", 39},
   {"cr8", 40},  {"cr9", 41},  {"cr10", 42}, {"cr11", 43},
   {"cr12", 44}, {"cr13", 45}, {"cr14", 46}, {"cr15", 47},
+  /* ATPCS additions to float register names.  */
+  {"s0",16},   {"s1",17},      {"s2",18},      {"s3",19},
+  {"s4",20},   {"s5",21},      {"s6",22},      {"s7",23},
+  {"d0",16},   {"d1",17},      {"d2",18},      {"d3",19},
+  {"d4",20},   {"d5",21},      {"d6",22},      {"d7",23},
+  /* FIXME: At some point we need to add VFP register names.  */
+  /* Array terminator.  */
   {NULL, 0}
 };
 
-#define bad_args       _("Bad arguments to instruction");
-#define bad_pc                 _("r15 not allowed here");
+#define BAD_ARGS       _("Bad arguments to instruction")
+#define BAD_PC                 _("r15 not allowed here")
+#define BAD_FLAGS      _("Instruction should not have flags")
+#define BAD_COND       _("Instruction is not conditional")
 
 static struct hash_control * arm_ops_hsh = NULL;
 static struct hash_control * arm_tops_hsh = NULL;
@@ -1250,7 +1270,7 @@ s_force_thumb (ignore)
      
   if (! thumb_mode)
     {
-      thumb_mode = 1;
+      thumb_mode = 2;
       
       record_alignment (now_seg, 1);
     }
@@ -1359,7 +1379,7 @@ s_thumb_set (equiv)
   
   THUMB_SET_FUNC (symbolP, 1);
   ARM_SET_THUMB (symbolP, 1);
-#if defined OBJ_COFF || defined OBJ_ELF
+#if defined OBJ_ELF || defined OBJ_COFF
   ARM_SET_INTERWORK (symbolP, support_interwork);
 #endif
 }
@@ -1372,7 +1392,11 @@ arm_s_text (ignore)
   if (now_seg != text_section)
     s_ltorg (0);
   
+#ifdef OBJ_ELF
+  obj_elf_text (ignore);
+#else
   s_text (ignore);
+#endif
 }
 
 static void
@@ -1387,7 +1411,11 @@ arm_s_data (ignore)
   else if (now_seg != data_section)
     s_ltorg (0);
   
+#ifdef OBJ_ELF
+  obj_elf_data (ignore);
+#else
   s_data (ignore);
+#endif
 }
 
 #ifdef OBJ_ELF
@@ -1502,8 +1530,10 @@ skip_past_comma (str)
   return comma ? SUCCESS : FAIL;
 }
 
-/* A standard register must be given at this point.  Shift is the place to
-   put it in the instruction. */
+/* A standard 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
 reg_required_here (str, shift)
@@ -1840,7 +1870,7 @@ do_mrs (str, flags)
 
   if (reg_required_here (&str, 12) == FAIL)
     {
-      inst.error = bad_args;
+      inst.error = BAD_ARGS;
       return;
     }
 
@@ -1874,7 +1904,7 @@ do_msr (str, flags)
       if (skip_past_comma (&str) == FAIL
          || (reg = reg_required_here (&str, 0)) == FAIL)
        {
-         inst.error = bad_args;
+         inst.error = BAD_ARGS;
          return;
        }
     }
@@ -1886,13 +1916,13 @@ do_msr (str, flags)
        inst.instruction |= PSR_CONTROL;
       else
        {
-         inst.error = bad_args;
+         inst.error = BAD_ARGS;
          return;
        }
       
       if (skip_past_comma (&str) == FAIL)
        {
-         inst.error = bad_args;
+         inst.error = BAD_ARGS;
          return;
        }
       
@@ -1962,21 +1992,21 @@ do_mull (str, flags)
 
   if ((rdlo = reg_required_here (&str, 12)) == FAIL)
     {
-      inst.error = bad_args;
+      inst.error = BAD_ARGS;
       return;
     }
 
   if (skip_past_comma (&str) == FAIL
       || (rdhi = reg_required_here (&str, 16)) == FAIL)
     {
-      inst.error = bad_args;
+      inst.error = BAD_ARGS;
       return;
     }
 
   if (skip_past_comma (&str) == FAIL
       || (rm = reg_required_here (&str, 0)) == FAIL)
     {
-      inst.error = bad_args;
+      inst.error = BAD_ARGS;
       return;
     }
 
@@ -1987,13 +2017,13 @@ do_mull (str, flags)
   if (skip_past_comma (&str) == FAIL
       || (rs = reg_required_here (&str, 8)) == FAIL)
     {
-      inst.error = bad_args;
+      inst.error = BAD_ARGS;
       return;
     }
 
   if (rdhi == REG_PC || rdhi == REG_PC || rdhi == REG_PC || rdhi == REG_PC)
     {
-      inst.error = bad_pc;
+      inst.error = BAD_PC;
       return;
     }
    
@@ -2014,26 +2044,26 @@ do_mul (str, flags)
 
   if ((rd = reg_required_here (&str, 16)) == FAIL)
     {
-      inst.error = bad_args;
+      inst.error = BAD_ARGS;
       return;
     }
 
   if (rd == REG_PC)
     {
-      inst.error = bad_pc;
+      inst.error = BAD_PC;
       return;
     }
 
   if (skip_past_comma (&str) == FAIL
       || (rm = reg_required_here (&str, 0)) == FAIL)
     {
-      inst.error = bad_args;
+      inst.error = BAD_ARGS;
       return;
     }
 
   if (rm == REG_PC)
     {
-      inst.error = bad_pc;
+      inst.error = BAD_PC;
       return;
     }
 
@@ -2043,13 +2073,13 @@ do_mul (str, flags)
   if (skip_past_comma (&str) == FAIL
       || (rm = reg_required_here (&str, 8)) == FAIL)
     {
-      inst.error = bad_args;
+      inst.error = BAD_ARGS;
       return;
     }
 
   if (rm == REG_PC)
     {
-      inst.error = bad_pc;
+      inst.error = BAD_PC;
       return;
     }
 
@@ -2070,26 +2100,26 @@ do_mla (str, flags)
 
   if ((rd = reg_required_here (&str, 16)) == FAIL)
     {
-      inst.error = bad_args;
+      inst.error = BAD_ARGS;
       return;
     }
 
   if (rd == REG_PC)
     {
-      inst.error = bad_pc;
+      inst.error = BAD_PC;
       return;
     }
 
   if (skip_past_comma (&str) == FAIL
       || (rm = reg_required_here (&str, 0)) == FAIL)
     {
-      inst.error = bad_args;
+      inst.error = BAD_ARGS;
       return;
     }
 
   if (rm == REG_PC)
     {
-      inst.error = bad_pc;
+      inst.error = BAD_PC;
       return;
     }
 
@@ -2101,13 +2131,13 @@ do_mla (str, flags)
       || skip_past_comma (&str) == FAIL
       || (rm = reg_required_here (&str, 12)) == FAIL)
     {
-      inst.error = bad_args;
+      inst.error = BAD_ARGS;
       return;
     }
 
   if (rd == REG_PC || rm == REG_PC)
     {
-      inst.error = bad_pc;
+      inst.error = BAD_PC;
       return;
     }
 
@@ -2597,7 +2627,7 @@ do_arit (str, flags)
       || data_op2 (&str) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -2621,7 +2651,7 @@ do_adr (str, flags)
       || my_get_expression (&inst.reloc.exp, &str))
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
   /* Frag hacking will turn this into a sub instruction if the offset turns
@@ -2651,7 +2681,7 @@ do_adrl (str, flags)
       || my_get_expression (& inst.reloc.exp, & str))
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
   
@@ -2678,7 +2708,7 @@ do_cmp (str, flags)
   if (reg_required_here (&str, 16) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -2686,7 +2716,7 @@ do_cmp (str, flags)
       || data_op2 (&str) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -2708,7 +2738,7 @@ do_mov (str, flags)
   if (reg_required_here (&str, 12) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -2716,7 +2746,7 @@ do_mov (str, flags)
       || data_op2 (&str) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -2834,7 +2864,7 @@ do_ldst (str, flags)
   if ((conflict_reg = reg_required_here (& str, 12)) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3160,7 +3190,7 @@ do_ldmstm (str, flags)
       || (range = reg_list (&str)) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3220,7 +3250,7 @@ do_swap (str, flags)
       || (reg = reg_required_here (&str, 0)) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3233,7 +3263,7 @@ do_swap (str, flags)
   if (skip_past_comma (&str) == FAIL
       || *str++ != '[')
     {
-      inst.error = bad_args;
+      inst.error = BAD_ARGS;
       return;
     }
 
@@ -3244,7 +3274,7 @@ do_swap (str, flags)
 
   if (reg == REG_PC)
     {
-      inst.error = bad_pc;
+      inst.error = BAD_PC;
       return;
     }
 
@@ -3317,13 +3347,15 @@ do_bx (str, flags)
   skip_whitespace (str);
 
   if ((reg = reg_required_here (&str, 0)) == FAIL)
-    return;
+    {
+      inst.error = BAD_ARGS;
+      return;
+    }
 
   if (reg == REG_PC)
-    as_tsktsk (_("Use of r15 in bx has undefined behaviour"));
+    inst.error = BAD_PC;
 
   end_of_line (str);
-  return;
 }
 
 static void
@@ -3338,7 +3370,7 @@ do_cdp (str, flags)
   if (co_proc_number (&str) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3346,7 +3378,7 @@ do_cdp (str, flags)
       || cp_opc_expr (&str, 20,4) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3354,7 +3386,7 @@ do_cdp (str, flags)
       || cp_reg_required_here (&str, 12) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3362,7 +3394,7 @@ do_cdp (str, flags)
       || cp_reg_required_here (&str, 16) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3370,7 +3402,7 @@ do_cdp (str, flags)
       || cp_reg_required_here (&str, 0) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3379,7 +3411,7 @@ do_cdp (str, flags)
       if (cp_opc_expr (&str, 5, 3) == FAIL)
        {
          if (!inst.error)
-           inst.error = bad_args;
+           inst.error = BAD_ARGS;
          return;
        }
     }
@@ -3401,7 +3433,7 @@ do_lstc (str, flags)
   if (co_proc_number (&str) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3409,7 +3441,7 @@ do_lstc (str, flags)
       || cp_reg_required_here (&str, 12) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3417,7 +3449,7 @@ do_lstc (str, flags)
       || cp_address_required_here (&str) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3439,7 +3471,7 @@ do_co_reg (str, flags)
   if (co_proc_number (&str) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3447,7 +3479,7 @@ do_co_reg (str, flags)
       || cp_opc_expr (&str, 21, 3) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3455,7 +3487,7 @@ do_co_reg (str, flags)
       || reg_required_here (&str, 12) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3463,7 +3495,7 @@ do_co_reg (str, flags)
       || cp_reg_required_here (&str, 16) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3471,7 +3503,7 @@ do_co_reg (str, flags)
       || cp_reg_required_here (&str, 0) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3480,10 +3512,14 @@ do_co_reg (str, flags)
       if (cp_opc_expr (&str, 5, 3) == FAIL)
        {
          if (!inst.error)
-           inst.error = bad_args;
+           inst.error = BAD_ARGS;
          return;
        }
     }
+  if (flags)
+    {
+      inst.error = BAD_COND;
+    }
 
   end_of_line (str);
   return;
@@ -3502,7 +3538,7 @@ do_fp_ctrl (str, flags)
   if (reg_required_here (&str, 12) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3537,7 +3573,7 @@ do_fp_ldst (str, flags)
   if (fp_reg_required_here (&str, 12) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3545,7 +3581,7 @@ do_fp_ldst (str, flags)
       || cp_address_required_here (&str) == FAIL)
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3564,7 +3600,7 @@ do_fp_ldmstm (str, flags)
   if (fp_reg_required_here (&str, 12) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3622,7 +3658,7 @@ do_fp_ldmstm (str, flags)
          || *str != '[')
        {
          if (! inst.error)
-           inst.error = bad_args;
+           inst.error = BAD_ARGS;
          return;
        }
 
@@ -3636,7 +3672,7 @@ do_fp_ldmstm (str, flags)
 
       if (*str != ']')
        {
-         inst.error = bad_args;
+         inst.error = BAD_ARGS;
          return;
        }
 
@@ -3684,7 +3720,7 @@ do_fp_ldmstm (str, flags)
           || cp_address_required_here (&str) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3715,7 +3751,7 @@ do_fp_dyadic (str, flags)
   if (fp_reg_required_here (&str, 12) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3723,7 +3759,7 @@ do_fp_dyadic (str, flags)
       || fp_reg_required_here (&str, 16) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3731,7 +3767,7 @@ do_fp_dyadic (str, flags)
       || fp_op2 (&str) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3764,7 +3800,7 @@ do_fp_monadic (str, flags)
   if (fp_reg_required_here (&str, 12) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3772,7 +3808,7 @@ do_fp_monadic (str, flags)
       || fp_op2 (&str) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3791,7 +3827,7 @@ do_fp_cmp (str, flags)
   if (fp_reg_required_here (&str, 16) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3799,7 +3835,7 @@ do_fp_cmp (str, flags)
       || fp_op2 (&str) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3832,7 +3868,7 @@ do_fp_from_reg (str, flags)
   if (fp_reg_required_here (&str, 16) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3840,7 +3876,7 @@ do_fp_from_reg (str, flags)
       || reg_required_here (&str, 12) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3863,7 +3899,7 @@ do_fp_to_reg (str, flags)
       || fp_reg_required_here (&str, 0) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -3929,7 +3965,7 @@ thumb_add_sub (str, subtract)
       || skip_past_comma (&str) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -4096,7 +4132,7 @@ thumb_shift (str, shift)
       || skip_past_comma (&str) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -4205,7 +4241,7 @@ thumb_mov_compare (str, move)
       || skip_past_comma (&str) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -4294,7 +4330,7 @@ thumb_load_store (str, load_store, size)
       || skip_past_comma (&str) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -4499,15 +4535,12 @@ do_t_arit (str)
 
   skip_whitespace (str);
 
-  if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
-    return;
-
-  if (skip_past_comma (&str) == FAIL
+  if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL
+      || skip_past_comma (&str) == FAIL
       || (Rs = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
     {
-      if (! inst.error)
-       inst.error = bad_args;
-      return;
+       inst.error = BAD_ARGS;
+       return;
     }
 
   if (skip_past_comma (&str) != FAIL)
@@ -4520,7 +4553,7 @@ do_t_arit (str)
          || inst.instruction == T_OPCODE_NEG
          || inst.instruction == T_OPCODE_MVN)
        {
-         inst.error = bad_args;
+         inst.error = BAD_ARGS;
          return;
        }
 
@@ -4689,7 +4722,7 @@ do_t_ldmstm (str)
       || (range = reg_list (&str)) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -4789,7 +4822,7 @@ do_t_push_pop (str)
   if ((range = reg_list (&str)) == FAIL)
     {
       if (! inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -4877,7 +4910,7 @@ do_t_adr (str)
       || my_get_expression (&inst.reloc.exp, &str))
     {
       if (!inst.error)
-       inst.error = bad_args;
+       inst.error = BAD_ARGS;
       return;
     }
 
@@ -5323,7 +5356,8 @@ md_apply_fix3 (fixP, val, seg)
          && S_GET_SEGMENT (fixP->fx_addsy) != seg)
        {
          if (target_oabi
-             && fixP->fx_r_type == BFD_RELOC_ARM_PCREL_BRANCH)
+             && (fixP->fx_r_type == BFD_RELOC_ARM_PCREL_BRANCH
+               ))
            value = 0;
          else
            value += md_pcrel_from (fixP);
@@ -5521,6 +5555,7 @@ md_apply_fix3 (fixP, val, seg)
       md_number_to_chars (buf, newval, INSN_SIZE);
       break;
 
+
     case BFD_RELOC_THUMB_PCREL_BRANCH9: /* conditional branch */
       newval = md_chars_to_number (buf, THUMB_SIZE);
       {
@@ -6050,6 +6085,13 @@ md_assemble (str)
       
       if (opcode)
        {
+         /* Check that this instruction is supported for this CPU.  */
+         if (thumb_mode == 1 && (opcode->variants & cpu_variant) == 0)
+            {
+               as_bad (_("selected processor does not support this opcode"));
+               return;
+            }
+
          inst.instruction = opcode->value;
          inst.size = opcode->size;
          (*opcode->parms)(p);
@@ -6060,6 +6102,7 @@ md_assemble (str)
   else
     {
       CONST struct asm_opcode * opcode;
+      unsigned long cond_code;
 
       inst.size = INSN_SIZE;
       /* p now points to the end of the opcode, probably white space, but we
@@ -6086,11 +6129,18 @@ md_assemble (str)
              inst.instruction = opcode->value;
              if (q == p)               /* Just a simple opcode.  */
                {
-                 if (opcode->comp_suffix != 0)
-                   as_bad (_("Opcode `%s' must have suffix from <%s>\n"), str,
-                           opcode->comp_suffix);
+                 if (opcode->comp_suffix)
+                   {
+                      if (*opcode->comp_suffix != '\0')
+                        as_bad (_("Opcode `%s' must have suffix from list: <%s>"),
+                            str, opcode->comp_suffix);
+                      else
+                        /* Not a conditional instruction. */
+                        (*opcode->parms)(q, 0);
+                   }
                  else
                    {
+                     /* A conditional instruction with default condition. */
                      inst.instruction |= COND_ALWAYS;
                      (*opcode->parms)(q, 0);
                    }
@@ -6098,7 +6148,7 @@ md_assemble (str)
                  return;
                }
 
-             /* Now check for a conditional.  */
+             /* Not just a simple opcode.  Check if extra is a conditional. */
              r = q;
              if (p - r >= 2)
                {
@@ -6114,18 +6164,33 @@ md_assemble (str)
                        as_tsktsk (
 _("Warning: Use of the 'nv' conditional is deprecated\n"));
 
-                     inst.instruction |= cond->value;
+                     cond_code = cond->value;
                      r += 2;
                    }
                  else
-                   inst.instruction |= COND_ALWAYS;
+                   cond_code = COND_ALWAYS;
                }
              else
-               inst.instruction |= COND_ALWAYS;
+               cond_code = COND_ALWAYS;
+
+             /* Apply the conditional, or complain it's not allowed. */
+             if (opcode->comp_suffix && *opcode->comp_suffix == '\0')
+               {
+                  /* Instruction isn't conditional */
+                  if (cond_code != COND_ALWAYS)
+                    {
+                      as_bad (_("Opcode `%s' is unconditional\n"), str);
+                      return;
+                    }
+               }
+             else
+               /* Instruction is conditional: set the condition into it. */
+               inst.instruction |= cond_code;       
+
 
              /* If there is a compulsory suffix, it should come here, before
                 any optional flags.  */
-             if (opcode->comp_suffix)
+             if (opcode->comp_suffix && *opcode->comp_suffix != '\0')
                {
                  CONST char *s = opcode->comp_suffix;
 
@@ -6225,7 +6290,7 @@ _("Warning: Use of the 'nv' conditional is deprecated\n"));
              if (regnum != FAIL)
                insert_reg_alias (str, regnum);
              else
-               as_warn (_("register '%s' does not exist"), q);
+               as_warn (_("register '%s' does not exist\n"), q);
            }
          else if (regnum != FAIL)
            {
@@ -6262,7 +6327,7 @@ _("Warning: Use of the 'nv' conditional is deprecated\n"));
  *            -m[arm]8[10]            Arm 8 processors
  *            -m[arm]9[20][tdmi]      Arm 9 processors
  *            -mstrongarm[110[0]]     StrongARM processors
- *            -m[arm]v[2345]         Arm architecures
+ *            -m[arm]v[2345]         Arm architectures
  *            -mall                   All (except the ARM1)
  *    FP variants:
  *            -mfpa10, -mfpa11        FPA10 and 11 co-processor instructions
@@ -6351,7 +6416,8 @@ md_parse_option (c, arg)
             }
           else if (streq (str, "thumb-interwork"))
             {
-              cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_THUMB | ARM_ARCH_V4;
+             if ((cpu_variant & ARM_THUMB) == 0)
+               cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_ARCH_V4T;
 #if defined OBJ_COFF || defined OBJ_ELF
               support_interwork = true;
 #endif
@@ -6473,6 +6539,7 @@ md_parse_option (c, arg)
                case 70:
                case 700:
                case 710:
+               case 720:
                case 7100:
                case 7500:
                  break;
@@ -6529,6 +6596,7 @@ md_parse_option (c, arg)
              else
                goto bad;
              break;
+
              
            case 's':
              if (streq (str, "strongarm")
@@ -6573,13 +6641,13 @@ md_parse_option (c, arg)
                    default:  as_bad (_("Invalid architecture variant -m%s"), arg); break;
                    }
                  break;
-                 
+
                case '5':
                  cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_ARCH_V5;
-                 
                  switch (*++str)
                    {
                    case 't': cpu_variant |= ARM_THUMB; break;
+                   case 'e': cpu_variant |= ARM_EXT_V5E; break;
                    case 0:   break;
                    default:  as_bad (_("Invalid architecture variant -m%s"), arg); break;
                    }
@@ -6620,7 +6688,7 @@ md_show_usage (fp)
 _("\
  ARM Specific Assembler Options:\n\
   -m[arm][<processor name>] select processor variant\n\
-  -m[arm]v[2|2a|3|3m|4|4t|5]select architecture variant\n\
+  -m[arm]v[2|2a|3|3m|4|4t|5[t][e]] select architecture variant\n\
   -mthumb                   only allow Thumb instructions\n\
   -mthumb-interwork         mark the assembled code as supporting interworking\n\
   -mall                     allow any instruction\n\
@@ -6829,12 +6897,14 @@ arm_adjust_symtab ()
     {
       if (ARM_IS_THUMB (sym))
         {
+         elf_sym = elf_symbol (symbol_get_bfdsym (sym));
+         bind = ELF_ST_BIND (elf_sym);
+         
+         /* If it's a .thumb_func, declare it as so, else tag label as .code 16.  */
          if (THUMB_IS_FUNC (sym))
-           {
-             elf_sym = elf_symbol (symbol_get_bfdsym (sym));
-             bind = ELF_ST_BIND (elf_sym);
-             elf_sym->internal_elf_sym.st_info = ELF_ST_INFO (bind, STT_ARM_TFUNC);
-            }
+           elf_sym->internal_elf_sym.st_info = ELF_ST_INFO (bind, STT_ARM_TFUNC);
+         else
+           elf_sym->internal_elf_sym.st_info = ELF_ST_INFO (bind, STT_ARM_16BIT);
          }
      }
 #endif
@@ -6984,7 +7054,7 @@ arm_parse_reloc ()
     /* 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
+    { NULL, 0,         BFD_RELOC_UNUSED }
 #undef MAP    
   };