Support for VFP instructions
authorRichard Earnshaw <richard.earnshaw@arm.com>
Tue, 15 Jan 2002 16:05:34 +0000 (16:05 +0000)
committerRichard Earnshaw <richard.earnshaw@arm.com>
Tue, 15 Jan 2002 16:05:34 +0000 (16:05 +0000)
* tc-arm.c (CP_WB_OK, CP_NO_WB): New defines.
(cp_address_required_here): New argument wb_ok.  When false, do not
accept write-back forms of addressing.  Change all callers.
(FPU_VFP_EXT_NONE, FPU_VFP_EXT_V1xD, FPU_VFP_VFP_V1)
(FPU_VFP_EXT_V2): Define.
(FPU_ARCH_VFP, FPU_ARCH_VFP_V1xD, FPU_ARCH_VFP_V1, FPU_ARCH_VFP_V2):
Define in terms of above.
(vfp_dp_reg_pos, vfp_sp_reg_pos, vfp_ldstm_type): New enums.
(vfp_reg): New struct.
(vfp_regs): New array of registers.
(insns): Add VFP instructions.
(sn_table): New array of VFP single-precision register names.
(dn_table): New array of VFP double-precision register names.
(all_reg_maps): Add the new register tables.
(arm_reg_type): Add new values for above.  Increase RET_TYPE_MAX.
(vfp_sp_reg_required_here, vfp_dp_reg_required_here, do_vfp_sp_monadic)
(do_vfp_dp_monadic, do_vfp_sp_dyadic, do_vfp_dp_dyadic)
(do_vfp_reg_from_sp, do_vfp_sp_reg2, do_vfp_sp_from_reg)
(do_vfp_reg_from_dp, do_vfp_reg2_from_dp, do_vfp_dp_from_reg)
(do_vfp_dp_from_reg2, vfp_psr_parse, vfp_psr_required_here)
(do_vfp_reg_from_ctrl, do_vfp_ctrl_from_reg, do_vfp_sp_ldst)
(do_vfp_dp_ldst, vfp_sp_reg_list, vfp_dp_reg_list, vfp_sp_ldstm)
(vfp_dp_ldstm, do_vfp_sp_ldstmia, do_vfp_sp_ldstmdb, do_vfp_ldstmia)
(do_vfp_dp_ldstmdb, do_vfp_xp_ldstmia, do_vfp_xp_ldstmdb)
(do_vfp_sp_compare_z, do_vfp_dp_compare_z, do_vfp_dp_sp_cvt)
(do_vfp_sp_dp_cvt): New functions.
(md_begin): Set soft-float flag for appropriate VFP work.
(md_atof): Handle VFP-format doubles.
(md_parse_option): Handle VFP command-line options.
(md_show_usage): Display VFP command-line options.

* testsuite/gas/arm/vfp1.s gas/arm/vf1.d: New files.
* testsuite/gas/arm/vfp1xD.s gas/arm/vf1xD.d: New files.
* testsuite/gas/arm/vfp-bad.s gas/arm/vfp-bad.l: New files.
* testsuite/gas/arm/arm.exp: Run new VFP tests.

gas/ChangeLog
gas/config/tc-arm.c
gas/testsuite/ChangeLog
gas/testsuite/gas/arm/arm.exp
gas/testsuite/gas/arm/vfp-bad.l [new file with mode: 0644]
gas/testsuite/gas/arm/vfp-bad.s [new file with mode: 0644]
gas/testsuite/gas/arm/vfp1.d [new file with mode: 0644]
gas/testsuite/gas/arm/vfp1.s [new file with mode: 0644]
gas/testsuite/gas/arm/vfp1xD.d [new file with mode: 0644]
gas/testsuite/gas/arm/vfp1xD.s [new file with mode: 0644]

index 6dbefcc..a8df4d1 100644 (file)
@@ -1,5 +1,39 @@
 2002-01-15  Richard Earnshaw  <rearnsha@arm.com>
 
+       Support for VFP instructions
+       * tc-arm.c (CP_WB_OK, CP_NO_WB): New defines.
+       (cp_address_required_here): New argument wb_ok.  When false, do not
+       accept write-back forms of addressing.  Change all callers.
+       (FPU_VFP_EXT_NONE, FPU_VFP_EXT_V1xD, FPU_VFP_VFP_V1)
+       (FPU_VFP_EXT_V2): Define.
+       (FPU_ARCH_VFP, FPU_ARCH_VFP_V1xD, FPU_ARCH_VFP_V1, FPU_ARCH_VFP_V2):
+       Define in terms of above.
+       (vfp_dp_reg_pos, vfp_sp_reg_pos, vfp_ldstm_type): New enums.
+       (vfp_reg): New struct.
+       (vfp_regs): New array of registers.
+       (insns): Add VFP instructions.
+       (sn_table): New array of VFP single-precision register names.
+       (dn_table): New array of VFP double-precision register names.
+       (all_reg_maps): Add the new register tables.
+       (arm_reg_type): Add new values for above.  Increase RET_TYPE_MAX.
+       (vfp_sp_reg_required_here, vfp_dp_reg_required_here, do_vfp_sp_monadic)
+       (do_vfp_dp_monadic, do_vfp_sp_dyadic, do_vfp_dp_dyadic)
+       (do_vfp_reg_from_sp, do_vfp_sp_reg2, do_vfp_sp_from_reg)
+       (do_vfp_reg_from_dp, do_vfp_reg2_from_dp, do_vfp_dp_from_reg)
+       (do_vfp_dp_from_reg2, vfp_psr_parse, vfp_psr_required_here)
+       (do_vfp_reg_from_ctrl, do_vfp_ctrl_from_reg, do_vfp_sp_ldst)
+       (do_vfp_dp_ldst, vfp_sp_reg_list, vfp_dp_reg_list, vfp_sp_ldstm)
+       (vfp_dp_ldstm, do_vfp_sp_ldstmia, do_vfp_sp_ldstmdb, do_vfp_ldstmia)
+       (do_vfp_dp_ldstmdb, do_vfp_xp_ldstmia, do_vfp_xp_ldstmdb)
+       (do_vfp_sp_compare_z, do_vfp_dp_compare_z, do_vfp_dp_sp_cvt)
+       (do_vfp_sp_dp_cvt): New functions.
+       (md_begin): Set soft-float flag for appropriate VFP work.
+       (md_atof): Handle VFP-format doubles.
+       (md_parse_option): Handle VFP command-line options.
+       (md_show_usage): Display VFP command-line options.
+
+2002-01-15  Richard Earnshaw  <rearnsha@arm.com>
+
        * tc-arm.c (md_parse_option): Tidy up setting of cpu_variant for 
        various command line options.
 
index 40401cf..94b21cc 100644 (file)
 #define ARM_ANY                0x00ffffff
 #define ARM_ALL                ARM_ANY
 
-#define FPU_FPA_EXT_V1 0x80000000      /* Base FPA instruction set.  */
-#define FPU_FPA_EXT_V2 0x40000000      /* LFM/SFM.                   */
-#define FPU_NONE       0
+#define FPU_FPA_EXT_V1  0x80000000     /* Base FPA instruction set.  */
+#define FPU_FPA_EXT_V2  0x40000000     /* LFM/SFM.                   */
+#define FPU_VFP_EXT_NONE 0x20000000    /* Use VFP word-ordering.     */
+#define FPU_VFP_EXT_V1xD 0x10000000    /* Base VFP instruction set.  */
+#define FPU_VFP_EXT_V1  0x08000000     /* Double-precision insns.    */
+#define FPU_VFP_EXT_V2  0x04000000     /* ARM10E VFPr1.              */
+#define FPU_NONE        0
 
 #define FPU_ARCH_FPE    FPU_FPA_EXT_V1
 #define FPU_ARCH_FPA   (FPU_ARCH_FPE | FPU_FPA_EXT_V2)
 
+#define FPU_ARCH_VFP       FPU_VFP_EXT_NONE
+#define FPU_ARCH_VFP_V1xD (FPU_VFP_EXT_V1xD | FPU_VFP_EXT_NONE)
+#define FPU_ARCH_VFP_V1   (FPU_ARCH_VFP_V1xD | FPU_VFP_EXT_V1)
+#define FPU_ARCH_VFP_V2          (FPU_ARCH_VFP_V1 | FPU_VFP_EXT_V2)
+
 /* Some useful combinations.  */
 #define FPU_ANY                0xff000000      /* Note this is ~ARM_ANY.  */
 
 #endif
 #endif
 
+/* For backwards compatibility we default to the FPA.  */
 #ifndef FPU_DEFAULT
 #define FPU_DEFAULT FPU_ARCH_FPA
 #endif
@@ -264,6 +274,10 @@ LITTLENUM_TYPE fp_values[NUM_FLOAT_VALS][MAX_LITTLENUMS];
 #define FAIL   (-1)
 #define SUCCESS (0)
 
+/* Whether a Co-processor load/store operation accepts write-back forms.  */
+#define CP_WB_OK 1
+#define CP_NO_WB 0
+
 #define SUFF_S 1
 #define SUFF_D 2
 #define SUFF_E 3
@@ -468,6 +482,38 @@ static const struct asm_psr psrs[] =
   {"SPSR_cxsf",        false, PSR_c | PSR_x | PSR_s | PSR_f},
 };
 
+enum vfp_dp_reg_pos
+{
+  VFP_REG_Dd, VFP_REG_Dm, VFP_REG_Dn
+};
+
+enum vfp_sp_reg_pos
+{
+  VFP_REG_Sd, VFP_REG_Sm, VFP_REG_Sn
+};
+
+enum vfp_ldstm_type
+{
+  VFP_LDSTMIA, VFP_LDSTMDB, VFP_LDSTMIAX, VFP_LDSTMDBX
+};
+
+/* VFP system registers.  */
+struct vfp_reg
+{
+  const char *name;
+  unsigned long regno;
+};
+
+static const struct vfp_reg vfp_regs[] = 
+{
+  {"fpsid", 0x00000000},
+  {"FPSID", 0x00000000},
+  {"fpscr", 0x00010000},
+  {"FPSCR", 0x00010000},
+  {"fpexc", 0x00080000},
+  {"FPEXC", 0x00080000}
+};
+
 /* Structure for a hash table entry for a register.  */
 struct reg_entry
 {
@@ -532,6 +578,30 @@ static const struct reg_entry fn_table[] =
   {NULL, 0}
 };
 
+/* VFP SP Registers.  */
+static const struct reg_entry sn_table[] =
+{
+  {"s0",  0},  {"s1",  1},  {"s2",  2},         {"s3", 3},
+  {"s4",  4},  {"s5",  5},  {"s6",  6},         {"s7", 7},
+  {"s8",  8},  {"s9",  9},  {"s10", 10}, {"s11", 11},
+  {"s12", 12}, {"s13", 13}, {"s14", 14}, {"s15", 15},
+  {"s16", 16}, {"s17", 17}, {"s18", 18}, {"s19", 19},
+  {"s20", 20}, {"s21", 21}, {"s22", 22}, {"s23", 23},
+  {"s24", 24}, {"s25", 25}, {"s26", 26}, {"s27", 27},
+  {"s28", 28}, {"s29", 29}, {"s30", 30}, {"s31", 31},
+  {NULL, 0}
+};
+
+/* VFP DP Registers.  */
+static const struct reg_entry dn_table[] =
+{
+  {"d0",  0},  {"d1",  1},  {"d2",  2},         {"d3", 3},
+  {"d4",  4},  {"d5",  5},  {"d6",  6},         {"d7", 7},
+  {"d8",  8},  {"d9",  9},  {"d10", 10}, {"d11", 11},
+  {"d12", 12}, {"d13", 13}, {"d14", 14}, {"d15", 15},
+  {NULL, 0}
+};
+
 /* Cirrus DSP coprocessor registers.  */
 static const struct reg_entry mav_mvf_table[] =
 {
@@ -595,6 +665,8 @@ struct reg_map all_reg_maps[] =
   {cp_table,        15, NULL, N_("bad or missing co-processor number")},
   {cn_table,        15, NULL, N_("co-processor register expected")},
   {fn_table,         7, NULL, N_("FPA register expected")},
+  {sn_table,       31, NULL, N_("VFP single precision register expected")},
+  {dn_table,       15, NULL, N_("VFP double precision register expected")},
   {mav_mvf_table,   15, NULL, N_("Maverick MVF register expected")},
   {mav_mvd_table,   15, NULL, N_("Maverick MVD register expected")},
   {mav_mvfx_table,  15, NULL, N_("Maverick MVFX register expected")},
@@ -611,14 +683,16 @@ enum arm_reg_type
   REG_TYPE_CP = 1,
   REG_TYPE_CN = 2,
   REG_TYPE_FN = 3,
-  REG_TYPE_MVF = 4,
-  REG_TYPE_MVD = 5,
-  REG_TYPE_MVFX = 6,
-  REG_TYPE_MVDX = 7,
-  REG_TYPE_MVAX = 8,
-  REG_TYPE_DSPSC = 9,
-
-  REG_TYPE_MAX = 10
+  REG_TYPE_SN = 4,
+  REG_TYPE_DN = 5,
+  REG_TYPE_MVF = 6,
+  REG_TYPE_MVD = 7,
+  REG_TYPE_MVFX = 8,
+  REG_TYPE_MVDX = 9,
+  REG_TYPE_MVAX = 10,
+  REG_TYPE_DSPSC = 11,
+
+  REG_TYPE_MAX = 12
 };
 
 /* Functions called by parser.  */
@@ -691,6 +765,33 @@ static void do_fpa_cmp             PARAMS ((char *));
 static void do_fpa_from_reg    PARAMS ((char *));
 static void do_fpa_to_reg      PARAMS ((char *));
 
