From bfae80f222dbbb8f86156c988a95124a880df6e7 Mon Sep 17 00:00:00 2001 From: Richard Earnshaw Date: Tue, 15 Jan 2002 16:05:34 +0000 Subject: [PATCH] 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. * 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 | 34 + gas/config/tc-arm.c | 1474 +++++++++++++++++++++++++++---- gas/testsuite/ChangeLog | 7 + gas/testsuite/gas/arm/arm.exp | 6 + gas/testsuite/gas/arm/vfp-bad.l | 9 + gas/testsuite/gas/arm/vfp-bad.s | 11 + gas/testsuite/gas/arm/vfp1.d | 190 ++++ gas/testsuite/gas/arm/vfp1.s | 278 ++++++ gas/testsuite/gas/arm/vfp1xD.d | 241 +++++ gas/testsuite/gas/arm/vfp1xD.s | 339 +++++++ 10 files changed, 2425 insertions(+), 164 deletions(-) create mode 100644 gas/testsuite/gas/arm/vfp-bad.l create mode 100644 gas/testsuite/gas/arm/vfp-bad.s create mode 100644 gas/testsuite/gas/arm/vfp1.d create mode 100644 gas/testsuite/gas/arm/vfp1.s create mode 100644 gas/testsuite/gas/arm/vfp1xD.d create mode 100644 gas/testsuite/gas/arm/vfp1xD.s diff --git a/gas/ChangeLog b/gas/ChangeLog index 6dbefccb0ee..a8df4d1ce34 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,37 @@ +2002-01-15 Richard Earnshaw + + 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 * tc-arm.c (md_parse_option): Tidy up setting of cpu_variant for diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c index 40401cf47ec..94b21cc9c60 100644 --- a/gas/config/tc-arm.c +++ b/gas/config/tc-arm.c @@ -82,13 +82,22 @@ #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. */ @@ -116,6 +125,7 @@ #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 diff --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog index 3be0e11a7a0..d6481ae51ef 100644 --- a/gas/testsuite/ChangeLog +++ b/gas/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2002-01-15 Richard Earnshaw + + * 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 * gas/elf/section2.e-m32r: New file. diff --git a/gas/testsuite/gas/arm/arm.exp b/gas/testsuite/gas/arm/arm.exp index 04ce07eaadb..ef6fb0161cf 100644 --- a/gas/testsuite/gas/arm/arm.exp +++ b/gas/testsuite/gas/arm/arm.exp @@ -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 index 00000000000..04bb04d4d7a --- /dev/null +++ b/gas/testsuite/gas/arm/vfp-bad.l @@ -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 index 00000000000..ac44371773f --- /dev/null +++ b/gas/testsuite/gas/arm/vfp-bad.s @@ -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 index 00000000000..9f378032d43 --- /dev/null +++ b/gas/testsuite/gas/arm/vfp1.d @@ -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 index 00000000000..9853baeede6 --- /dev/null +++ b/gas/testsuite/gas/arm/vfp1.s @@ -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 index 00000000000..8e35638cb5e --- /dev/null +++ b/gas/testsuite/gas/arm/vfp1xD.d @@ -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 index 00000000000..82f080f499b --- /dev/null +++ b/gas/testsuite/gas/arm/vfp1xD.s @@ -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 + -- 2.30.2