#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
#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
{"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
{
{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[] =
{
{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")},
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. */
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 *));
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 *));
{"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},
}
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;
{
p++;
- if (skip_past_comma (& p) == SUCCESS)
+ if (wb_ok && skip_past_comma (& p) == SUCCESS)
{
/* [Rn], #expr */
write_back = WRITE_BACK;
skip_whitespace (p);
- if (*p == '!')
+ if (wb_ok && *p == '!')
{
if (reg == REG_PC)
{
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;
}
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;
}
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;
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;
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;
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);
}
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;
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
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"))
{
-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
--- /dev/null
+#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
--- /dev/null
+#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