+/* VFP instructions.  */
+static void do_vfp_sp_monadic  PARAMS ((char *));
+static void do_vfp_dp_monadic  PARAMS ((char *));
+static void do_vfp_sp_dyadic   PARAMS ((char *));
+static void do_vfp_dp_dyadic   PARAMS ((char *));
+static void do_vfp_reg_from_sp  PARAMS ((char *));
+static void do_vfp_sp_from_reg  PARAMS ((char *));
+static void do_vfp_sp_reg2     PARAMS ((char *));
+static void do_vfp_reg_from_dp  PARAMS ((char *));
+static void do_vfp_reg2_from_dp PARAMS ((char *));
+static void do_vfp_dp_from_reg  PARAMS ((char *));
+static void do_vfp_dp_from_reg2 PARAMS ((char *));
+static void do_vfp_reg_from_ctrl PARAMS ((char *));
+static void do_vfp_ctrl_from_reg PARAMS ((char *));
+static void do_vfp_sp_ldst     PARAMS ((char *));
+static void do_vfp_dp_ldst     PARAMS ((char *));
+static void do_vfp_sp_ldstmia  PARAMS ((char *));
+static void do_vfp_sp_ldstmdb  PARAMS ((char *));
+static void do_vfp_dp_ldstmia  PARAMS ((char *));
+static void do_vfp_dp_ldstmdb  PARAMS ((char *));
+static void do_vfp_xp_ldstmia  PARAMS ((char *));
+static void do_vfp_xp_ldstmdb  PARAMS ((char *));
+static void do_vfp_sp_compare_z        PARAMS ((char *));
+static void do_vfp_dp_compare_z        PARAMS ((char *));
+static void do_vfp_dp_sp_cvt   PARAMS ((char *));
+static void do_vfp_sp_dp_cvt   PARAMS ((char *));
+
 /* XScale.  */
 static void do_mia             PARAMS ((char *));
 static void do_mar             PARAMS ((char *));
@@ -776,8 +877,16 @@ static int co_proc_number  PARAMS ((char **));
 static int cp_opc_expr         PARAMS ((char **, int, int));
 static int cp_reg_required_here        PARAMS ((char **, int));
 static int fp_reg_required_here        PARAMS ((char **, int));
+static int vfp_sp_reg_required_here PARAMS ((char **, enum vfp_sp_reg_pos));
+static int vfp_dp_reg_required_here PARAMS ((char **, enum vfp_dp_reg_pos));
+static void vfp_sp_ldstm       PARAMS ((char *, enum vfp_ldstm_type));
+static void vfp_dp_ldstm       PARAMS ((char *, enum vfp_ldstm_type));
+static long vfp_sp_reg_list    PARAMS ((char **, enum vfp_sp_reg_pos));
+static long vfp_dp_reg_list    PARAMS ((char **));
+static int vfp_psr_required_here PARAMS ((char **str));
+static const struct vfp_reg *vfp_psr_parse PARAMS ((char **str));
 static int cp_address_offset   PARAMS ((char **));
-static int cp_address_required_here    PARAMS ((char **));
+static int cp_address_required_here    PARAMS ((char **, int));
 static int my_get_float_expression     PARAMS ((char **));
 static int skip_past_comma     PARAMS ((char **));
 static int walk_no_bignums     PARAMS ((symbolS *));
@@ -1473,6 +1582,119 @@ static const struct asm_opcode insns[] =
   {"sfmfd",      0xed000200, 3,  FPU_FPA_EXT_V2,   do_fpa_ldmstm},
   {"sfmea",      0xec800200, 3,  FPU_FPA_EXT_V2,   do_fpa_ldmstm},
 
+  /* VFP V1xD (single precision).  */
+  /* Moves and type conversions.  */
+  {"fcpys",   0xeeb00a40, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
+  {"fmrs",    0xee100a10, 4, FPU_VFP_EXT_V1xD, do_vfp_reg_from_sp},
+  {"fmsr",    0xee000a10, 4, FPU_VFP_EXT_V1xD, do_vfp_sp_from_reg},
+  {"fmstat",  0xeef1fa10, 6, FPU_VFP_EXT_V1xD, do_empty},
+  {"fsitos",  0xeeb80ac0, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
+  {"fuitos",  0xeeb80a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
+  {"ftosis",  0xeebd0a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
+  {"ftosizs", 0xeebd0ac0, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
+  {"ftouis",  0xeebc0a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
+  {"ftouizs", 0xeebc0ac0, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
+  {"fmrx",    0xeef00a10, 4, FPU_VFP_EXT_V1xD, do_vfp_reg_from_ctrl},
+  {"fmxr",    0xeee00a10, 4, FPU_VFP_EXT_V1xD, do_vfp_ctrl_from_reg},
+
+  /* Memory operations.  */
+  {"flds",    0xed100a00, 4, FPU_VFP_EXT_V1xD, do_vfp_sp_ldst},
+  {"fsts",    0xed000a00, 4, FPU_VFP_EXT_V1xD, do_vfp_sp_ldst},
+  {"fldmias", 0xec900a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmia},
+  {"fldmfds", 0xec900a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmia},
+  {"fldmdbs", 0xed300a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmdb},
+  {"fldmeas", 0xed300a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmdb},
+  {"fldmiax", 0xec900b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmia},
+  {"fldmfdx", 0xec900b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmia},
+  {"fldmdbx", 0xed300b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmdb},
+  {"fldmeax", 0xed300b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmdb},
+  {"fstmias", 0xec800a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmia},
+  {"fstmeas", 0xec800a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmia},
+  {"fstmdbs", 0xed200a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmdb},
+  {"fstmfds", 0xed200a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmdb},
+  {"fstmiax", 0xec800b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmia},
+  {"fstmeax", 0xec800b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmia},
+  {"fstmdbx", 0xed200b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmdb},
+  {"fstmfdx", 0xed200b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmdb},
+
+  /* Monadic operations.  */
+  {"fabss",   0xeeb00ac0, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
+  {"fnegs",   0xeeb10a40, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
+  {"fsqrts",  0xeeb10ac0, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
+
+  /* Dyadic operations.  */
+  {"fadds",   0xee300a00, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
+  {"fsubs",   0xee300a40, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
+  {"fmuls",   0xee200a00, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
+  {"fdivs",   0xee800a00, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
+  {"fmacs",   0xee000a00, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
+  {"fmscs",   0xee100a00, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
+  {"fnmuls",  0xee200a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
+  {"fnmacs",  0xee000a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
+  {"fnmscs",  0xee100a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
+
+  /* Comparisons.  */
+  {"fcmps",   0xeeb40a40, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
+  {"fcmpzs",  0xeeb50a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_compare_z},
+  {"fcmpes",  0xeeb40ac0, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
+  {"fcmpezs", 0xeeb50ac0, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_compare_z},
+
+  /* VFP V1 (Double precision).  */
+  /* Moves and type conversions.  */
+  {"fcpyd",   0xeeb00b40, 5, FPU_VFP_EXT_V1,   do_vfp_dp_monadic},
+  {"fcvtds",  0xeeb70ac0, 6, FPU_VFP_EXT_V1,   do_vfp_dp_sp_cvt},
+  {"fcvtsd",  0xeeb70bc0, 6, FPU_VFP_EXT_V1,   do_vfp_sp_dp_cvt},
+  {"fmdhr",   0xee200b10, 5, FPU_VFP_EXT_V1,   do_vfp_dp_from_reg},
+  {"fmdlr",   0xee000b10, 5, FPU_VFP_EXT_V1,   do_vfp_dp_from_reg},
+  {"fmrdh",   0xee300b10, 5, FPU_VFP_EXT_V1,   do_vfp_reg_from_dp},
+  {"fmrdl",   0xee100b10, 5, FPU_VFP_EXT_V1,   do_vfp_reg_from_dp},
+  {"fsitod",  0xeeb80bc0, 6, FPU_VFP_EXT_V1,   do_vfp_dp_sp_cvt},
+  {"fuitod",  0xeeb80b40, 6, FPU_VFP_EXT_V1,   do_vfp_dp_sp_cvt},
+  {"ftosid",  0xeebd0b40, 6, FPU_VFP_EXT_V1,   do_vfp_sp_dp_cvt},
+  {"ftosizd", 0xeebd0bc0, 7, FPU_VFP_EXT_V1,   do_vfp_sp_dp_cvt},
+  {"ftouid",  0xeebc0b40, 6, FPU_VFP_EXT_V1,   do_vfp_sp_dp_cvt},
+  {"ftouizd", 0xeebc0bc0, 7, FPU_VFP_EXT_V1,   do_vfp_sp_dp_cvt},
+
+  /* Memory operations.  */
+  {"fldd",    0xed100b00, 4, FPU_VFP_EXT_V1,   do_vfp_dp_ldst},
+  {"fstd",    0xed000b00, 4, FPU_VFP_EXT_V1,   do_vfp_dp_ldst},
+  {"fldmiad", 0xec900b00, 7, FPU_VFP_EXT_V1,   do_vfp_dp_ldstmia},
+  {"fldmfdd", 0xec900b00, 7, FPU_VFP_EXT_V1,   do_vfp_dp_ldstmia},
+  {"fldmdbd", 0xed300b00, 7, FPU_VFP_EXT_V1,   do_vfp_dp_ldstmdb},
+  {"fldmead", 0xed300b00, 7, FPU_VFP_EXT_V1,   do_vfp_dp_ldstmdb},
+  {"fstmiad", 0xec800b00, 7, FPU_VFP_EXT_V1,   do_vfp_dp_ldstmia},
+  {"fstmead", 0xec800b00, 7, FPU_VFP_EXT_V1,   do_vfp_dp_ldstmia},
+  {"fstmdbd", 0xed200b00, 7, FPU_VFP_EXT_V1,   do_vfp_dp_ldstmdb},
+  {"fstmfdd", 0xed200b00, 7, FPU_VFP_EXT_V1,   do_vfp_dp_ldstmdb},
+
+  /* Monadic operations.  */
+  {"fabsd",   0xeeb00bc0, 5, FPU_VFP_EXT_V1,   do_vfp_dp_monadic},
+  {"fnegd",   0xeeb10b40, 5, FPU_VFP_EXT_V1,   do_vfp_dp_monadic},
+  {"fsqrtd",  0xeeb10bc0, 6, FPU_VFP_EXT_V1,   do_vfp_dp_monadic},
+
+  /* Dyadic operations.  */
+  {"faddd",   0xee300b00, 5, FPU_VFP_EXT_V1,   do_vfp_dp_dyadic},
+  {"fsubd",   0xee300b40, 5, FPU_VFP_EXT_V1,   do_vfp_dp_dyadic},
+  {"fmuld",   0xee200b00, 5, FPU_VFP_EXT_V1,   do_vfp_dp_dyadic},
+  {"fdivd",   0xee800b00, 5, FPU_VFP_EXT_V1,   do_vfp_dp_dyadic},
+  {"fmacd",   0xee000b00, 5, FPU_VFP_EXT_V1,   do_vfp_dp_dyadic},
+  {"fmscd",   0xee100b00, 5, FPU_VFP_EXT_V1,   do_vfp_dp_dyadic},
+  {"fnmuld",  0xee200b40, 6, FPU_VFP_EXT_V1,   do_vfp_dp_dyadic},
+  {"fnmacd",  0xee000b40, 6, FPU_VFP_EXT_V1,   do_vfp_dp_dyadic},
+  {"fnmscd",  0xee100b40, 6, FPU_VFP_EXT_V1,   do_vfp_dp_dyadic},
+
+  /* Comparisons.  */
+  {"fcmpd",   0xeeb40b40, 5, FPU_VFP_EXT_V1,   do_vfp_dp_monadic},
+  {"fcmpzd",  0xeeb50b40, 6, FPU_VFP_EXT_V1,   do_vfp_dp_compare_z},
+  {"fcmped",  0xeeb40bc0, 6, FPU_VFP_EXT_V1,   do_vfp_dp_monadic},
+  {"fcmpezd", 0xeeb50bc0, 7, FPU_VFP_EXT_V1,   do_vfp_dp_compare_z},
+
+  /* VFP V2.  */
+  {"fmsrr",   0xec400a10, 5, FPU_VFP_EXT_V2,   do_vfp_sp_reg2},
+  {"fmrrs",   0xec500a10, 5, FPU_VFP_EXT_V2,   do_vfp_sp_reg2},
+  {"fmdrr",   0xec400b10, 5, FPU_VFP_EXT_V2,   do_vfp_dp_from_reg2},
+  {"fmrrd",   0xec500b10, 5, FPU_VFP_EXT_V2,   do_vfp_reg2_from_dp},
+
   /* Intel XScale extensions to ARM V5 ISA.  (All use CP0).  */
   {"mia",        0xee200010, 3,  ARM_EXT_XSCALE,   do_mia},
   {"miaph",      0xee280010, 5,  ARM_EXT_XSCALE,   do_mia},
@@ -2723,8 +2945,9 @@ cp_address_offset (str)
 }
 
 static int
-cp_address_required_here (str)
+cp_address_required_here (str, wb_ok)
      char ** str;
+     int wb_ok;
 {
   char * p = * str;
   int    pre_inc = 0;
@@ -2746,7 +2969,7 @@ cp_address_required_here (str)
        {
          p++;
 
-         if (skip_past_comma (& p) == SUCCESS)
+         if (wb_ok && skip_past_comma (& p) == SUCCESS)
            {
              /* [Rn], #expr  */
              write_back = WRITE_BACK;
@@ -2788,7 +3011,7 @@ cp_address_required_here (str)
 
          skip_whitespace (p);
 
-         if (*p == '!')
+         if (wb_ok && *p == '!')
            {
              if (reg == REG_PC)
                {
@@ -3496,7 +3719,7 @@ do_lstc2 (str)
        inst.error = BAD_ARGS;
     }
   else if (skip_past_comma (& str) == FAIL
-          || cp_address_required_here (& str) == FAIL)
+          || cp_address_required_here (&str, CP_WB_OK) == FAIL)
     {
       if (! inst.error)
        inst.error = BAD_ARGS;
@@ -5724,7 +5947,7 @@ do_lstc (str)
     }
 
   if (skip_past_comma (&str) == FAIL
-      || cp_address_required_here (&str) == FAIL)
+      || cp_address_required_here (&str, CP_WB_OK) == FAIL)
     {
       if (! inst.error)
        inst.error = BAD_ARGS;
@@ -5831,7 +6054,7 @@ do_fpa_ldst (str)
     }
 
   if (skip_past_comma (&str) == FAIL
-      || cp_address_required_here (&str) == FAIL)
+      || cp_address_required_here (&str, CP_WB_OK) == FAIL)
     {
       if (!inst.error)
        inst.error = BAD_ARGS;
@@ -5970,7 +6193,7 @@ do_fpa_ldmstm (str)
       inst.instruction |= offset;
     }
   else if (skip_past_comma (&str) == FAIL
-          || cp_address_required_here (&str) == FAIL)
+          || cp_address_required_here (&str, CP_WB_OK) == FAIL)
     {
       if (! inst.error)
        inst.error = BAD_ARGS;
@@ -6109,178 +6332,1079 @@ do_fpa_to_reg (str)
   return;
 }
 
-/* Thumb specific routines.  */
-
-/* Parse and validate that a register is of the right form, this saves
-   repeated checking of this information in many similar cases.
-   Unlike the 32-bit case we do not insert the register into the opcode
-   here, since the position is often unknown until the full instruction
-   has been parsed.  */
-
 static int
-thumb_reg (strp, hi_lo)
-     char ** strp;
-     int     hi_lo;
+vfp_sp_reg_required_here (str, pos)
+     char **str;
+     enum vfp_sp_reg_pos pos;
 {
-  int reg;
-
-  if ((reg = reg_required_here (strp, -1)) == FAIL)
-    return FAIL;
+  int    reg;
+  char *start = *str;
 
-  switch (hi_lo)
+  if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_SN].htab)) != FAIL)
     {
-    case THUMB_REG_LO:
-      if (reg > 7)
+      switch (pos)
        {
-         inst.error = _("lo register required");
-         return FAIL;
+       case VFP_REG_Sd:
+         inst.instruction |= ((reg >> 1) << 12) | ((reg & 1) << 22);
+         break;
+
+       case VFP_REG_Sn:
+         inst.instruction |= ((reg >> 1) << 16) | ((reg & 1) << 7);
+         break;
+
+       case VFP_REG_Sm:
+         inst.instruction |= ((reg >> 1) << 0) | ((reg & 1) << 5);
+         break;
+
+       default:
+         abort ();
        }
-      break;
+      return reg;
+    }
 
-    case THUMB_REG_HI:
-      if (reg < 8)
+  /* In the few cases where we might be able to accept something else
+     this error can be overridden.  */
+  inst.error = _(all_reg_maps[REG_TYPE_SN].expected);
+
+  /* Restore the start point.  */
+  *str = start;
+  return FAIL;
+}
+
+static int
+vfp_dp_reg_required_here (str, pos)
+     char **str;
+     enum vfp_sp_reg_pos pos;
+{
+  int   reg;
+  char *start = *str;
+
+  if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_DN].htab)) != FAIL)
+    {
+      switch (pos)
        {
-         inst.error = _("hi register required");
-         return FAIL;
-       }
-      break;
+       case VFP_REG_Dd:
+         inst.instruction |= reg << 12;
+         break;
 
-    default:
-      break;
+       case VFP_REG_Dn:
+         inst.instruction |= reg << 16;
+         break;
+
+       case VFP_REG_Dm:
+         inst.instruction |= reg << 0;
+         break;
+
+       default:
+         abort ();
+       }
+      return reg;
     }
 
-  return reg;
-}
+  /* In the few cases where we might be able to accept something else
+     this error can be overridden.  */
+  inst.error = _(all_reg_maps[REG_TYPE_DN].expected);
 
-/* Parse an add or subtract instruction, SUBTRACT is non-zero if the opcode
-   was SUB.  */
+  /* Restore the start point.  */
+  *str = start;
+  return FAIL;
+}
 
 static void
-thumb_add_sub (str, subtract)
-     char * str;
-     int    subtract;
+do_vfp_sp_monadic (str)
+     char *str;
 {
-  int Rd, Rs, Rn = FAIL;
-
   skip_whitespace (str);
 
-  if ((Rd = thumb_reg (&str, THUMB_REG_ANY)) == FAIL
-      || skip_past_comma (&str) == FAIL)
+  if (vfp_sp_reg_required_here (&str, VFP_REG_Sd) == FAIL)
+    return;
+
+  if (skip_past_comma (&str) == FAIL
+      || vfp_sp_reg_required_here (&str, VFP_REG_Sm) == FAIL)
     {
       if (! inst.error)
        inst.error = BAD_ARGS;
       return;
     }
 
-  if (is_immediate_prefix (*str))
+  end_of_line (str);
+  return;
+}
+
+static void
+do_vfp_dp_monadic (str)
+     char *str;
+{
+  skip_whitespace (str);
+
+  if (vfp_dp_reg_required_here (&str, VFP_REG_Dd) == FAIL)
+    return;
+
+  if (skip_past_comma (&str) == FAIL
+      || vfp_dp_reg_required_here (&str, VFP_REG_Dm) == FAIL)
     {
-      Rs = Rd;
-      str++;
-      if (my_get_expression (&inst.reloc.exp, &str))
-       return;
+      if (! inst.error)
+       inst.error = BAD_ARGS;
+      return;
     }
-  else
-    {
-      if ((Rs = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
-       return;
 
-      if (skip_past_comma (&str) == FAIL)
-       {
-         /* Two operand format, shuffle the registers
-            and pretend there are 3.  */
-         Rn = Rs;
-         Rs = Rd;
-       }
-      else if (is_immediate_prefix (*str))
-       {
-         str++;
-         if (my_get_expression (&inst.reloc.exp, &str))
-           return;
-       }
-      else if ((Rn = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
-       return;
-    }
+  end_of_line (str);
+  return;
+}
 
-  /* We now have Rd and Rs set to registers, and Rn set to a register or FAIL;
-     for the latter case, EXPR contains the immediate that was found.  */
-  if (Rn != FAIL)
-    {
-      /* All register format.  */
-      if (Rd > 7 || Rs > 7 || Rn > 7)
-       {
-         if (Rs != Rd)
-           {
-             inst.error = _("dest and source1 must be the same register");
-             return;
-           }
+static void
+do_vfp_sp_dyadic (str)
+     char *str;
+{
+  skip_whitespace (str);
 
-         /* Can't do this for SUB.  */
-         if (subtract)
-           {
-             inst.error = _("subtract valid only on lo regs");
-             return;
-           }
+  if (vfp_sp_reg_required_here (&str, VFP_REG_Sd) == FAIL)
+    return;
 
-         inst.instruction = (T_OPCODE_ADD_HI
-                             | (Rd > 7 ? THUMB_H1 : 0)
-                             | (Rn > 7 ? THUMB_H2 : 0));
-         inst.instruction |= (Rd & 7) | ((Rn & 7) << 3);
-       }
-      else
-       {
-         inst.instruction = subtract ? T_OPCODE_SUB_R3 : T_OPCODE_ADD_R3;
-         inst.instruction |= Rd | (Rs << 3) | (Rn << 6);
-       }
-    }
-  else
+  if (skip_past_comma (&str) == FAIL
+      || vfp_sp_reg_required_here (&str, VFP_REG_Sn) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || vfp_sp_reg_required_here (&str, VFP_REG_Sm) == FAIL)
     {
-      /* Immediate expression, now things start to get nasty.  */
+      if (! inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
 
-      /* First deal with HI regs, only very restricted cases allowed:
-        Adjusting SP, and using PC or SP to get an address.  */
-      if ((Rd > 7 && (Rd != REG_SP || Rs != REG_SP))
-         || (Rs > 7 && Rs != REG_SP && Rs != REG_PC))
-       {
-         inst.error = _("invalid Hi register with immediate");
-         return;
-       }
+  end_of_line (str);
+  return;
+}
 
-      if (inst.reloc.exp.X_op != O_constant)
-       {
-         /* Value isn't known yet, all we can do is store all the fragments
-            we know about in the instruction and let the reloc hacking
-            work it all out.  */
-         inst.instruction = (subtract ? 0x8000 : 0) | (Rd << 4) | Rs;
-         inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
-       }
-      else
-       {
-         int offset = inst.reloc.exp.X_add_number;
+static void
+do_vfp_dp_dyadic (str)
+     char *str;
+{
+  skip_whitespace (str);
 
-         if (subtract)
-           offset = -offset;
+  if (vfp_dp_reg_required_here (&str, VFP_REG_Dd) == FAIL)
+    return;
 
-         if (offset < 0)
-           {
-             offset = -offset;
-             subtract = 1;
+  if (skip_past_comma (&str) == FAIL
+      || vfp_dp_reg_required_here (&str, VFP_REG_Dn) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || vfp_dp_reg_required_here (&str, VFP_REG_Dm) == FAIL)
+    {
+      if (! inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
 
-             /* Quick check, in case offset is MIN_INT.  */
-             if (offset < 0)
-               {
-                 inst.error = _("immediate value out of range");
-                 return;
-               }
-           }
-         else
-           subtract = 0;
+  end_of_line (str);
+  return;
+}
 
-         if (Rd == REG_SP)
-           {
-             if (offset & ~0x1fc)
-               {
-                 inst.error = _("invalid immediate value for stack adjust");
-                 return;
+static void
+do_vfp_reg_from_sp (str)
+     char *str;
+{
+  skip_whitespace (str);
+
+  if (reg_required_here (&str, 12) == FAIL)
+    return;
+
+  if (skip_past_comma (&str) == FAIL
+      || vfp_sp_reg_required_here (&str, VFP_REG_Sn) == FAIL)
+    {
+      if (! inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  end_of_line (str);
+  return;
+}
+
+static void
+do_vfp_sp_reg2 (str)
+     char *str;
+{
+  skip_whitespace (str);
+
+  if (reg_required_here (&str, 12) == FAIL)
+    return;
+
+  if (skip_past_comma (&str) == FAIL
+      || reg_required_here (&str, 16) == FAIL
+      || skip_past_comma (&str) == FAIL)
+    {
+      if (! inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  /* We require exactly two consecutive SP registers.  */
+  if (vfp_sp_reg_list (&str, VFP_REG_Sm) != 2)
+    {
+      if (! inst.error)
+       inst.error = _("only two consecutive VFP SP registers allowed here");
+    }
+
+  end_of_line (str);
+  return;
+}
+
+static void
+do_vfp_sp_from_reg (str)
+     char *str;
+{
+  skip_whitespace (str);
+
+  if (vfp_sp_reg_required_here (&str, VFP_REG_Sn) == FAIL)
+    return;
+
+  if (skip_past_comma (&str) == FAIL
+      || reg_required_here (&str, 12) == FAIL)
+    {
+      if (! inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  end_of_line (str);
+  return;
+}
+
+static void
+do_vfp_reg_from_dp (str)
+     char *str;
+{
+  skip_whitespace (str);
+
+  if (reg_required_here (&str, 12) == FAIL)
+    return;
+
+  if (skip_past_comma (&str) == FAIL
+      || vfp_dp_reg_required_here (&str, VFP_REG_Dn) == FAIL)
+    {
+      if (! inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  end_of_line (str);
+  return;
+}
+
+static void
+do_vfp_reg2_from_dp (str)
+     char *str;
+{
+  skip_whitespace (str);
+
+  if (reg_required_here (&str, 12) == FAIL)
+    return;
+
+  if (skip_past_comma (&str) == FAIL
+      || reg_required_here (&str, 16) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || vfp_dp_reg_required_here (&str, VFP_REG_Dm) == FAIL)
+    {
+      if (! inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  end_of_line (str);
+  return;
+}
+
+static void
+do_vfp_dp_from_reg (str)
+     char *str;
+{
+  skip_whitespace (str);
+
+  if (vfp_dp_reg_required_here (&str, VFP_REG_Dn) == FAIL)
+    return;
+
+  if (skip_past_comma (&str) == FAIL
+      || reg_required_here (&str, 12) == FAIL)
+    {
+      if (! inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  end_of_line (str);
+  return;
+}
+
+static void
+do_vfp_dp_from_reg2 (str)
+     char *str;
+{
+  skip_whitespace (str);
+
+  if (vfp_dp_reg_required_here (&str, VFP_REG_Dm) == FAIL)
+    return;
+
+  if (skip_past_comma (&str) == FAIL
+      || reg_required_here (&str, 12) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || reg_required_here (&str, 16))
+    {
+      if (! inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  end_of_line (str);
+  return;
+}
+
+static const struct vfp_reg *
+vfp_psr_parse (str)
+     char **str;
+{
+  char *start = *str;
+  char  c;
+  char *p;
+  const struct vfp_reg *vreg;
+
+  p = start;
+
+  /* Find the end of the current token.  */
+  do
+    {
+      c = *p++;
+    }
+  while (ISALPHA (c));
+
+  /* Mark it.  */
+  *--p = 0;
+
+  for (vreg = vfp_regs + 0; 
+       vreg < vfp_regs + sizeof (vfp_regs) / sizeof (struct vfp_reg);
+       vreg++)
+    {
+      if (strcmp (start, vreg->name) == 0)
+       {
+         *p = c;
+         *str = p;
+         return vreg;
+       }
+    }
+
+  *p = c;
+  return NULL;
+}
+
+static int
+vfp_psr_required_here (str)
+     char **str;
+{
+  char *start = *str;
+  const struct vfp_reg *vreg;
+
+  vreg = vfp_psr_parse (str);
+
+  if (vreg)
+    {
+      inst.instruction |= vreg->regno;
+      return SUCCESS;
+    }
+
+  inst.error = _("VFP system register expected");
+
+  *str = start;
+  return FAIL;
+}
+
+static void
+do_vfp_reg_from_ctrl (str)
+     char *str;
+{
+  skip_whitespace (str);
+
+  if (reg_required_here (&str, 12) == FAIL)
+    return;
+
+  if (skip_past_comma (&str) == FAIL
+      || vfp_psr_required_here (&str) == FAIL)
+    {
+      if (! inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  end_of_line (str);
+  return;
+}
+
+static void
+do_vfp_ctrl_from_reg (str)
+     char *str;
+{
+  skip_whitespace (str);
+
+  if (vfp_psr_required_here (&str) == FAIL)
+    return;
+
+  if (skip_past_comma (&str) == FAIL
+      || reg_required_here (&str, 12) == FAIL)
+    {
+      if (! inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  end_of_line (str);
+  return;
+}
+
+static void
+do_vfp_sp_ldst (str)
+     char *str;
+{
+  skip_whitespace (str);
+
+  if (vfp_sp_reg_required_here (&str, VFP_REG_Sd) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  if (skip_past_comma (&str) == FAIL
+      || cp_address_required_here (&str, CP_NO_WB) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  end_of_line (str);
+  return;
+}
+
+static void
+do_vfp_dp_ldst (str)
+     char *str;
+{
+  skip_whitespace (str);
+
+  if (vfp_dp_reg_required_here (&str, VFP_REG_Dd) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  if (skip_past_comma (&str) == FAIL
+      || cp_address_required_here (&str, CP_NO_WB) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  end_of_line (str);
+  return;
+}
+
+/* Parse and encode a VFP SP register list, storing the initial
+   register in position POS and returning the range as the result.  If
+   the string is invalid return FAIL (an invalid range).  */
+static long
+vfp_sp_reg_list (str, pos)
+     char **str;
+     enum vfp_sp_reg_pos pos;
+{
+  long range = 0;
+  int base_reg = 0;
+  int new_base;
+  long base_bits = 0;
+  int count = 0;
+  long tempinst;
+  unsigned long mask = 0;
+  int warned = 0;
+
+  if (**str != '{')
+    return FAIL;
+
+  (*str)++;
+  skip_whitespace (*str);
+
+  tempinst = inst.instruction;
+
+  do
+    {
+      inst.instruction = 0;
+
+      if ((new_base = vfp_sp_reg_required_here (str, pos)) == FAIL)
+       return FAIL;
+
+      if (count == 0 || base_reg > new_base)
+       {
+         base_reg = new_base;
+         base_bits = inst.instruction;
+       }
+
+      if (mask & (1 << new_base))
+       {
+         inst.error = _("invalid register list");
+         return FAIL;
+       }
+
+      if ((mask >> new_base) != 0 && ! warned)
+       {
+         as_tsktsk (_("register list not in ascending order"));
+         warned = 1;
+       }
+
+      mask |= 1 << new_base;
+      count++;
+
+      skip_whitespace (*str);
+
+      if (**str == '-') /* We have the start of a range expression */
+       {
+         int high_range;
+
+         (*str)++;
+
+         if ((high_range
+              = arm_reg_parse (str, all_reg_maps[REG_TYPE_SN].htab))
+             == FAIL)
+           {
+             inst.error = _(all_reg_maps[REG_TYPE_SN].expected);
+             return FAIL;
+           }
+
+         if (high_range <= new_base)
+           {
+             inst.error = _("register range not in ascending order");
+             return FAIL;
+           }
+
+         for (new_base++; new_base <= high_range; new_base++)
+           {
+             if (mask & (1 << new_base))
+               {
+                 inst.error = _("invalid register list");
+                 return FAIL;
+               }
+
+             mask |= 1 << new_base;
+             count++;
+           }
+       }
+    }
+  while (skip_past_comma (str) != FAIL);
+
+  if (**str != '}')
+    {
+      inst.error = _("invalid register list");
+      return FAIL;
+    }
+
+  (*str)++;
+
+  range = count;
+
+  /* Sanity check -- should have raised a parse error above.  */
+  if (count == 0 || count > 32)
+    abort();
+
+  /* Final test -- the registers must be consecutive.  */
+  while (count--)
+    {
+      if ((mask & (1 << base_reg++)) == 0)
+       {
+         inst.error = _("non-contiguous register range");
+         return FAIL;
+       }
+    }
+
+  inst.instruction = tempinst | base_bits;
+  return range;
+}
+
+static long
+vfp_dp_reg_list (str)
+     char **str;
+{
+  long range = 0;
+  int base_reg = 0;
+  int new_base;
+  int count = 0;
+  long tempinst;
+  unsigned long mask = 0;
+  int warned = 0;
+
+  if (**str != '{')
+    return FAIL;
+
+  (*str)++;
+  skip_whitespace (*str);
+
+  tempinst = inst.instruction;
+
+  do
+    {
+      inst.instruction = 0;
+
+      if ((new_base = vfp_dp_reg_required_here (str, VFP_REG_Dd)) == FAIL)
+       return FAIL;
+
+      if (count == 0 || base_reg > new_base)
+       {
+         base_reg = new_base;
+         range = inst.instruction;
+       }
+
+      if (mask & (1 << new_base))
+       {
+         inst.error = _("invalid register list");
+         return FAIL;
+       }
+
+      if ((mask >> new_base) != 0 && ! warned)
+       {
+         as_tsktsk (_("register list not in ascending order"));
+         warned = 1;
+       }
+
+      mask |= 1 << new_base;
+      count++;
+
+      skip_whitespace (*str);
+
+      if (**str == '-') /* We have the start of a range expression */
+       {
+         int high_range;
+
+         (*str)++;
+
+         if ((high_range
+              = arm_reg_parse (str, all_reg_maps[REG_TYPE_DN].htab))
+             == FAIL)
+           {
+             inst.error = _(all_reg_maps[REG_TYPE_DN].expected);
+             return FAIL;
+           }
+
+         if (high_range <= new_base)
+           {
+             inst.error = _("register range not in ascending order");
+             return FAIL;
+           }
+
+         for (new_base++; new_base <= high_range; new_base++)
+           {
+             if (mask & (1 << new_base))
+               {
+                 inst.error = _("invalid register list");
+                 return FAIL;
+               }
+
+             mask |= 1 << new_base;
+             count++;
+           }
+       }
+    }
+  while (skip_past_comma (str) != FAIL);
+
+  if (**str != '}')
+    {
+      inst.error = _("invalid register list");
+      return FAIL;
+    }
+
+  (*str)++;
+
+  range |= 2 * count;
+
+  /* Sanity check -- should have raised a parse error above.  */
+  if (count == 0 || count > 16)
+    abort();
+
+  /* Final test -- the registers must be consecutive.  */
+  while (count--)
+    {
+      if ((mask & (1 << base_reg++)) == 0)
+       {
+         inst.error = _("non-contiguous register range");
+         return FAIL;
+       }
+    }
+
+  inst.instruction = tempinst;
+  return range;
+}
+
+static void
+vfp_sp_ldstm(str, ldstm_type)
+     char *str;
+     enum vfp_ldstm_type ldstm_type;
+{
+  long range;
+
+  skip_whitespace (str);
+
+  if (reg_required_here (&str, 16) == FAIL)
+    return;
+
+  skip_whitespace (str);
+
+  if (*str == '!')
+    {
+      inst.instruction |= WRITE_BACK;
+      str++;
+    }
+  else if (ldstm_type != VFP_LDSTMIA)
+    {
+      inst.error = _("this addressing mode requires base-register writeback");
+      return;
+    }
+
+  if (skip_past_comma (&str) == FAIL
+      || (range = vfp_sp_reg_list (&str, VFP_REG_Sd)) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  inst.instruction |= range;
+  end_of_line (str);
+}
+
+static void
+vfp_dp_ldstm(str, ldstm_type)
+     char *str;
+     enum vfp_ldstm_type ldstm_type;
+{
+  long range;
+
+  skip_whitespace (str);
+
+  if (reg_required_here (&str, 16) == FAIL)
+    return;
+
+  skip_whitespace (str);
+
+  if (*str == '!')
+    {
+      inst.instruction |= WRITE_BACK;
+      str++;
+    }
+  else if (ldstm_type != VFP_LDSTMIA && ldstm_type != VFP_LDSTMIAX)
+    {
+      inst.error = _("this addressing mode requires base-register writeback");
+      return;
+    }
+
+  if (skip_past_comma (&str) == FAIL
+      || (range = vfp_dp_reg_list (&str)) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  if (ldstm_type == VFP_LDSTMIAX || ldstm_type == VFP_LDSTMDBX)
+    range += 1;
+
+  inst.instruction |= range;
+  end_of_line (str);
+}
+
+static void
+do_vfp_sp_ldstmia (str)
+     char *str;
+{
+  vfp_sp_ldstm (str, VFP_LDSTMIA);
+}
+
+static void
+do_vfp_sp_ldstmdb (str)
+     char *str;
+{
+  vfp_sp_ldstm (str, VFP_LDSTMDB);
+}
+
+static void
+do_vfp_dp_ldstmia (str)
+     char *str;
+{
+  vfp_dp_ldstm (str, VFP_LDSTMIA);
+}
+
+static void
+do_vfp_dp_ldstmdb (str)
+     char *str;
+{
+  vfp_dp_ldstm (str, VFP_LDSTMDB);
+}
+
+static void
+do_vfp_xp_ldstmia (str)
+     char *str;
+{
+  vfp_dp_ldstm (str, VFP_LDSTMIAX);
+}
+
+static void
+do_vfp_xp_ldstmdb (str)
+     char *str;
+{
+  vfp_dp_ldstm (str, VFP_LDSTMDBX);
+}
+
+static void
+do_vfp_sp_compare_z (str)
+     char *str;
+{
+  skip_whitespace (str);
+
+  if (vfp_sp_reg_required_here (&str, VFP_REG_Sd) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  end_of_line (str);
+  return;
+}
+
+static void
+do_vfp_dp_compare_z (str)
+     char *str;
+{
+  skip_whitespace (str);
+
+  if (vfp_dp_reg_required_here (&str, VFP_REG_Dd) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  end_of_line (str);
+  return;
+}
+
+static void
+do_vfp_dp_sp_cvt (str)
+     char *str;
+{
+  skip_whitespace (str);
+
+  if (vfp_dp_reg_required_here (&str, VFP_REG_Dd) == FAIL)
+    return;
+
+  if (skip_past_comma (&str) == FAIL
+      || vfp_sp_reg_required_here (&str, VFP_REG_Sm) == FAIL)
+    {
+      if (! inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  end_of_line (str);
+  return;
+}
+
+static void
+do_vfp_sp_dp_cvt (str)
+     char *str;
+{
+  skip_whitespace (str);
+
+  if (vfp_sp_reg_required_here (&str, VFP_REG_Sd) == FAIL)
+    return;
+
+  if (skip_past_comma (&str) == FAIL
+      || vfp_dp_reg_required_here (&str, VFP_REG_Dm) == FAIL)
+    {
+      if (! inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  end_of_line (str);
+  return;
+}
+
+/* Thumb specific routines.  */
+
+/* Parse and validate that a register is of the right form, this saves
+   repeated checking of this information in many similar cases.
+   Unlike the 32-bit case we do not insert the register into the opcode
+   here, since the position is often unknown until the full instruction
+   has been parsed.  */
+
+static int
+thumb_reg (strp, hi_lo)
+     char ** strp;
+     int     hi_lo;
+{
+  int reg;
+
+  if ((reg = reg_required_here (strp, -1)) == FAIL)
+    return FAIL;
+
+  switch (hi_lo)
+    {
+    case THUMB_REG_LO:
+      if (reg > 7)
+       {
+         inst.error = _("lo register required");
+         return FAIL;
+       }
+      break;
+
+    case THUMB_REG_HI:
+      if (reg < 8)
+       {
+         inst.error = _("hi register required");
+         return FAIL;
+       }
+      break;
+
+    default:
+      break;
+    }
+
+  return reg;
+}
+
+/* Parse an add or subtract instruction, SUBTRACT is non-zero if the opcode
+   was SUB.  */
+
+static void
+thumb_add_sub (str, subtract)
+     char * str;
+     int    subtract;
+{
+  int Rd, Rs, Rn = FAIL;
+
+  skip_whitespace (str);
+
+  if ((Rd = thumb_reg (&str, THUMB_REG_ANY)) == FAIL
+      || skip_past_comma (&str) == FAIL)
+    {
+      if (! inst.error)
+       inst.error = BAD_ARGS;
+      return;
+    }
+
+  if (is_immediate_prefix (*str))
+    {
+      Rs = Rd;
+      str++;
+      if (my_get_expression (&inst.reloc.exp, &str))
+       return;
+    }
+  else
+    {
+      if ((Rs = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
+       return;
+
+      if (skip_past_comma (&str) == FAIL)
+       {
+         /* Two operand format, shuffle the registers
+            and pretend there are 3.  */
+         Rn = Rs;
+         Rs = Rd;
+       }
+      else if (is_immediate_prefix (*str))
+       {
+         str++;
+         if (my_get_expression (&inst.reloc.exp, &str))
+           return;
+       }
+      else if ((Rn = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
+       return;
+    }
+
+  /* We now have Rd and Rs set to registers, and Rn set to a register or FAIL;
+     for the latter case, EXPR contains the immediate that was found.  */
+  if (Rn != FAIL)
+    {
+      /* All register format.  */
+      if (Rd > 7 || Rs > 7 || Rn > 7)
+       {
+         if (Rs != Rd)
+           {
+             inst.error = _("dest and source1 must be the same register");
+             return;
+           }
+
+         /* Can't do this for SUB.  */
+         if (subtract)
+           {
+             inst.error = _("subtract valid only on lo regs");
+             return;
+           }
+
+         inst.instruction = (T_OPCODE_ADD_HI
+                             | (Rd > 7 ? THUMB_H1 : 0)
+                             | (Rn > 7 ? THUMB_H2 : 0));
+         inst.instruction |= (Rd & 7) | ((Rn & 7) << 3);
+       }
+      else
+       {
+         inst.instruction = subtract ? T_OPCODE_SUB_R3 : T_OPCODE_ADD_R3;
+         inst.instruction |= Rd | (Rs << 3) | (Rn << 6);
+       }
+    }
+  else
+    {
+      /* Immediate expression, now things start to get nasty.  */
+
+      /* First deal with HI regs, only very restricted cases allowed:
+        Adjusting SP, and using PC or SP to get an address.  */
+      if ((Rd > 7 && (Rd != REG_SP || Rs != REG_SP))
+         || (Rs > 7 && Rs != REG_SP && Rs != REG_PC))
+       {
+         inst.error = _("invalid Hi register with immediate");
+         return;
+       }
+
+      if (inst.reloc.exp.X_op != O_constant)
+       {
+         /* Value isn't known yet, all we can do is store all the fragments
+            we know about in the instruction and let the reloc hacking
+            work it all out.  */
+         inst.instruction = (subtract ? 0x8000 : 0) | (Rd << 4) | Rs;
+         inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
+       }
+      else
+       {
+         int offset = inst.reloc.exp.X_add_number;
+
+         if (subtract)
+           offset = -offset;
+
+         if (offset < 0)
+           {
+             offset = -offset;
+             subtract = 1;
+
+             /* Quick check, in case offset is MIN_INT.  */
+             if (offset < 0)
+               {
+                 inst.error = _("immediate value out of range");
+                 return;
+               }
+           }
+         else
+           subtract = 0;
+
+         if (Rd == REG_SP)
+           {
+             if (offset & ~0x1fc)
+               {
+                 inst.error = _("invalid immediate value for stack adjust");
+                 return;
                }
              inst.instruction = subtract ? T_OPCODE_SUB_ST : T_OPCODE_ADD_ST;
              inst.instruction |= offset >> 2;
@@ -8014,7 +9138,9 @@ md_begin ()
     if (support_interwork) flags |= F_INTERWORK;
     if (uses_apcs_float)   flags |= F_APCS_FLOAT;
     if (pic_code)          flags |= F_PIC;
-    if ((cpu_variant & FPU_ANY) == FPU_NONE) flags |= F_SOFT_FLOAT;
+    if ((cpu_variant & FPU_ANY) == FPU_NONE
+       || (cpu_variant & FPU_ANY) == FPU_ARCH_VFP)
+      flags |= F_SOFT_FLOAT;
 
     bfd_set_private_flags (stdoutput, flags);
 
@@ -8201,14 +9327,21 @@ md_atof (type, litP, sizeP)
     }
   else
     {
-      /* For a 4 byte float the order of elements in `words' is 1 0.  For an
-        8 byte float the order is 1 0 3 2.  */
-      for (i = 0; i < prec; i += 2)
-       {
-         md_number_to_chars (litP, (valueT) words[i + 1], 2);
-         md_number_to_chars (litP + 2, (valueT) words[i], 2);
-         litP += 4;
-       }
+      if (cpu_variant & FPU_ARCH_VFP)
+       for (i = prec - 1; i >= 0; i--)
+         {
+           md_number_to_chars (litP, (valueT) words[i], 2);
+           litP += 2;
+         }
+      else
+       /* For a 4 byte float the order of elements in `words' is 1 0.
+          For an 8 byte float the order is 1 0 3 2.  */
+       for (i = 0; i < prec; i += 2)
+         {
+           md_number_to_chars (litP, (valueT) words[i + 1], 2);
+           md_number_to_chars (litP + 2, (valueT) words[i], 2);
+           litP += 4;
+         }
     }
 
   return 0;
@@ -9271,6 +10404,8 @@ md_assemble (str)
       FP variants:
               -mfpa10, -mfpa11        FPA10 and 11 co-processor instructions
               -mfpe-old               (No float load/store multiples)
+             -mvfpxd                 VFP Single precision
+             -mvfp                   All VFP
               -mno-fpu                Disable all floating point instructions
       Run-time endian selection:
               -EB                     big endian cpu
@@ -9378,6 +10513,15 @@ md_parse_option (c, arg)
            goto bad;
          break;
 
+       case 'v':
+         if (streq (str, "vfpxd"))
+           cpu_variant = (cpu_variant & ~FPU_ANY) | FPU_ARCH_VFP_V1xD;
+         else if (streq (str, "vfp"))
+           cpu_variant = (cpu_variant & ~FPU_ANY) | FPU_ARCH_VFP_V2;
+         else
+           goto bad;
+         break;
+
        default:
          if (streq (str, "all"))
            {
@@ -9676,6 +10820,8 @@ md_show_usage (fp)
   -mall                     allow any instruction\n\
   -mfpa10, -mfpa11          select floating point architecture\n\
   -mfpe-old                 don't allow floating-point multiple instructions\n\
+  -mvfpxd                   allow vfp single-precision instructions\n\
+  -mvfp                     allow all vfp instructions\n\
   -mno-fpu                  don't allow any floating-point instructions.\n\
   -k                        generate PIC code.\n"));
 #if defined OBJ_COFF || defined OBJ_ELF
index 3be0e11..d6481ae 100644 (file)
@@ -1,3 +1,10 @@
+2002-01-15   Richard Earnshaw  <rearnsha@arm.com>
+
+       * gas/arm/vfp1.s gas/arm/vf1.d: New files.
+       * gas/arm/vfp1xD.s gas/arm/vf1xD.d: New files.
+       * gas/arm/vfp-bad.s gas/arm/vfp-bad.l: New files.
+       * gas/arm/arm.exp: Run new VFP tests.
+
 2002-01-15  Nick Clifton  <nickc@cambridge.redhat.com>
 
        * gas/elf/section2.e-m32r: New file.
index 04ce07e..ef6fb01 100644 (file)
@@ -47,6 +47,12 @@ if {[istarget *arm*-*-*] || [istarget "xscale-*-*"]} then {
 
     run_dump_test "fpa-mem"
 
+    run_dump_test "vfp1xD"
+
+    run_dump_test "vfp1"
+
+    run_errors_test "vfp-bad" "-mvfp" "VFP errors"
+
     run_dump_test "xscale"
 
     run_dump_test "adrl"
diff --git a/gas/testsuite/gas/arm/vfp-bad.l b/gas/testsuite/gas/arm/vfp-bad.l
new file mode 100644 (file)
index 0000000..04bb04d
--- /dev/null
@@ -0,0 +1,9 @@
+[^:]*: Assembler messages:
+[^:]*:4: Error: garbage following instruction -- `fstd d0,\[r0\],#8'
+[^:]*:5: Error: garbage following instruction -- `fstd d0,\[r0,#-8\]!'
+[^:]*:6: Error: garbage following instruction -- `fsts s0,\[r0\],#8'
+[^:]*:7: Error: garbage following instruction -- `fsts s0,\[r0,#-8\]!'
+[^:]*:8: Error: garbage following instruction -- `fldd d0,\[r0\],#8'
+[^:]*:9: Error: garbage following instruction -- `fldd d0,\[r0,#-8\]!'
+[^:]*:10: Error: garbage following instruction -- `flds s0,\[r0\],#8'
+[^:]*:11: Error: garbage following instruction -- `flds s0,\[r0,#-8\]!'
diff --git a/gas/testsuite/gas/arm/vfp-bad.s b/gas/testsuite/gas/arm/vfp-bad.s
new file mode 100644 (file)
index 0000000..ac44371
--- /dev/null
@@ -0,0 +1,11 @@
+        .global entry
+        .text
+entry:
+       fstd    d0, [r0], #8
+       fstd    d0, [r0, #-8]!
+       fsts    s0, [r0], #8
+       fsts    s0, [r0, #-8]!
+       fldd    d0, [r0], #8
+       fldd    d0, [r0, #-8]!
+       flds    s0, [r0], #8
+       flds    s0, [r0, #-8]!
diff --git a/gas/testsuite/gas/arm/vfp1.d b/gas/testsuite/gas/arm/vfp1.d
new file mode 100644 (file)
index 0000000..9f37803
--- /dev/null
@@ -0,0 +1,190 @@
+#objdump: -dr --prefix-addresses --show-raw-insn
+#name: VFP Double-precision instructions
+#as: -mvfp
+
+# Test the ARM VFP Double Precision instructions
+
+.*: +file format .*arm.*
+
+Disassembly of section .text:
+0+000 <[^>]*> eeb40bc0         fcmped  d0, d0
+0+004 <[^>]*> eeb50bc0         fcmpezd d0
+0+008 <[^>]*> eeb40b40         fcmpd   d0, d0
+0+00c <[^>]*> eeb50b40         fcmpzd  d0
+0+010 <[^>]*> eeb00bc0         fabsd   d0, d0
+0+014 <[^>]*> eeb00b40         fcpyd   d0, d0
+0+018 <[^>]*> eeb10b40         fnegd   d0, d0
+0+01c <[^>]*> eeb10bc0         fsqrtd  d0, d0
+0+020 <[^>]*> ee300b00         faddd   d0, d0, d0
+0+024 <[^>]*> ee800b00         fdivd   d0, d0, d0
+0+028 <[^>]*> ee000b00         fmacd   d0, d0, d0
+0+02c <[^>]*> ee100b00         fmscd   d0, d0, d0
+0+030 <[^>]*> ee200b00         fmuld   d0, d0, d0
+0+034 <[^>]*> ee000b40         fnmacd  d0, d0, d0
+0+038 <[^>]*> ee100b40         fnmscd  d0, d0, d0
+0+03c <[^>]*> ee200b40         fnmuld  d0, d0, d0
+0+040 <[^>]*> ee300b40         fsubd   d0, d0, d0
+0+044 <[^>]*> ed900b00         fldd    d0, \[r0\]
+0+048 <[^>]*> ed800b00         fstd    d0, \[r0\]
+0+04c <[^>]*> ec900b02         fldmiad r0, {d0}
+0+050 <[^>]*> ec900b02         fldmiad r0, {d0}
+0+054 <[^>]*> ecb00b02         fldmiad r0!, {d0}
+0+058 <[^>]*> ecb00b02         fldmiad r0!, {d0}
+0+05c <[^>]*> ed300b02         fldmdbd r0!, {d0}
+0+060 <[^>]*> ed300b02         fldmdbd r0!, {d0}
+0+064 <[^>]*> ec800b02         fstmiad r0, {d0}
+0+068 <[^>]*> ec800b02         fstmiad r0, {d0}
+0+06c <[^>]*> eca00b02         fstmiad r0!, {d0}
+0+070 <[^>]*> eca00b02         fstmiad r0!, {d0}
+0+074 <[^>]*> ed200b02         fstmdbd r0!, {d0}
+0+078 <[^>]*> ed200b02         fstmdbd r0!, {d0}
+0+07c <[^>]*> eeb80bc0         fsitod  d0, s0
+0+080 <[^>]*> eeb80b40         fuitod  d0, s0
+0+084 <[^>]*> eebd0b40         ftosid  s0, d0
+0+088 <[^>]*> eebd0bc0         ftosizd s0, d0
+0+08c <[^>]*> eebc0b40         ftouid  s0, d0
+0+090 <[^>]*> eebc0bc0         ftouizd s0, d0
+0+094 <[^>]*> eeb70ac0         fcvtds  d0, s0
+0+098 <[^>]*> eeb70bc0         fcvtsd  s0, d0
+0+09c <[^>]*> ee300b10         fmrdh   r0, d0
+0+0a0 <[^>]*> ee100b10         fmrdl   r0, d0
+0+0a4 <[^>]*> ee200b10         fmdhr   d0, r0
+0+0a8 <[^>]*> ee000b10         fmdlr   d0, r0
+0+0ac <[^>]*> eeb51b40         fcmpzd  d1
+0+0b0 <[^>]*> eeb52b40         fcmpzd  d2
+0+0b4 <[^>]*> eeb5fb40         fcmpzd  d15
+0+0b8 <[^>]*> eeb40b41         fcmpd   d0, d1
+0+0bc <[^>]*> eeb40b42         fcmpd   d0, d2
+0+0c0 <[^>]*> eeb40b4f         fcmpd   d0, d15
+0+0c4 <[^>]*> eeb41b40         fcmpd   d1, d0
+0+0c8 <[^>]*> eeb42b40         fcmpd   d2, d0
+0+0cc <[^>]*> eeb4fb40         fcmpd   d15, d0
+0+0d0 <[^>]*> eeb45b4c         fcmpd   d5, d12
+0+0d4 <[^>]*> eeb10b41         fnegd   d0, d1
+0+0d8 <[^>]*> eeb10b42         fnegd   d0, d2
+0+0dc <[^>]*> eeb10b4f         fnegd   d0, d15
+0+0e0 <[^>]*> eeb11b40         fnegd   d1, d0
+0+0e4 <[^>]*> eeb12b40         fnegd   d2, d0
+0+0e8 <[^>]*> eeb1fb40         fnegd   d15, d0
+0+0ec <[^>]*> eeb1cb45         fnegd   d12, d5
+0+0f0 <[^>]*> ee300b01         faddd   d0, d0, d1
+0+0f4 <[^>]*> ee300b02         faddd   d0, d0, d2
+0+0f8 <[^>]*> ee300b0f         faddd   d0, d0, d15
+0+0fc <[^>]*> ee310b00         faddd   d0, d1, d0
+0+100 <[^>]*> ee320b00         faddd   d0, d2, d0
+0+104 <[^>]*> ee3f0b00         faddd   d0, d15, d0
+0+108 <[^>]*> ee301b00         faddd   d1, d0, d0
+0+10c <[^>]*> ee302b00         faddd   d2, d0, d0
+0+110 <[^>]*> ee30fb00         faddd   d15, d0, d0
+0+114 <[^>]*> ee39cb05         faddd   d12, d9, d5
+0+118 <[^>]*> eeb70ae0         fcvtds  d0, s1
+0+11c <[^>]*> eeb70ac1         fcvtds  d0, s2
+0+120 <[^>]*> eeb70aef         fcvtds  d0, s31
+0+124 <[^>]*> eeb71ac0         fcvtds  d1, s0
+0+128 <[^>]*> eeb72ac0         fcvtds  d2, s0
+0+12c <[^>]*> eeb7fac0         fcvtds  d15, s0
+0+130 <[^>]*> eef70bc0         fcvtsd  s1, d0
+0+134 <[^>]*> eeb71bc0         fcvtsd  s2, d0
+0+138 <[^>]*> eef7fbc0         fcvtsd  s31, d0
+0+13c <[^>]*> eeb70bc1         fcvtsd  s0, d1
+0+140 <[^>]*> eeb70bc2         fcvtsd  s0, d2
+0+144 <[^>]*> eeb70bcf         fcvtsd  s0, d15
+0+148 <[^>]*> ee301b10         fmrdh   r1, d0
+0+14c <[^>]*> ee30eb10         fmrdh   lr, d0
+0+150 <[^>]*> ee310b10         fmrdh   r0, d1
+0+154 <[^>]*> ee320b10         fmrdh   r0, d2
+0+158 <[^>]*> ee3f0b10         fmrdh   r0, d15
+0+15c <[^>]*> ee101b10         fmrdl   r1, d0
+0+160 <[^>]*> ee10eb10         fmrdl   lr, d0
+0+164 <[^>]*> ee110b10         fmrdl   r0, d1
+0+168 <[^>]*> ee120b10         fmrdl   r0, d2
+0+16c <[^>]*> ee1f0b10         fmrdl   r0, d15
+0+170 <[^>]*> ee201b10         fmdhr   d0, r1
+0+174 <[^>]*> ee20eb10         fmdhr   d0, lr
+0+178 <[^>]*> ee210b10         fmdhr   d1, r0
+0+17c <[^>]*> ee220b10         fmdhr   d2, r0
+0+180 <[^>]*> ee2f0b10         fmdhr   d15, r0
+0+184 <[^>]*> ee001b10         fmdlr   d0, r1
+0+188 <[^>]*> ee00eb10         fmdlr   d0, lr
+0+18c <[^>]*> ee010b10         fmdlr   d1, r0
+0+190 <[^>]*> ee020b10         fmdlr   d2, r0
+0+194 <[^>]*> ee0f0b10         fmdlr   d15, r0
+0+198 <[^>]*> ed910b00         fldd    d0, \[r1\]
+0+19c <[^>]*> ed9e0b00         fldd    d0, \[lr\]
+0+1a0 <[^>]*> ed900b00         fldd    d0, \[r0\]
+0+1a4 <[^>]*> ed900bff         fldd    d0, \[r0, #1020\]
+0+1a8 <[^>]*> ed100bff         fldd    d0, \[r0, -#1020\]
+0+1ac <[^>]*> ed901b00         fldd    d1, \[r0\]
+0+1b0 <[^>]*> ed902b00         fldd    d2, \[r0\]
+0+1b4 <[^>]*> ed90fb00         fldd    d15, \[r0\]
+0+1b8 <[^>]*> ed8ccbc9         fstd    d12, \[ip, #804\]
+0+1bc <[^>]*> ec901b02         fldmiad r0, {d1}
+0+1c0 <[^>]*> ec902b02         fldmiad r0, {d2}
+0+1c4 <[^>]*> ec90fb02         fldmiad r0, {d15}
+0+1c8 <[^>]*> ec900b04         fldmiad r0, {d0-d1}
+0+1cc <[^>]*> ec900b06         fldmiad r0, {d0-d2}
+0+1d0 <[^>]*> ec900b20         fldmiad r0, {d0-d15}
+0+1d4 <[^>]*> ec901b1e         fldmiad r0, {d1-d15}
+0+1d8 <[^>]*> ec902b1c         fldmiad r0, {d2-d15}
+0+1dc <[^>]*> ec90eb04         fldmiad r0, {d14-d15}
+0+1e0 <[^>]*> ec910b02         fldmiad r1, {d0}
+0+1e4 <[^>]*> ec9e0b02         fldmiad lr, {d0}
+0+1e8 <[^>]*> eeb50b40         fcmpzd  d0
+0+1ec <[^>]*> eeb51b40         fcmpzd  d1
+0+1f0 <[^>]*> eeb52b40         fcmpzd  d2
+0+1f4 <[^>]*> eeb53b40         fcmpzd  d3
+0+1f8 <[^>]*> eeb54b40         fcmpzd  d4
+0+1fc <[^>]*> eeb55b40         fcmpzd  d5
+0+200 <[^>]*> eeb56b40         fcmpzd  d6
+0+204 <[^>]*> eeb57b40         fcmpzd  d7
+0+208 <[^>]*> eeb58b40         fcmpzd  d8
+0+20c <[^>]*> eeb59b40         fcmpzd  d9
+0+210 <[^>]*> eeb5ab40         fcmpzd  d10
+0+214 <[^>]*> eeb5bb40         fcmpzd  d11
+0+218 <[^>]*> eeb5cb40         fcmpzd  d12
+0+21c <[^>]*> eeb5db40         fcmpzd  d13
+0+220 <[^>]*> eeb5eb40         fcmpzd  d14
+0+224 <[^>]*> eeb5fb40         fcmpzd  d15
+0+228 <[^>]*> 0eb41bcf         fcmpedeq        d1, d15
+0+22c <[^>]*> 0eb52bc0         fcmpezdeq       d2
+0+230 <[^>]*> 0eb43b4e         fcmpdeq d3, d14
+0+234 <[^>]*> 0eb54b40         fcmpzdeq        d4
+0+238 <[^>]*> 0eb05bcd         fabsdeq d5, d13
+0+23c <[^>]*> 0eb06b4c         fcpydeq d6, d12
+0+240 <[^>]*> 0eb17b4b         fnegdeq d7, d11
+0+244 <[^>]*> 0eb18bca         fsqrtdeq        d8, d10
+0+248 <[^>]*> 0e319b0f         fadddeq d9, d1, d15
+0+24c <[^>]*> 0e832b0e         fdivdeq d2, d3, d14
+0+250 <[^>]*> 0e0d4b0c         fmacdeq d4, d13, d12
+0+254 <[^>]*> 0e165b0b         fmscdeq d5, d6, d11
+0+258 <[^>]*> 0e2a7b09         fmuldeq d7, d10, d9
+0+25c <[^>]*> 0e098b4a         fnmacdeq        d8, d9, d10
+0+260 <[^>]*> 0e167b4b         fnmscdeq        d7, d6, d11
+0+264 <[^>]*> 0e245b4c         fnmuldeq        d5, d4, d12
+0+268 <[^>]*> 0e3d3b4e         fsubdeq d3, d13, d14
+0+26c <[^>]*> 0d952b00         flddeq  d2, \[r5\]
+0+270 <[^>]*> 0d8c1b00         fstdeq  d1, \[ip\]
+0+274 <[^>]*> 0c911b02         fldmiadeq       r1, {d1}
+0+278 <[^>]*> 0c922b02         fldmiadeq       r2, {d2}
+0+27c <[^>]*> 0cb33b02         fldmiadeq       r3!, {d3}
+0+280 <[^>]*> 0cb44b02         fldmiadeq       r4!, {d4}
+0+284 <[^>]*> 0d355b02         fldmdbdeq       r5!, {d5}
+0+288 <[^>]*> 0d366b02         fldmdbdeq       r6!, {d6}
+0+28c <[^>]*> 0c87fb02         fstmiadeq       r7, {d15}
+0+290 <[^>]*> 0c88eb02         fstmiadeq       r8, {d14}
+0+294 <[^>]*> 0ca9db02         fstmiadeq       r9!, {d13}
+0+298 <[^>]*> 0caacb02         fstmiadeq       sl!, {d12}
+0+29c <[^>]*> 0d2bbb02         fstmdbdeq       fp!, {d11}
+0+2a0 <[^>]*> 0d2cab02         fstmdbdeq       ip!, {d10}
+0+2a4 <[^>]*> 0eb8fbe0         fsitodeq        d15, s1
+0+2a8 <[^>]*> 0eb81b6f         fuitodeq        d1, s31
+0+2ac <[^>]*> 0efd0b4f         ftosideq        s1, d15
+0+2b0 <[^>]*> 0efdfbc2         ftosizdeq       s31, d2
+0+2b4 <[^>]*> 0efc7b42         ftouideq        s15, d2
+0+2b8 <[^>]*> 0efc5bc3         ftouizdeq       s11, d3
+0+2bc <[^>]*> 0eb71ac5         fcvtdseq        d1, s10
+0+2c0 <[^>]*> 0ef75bc1         fcvtsdeq        s11, d1
+0+2c4 <[^>]*> 0e318b10         fmrdheq r8, d1
+0+2c8 <[^>]*> 0e1f7b10         fmrdleq r7, d15
+0+2cc <[^>]*> 0e21fb10         fmdhreq d1, pc
+0+2d0 <[^>]*> 0e0f1b10         fmdlreq d15, r1
diff --git a/gas/testsuite/gas/arm/vfp1.s b/gas/testsuite/gas/arm/vfp1.s
new file mode 100644 (file)
index 0000000..9853bae
--- /dev/null
@@ -0,0 +1,278 @@
+@ VFP Instructions for D variants (Double precision)
+       .text
+       .global F
+F:
+       @ First we test the basic syntax and bit patterns of the opcodes.
+       @ Most of these tests deliberatly use d0/r0 to avoid setting
+       @ any more bits than necessary.
+
+       @ Comparison operations
+
+       fcmped  d0, d0
+       fcmpezd d0
+       fcmpd   d0, d0
+       fcmpzd  d0
+
+       @ Monadic data operations
+
+       fabsd   d0, d0
+       fcpyd   d0, d0
+       fnegd   d0, d0
+       fsqrtd  d0, d0
+
+       @ Dyadic data operations
+
+       faddd   d0, d0, d0
+       fdivd   d0, d0, d0
+       fmacd   d0, d0, d0
+       fmscd   d0, d0, d0
+       fmuld   d0, d0, d0
+       fnmacd  d0, d0, d0
+       fnmscd  d0, d0, d0
+       fnmuld  d0, d0, d0
+       fsubd   d0, d0, d0
+
+       @ Load/store operations
+
+       fldd    d0, [r0]
+       fstd    d0, [r0]
+
+       @ Load/store multiple operations
+
+       fldmiad r0, {d0}
+       fldmfdd r0, {d0}
+       fldmiad r0!, {d0}
+       fldmfdd r0!, {d0}
+       fldmdbd r0!, {d0}
+       fldmead r0!, {d0}
+
+       fstmiad r0, {d0}
+       fstmead r0, {d0}
+       fstmiad r0!, {d0}
+       fstmead r0!, {d0}
+       fstmdbd r0!, {d0}
+       fstmfdd r0!, {d0}
+
+       @ Conversion operations
+
+       fsitod  d0, s0
+       fuitod  d0, s0
+
+       ftosid  s0, d0
+       ftosizd s0, d0
+       ftouid  s0, d0
+       ftouizd s0, d0
+
+       fcvtds  d0, s0
+       fcvtsd  s0, d0
+       
+       @ ARM from VFP operations
+
+       fmrdh   r0, d0
+       fmrdl   r0, d0
+
+       @ VFP From ARM operations
+
+       fmdhr   d0, r0
+       fmdlr   d0, r0
+
+       @ Now we test that the register fields are updated correctly for
+       @ each class of instruction.
+
+       @ Single register operations (compare-zero):
+
+       fcmpzd  d1
+       fcmpzd  d2
+       fcmpzd  d15
+
+       @ Two register comparison operations:
+
+       fcmpd   d0, d1
+       fcmpd   d0, d2
+       fcmpd   d0, d15
+       fcmpd   d1, d0
+       fcmpd   d2, d0
+       fcmpd   d15, d0
+       fcmpd   d5, d12
+
+       @ Two register data operations (monadic)
+
+       fnegd   d0, d1
+       fnegd   d0, d2
+       fnegd   d0, d15
+       fnegd   d1, d0
+       fnegd   d2, d0
+       fnegd   d15, d0
+       fnegd   d12, d5
+       
+       @ Three register data operations (dyadic)
+
+       faddd   d0, d0, d1
+       faddd   d0, d0, d2
+       faddd   d0, d0, d15
+       faddd   d0, d1, d0
+       faddd   d0, d2, d0
+       faddd   d0, d15, d0
+       faddd   d1, d0, d0
+       faddd   d2, d0, d0
+       faddd   d15, d0, d0
+       faddd   d12, d9, d5
+
+       @ Conversion operations
+
+       fcvtds  d0, s1
+       fcvtds  d0, s2
+       fcvtds  d0, s31
+       fcvtds  d1, s0
+       fcvtds  d2, s0
+       fcvtds  d15, s0
+       fcvtsd  s1, d0
+       fcvtsd  s2, d0
+       fcvtsd  s31, d0
+       fcvtsd  s0, d1
+       fcvtsd  s0, d2
+       fcvtsd  s0, d15
+
+       @ Move to VFP from ARM
+
+       fmrdh   r1, d0
+       fmrdh   r14, d0
+       fmrdh   r0, d1
+       fmrdh   r0, d2
+       fmrdh   r0, d15
+       fmrdl   r1, d0
+       fmrdl   r14, d0
+       fmrdl   r0, d1
+       fmrdl   r0, d2
+       fmrdl   r0, d15
+
+       @ Move to ARM from VFP
+
+       fmdhr   d0, r1
+       fmdhr   d0, r14
+       fmdhr   d1, r0
+       fmdhr   d2, r0
+       fmdhr   d15, r0
+       fmdlr   d0, r1
+       fmdlr   d0, r14
+       fmdlr   d1, r0
+       fmdlr   d2, r0
+       fmdlr   d15, r0
+
+       @ Load/store operations
+
+       fldd    d0, [r1]
+       fldd    d0, [r14]
+       fldd    d0, [r0, #0]
+       fldd    d0, [r0, #1020]
+       fldd    d0, [r0, #-1020]
+       fldd    d1, [r0]
+       fldd    d2, [r0]
+       fldd    d15, [r0]
+       fstd    d12, [r12, #804]
+
+       @ Load/store multiple operations
+
+       fldmiad r0, {d1}
+       fldmiad r0, {d2}
+       fldmiad r0, {d15}
+       fldmiad r0, {d0-d1}
+       fldmiad r0, {d0-d2}
+       fldmiad r0, {d0-d15}
+       fldmiad r0, {d1-d15}
+       fldmiad r0, {d2-d15}
+       fldmiad r0, {d14-d15}
+       fldmiad r1, {d0}
+       fldmiad r14, {d0}
+
+       @ Check that we assemble all the register names correctly
+
+       fcmpzd  d0
+       fcmpzd  d1
+       fcmpzd  d2
+       fcmpzd  d3
+       fcmpzd  d4
+       fcmpzd  d5
+       fcmpzd  d6
+       fcmpzd  d7
+       fcmpzd  d8
+       fcmpzd  d9
+       fcmpzd  d10
+       fcmpzd  d11
+       fcmpzd  d12
+       fcmpzd  d13
+       fcmpzd  d14
+       fcmpzd  d15
+
+       @ Now we check the placement of the conditional execution substring.
+       @ On VFP this is always at the end of the instruction.
+       
+       @ Comparison operations
+
+       fcmpedeq        d1, d15
+       fcmpezdeq       d2
+       fcmpdeq d3, d14
+       fcmpzdeq        d4
+
+       @ Monadic data operations
+
+       fabsdeq d5, d13
+       fcpydeq d6, d12
+       fnegdeq d7, d11
+       fsqrtdeq        d8, d10
+
+       @ Dyadic data operations
+
+       fadddeq d9, d1, d15
+       fdivdeq d2, d3, d14
+       fmacdeq d4, d13, d12
+       fmscdeq d5, d6, d11
+       fmuldeq d7, d10, d9
+       fnmacdeq        d8, d9, d10
+       fnmscdeq        d7, d6, d11
+       fnmuldeq        d5, d4, d12
+       fsubdeq d3, d13, d14
+
+       @ Load/store operations
+
+       flddeq  d2, [r5]
+       fstdeq  d1, [r12]
+
+       @ Load/store multiple operations
+
+       fldmiadeq       r1, {d1}
+       fldmfddeq       r2, {d2}
+       fldmiadeq       r3!, {d3}
+       fldmfddeq       r4!, {d4}
+       fldmdbdeq       r5!, {d5}
+       fldmeadeq       r6!, {d6}
+
+       fstmiadeq       r7, {d15}
+       fstmeadeq       r8, {d14}
+       fstmiadeq       r9!, {d13}
+       fstmeadeq       r10!, {d12}
+       fstmdbdeq       r11!, {d11}
+       fstmfddeq       r12!, {d10}
+
+       @ Conversion operations
+
+       fsitodeq        d15, s1
+       fuitodeq        d1, s31
+
+       ftosideq        s1, d15
+       ftosizdeq       s31, d2
+       ftouideq        s15, d2
+       ftouizdeq       s11, d3
+
+       fcvtdseq        d1, s10
+       fcvtsdeq        s11, d1
+       
+       @ ARM from VFP operations
+
+       fmrdheq r8, d1
+       fmrdleq r7, d15
+
+       @ VFP From ARM operations
+
+       fmdhreq d1, r15
+       fmdlreq d15, r1
diff --git a/gas/testsuite/gas/arm/vfp1xD.d b/gas/testsuite/gas/arm/vfp1xD.d
new file mode 100644 (file)
index 0000000..8e35638
--- /dev/null
@@ -0,0 +1,241 @@
+#objdump: -dr --prefix-addresses --show-raw-insn
+#name: VFP Single-precision instructions
+#as: -mvfpxd
+
+# Test the ARM VFP Single Precision instructions
+
+.*: +file format .*arm.*
+
+Disassembly of section .text:
+0+000 <[^>]*> eef1fa10         fmstat
+0+004 <[^>]*> eeb40ac0         fcmpes  s0, s0
+0+008 <[^>]*> eeb50ac0         fcmpezs s0
+0+00c <[^>]*> eeb40a40         fcmps   s0, s0
+0+010 <[^>]*> eeb50a40         fcmpzs  s0
+0+014 <[^>]*> eeb00ac0         fabss   s0, s0
+0+018 <[^>]*> eeb00a40         fcpys   s0, s0
+0+01c <[^>]*> eeb10a40         fnegs   s0, s0
+0+020 <[^>]*> eeb10ac0         fsqrts  s0, s0
+0+024 <[^>]*> ee300a00         fadds   s0, s0, s0
+0+028 <[^>]*> ee800a00         fdivs   s0, s0, s0
+0+02c <[^>]*> ee000a00         fmacs   s0, s0, s0
+0+030 <[^>]*> ee100a00         fmscs   s0, s0, s0
+0+034 <[^>]*> ee200a00         fmuls   s0, s0, s0
+0+038 <[^>]*> ee000a40         fnmacs  s0, s0, s0
+0+03c <[^>]*> ee100a40         fnmscs  s0, s0, s0
+0+040 <[^>]*> ee200a40         fnmuls  s0, s0, s0
+0+044 <[^>]*> ee300a40         fsubs   s0, s0, s0
+0+048 <[^>]*> ed900a00         flds    s0, \[r0\]
+0+04c <[^>]*> ed800a00         fsts    s0, \[r0\]
+0+050 <[^>]*> ec900a01         fldmias r0, {s0}
+0+054 <[^>]*> ec900a01         fldmias r0, {s0}
+0+058 <[^>]*> ecb00a01         fldmias r0!, {s0}
+0+05c <[^>]*> ecb00a01         fldmias r0!, {s0}
+0+060 <[^>]*> ed300a01         fldmdbs r0!, {s0}
+0+064 <[^>]*> ed300a01         fldmdbs r0!, {s0}
+0+068 <[^>]*> ec900b03         fldmiax r0, {d0}
+0+06c <[^>]*> ec900b03         fldmiax r0, {d0}
+0+070 <[^>]*> ecb00b03         fldmiax r0!, {d0}
+0+074 <[^>]*> ecb00b03         fldmiax r0!, {d0}
+0+078 <[^>]*> ed300b03         fldmdbx r0!, {d0}
+0+07c <[^>]*> ed300b03         fldmdbx r0!, {d0}
+0+080 <[^>]*> ec800a01         fstmias r0, {s0}
+0+084 <[^>]*> ec800a01         fstmias r0, {s0}
+0+088 <[^>]*> eca00a01         fstmias r0!, {s0}
+0+08c <[^>]*> eca00a01         fstmias r0!, {s0}
+0+090 <[^>]*> ed200a01         fstmdbs r0!, {s0}
+0+094 <[^>]*> ed200a01         fstmdbs r0!, {s0}
+0+098 <[^>]*> ec800b03         fstmiax r0, {d0}
+0+09c <[^>]*> ec800b03         fstmiax r0, {d0}
+0+0a0 <[^>]*> eca00b03         fstmiax r0!, {d0}
+0+0a4 <[^>]*> eca00b03         fstmiax r0!, {d0}
+0+0a8 <[^>]*> ed200b03         fstmdbx r0!, {d0}
+0+0ac <[^>]*> ed200b03         fstmdbx r0!, {d0}
+0+0b0 <[^>]*> eeb80ac0         fsitos  s0, s0
+0+0b4 <[^>]*> eeb80a40         fuitos  s0, s0
+0+0b8 <[^>]*> eebd0a40         ftosis  s0, s0
+0+0bc <[^>]*> eebd0ac0         ftosizs s0, s0
+0+0c0 <[^>]*> eebc0a40         ftouis  s0, s0
+0+0c4 <[^>]*> eebc0ac0         ftouizs s0, s0
+0+0c8 <[^>]*> ee100a10         fmrs    r0, s0
+0+0cc <[^>]*> eef00a10         fmrx    r0, fpsid
+0+0d0 <[^>]*> eef10a10         fmrx    r0, fpscr
+0+0d4 <[^>]*> eef80a10         fmrx    r0, fpexc
+0+0d8 <[^>]*> ee000a10         fmsr    s0, r0
+0+0dc <[^>]*> eee00a10         fmxr    fpsid, r0
+0+0e0 <[^>]*> eee10a10         fmxr    fpscr, r0
+0+0e4 <[^>]*> eee80a10         fmxr    fpexc, r0
+0+0e8 <[^>]*> eef50a40         fcmpzs  s1
+0+0ec <[^>]*> eeb51a40         fcmpzs  s2
+0+0f0 <[^>]*> eef5fa40         fcmpzs  s31
+0+0f4 <[^>]*> eeb40a60         fcmps   s0, s1
+0+0f8 <[^>]*> eeb40a41         fcmps   s0, s2
+0+0fc <[^>]*> eeb40a6f         fcmps   s0, s31
+0+100 <[^>]*> eef40a40         fcmps   s1, s0
+0+104 <[^>]*> eeb41a40         fcmps   s2, s0
+0+108 <[^>]*> eef4fa40         fcmps   s31, s0
+0+10c <[^>]*> eef4aa46         fcmps   s21, s12
+0+110 <[^>]*> eeb10a60         fnegs   s0, s1
+0+114 <[^>]*> eeb10a41         fnegs   s0, s2
+0+118 <[^>]*> eeb10a6f         fnegs   s0, s31
+0+11c <[^>]*> eef10a40         fnegs   s1, s0
+0+120 <[^>]*> eeb11a40         fnegs   s2, s0
+0+124 <[^>]*> eef1fa40         fnegs   s31, s0
+0+128 <[^>]*> eeb16a6a         fnegs   s12, s21
+0+12c <[^>]*> ee300a20         fadds   s0, s0, s0
+0+130 <[^>]*> ee300a01         fadds   s0, s0, s0
+0+134 <[^>]*> ee300a2f         fadds   s0, s0, s0
+0+138 <[^>]*> ee300a80         fadds   s0, s1, s0
+0+13c <[^>]*> ee310a00         fadds   s0, s2, s0
+0+140 <[^>]*> ee3f0a80         fadds   s0, s31, s0
+0+144 <[^>]*> ee700a00         fadds   s1, s0, s1
+0+148 <[^>]*> ee301a00         fadds   s2, s0, s2
+0+14c <[^>]*> ee70fa00         fadds   s31, s0, s31
+0+150 <[^>]*> ee3a6aa2         fadds   s12, s21, s12
+0+154 <[^>]*> eeb80ae0         fsitos  s0, s1
+0+158 <[^>]*> eeb80ac1         fsitos  s0, s2
+0+15c <[^>]*> eeb80aef         fsitos  s0, s31
+0+160 <[^>]*> eef80ac0         fsitos  s1, s0
+0+164 <[^>]*> eeb81ac0         fsitos  s2, s0
+0+168 <[^>]*> eef8fac0         fsitos  s31, s0
+0+16c <[^>]*> eebd0a60         ftosis  s0, s1
+0+170 <[^>]*> eebd0a41         ftosis  s0, s2
+0+174 <[^>]*> eebd0a6f         ftosis  s0, s31
+0+178 <[^>]*> eefd0a40         ftosis  s1, s0
+0+17c <[^>]*> eebd1a40         ftosis  s2, s0
+0+180 <[^>]*> eefdfa40         ftosis  s31, s0
+0+184 <[^>]*> ee001a10         fmsr    s0, r1
+0+188 <[^>]*> ee007a10         fmsr    s0, r7
+0+18c <[^>]*> ee00ea10         fmsr    s0, lr
+0+190 <[^>]*> ee000a90         fmsr    s1, r0
+0+194 <[^>]*> ee010a10         fmsr    s2, r0
+0+198 <[^>]*> ee0f0a90         fmsr    s31, r0
+0+19c <[^>]*> ee0a7a90         fmsr    s21, r7
+0+1a0 <[^>]*> eee01a10         fmxr    fpsid, r1
+0+1a4 <[^>]*> eee0ea10         fmxr    fpsid, lr
+0+1a8 <[^>]*> ee100a90         fmrs    r0, s1
+0+1ac <[^>]*> ee110a10         fmrs    r0, s2
+0+1b0 <[^>]*> ee1f0a90         fmrs    r0, s31
+0+1b4 <[^>]*> ee101a10         fmrs    r1, s0
+0+1b8 <[^>]*> ee107a10         fmrs    r7, s0
+0+1bc <[^>]*> ee10ea10         fmrs    lr, s0
+0+1c0 <[^>]*> ee159a90         fmrs    r9, s11
+0+1c4 <[^>]*> eef01a10         fmrx    r1, fpsid
+0+1c8 <[^>]*> eef0ea10         fmrx    lr, fpsid
+0+1cc <[^>]*> ed910a00         flds    s0, \[r1\]
+0+1d0 <[^>]*> ed9e0a00         flds    s0, \[lr\]
+0+1d4 <[^>]*> ed900a00         flds    s0, \[r0\]
+0+1d8 <[^>]*> ed900aff         flds    s0, \[r0, #1020\]
+0+1dc <[^>]*> ed100aff         flds    s0, \[r0, -#1020\]
+0+1e0 <[^>]*> edd00a00         flds    s1, \[r0\]
+0+1e4 <[^>]*> ed901a00         flds    s2, \[r0\]
+0+1e8 <[^>]*> edd0fa00         flds    s31, \[r0\]
+0+1ec <[^>]*> edccaac9         fsts    s21, \[ip, #804\]
+0+1f0 <[^>]*> ecd00a01         fldmias r0, {s1}
+0+1f4 <[^>]*> ec901a01         fldmias r0, {s2}
+0+1f8 <[^>]*> ecd0fa01         fldmias r0, {s31}
+0+1fc <[^>]*> ec900a02         fldmias r0, {s0-s1}
+0+200 <[^>]*> ec900a03         fldmias r0, {s0-s2}
+0+204 <[^>]*> ec900a20         fldmias r0, {s0-s31}
+0+208 <[^>]*> ecd00a1f         fldmias r0, {s1-s31}
+0+20c <[^>]*> ec901a1e         fldmias r0, {s2-s31}
+0+210 <[^>]*> ec90fa02         fldmias r0, {s30-s31}
+0+214 <[^>]*> ec910a01         fldmias r1, {s0}
+0+218 <[^>]*> ec9e0a01         fldmias lr, {s0}
+0+21c <[^>]*> ec801b03         fstmiax r0, {d1}
+0+220 <[^>]*> ec802b03         fstmiax r0, {d2}
+0+224 <[^>]*> ec80fb03         fstmiax r0, {d15}
+0+228 <[^>]*> ec800b05         fstmiax r0, {d0-d1}
+0+22c <[^>]*> ec800b07         fstmiax r0, {d0-d2}
+0+230 <[^>]*> ec800b21         fstmiax r0, {d0-d15}
+0+234 <[^>]*> ec801b1f         fstmiax r0, {d1-d15}
+0+238 <[^>]*> ec802b1d         fstmiax r0, {d2-d15}
+0+23c <[^>]*> ec80eb05         fstmiax r0, {d14-d15}
+0+240 <[^>]*> ec810b03         fstmiax r1, {d0}
+0+244 <[^>]*> ec8e0b03         fstmiax lr, {d0}
+0+248 <[^>]*> eeb50a40         fcmpzs  s0
+0+24c <[^>]*> eef50a40         fcmpzs  s1
+0+250 <[^>]*> eeb51a40         fcmpzs  s2
+0+254 <[^>]*> eef51a40         fcmpzs  s3
+0+258 <[^>]*> eeb52a40         fcmpzs  s4
+0+25c <[^>]*> eef52a40         fcmpzs  s5
+0+260 <[^>]*> eeb53a40         fcmpzs  s6
+0+264 <[^>]*> eef53a40         fcmpzs  s7
+0+268 <[^>]*> eeb54a40         fcmpzs  s8
+0+26c <[^>]*> eef54a40         fcmpzs  s9
+0+270 <[^>]*> eeb55a40         fcmpzs  s10
+0+274 <[^>]*> eef55a40         fcmpzs  s11
+0+278 <[^>]*> eeb56a40         fcmpzs  s12
+0+27c <[^>]*> eef56a40         fcmpzs  s13
+0+280 <[^>]*> eeb57a40         fcmpzs  s14
+0+284 <[^>]*> eef57a40         fcmpzs  s15
+0+288 <[^>]*> eeb58a40         fcmpzs  s16
+0+28c <[^>]*> eef58a40         fcmpzs  s17
+0+290 <[^>]*> eeb59a40         fcmpzs  s18
+0+294 <[^>]*> eef59a40         fcmpzs  s19
+0+298 <[^>]*> eeb5aa40         fcmpzs  s20
+0+29c <[^>]*> eef5aa40         fcmpzs  s21
+0+2a0 <[^>]*> eeb5ba40         fcmpzs  s22
+0+2a4 <[^>]*> eef5ba40         fcmpzs  s23
+0+2a8 <[^>]*> eeb5ca40         fcmpzs  s24
+0+2ac <[^>]*> eef5ca40         fcmpzs  s25
+0+2b0 <[^>]*> eeb5da40         fcmpzs  s26
+0+2b4 <[^>]*> eef5da40         fcmpzs  s27
+0+2b8 <[^>]*> eeb5ea40         fcmpzs  s28
+0+2bc <[^>]*> eef5ea40         fcmpzs  s29
+0+2c0 <[^>]*> eeb5fa40         fcmpzs  s30
+0+2c4 <[^>]*> eef5fa40         fcmpzs  s31
+0+2c8 <[^>]*> 0ef1fa10         fmstateq
+0+2cc <[^>]*> 0ef41ae3         fcmpeseq        s3, s7
+0+2d0 <[^>]*> 0ef52ac0         fcmpezseq       s5
+0+2d4 <[^>]*> 0ef40a41         fcmpseq s1, s2
+0+2d8 <[^>]*> 0ef50a40         fcmpzseq        s1
+0+2dc <[^>]*> 0ef00ae1         fabsseq s1, s3
+0+2e0 <[^>]*> 0ef0fa69         fcpyseq s31, s19
+0+2e4 <[^>]*> 0eb1aa44         fnegseq s20, s8
+0+2e8 <[^>]*> 0ef12ae3         fsqrtseq        s5, s7
+0+2ec <[^>]*> 0e323a82         faddseq s6, s5, s6
+0+2f0 <[^>]*> 0ec11a20         fdivseq s3, s2, s1
+0+2f4 <[^>]*> 0e4ffa2e         fmacseq s31, s30, s29
+0+2f8 <[^>]*> 0e1dea8d         fmscseq s28, s27, s26
+0+2fc <[^>]*> 0e6cca2b         fmulseq s25, s24, s23
+0+300 <[^>]*> 0e0abaca         fnmacseq        s22, s21, s20
+0+304 <[^>]*> 0e599a68         fnmscseq        s19, s18, s17
+0+308 <[^>]*> 0e278ac7         fnmulseq        s16, s15, s14
+0+30c <[^>]*> 0e766a65         fsubseq s13, s12, s11
+0+310 <[^>]*> 0d985a00         fldseq  s10, \[r8\]
+0+314 <[^>]*> 0dc74a00         fstseq  s9, \[r7\]
+0+318 <[^>]*> 0c914a01         fldmiaseq       r1, {s8}
+0+31c <[^>]*> 0cd23a01         fldmiaseq       r2, {s7}
+0+320 <[^>]*> 0cb33a01         fldmiaseq       r3!, {s6}
+0+324 <[^>]*> 0cf42a01         fldmiaseq       r4!, {s5}
+0+328 <[^>]*> 0d352a01         fldmdbseq       r5!, {s4}
+0+32c <[^>]*> 0d761a01         fldmdbseq       r6!, {s3}
+0+330 <[^>]*> 0c971b03         fldmiaxeq       r7, {d1}
+0+334 <[^>]*> 0c982b03         fldmiaxeq       r8, {d2}
+0+338 <[^>]*> 0cb93b03         fldmiaxeq       r9!, {d3}
+0+33c <[^>]*> 0cba4b03         fldmiaxeq       sl!, {d4}
+0+340 <[^>]*> 0d3b5b03         fldmdbxeq       fp!, {d5}
+0+344 <[^>]*> 0d3c6b03         fldmdbxeq       ip!, {d6}
+0+348 <[^>]*> 0c8d1a01         fstmiaseq       sp, {s2}
+0+34c <[^>]*> 0cce0a01         fstmiaseq       lr, {s1}
+0+350 <[^>]*> 0ce1fa01         fstmiaseq       r1!, {s31}
+0+354 <[^>]*> 0ca2fa01         fstmiaseq       r2!, {s30}
+0+358 <[^>]*> 0d63ea01         fstmdbseq       r3!, {s29}
+0+35c <[^>]*> 0d24ea01         fstmdbseq       r4!, {s28}
+0+360 <[^>]*> 0c857b03         fstmiaxeq       r5, {d7}
+0+364 <[^>]*> 0c868b03         fstmiaxeq       r6, {d8}
+0+368 <[^>]*> 0ca79b03         fstmiaxeq       r7!, {d9}
+0+36c <[^>]*> 0ca8ab03         fstmiaxeq       r8!, {d10}
+0+370 <[^>]*> 0d29bb03         fstmdbxeq       r9!, {d11}
+0+374 <[^>]*> 0d2acb03         fstmdbxeq       sl!, {d12}
+0+378 <[^>]*> 0ef8dac3         fsitoseq        s27, s6
+0+37c <[^>]*> 0efdca62         ftosiseq        s25, s5
+0+380 <[^>]*> 0efdbac2         ftosizseq       s23, s4
+0+384 <[^>]*> 0efcaa61         ftouiseq        s21, s3
+0+388 <[^>]*> 0efc9ac1         ftouizseq       s19, s2
+0+38c <[^>]*> 0ef88a60         fuitoseq        s17, s1
+0+390 <[^>]*> 0e11ba90         fmrseq  fp, s3
+0+394 <[^>]*> 0ef09a10         fmrxeq  r9, fpsid
+0+398 <[^>]*> 0e019a90         fmsreq  s3, r9
+0+39c <[^>]*> 0ee08a10         fmxreq  fpsid, r8
diff --git a/gas/testsuite/gas/arm/vfp1xD.s b/gas/testsuite/gas/arm/vfp1xD.s
new file mode 100644 (file)
index 0000000..82f080f
--- /dev/null
@@ -0,0 +1,339 @@
+@ VFP Instructions for v1xD variants (Single precision only)
+       .text
+       .global F
+F:
+       @ First we test the basic syntax and bit patterns of the opcodes.
+       @ Most of these tests deliberatly use s0/r0 to avoid setting
+       @ any more bits than necessary.
+
+       @ Comparison operations
+
+       fmstat
+
+       fcmpes  s0, s0
+       fcmpezs s0
+       fcmps   s0, s0
+       fcmpzs  s0
+
+       @ Monadic data operations
+
+       fabss   s0, s0
+       fcpys   s0, s0
+       fnegs   s0, s0
+       fsqrts  s0, s0
+
+       @ Dyadic data operations
+
+       fadds   s0, s0, s0
+       fdivs   s0, s0, s0
+       fmacs   s0, s0, s0
+       fmscs   s0, s0, s0
+       fmuls   s0, s0, s0
+       fnmacs  s0, s0, s0
+       fnmscs  s0, s0, s0
+       fnmuls  s0, s0, s0
+       fsubs   s0, s0, s0
+
+       @ Load/store operations
+
+       flds    s0, [r0]
+       fsts    s0, [r0]
+
+       @ Load/store multiple operations
+
+       fldmias r0, {s0}
+       fldmfds r0, {s0}
+       fldmias r0!, {s0}
+       fldmfds r0!, {s0}
+       fldmdbs r0!, {s0}
+       fldmeas r0!, {s0}
+
+       fldmiax r0, {d0}
+       fldmfdx r0, {d0}
+       fldmiax r0!, {d0}
+       fldmfdx r0!, {d0}
+       fldmdbx r0!, {d0}
+       fldmeax r0!, {d0}
+
+       fstmias r0, {s0}
+       fstmeas r0, {s0}
+       fstmias r0!, {s0}
+       fstmeas r0!, {s0}
+       fstmdbs r0!, {s0}
+       fstmfds r0!, {s0}
+
+       fstmiax r0, {d0}
+       fstmeax r0, {d0}
+       fstmiax r0!, {d0}
+       fstmeax r0!, {d0}
+       fstmdbx r0!, {d0}
+       fstmfdx r0!, {d0}
+
+       @ Conversion operations
+
+       fsitos  s0, s0
+       fuitos  s0, s0
+
+       ftosis  s0, s0
+       ftosizs s0, s0
+       ftouis  s0, s0
+       ftouizs s0, s0
+
+       @ ARM from VFP operations
+
+       fmrs    r0, s0
+       fmrx    r0, fpsid
+       fmrx    r0, fpscr
+       fmrx    r0, fpexc
+
+       @ VFP From ARM operations
+
+       fmsr    s0, r0
+       fmxr    fpsid, r0
+       fmxr    fpscr, r0
+       fmxr    fpexc, r0
+
+       @ Now we test that the register fields are updated correctly for
+       @ each class of instruction.
+
+       @ Single register operations (compare-zero):
+
+       fcmpzs  s1
+       fcmpzs  s2
+       fcmpzs  s31
+
+       @ Two register comparison operations:
+
+       fcmps   s0, s1
+       fcmps   s0, s2
+       fcmps   s0, s31
+       fcmps   s1, s0
+       fcmps   s2, s0
+       fcmps   s31, s0
+       fcmps   s21, s12
+
+       @ Two register data operations (monadic)
+
+       fnegs   s0, s1
+       fnegs   s0, s2
+       fnegs   s0, s31
+       fnegs   s1, s0
+       fnegs   s2, s0
+       fnegs   s31, s0
+       fnegs   s12, s21
+       
+       @ Three register data operations (dyadic)
+
+       fadds   s0, s0, s1
+       fadds   s0, s0, s2
+       fadds   s0, s0, s31
+       fadds   s0, s1, s0
+       fadds   s0, s2, s0
+       fadds   s0, s31, s0
+       fadds   s1, s0, s0
+       fadds   s2, s0, s0
+       fadds   s31, s0, s0
+       fadds   s12, s21, s5
+
+       @ Conversion operations
+
+       fsitos  s0, s1
+       fsitos  s0, s2
+       fsitos  s0, s31
+       fsitos  s1, s0
+       fsitos  s2, s0
+       fsitos  s31, s0
+
+       ftosis  s0, s1
+       ftosis  s0, s2
+       ftosis  s0, s31
+       ftosis  s1, s0
+       ftosis  s2, s0
+       ftosis  s31, s0
+
+       @ Move to VFP from ARM
+
+       fmsr    s0, r1
+       fmsr    s0, r7
+       fmsr    s0, r14
+       fmsr    s1, r0
+       fmsr    s2, r0
+       fmsr    s31, r0
+       fmsr    s21, r7
+
+       fmxr    fpsid, r1
+       fmxr    fpsid, r14
+
+       @ Move to ARM from VFP
+
+       fmrs    r0, s1
+       fmrs    r0, s2
+       fmrs    r0, s31
+       fmrs    r1, s0
+       fmrs    r7, s0
+       fmrs    r14, s0
+       fmrs    r9, s11
+
+       fmrx    r1, fpsid
+       fmrx    r14, fpsid
+
+       @ Load/store operations
+
+       flds    s0, [r1]
+       flds    s0, [r14]
+       flds    s0, [r0, #0]
+       flds    s0, [r0, #1020]
+       flds    s0, [r0, #-1020]
+       flds    s1, [r0]
+       flds    s2, [r0]
+       flds    s31, [r0]
+       fsts    s21, [r12, #804]
+
+       @ Load/store multiple operations
+
+       fldmias r0, {s1}
+       fldmias r0, {s2}
+       fldmias r0, {s31}
+       fldmias r0, {s0-s1}
+       fldmias r0, {s0-s2}
+       fldmias r0, {s0-s31}
+       fldmias r0, {s1-s31}
+       fldmias r0, {s2-s31}
+       fldmias r0, {s30-s31}
+       fldmias r1, {s0}
+       fldmias r14, {s0}
+
+       fstmiax r0, {d1}
+       fstmiax r0, {d2}
+       fstmiax r0, {d15}
+       fstmiax r0, {d0-d1}
+       fstmiax r0, {d0-d2}
+       fstmiax r0, {d0-d15}
+       fstmiax r0, {d1-d15}
+       fstmiax r0, {d2-d15}
+       fstmiax r0, {d14-d15}
+       fstmiax r1, {d0}
+       fstmiax r14, {d0}
+
+       @ Check that we assemble all the register names correctly
+
+       fcmpzs  s0
+       fcmpzs  s1
+       fcmpzs  s2
+       fcmpzs  s3
+       fcmpzs  s4
+       fcmpzs  s5
+       fcmpzs  s6
+       fcmpzs  s7
+       fcmpzs  s8
+       fcmpzs  s9
+       fcmpzs  s10
+       fcmpzs  s11
+       fcmpzs  s12
+       fcmpzs  s13
+       fcmpzs  s14
+       fcmpzs  s15
+       fcmpzs  s16
+       fcmpzs  s17
+       fcmpzs  s18
+       fcmpzs  s19
+       fcmpzs  s20
+       fcmpzs  s21
+       fcmpzs  s22
+       fcmpzs  s23
+       fcmpzs  s24
+       fcmpzs  s25
+       fcmpzs  s26
+       fcmpzs  s27
+       fcmpzs  s28
+       fcmpzs  s29
+       fcmpzs  s30
+       fcmpzs  s31
+
+       @ Now we check the placement of the conditional execution substring.
+       @ On VFP this is always at the end of the instruction.
+       @ We use different register numbers here to check for correct
+       @ disassembly
+       
+       @ Comparison operations
+
+       fmstateq
+
+       fcmpeseq        s3, s7
+       fcmpezseq       s5
+       fcmpseq s1, s2
+       fcmpzseq        s1
+
+       @ Monadic data operations
+
+       fabsseq s1, s3
+       fcpyseq s31, s19
+       fnegseq s20, s8
+       fsqrtseq        s5, s7
+
+       @ Dyadic data operations
+
+       faddseq s6, s5, s4
+       fdivseq s3, s2, s1
+       fmacseq s31, s30, s29
+       fmscseq s28, s27, s26
+       fmulseq s25, s24, s23
+       fnmacseq        s22, s21, s20
+       fnmscseq        s19, s18, s17
+       fnmulseq        s16, s15, s14
+       fsubseq s13, s12, s11
+
+       @ Load/store operations
+
+       fldseq  s10, [r8]
+       fstseq  s9, [r7]
+
+       @ Load/store multiple operations
+
+       fldmiaseq       r1, {s8}
+       fldmfdseq       r2, {s7}
+       fldmiaseq       r3!, {s6}
+       fldmfdseq       r4!, {s5}
+       fldmdbseq       r5!, {s4}
+       fldmeaseq       r6!, {s3}
+
+       fldmiaxeq       r7, {d1}
+       fldmfdxeq       r8, {d2}
+       fldmiaxeq       r9!, {d3}
+       fldmfdxeq       r10!, {d4}
+       fldmdbxeq       r11!, {d5}
+       fldmeaxeq       r12!, {d6}
+
+       fstmiaseq       r13, {s2}
+       fstmeaseq       r14, {s1}
+       fstmiaseq       r1!, {s31}
+       fstmeaseq       r2!, {s30}
+       fstmdbseq       r3!, {s29}
+       fstmfdseq       r4!, {s28}
+
+       fstmiaxeq       r5, {d7}
+       fstmeaxeq       r6, {d8}
+       fstmiaxeq       r7!, {d9}
+       fstmeaxeq       r8!, {d10}
+       fstmdbxeq       r9!, {d11}
+       fstmfdxeq       r10!, {d12}
+
+       @ Conversion operations
+
+       fsitoseq        s27, s6
+       ftosiseq        s25, s5
+       ftosizseq       s23, s4
+       ftouiseq        s21, s3
+       ftouizseq       s19, s2
+       fuitoseq        s17, s1
+
+       @ ARM from VFP operations
+
+       fmrseq  r11, s3
+       fmrxeq  r9, fpsid
+
+       @ VFP From ARM operations
+
+       fmsreq  s3, r9
+       fmxreq  fpsid, r8
+