X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-arm.c;h=39f1b65495ea29bc13ae72c5e4843ff20b423154;hb=3765b1be13d34da8aae366959c3601a09afa193b;hp=83f997df9bd55310d12083621a66af8f99a6244a;hpb=f2b7cb0a5f1e11dbfe5b0fe186070c6ff95757a9;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c index 83f997df9b..39f1b65495 100644 --- a/gas/config/tc-arm.c +++ b/gas/config/tc-arm.c @@ -1,5 +1,5 @@ /* tc-arm.c -- Assemble for the ARM - Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 + Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org) Modified by David Taylor (dtaylor@armltd.co.uk) @@ -39,6 +39,9 @@ #include "dwarf2dbg.h" #endif +/* XXX Set this to 1 after the next binutils release */ +#define WARN_DEPRECATED 0 + /* The following bitmasks control CPU extensions: */ #define ARM_EXT_V1 0x00000001 /* All processors (core set). */ #define ARM_EXT_V2 0x00000002 /* Multiply instructions. */ @@ -51,9 +54,11 @@ #define ARM_EXT_V5T 0x00000100 /* Thumb v2. */ #define ARM_EXT_V5ExP 0x00000200 /* DSP core set. */ #define ARM_EXT_V5E 0x00000400 /* DSP Double transfers. */ -/* Processor specific extensions. */ -#define ARM_EXT_XSCALE 0x00000800 /* Allow MIA etc. */ -#define ARM_EXT_MAVERICK 0x00001000 /* Use Cirrus/DSP coprocessor. */ +#define ARM_EXT_V5J 0x00000800 /* Jazelle extension. */ + +/* Co-processor space extensions. */ +#define ARM_CEXT_XSCALE 0x00800000 /* Allow MIA etc. */ +#define ARM_CEXT_MAVERICK 0x00400000 /* Use Cirrus/DSP coprocessor. */ /* Architectures are the sum of the base and extensions. The ARM ARM (rev E) defines the following: ARMv3, ARMv3M, ARMv4xM, ARMv4, ARMv4TxM, ARMv4T, @@ -75,22 +80,33 @@ #define ARM_ARCH_V5T (ARM_ARCH_V5 | ARM_EXT_V4T | ARM_EXT_V5T) #define ARM_ARCH_V5TExP (ARM_ARCH_V5T | ARM_EXT_V5ExP) #define ARM_ARCH_V5TE (ARM_ARCH_V5TExP | ARM_EXT_V5E) +#define ARM_ARCH_V5TEJ (ARM_ARCH_V5TE | ARM_EXT_V5J) + /* Processors with specific extensions in the co-processor space. */ -#define ARM_ARCH_XSCALE (ARM_ARCH_V5TE | ARM_EXT_XSCALE) +#define ARM_ARCH_XSCALE (ARM_ARCH_V5TE | ARM_CEXT_XSCALE) /* Some useful combinations: */ -#define ARM_ANY 0x00ffffff -#define ARM_ALL ARM_ANY +#define ARM_ANY 0x0000ffff /* Any basic core. */ +#define ARM_ALL 0x00ffffff /* Any core + co-processor */ +#define CPROC_ANY 0x00ff0000 /* Any co-processor */ +#define FPU_ANY 0xff000000 /* Note this is ~ARM_ALL. */ + -#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) -/* Some useful combinations. */ -#define FPU_ANY 0xff000000 /* Note this is ~ARM_ANY. */ +#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) /* Types of processor to assemble for. */ #define ARM_1 ARM_ARCH_V1 @@ -111,11 +127,12 @@ #if defined __thumb__ #define CPU_DEFAULT (ARM_ARCH_V5T) #else -#define CPU_DEFAULT ARM_ALL +#define CPU_DEFAULT ARM_ANY #endif #endif #endif +/* For backwards compatibility we default to the FPA. */ #ifndef FPU_DEFAULT #define FPU_DEFAULT FPU_ARCH_FPA #endif @@ -123,17 +140,27 @@ #define streq(a, b) (strcmp (a, b) == 0) #define skip_whitespace(str) while (*(str) == ' ') ++(str) -static unsigned long cpu_variant = CPU_DEFAULT | FPU_DEFAULT; +static unsigned long cpu_variant; static int target_oabi = 0; -#if defined OBJ_COFF || defined OBJ_ELF /* Flags stored in private area of BFD structure. */ -static boolean uses_apcs_26 = false; -static boolean atpcs = false; -static boolean support_interwork = false; -static boolean uses_apcs_float = false; -static boolean pic_code = false; -#endif +static int uses_apcs_26 = false; +static int atpcs = false; +static int support_interwork = false; +static int uses_apcs_float = false; +static int pic_code = false; + +/* Variables that we set while parsing command-line options. Once all + options have been read we re-process these values to set the real + assembly flags. */ +static int legacy_cpu = -1; +static int legacy_fpu = -1; + +static int mcpu_cpu_opt = -1; +static int mcpu_fpu_opt = -1; +static int march_cpu_opt = -1; +static int march_fpu_opt = -1; +static int mfpu_opt = -1; /* This array holds the chars that always start a comment. If the pre-processor is disabled, these aren't very useful. */ @@ -264,6 +291,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,16 +499,218 @@ static const struct asm_psr psrs[] = {"SPSR_cxsf", false, PSR_c | PSR_x | PSR_s | PSR_f}, }; -enum cirrus_regtype - { - CIRRUS_REGTYPE_MVF = 1, - CIRRUS_REGTYPE_MVFX = 2, - CIRRUS_REGTYPE_MVD = 3, - CIRRUS_REGTYPE_MVDX = 4, - CIRRUS_REGTYPE_MVAX = 5, - CIRRUS_REGTYPE_DSPSC = 6, - CIRRUS_REGTYPE_ANY = 7 - }; +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 +{ + const char * name; + int number; +}; + +/* Some well known registers that we refer to directly elsewhere. */ +#define REG_SP 13 +#define REG_LR 14 +#define REG_PC 15 + +/* These are the standard names. Users can add aliases with .req. */ +/* Integer Register Numbers. */ +static const struct reg_entry rn_table[] = +{ + {"r0", 0}, {"r1", 1}, {"r2", 2}, {"r3", 3}, + {"r4", 4}, {"r5", 5}, {"r6", 6}, {"r7", 7}, + {"r8", 8}, {"r9", 9}, {"r10", 10}, {"r11", 11}, + {"r12", 12}, {"r13", REG_SP}, {"r14", REG_LR}, {"r15", REG_PC}, + /* ATPCS Synonyms. */ + {"a1", 0}, {"a2", 1}, {"a3", 2}, {"a4", 3}, + {"v1", 4}, {"v2", 5}, {"v3", 6}, {"v4", 7}, + {"v5", 8}, {"v6", 9}, {"v7", 10}, {"v8", 11}, + /* Well-known aliases. */ + {"wr", 7}, + {"sb", 9}, {"sl", 10}, {"fp", 11}, + {"ip", 12}, {"sp", REG_SP}, {"lr", REG_LR}, {"pc", REG_PC}, + {NULL, 0} +}; + +/* Co-processor Numbers. */ +static const struct reg_entry cp_table[] = +{ + {"p0", 0}, {"p1", 1}, {"p2", 2}, {"p3", 3}, + {"p4", 4}, {"p5", 5}, {"p6", 6}, {"p7", 7}, + {"p8", 8}, {"p9", 9}, {"p10", 10}, {"p11", 11}, + {"p12", 12}, {"p13", 13}, {"p14", 14}, {"p15", 15}, + {NULL, 0} +}; + +/* Co-processor Register Numbers. */ +static const struct reg_entry cn_table[] = +{ + {"c0", 0}, {"c1", 1}, {"c2", 2}, {"c3", 3}, + {"c4", 4}, {"c5", 5}, {"c6", 6}, {"c7", 7}, + {"c8", 8}, {"c9", 9}, {"c10", 10}, {"c11", 11}, + {"c12", 12}, {"c13", 13}, {"c14", 14}, {"c15", 15}, + /* Not really valid, but kept for back-wards compatibility. */ + {"cr0", 0}, {"cr1", 1}, {"cr2", 2}, {"cr3", 3}, + {"cr4", 4}, {"cr5", 5}, {"cr6", 6}, {"cr7", 7}, + {"cr8", 8}, {"cr9", 9}, {"cr10", 10}, {"cr11", 11}, + {"cr12", 12}, {"cr13", 13}, {"cr14", 14}, {"cr15", 15}, + {NULL, 0} +}; + +/* FPA Registers. */ +static const struct reg_entry fn_table[] = +{ + {"f0", 0}, {"f1", 1}, {"f2", 2}, {"f3", 3}, + {"f4", 4}, {"f5", 5}, {"f6", 6}, {"f7", 7}, + {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} +}; + +/* Maverick DSP coprocessor registers. */ +static const struct reg_entry mav_mvf_table[] = +{ + {"mvf0", 0}, {"mvf1", 1}, {"mvf2", 2}, {"mvf3", 3}, + {"mvf4", 4}, {"mvf5", 5}, {"mvf6", 6}, {"mvf7", 7}, + {"mvf8", 8}, {"mvf9", 9}, {"mvf10", 10}, {"mvf11", 11}, + {"mvf12", 12}, {"mvf13", 13}, {"mvf14", 14}, {"mvf15", 15}, + {NULL, 0} +}; + +static const struct reg_entry mav_mvd_table[] = +{ + {"mvd0", 0}, {"mvd1", 1}, {"mvd2", 2}, {"mvd3", 3}, + {"mvd4", 4}, {"mvd5", 5}, {"mvd6", 6}, {"mvd7", 7}, + {"mvd8", 8}, {"mvd9", 9}, {"mvd10", 10}, {"mvd11", 11}, + {"mvd12", 12}, {"mvd13", 13}, {"mvd14", 14}, {"mvd15", 15}, + {NULL, 0} +}; + +static const struct reg_entry mav_mvfx_table[] = +{ + {"mvfx0", 0}, {"mvfx1", 1}, {"mvfx2", 2}, {"mvfx3", 3}, + {"mvfx4", 4}, {"mvfx5", 5}, {"mvfx6", 6}, {"mvfx7", 7}, + {"mvfx8", 8}, {"mvfx9", 9}, {"mvfx10", 10}, {"mvfx11", 11}, + {"mvfx12", 12}, {"mvfx13", 13}, {"mvfx14", 14}, {"mvfx15", 15}, + {NULL, 0} +}; + +static const struct reg_entry mav_mvdx_table[] = +{ + {"mvdx0", 0}, {"mvdx1", 1}, {"mvdx2", 2}, {"mvdx3", 3}, + {"mvdx4", 4}, {"mvdx5", 5}, {"mvdx6", 6}, {"mvdx7", 7}, + {"mvdx8", 8}, {"mvdx9", 9}, {"mvdx10", 10}, {"mvdx11", 11}, + {"mvdx12", 12}, {"mvdx13", 13}, {"mvdx14", 14}, {"mvdx15", 15}, + {NULL, 0} +}; + +static const struct reg_entry mav_mvax_table[] = +{ + {"mvax0", 0}, {"mvax1", 1}, {"mvax2", 2}, {"mvax3", 3}, + {NULL, 0} +}; + +static const struct reg_entry mav_dspsc_table[] = +{ + {"dspsc", 0}, + {NULL, 0} +}; + +struct reg_map +{ + const struct reg_entry *names; + int max_regno; + struct hash_control *htab; + const char *expected; +}; + +struct reg_map all_reg_maps[] = +{ + {rn_table, 15, NULL, N_("ARM register expected")}, + {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")}, + {mav_mvdx_table, 15, NULL, N_("Maverick MVFX register expected")}, + {mav_mvax_table, 3, NULL, N_("Maverick MVAX register expected")}, + {mav_dspsc_table, 0, NULL, N_("Maverick DSPSC register expected")}, +}; + +/* Enumeration matching entries in table above. */ +enum arm_reg_type +{ + REG_TYPE_RN = 0, +#define REG_TYPE_FIRST REG_TYPE_RN + REG_TYPE_CP = 1, + REG_TYPE_CN = 2, + REG_TYPE_FN = 3, + 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. */ /* ARM instructions. */ @@ -515,7 +748,7 @@ static void do_ldstv4 PARAMS ((char *)); /* ARM v4T. */ static void do_bx PARAMS ((char *)); -/* ARM v5. */ +/* ARM v5T. */ static void do_blx PARAMS ((char *)); static void do_bkpt PARAMS ((char *)); static void do_clz PARAMS ((char *)); @@ -523,17 +756,20 @@ static void do_lstc2 PARAMS ((char *)); static void do_cdp2 PARAMS ((char *)); static void do_co_reg2 PARAMS ((char *)); -/* ARM v5ExP. */ +/* ARM v5TExP. */ static void do_smla PARAMS ((char *)); static void do_smlal PARAMS ((char *)); static void do_smul PARAMS ((char *)); static void do_qadd PARAMS ((char *)); -/* ARM v5E. */ +/* ARM v5TE. */ static void do_pld PARAMS ((char *)); static void do_ldrd PARAMS ((char *)); static void do_co_reg2c PARAMS ((char *)); +/* ARM v5TEJ. */ +static void do_bxj PARAMS ((char *)); + /* Coprocessor Instructions. */ static void do_cdp PARAMS ((char *)); static void do_lstc PARAMS ((char *)); @@ -549,40 +785,102 @@ 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 *)); -static void do_mra PARAMS ((char *)); +static void do_xsc_mia PARAMS ((char *)); +static void do_xsc_mar PARAMS ((char *)); +static void do_xsc_mra PARAMS ((char *)); /* Maverick. */ -static void do_c_binops PARAMS ((char *, int)); -static void do_c_binops_1 PARAMS ((char *)); -static void do_c_binops_2 PARAMS ((char *)); -static void do_c_binops_3 PARAMS ((char *)); -static void do_c_triple PARAMS ((char *, int)); -static void do_c_triple_4 PARAMS ((char *)); -static void do_c_triple_5 PARAMS ((char *)); -static void do_c_quad PARAMS ((char *, int)); -static void do_c_quad_6 PARAMS ((char *)); -static void do_c_dspsc PARAMS ((char *, int)); -static void do_c_dspsc_1 PARAMS ((char *)); -static void do_c_dspsc_2 PARAMS ((char *)); -static void do_c_shift PARAMS ((char *, int)); -static void do_c_shift_1 PARAMS ((char *)); -static void do_c_shift_2 PARAMS ((char *)); -static void do_c_ldst PARAMS ((char *, int)); -static void do_c_ldst_1 PARAMS ((char *)); -static void do_c_ldst_2 PARAMS ((char *)); -static void do_c_ldst_3 PARAMS ((char *)); -static void do_c_ldst_4 PARAMS ((char *)); -static int cirrus_reg_required_here PARAMS ((char **, int, - enum cirrus_regtype)); -static int cirrus_valid_reg PARAMS ((int, enum cirrus_regtype)); -static int cirrus_parse_offset PARAMS ((char **, int *)); +static void do_mav_binops PARAMS ((char *, int, enum arm_reg_type, + enum arm_reg_type)); +static void do_mav_binops_1a PARAMS ((char *)); +static void do_mav_binops_1b PARAMS ((char *)); +static void do_mav_binops_1c PARAMS ((char *)); +static void do_mav_binops_1d PARAMS ((char *)); +static void do_mav_binops_1e PARAMS ((char *)); +static void do_mav_binops_1f PARAMS ((char *)); +static void do_mav_binops_1g PARAMS ((char *)); +static void do_mav_binops_1h PARAMS ((char *)); +static void do_mav_binops_1i PARAMS ((char *)); +static void do_mav_binops_1j PARAMS ((char *)); +static void do_mav_binops_1k PARAMS ((char *)); +static void do_mav_binops_1l PARAMS ((char *)); +static void do_mav_binops_1m PARAMS ((char *)); +static void do_mav_binops_1n PARAMS ((char *)); +static void do_mav_binops_1o PARAMS ((char *)); +static void do_mav_binops_2a PARAMS ((char *)); +static void do_mav_binops_2b PARAMS ((char *)); +static void do_mav_binops_2c PARAMS ((char *)); +static void do_mav_binops_3a PARAMS ((char *)); +static void do_mav_binops_3b PARAMS ((char *)); +static void do_mav_binops_3c PARAMS ((char *)); +static void do_mav_binops_3d PARAMS ((char *)); +static void do_mav_triple PARAMS ((char *, int, enum arm_reg_type, + enum arm_reg_type, + enum arm_reg_type)); +static void do_mav_triple_4a PARAMS ((char *)); +static void do_mav_triple_4b PARAMS ((char *)); +static void do_mav_triple_5a PARAMS ((char *)); +static void do_mav_triple_5b PARAMS ((char *)); +static void do_mav_triple_5c PARAMS ((char *)); +static void do_mav_triple_5d PARAMS ((char *)); +static void do_mav_triple_5e PARAMS ((char *)); +static void do_mav_triple_5f PARAMS ((char *)); +static void do_mav_triple_5g PARAMS ((char *)); +static void do_mav_triple_5h PARAMS ((char *)); +static void do_mav_quad PARAMS ((char *, int, enum arm_reg_type, + enum arm_reg_type, + enum arm_reg_type, + enum arm_reg_type)); +static void do_mav_quad_6a PARAMS ((char *)); +static void do_mav_quad_6b PARAMS ((char *)); +static void do_mav_dspsc_1 PARAMS ((char *)); +static void do_mav_dspsc_2 PARAMS ((char *)); +static void do_mav_shift PARAMS ((char *, enum arm_reg_type, + enum arm_reg_type)); +static void do_mav_shift_1 PARAMS ((char *)); +static void do_mav_shift_2 PARAMS ((char *)); +static void do_mav_ldst PARAMS ((char *, enum arm_reg_type)); +static void do_mav_ldst_1 PARAMS ((char *)); +static void do_mav_ldst_2 PARAMS ((char *)); +static void do_mav_ldst_3 PARAMS ((char *)); +static void do_mav_ldst_4 PARAMS ((char *)); + +static int mav_reg_required_here PARAMS ((char **, int, + enum arm_reg_type)); +static int mav_parse_offset PARAMS ((char **, int *)); static void fix_new_arm PARAMS ((fragS *, int, short, expressionS *, int, int)); -static int arm_reg_parse PARAMS ((char **)); +static int arm_reg_parse PARAMS ((char **, struct hash_control *)); +static enum arm_reg_type arm_reg_parse_any PARAMS ((char *)); static const struct asm_psr * arm_psr_parse PARAMS ((char **)); static void symbol_locate PARAMS ((symbolS *, const char *, segT, valueT, fragS *)); @@ -599,8 +897,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 *)); @@ -613,14 +919,17 @@ static int decode_shift PARAMS ((char **, int)); static int ldst_extend PARAMS ((char **)); static int ldst_extend_v4 PARAMS ((char **)); static void thumb_add_sub PARAMS ((char *, int)); -static void insert_reg PARAMS ((int)); +static void insert_reg PARAMS ((const struct reg_entry *, + struct hash_control *)); static void thumb_shift PARAMS ((char *, int)); static void thumb_mov_compare PARAMS ((char *, int)); static void build_arm_ops_hsh PARAMS ((void)); static void set_constant_flonums PARAMS ((void)); static valueT md_chars_to_number PARAMS ((char *, int)); -static void insert_reg_alias PARAMS ((char *, int)); -static void output_inst PARAMS ((void)); +static void build_reg_hsh PARAMS ((struct reg_map *)); +static void insert_reg_alias PARAMS ((char *, int, struct hash_control *)); +static int create_register_alias PARAMS ((char *, char *)); +static void output_inst PARAMS ((const char *)); static int accum0_required_here PARAMS ((char **)); static int ld_mode_required_here PARAMS ((char **)); static void do_branch25 PARAMS ((char *)); @@ -634,22 +943,22 @@ static bfd_reloc_code_real_type arm_parse_reloc PARAMS ((void)); #define INSN_SIZE 4 /* "INSN X,Y" where X:bit12, Y:bit16. */ -#define CIRRUS_MODE1 0x100c +#define MAV_MODE1 0x100c /* "INSN X,Y" where X:bit16, Y:bit12. */ -#define CIRRUS_MODE2 0x0c10 +#define MAV_MODE2 0x0c10 /* "INSN X,Y" where X:0, Y:bit16. */ -#define CIRRUS_MODE3 0x1000 +#define MAV_MODE3 0x1000 /* "INSN X,Y,Z" where X:16, Y:0, Z:12. */ -#define CIRRUS_MODE4 0x0c0010 +#define MAV_MODE4 0x0c0010 /* "INSN X,Y,Z" where X:12, Y:16, Z:0. */ -#define CIRRUS_MODE5 0x00100c +#define MAV_MODE5 0x00100c /* "INSN W,X,Y,Z" where W:5, X:12, Y:16, Z:0. */ -#define CIRRUS_MODE6 0x00100c05 +#define MAV_MODE6 0x00100c05 struct asm_opcode { @@ -797,11 +1106,11 @@ static const struct asm_opcode insns[] = {"strh", 0xe00000b0, 3, ARM_EXT_V4, do_ldstv4}, /* ARM Architecture 4T. */ - /* Note: bx (and blx) are required on V5, even if the processor does + /* Note: bx (and blx) are required on V5, even if the processor does not support Thumb. */ {"bx", 0xe12fff10, 2, ARM_EXT_V4T | ARM_EXT_V5, do_bx}, - /* ARM Architecture 5. */ + /* ARM Architecture 5T. */ /* Note: blx has 2 variants, so the .value is set dynamically. Only one of the variants has conditional execution. */ {"blx", 0xe0000000, 3, ARM_EXT_V5, do_blx}, @@ -815,7 +1124,7 @@ static const struct asm_opcode insns[] = {"mcr2", 0xfe000010, 0, ARM_EXT_V5, do_co_reg2}, {"mrc2", 0xfe100010, 0, ARM_EXT_V5, do_co_reg2}, - /* ARM Architecture 5ExP. */ + /* ARM Architecture 5TExP. */ {"smlabb", 0xe1000080, 6, ARM_EXT_V5ExP, do_smla}, {"smlatb", 0xe10000a0, 6, ARM_EXT_V5ExP, do_smla}, {"smlabt", 0xe10000c0, 6, ARM_EXT_V5ExP, do_smla}, @@ -842,7 +1151,7 @@ static const struct asm_opcode insns[] = {"qsub", 0xe1200050, 4, ARM_EXT_V5ExP, do_qadd}, {"qdsub", 0xe1600050, 5, ARM_EXT_V5ExP, do_qadd}, - /* ARM Architecture 5E. */ + /* ARM Architecture 5TE. */ {"pld", 0xf450f000, 0, ARM_EXT_V5E, do_pld}, {"ldrd", 0xe00000d0, 3, ARM_EXT_V5E, do_ldrd}, {"strd", 0xe00000f0, 3, ARM_EXT_V5E, do_ldrd}, @@ -850,6 +1159,9 @@ static const struct asm_opcode insns[] = {"mcrr", 0xec400000, 4, ARM_EXT_V5E, do_co_reg2c}, {"mrrc", 0xec500000, 4, ARM_EXT_V5E, do_co_reg2c}, + /* ARM Architecture 5TEJ. */ + {"bxj", 0xe12fff20, 3, ARM_EXT_V5J, do_bxj}, + /* Core FPA instruction set (V1). */ {"wfs", 0xee200110, 3, FPU_FPA_EXT_V1, do_fpa_ctrl}, {"rfs", 0xee300110, 3, FPU_FPA_EXT_V1, do_fpa_ctrl}, @@ -1293,93 +1605,206 @@ 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}, - {"miabb", 0xee2c0010, 5, ARM_EXT_XSCALE, do_mia}, - {"miabt", 0xee2d0010, 5, ARM_EXT_XSCALE, do_mia}, - {"miatb", 0xee2e0010, 5, ARM_EXT_XSCALE, do_mia}, - {"miatt", 0xee2f0010, 5, ARM_EXT_XSCALE, do_mia}, - {"mar", 0xec400000, 3, ARM_EXT_XSCALE, do_mar}, - {"mra", 0xec500000, 3, ARM_EXT_XSCALE, do_mra}, - - /* Cirrus DSP instructions. */ - {"cfldrs", 0xec100400, 6, ARM_EXT_MAVERICK, do_c_ldst_1}, - {"cfldrd", 0xec500400, 6, ARM_EXT_MAVERICK, do_c_ldst_2}, - {"cfldr32", 0xec100500, 7, ARM_EXT_MAVERICK, do_c_ldst_3}, - {"cfldr64", 0xec500500, 7, ARM_EXT_MAVERICK, do_c_ldst_4}, - {"cfstrs", 0xec000400, 6, ARM_EXT_MAVERICK, do_c_ldst_1}, - {"cfstrd", 0xec400400, 6, ARM_EXT_MAVERICK, do_c_ldst_2}, - {"cfstr32", 0xec000500, 7, ARM_EXT_MAVERICK, do_c_ldst_3}, - {"cfstr64", 0xec400500, 7, ARM_EXT_MAVERICK, do_c_ldst_4}, - {"cfmvsr", 0xee000450, 6, ARM_EXT_MAVERICK, do_c_binops_2}, - {"cfmvrs", 0xee100450, 6, ARM_EXT_MAVERICK, do_c_binops_1}, - {"cfmvdlr", 0xee000410, 7, ARM_EXT_MAVERICK, do_c_binops_2}, - {"cfmvrdl", 0xee100410, 7, ARM_EXT_MAVERICK, do_c_binops_1}, - {"cfmvdhr", 0xee000430, 7, ARM_EXT_MAVERICK, do_c_binops_2}, - {"cfmvrdh", 0xee100430, 7, ARM_EXT_MAVERICK, do_c_binops_1}, - {"cfmv64lr", 0xee000510, 8, ARM_EXT_MAVERICK, do_c_binops_2}, - {"cfmvr64l", 0xee100510, 8, ARM_EXT_MAVERICK, do_c_binops_1}, - {"cfmv64hr", 0xee000530, 8, ARM_EXT_MAVERICK, do_c_binops_2}, - {"cfmvr64h", 0xee100530, 8, ARM_EXT_MAVERICK, do_c_binops_1}, - {"cfmval32", 0xee100610, 8, ARM_EXT_MAVERICK, do_c_binops_3}, - {"cfmv32al", 0xee000610, 8, ARM_EXT_MAVERICK, do_c_binops_3}, - {"cfmvam32", 0xee100630, 8, ARM_EXT_MAVERICK, do_c_binops_3}, - {"cfmv32am", 0xee000630, 8, ARM_EXT_MAVERICK, do_c_binops_3}, - {"cfmvah32", 0xee100650, 8, ARM_EXT_MAVERICK, do_c_binops_3}, - {"cfmv32ah", 0xee000650, 8, ARM_EXT_MAVERICK, do_c_binops_3}, - {"cfmv32a", 0xee000670, 7, ARM_EXT_MAVERICK, do_c_binops_3}, - {"cfmva32", 0xee100670, 7, ARM_EXT_MAVERICK, do_c_binops_3}, - {"cfmv64a", 0xee000690, 7, ARM_EXT_MAVERICK, do_c_binops_3}, - {"cfmva64", 0xee100690, 7, ARM_EXT_MAVERICK, do_c_binops_3}, - {"cfmvsc32", 0xee1006b0, 8, ARM_EXT_MAVERICK, do_c_dspsc_1}, - {"cfmv32sc", 0xee0006b0, 8, ARM_EXT_MAVERICK, do_c_dspsc_2}, - {"cfcpys", 0xee000400, 6, ARM_EXT_MAVERICK, do_c_binops_1}, - {"cfcpyd", 0xee000420, 6, ARM_EXT_MAVERICK, do_c_binops_1}, - {"cfcvtsd", 0xee000460, 7, ARM_EXT_MAVERICK, do_c_binops_1}, - {"cfcvtds", 0xee000440, 7, ARM_EXT_MAVERICK, do_c_binops_1}, - {"cfcvt32s", 0xee000480, 8, ARM_EXT_MAVERICK, do_c_binops_1}, - {"cfcvt32d", 0xee0004a0, 8, ARM_EXT_MAVERICK, do_c_binops_1}, - {"cfcvt64s", 0xee0004c0, 8, ARM_EXT_MAVERICK, do_c_binops_1}, - {"cfcvt64d", 0xee0004e0, 8, ARM_EXT_MAVERICK, do_c_binops_1}, - {"cfcvts32", 0xee100580, 8, ARM_EXT_MAVERICK, do_c_binops_1}, - {"cfcvtd32", 0xee1005a0, 8, ARM_EXT_MAVERICK, do_c_binops_1}, - {"cftruncs32", 0xee1005c0, 10, ARM_EXT_MAVERICK, do_c_binops_1}, - {"cftruncd32", 0xee1005e0, 10, ARM_EXT_MAVERICK, do_c_binops_1}, - {"cfrshl32", 0xee000550, 8, ARM_EXT_MAVERICK, do_c_triple_4}, - {"cfrshl64", 0xee000570, 8, ARM_EXT_MAVERICK, do_c_triple_4}, - {"cfsh32", 0xee000500, 6, ARM_EXT_MAVERICK, do_c_shift_1}, - {"cfsh64", 0xee200500, 6, ARM_EXT_MAVERICK, do_c_shift_2}, - {"cfcmps", 0xee100490, 6, ARM_EXT_MAVERICK, do_c_triple_5}, - {"cfcmpd", 0xee1004b0, 6, ARM_EXT_MAVERICK, do_c_triple_5}, - {"cfcmp32", 0xee100590, 7, ARM_EXT_MAVERICK, do_c_triple_5}, - {"cfcmp64", 0xee1005b0, 7, ARM_EXT_MAVERICK, do_c_triple_5}, - {"cfabss", 0xee300400, 6, ARM_EXT_MAVERICK, do_c_binops_1}, - {"cfabsd", 0xee300420, 6, ARM_EXT_MAVERICK, do_c_binops_1}, - {"cfnegs", 0xee300440, 6, ARM_EXT_MAVERICK, do_c_binops_1}, - {"cfnegd", 0xee300460, 6, ARM_EXT_MAVERICK, do_c_binops_1}, - {"cfadds", 0xee300480, 6, ARM_EXT_MAVERICK, do_c_triple_5}, - {"cfaddd", 0xee3004a0, 6, ARM_EXT_MAVERICK, do_c_triple_5}, - {"cfsubs", 0xee3004c0, 6, ARM_EXT_MAVERICK, do_c_triple_5}, - {"cfsubd", 0xee3004e0, 6, ARM_EXT_MAVERICK, do_c_triple_5}, - {"cfmuls", 0xee100400, 6, ARM_EXT_MAVERICK, do_c_triple_5}, - {"cfmuld", 0xee100420, 6, ARM_EXT_MAVERICK, do_c_triple_5}, - {"cfabs32", 0xee300500, 7, ARM_EXT_MAVERICK, do_c_binops_1}, - {"cfabs64", 0xee300520, 7, ARM_EXT_MAVERICK, do_c_binops_1}, - {"cfneg32", 0xee300540, 7, ARM_EXT_MAVERICK, do_c_binops_1}, - {"cfneg64", 0xee300560, 7, ARM_EXT_MAVERICK, do_c_binops_1}, - {"cfadd32", 0xee300580, 7, ARM_EXT_MAVERICK, do_c_triple_5}, - {"cfadd64", 0xee3005a0, 7, ARM_EXT_MAVERICK, do_c_triple_5}, - {"cfsub32", 0xee3005c0, 7, ARM_EXT_MAVERICK, do_c_triple_5}, - {"cfsub64", 0xee3005e0, 7, ARM_EXT_MAVERICK, do_c_triple_5}, - {"cfmul32", 0xee100500, 7, ARM_EXT_MAVERICK, do_c_triple_5}, - {"cfmul64", 0xee100520, 7, ARM_EXT_MAVERICK, do_c_triple_5}, - {"cfmac32", 0xee100540, 7, ARM_EXT_MAVERICK, do_c_triple_5}, - {"cfmsc32", 0xee100560, 7, ARM_EXT_MAVERICK, do_c_triple_5}, - {"cfmadd32", 0xee000600, 8, ARM_EXT_MAVERICK, do_c_quad_6}, - {"cfmsub32", 0xee100600, 8, ARM_EXT_MAVERICK, do_c_quad_6}, - {"cfmadda32", 0xee200600, 9, ARM_EXT_MAVERICK, do_c_quad_6}, - {"cfmsuba32", 0xee300600, 9, ARM_EXT_MAVERICK, do_c_quad_6}, + {"mia", 0xee200010, 3, ARM_CEXT_XSCALE, do_xsc_mia}, + {"miaph", 0xee280010, 5, ARM_CEXT_XSCALE, do_xsc_mia}, + {"miabb", 0xee2c0010, 5, ARM_CEXT_XSCALE, do_xsc_mia}, + {"miabt", 0xee2d0010, 5, ARM_CEXT_XSCALE, do_xsc_mia}, + {"miatb", 0xee2e0010, 5, ARM_CEXT_XSCALE, do_xsc_mia}, + {"miatt", 0xee2f0010, 5, ARM_CEXT_XSCALE, do_xsc_mia}, + {"mar", 0xec400000, 3, ARM_CEXT_XSCALE, do_xsc_mar}, + {"mra", 0xec500000, 3, ARM_CEXT_XSCALE, do_xsc_mra}, + + /* Cirrus Maverick instructions. */ + {"cfldrs", 0xec100400, 6, ARM_CEXT_MAVERICK, do_mav_ldst_1}, + {"cfldrd", 0xec500400, 6, ARM_CEXT_MAVERICK, do_mav_ldst_2}, + {"cfldr32", 0xec100500, 7, ARM_CEXT_MAVERICK, do_mav_ldst_3}, + {"cfldr64", 0xec500500, 7, ARM_CEXT_MAVERICK, do_mav_ldst_4}, + {"cfstrs", 0xec000400, 6, ARM_CEXT_MAVERICK, do_mav_ldst_1}, + {"cfstrd", 0xec400400, 6, ARM_CEXT_MAVERICK, do_mav_ldst_2}, + {"cfstr32", 0xec000500, 7, ARM_CEXT_MAVERICK, do_mav_ldst_3}, + {"cfstr64", 0xec400500, 7, ARM_CEXT_MAVERICK, do_mav_ldst_4}, + {"cfmvsr", 0xee000450, 6, ARM_CEXT_MAVERICK, do_mav_binops_2a}, + {"cfmvrs", 0xee100450, 6, ARM_CEXT_MAVERICK, do_mav_binops_1a}, + {"cfmvdlr", 0xee000410, 7, ARM_CEXT_MAVERICK, do_mav_binops_2b}, + {"cfmvrdl", 0xee100410, 7, ARM_CEXT_MAVERICK, do_mav_binops_1b}, + {"cfmvdhr", 0xee000430, 7, ARM_CEXT_MAVERICK, do_mav_binops_2b}, + {"cfmvrdh", 0xee100430, 7, ARM_CEXT_MAVERICK, do_mav_binops_1b}, + {"cfmv64lr", 0xee000510, 8, ARM_CEXT_MAVERICK, do_mav_binops_2c}, + {"cfmvr64l", 0xee100510, 8, ARM_CEXT_MAVERICK, do_mav_binops_1c}, + {"cfmv64hr", 0xee000530, 8, ARM_CEXT_MAVERICK, do_mav_binops_2c}, + {"cfmvr64h", 0xee100530, 8, ARM_CEXT_MAVERICK, do_mav_binops_1c}, + {"cfmval32", 0xee100610, 8, ARM_CEXT_MAVERICK, do_mav_binops_3a}, + {"cfmv32al", 0xee000610, 8, ARM_CEXT_MAVERICK, do_mav_binops_3b}, + {"cfmvam32", 0xee100630, 8, ARM_CEXT_MAVERICK, do_mav_binops_3a}, + {"cfmv32am", 0xee000630, 8, ARM_CEXT_MAVERICK, do_mav_binops_3b}, + {"cfmvah32", 0xee100650, 8, ARM_CEXT_MAVERICK, do_mav_binops_3a}, + {"cfmv32ah", 0xee000650, 8, ARM_CEXT_MAVERICK, do_mav_binops_3b}, + {"cfmva32", 0xee100670, 7, ARM_CEXT_MAVERICK, do_mav_binops_3a}, + {"cfmv32a", 0xee000670, 7, ARM_CEXT_MAVERICK, do_mav_binops_3b}, + {"cfmva64", 0xee100690, 7, ARM_CEXT_MAVERICK, do_mav_binops_3c}, + {"cfmv64a", 0xee000690, 7, ARM_CEXT_MAVERICK, do_mav_binops_3d}, + {"cfmvsc32", 0xee1006b0, 8, ARM_CEXT_MAVERICK, do_mav_dspsc_1}, + {"cfmv32sc", 0xee0006b0, 8, ARM_CEXT_MAVERICK, do_mav_dspsc_2}, + {"cfcpys", 0xee000400, 6, ARM_CEXT_MAVERICK, do_mav_binops_1d}, + {"cfcpyd", 0xee000420, 6, ARM_CEXT_MAVERICK, do_mav_binops_1e}, + {"cfcvtsd", 0xee000460, 7, ARM_CEXT_MAVERICK, do_mav_binops_1f}, + {"cfcvtds", 0xee000440, 7, ARM_CEXT_MAVERICK, do_mav_binops_1g}, + {"cfcvt32s", 0xee000480, 8, ARM_CEXT_MAVERICK, do_mav_binops_1h}, + {"cfcvt32d", 0xee0004a0, 8, ARM_CEXT_MAVERICK, do_mav_binops_1i}, + {"cfcvt64s", 0xee0004c0, 8, ARM_CEXT_MAVERICK, do_mav_binops_1j}, + {"cfcvt64d", 0xee0004e0, 8, ARM_CEXT_MAVERICK, do_mav_binops_1k}, + {"cfcvts32", 0xee100580, 8, ARM_CEXT_MAVERICK, do_mav_binops_1l}, + {"cfcvtd32", 0xee1005a0, 8, ARM_CEXT_MAVERICK, do_mav_binops_1m}, + {"cftruncs32", 0xee1005c0, 10, ARM_CEXT_MAVERICK, do_mav_binops_1l}, + {"cftruncd32", 0xee1005e0, 10, ARM_CEXT_MAVERICK, do_mav_binops_1m}, + {"cfrshl32", 0xee000550, 8, ARM_CEXT_MAVERICK, do_mav_triple_4a}, + {"cfrshl64", 0xee000570, 8, ARM_CEXT_MAVERICK, do_mav_triple_4b}, + {"cfsh32", 0xee000500, 6, ARM_CEXT_MAVERICK, do_mav_shift_1}, + {"cfsh64", 0xee200500, 6, ARM_CEXT_MAVERICK, do_mav_shift_2}, + {"cfcmps", 0xee100490, 6, ARM_CEXT_MAVERICK, do_mav_triple_5a}, + {"cfcmpd", 0xee1004b0, 6, ARM_CEXT_MAVERICK, do_mav_triple_5b}, + {"cfcmp32", 0xee100590, 7, ARM_CEXT_MAVERICK, do_mav_triple_5c}, + {"cfcmp64", 0xee1005b0, 7, ARM_CEXT_MAVERICK, do_mav_triple_5d}, + {"cfabss", 0xee300400, 6, ARM_CEXT_MAVERICK, do_mav_binops_1d}, + {"cfabsd", 0xee300420, 6, ARM_CEXT_MAVERICK, do_mav_binops_1e}, + {"cfnegs", 0xee300440, 6, ARM_CEXT_MAVERICK, do_mav_binops_1d}, + {"cfnegd", 0xee300460, 6, ARM_CEXT_MAVERICK, do_mav_binops_1e}, + {"cfadds", 0xee300480, 6, ARM_CEXT_MAVERICK, do_mav_triple_5e}, + {"cfaddd", 0xee3004a0, 6, ARM_CEXT_MAVERICK, do_mav_triple_5f}, + {"cfsubs", 0xee3004c0, 6, ARM_CEXT_MAVERICK, do_mav_triple_5e}, + {"cfsubd", 0xee3004e0, 6, ARM_CEXT_MAVERICK, do_mav_triple_5f}, + {"cfmuls", 0xee100400, 6, ARM_CEXT_MAVERICK, do_mav_triple_5e}, + {"cfmuld", 0xee100420, 6, ARM_CEXT_MAVERICK, do_mav_triple_5f}, + {"cfabs32", 0xee300500, 7, ARM_CEXT_MAVERICK, do_mav_binops_1n}, + {"cfabs64", 0xee300520, 7, ARM_CEXT_MAVERICK, do_mav_binops_1o}, + {"cfneg32", 0xee300540, 7, ARM_CEXT_MAVERICK, do_mav_binops_1n}, + {"cfneg64", 0xee300560, 7, ARM_CEXT_MAVERICK, do_mav_binops_1o}, + {"cfadd32", 0xee300580, 7, ARM_CEXT_MAVERICK, do_mav_triple_5g}, + {"cfadd64", 0xee3005a0, 7, ARM_CEXT_MAVERICK, do_mav_triple_5h}, + {"cfsub32", 0xee3005c0, 7, ARM_CEXT_MAVERICK, do_mav_triple_5g}, + {"cfsub64", 0xee3005e0, 7, ARM_CEXT_MAVERICK, do_mav_triple_5h}, + {"cfmul32", 0xee100500, 7, ARM_CEXT_MAVERICK, do_mav_triple_5g}, + {"cfmul64", 0xee100520, 7, ARM_CEXT_MAVERICK, do_mav_triple_5h}, + {"cfmac32", 0xee100540, 7, ARM_CEXT_MAVERICK, do_mav_triple_5g}, + {"cfmsc32", 0xee100560, 7, ARM_CEXT_MAVERICK, do_mav_triple_5g}, + {"cfmadd32", 0xee000600, 8, ARM_CEXT_MAVERICK, do_mav_quad_6a}, + {"cfmsub32", 0xee100600, 8, ARM_CEXT_MAVERICK, do_mav_quad_6a}, + {"cfmadda32", 0xee200600, 9, ARM_CEXT_MAVERICK, do_mav_quad_6b}, + {"cfmsuba32", 0xee300600, 9, ARM_CEXT_MAVERICK, do_mav_quad_6b}, }; /* Defines for various bits that we will want to toggle. */ @@ -1608,95 +2033,15 @@ static const struct thumb_opcode tinsns[] = {"bkpt", 0xbe00, 2, ARM_EXT_V5T, do_t_bkpt}, }; -struct reg_entry -{ - const char * name; - int number; -}; - -#define int_register(reg) ((reg) >= 0 && (reg) <= 15) -#define cp_register(reg) ((reg) >= 32 && (reg) <= 47) -#define fp_register(reg) ((reg) >= 16 && (reg) <= 23) - -#define ARM_EXT_MAVERICKSC_REG 134 - -#define cirrus_register(reg) ((reg) >= 50 && (reg) <= 134) -#define cirrus_mvf_register(reg) ((reg) >= 50 && (reg) <= 65) -#define cirrus_mvd_register(reg) ((reg) >= 70 && (reg) <= 85) -#define cirrus_mvfx_register(reg) ((reg) >= 90 && (reg) <= 105) -#define cirrus_mvdx_register(reg) ((reg) >= 110 && (reg) <= 125) -#define cirrus_mvax_register(reg) ((reg) >= 130 && (reg) <= 133) -#define ARM_EXT_MAVERICKsc_register(reg) ((reg) == ARM_EXT_MAVERICKSC_REG) - -#define REG_SP 13 -#define REG_LR 14 -#define REG_PC 15 - -/* These are the standard names. Users can add aliases with .req. */ -static const struct reg_entry reg_table[] = -{ - /* Processor Register Numbers. */ - {"r0", 0}, {"r1", 1}, {"r2", 2}, {"r3", 3}, - {"r4", 4}, {"r5", 5}, {"r6", 6}, {"r7", 7}, - {"r8", 8}, {"r9", 9}, {"r10", 10}, {"r11", 11}, - {"r12", 12}, {"r13", REG_SP},{"r14", REG_LR},{"r15", REG_PC}, - /* APCS conventions. */ - {"a1", 0}, {"a2", 1}, {"a3", 2}, {"a4", 3}, - {"v1", 4}, {"v2", 5}, {"v3", 6}, {"v4", 7}, {"v5", 8}, - {"v6", 9}, {"sb", 9}, {"v7", 10}, {"sl", 10}, - {"fp", 11}, {"ip", 12}, {"sp", REG_SP},{"lr", REG_LR},{"pc", REG_PC}, - /* ATPCS additions to APCS conventions. */ - {"wr", 7}, {"v8", 11}, - /* FP Registers. */ - {"f0", 16}, {"f1", 17}, {"f2", 18}, {"f3", 19}, - {"f4", 20}, {"f5", 21}, {"f6", 22}, {"f7", 23}, - {"c0", 32}, {"c1", 33}, {"c2", 34}, {"c3", 35}, - {"c4", 36}, {"c5", 37}, {"c6", 38}, {"c7", 39}, - {"c8", 40}, {"c9", 41}, {"c10", 42}, {"c11", 43}, - {"c12", 44}, {"c13", 45}, {"c14", 46}, {"c15", 47}, - {"cr0", 32}, {"cr1", 33}, {"cr2", 34}, {"cr3", 35}, - {"cr4", 36}, {"cr5", 37}, {"cr6", 38}, {"cr7", 39}, - {"cr8", 40}, {"cr9", 41}, {"cr10", 42}, {"cr11", 43}, - {"cr12", 44}, {"cr13", 45}, {"cr14", 46}, {"cr15", 47}, - /* ATPCS additions to float register names. */ - {"s0",16}, {"s1",17}, {"s2",18}, {"s3",19}, - {"s4",20}, {"s5",21}, {"s6",22}, {"s7",23}, - {"d0",16}, {"d1",17}, {"d2",18}, {"d3",19}, - {"d4",20}, {"d5",21}, {"d6",22}, {"d7",23}, - /* Cirrus DSP coprocessor registers. */ - {"mvf0", 50}, {"mvf1", 51}, {"mvf2", 52}, {"mvf3", 53}, - {"mvf4", 54}, {"mvf5", 55}, {"mvf6", 56}, {"mvf7", 57}, - {"mvf8", 58}, {"mvf9", 59}, {"mvf10", 60}, {"mvf11", 61}, - {"mvf12", 62},{"mvf13", 63}, {"mvf14", 64}, {"mvf15", 65}, - {"mvd0", 70}, {"mvd1", 71}, {"mvd2", 72}, {"mvd3", 73}, - {"mvd4", 74}, {"mvd5", 75}, {"mvd6", 76}, {"mvd7", 77}, - {"mvd8", 78}, {"mvd9", 79}, {"mvd10", 80}, {"mvd11", 81}, - {"mvd12", 82},{"mvd13", 83}, {"mvd14", 84}, {"mvd15", 85}, - {"mvfx0", 90},{"mvfx1", 91}, {"mvfx2", 92}, {"mvfx3", 93}, - {"mvfx4", 94},{"mvfx5", 95}, {"mvfx6", 96}, {"mvfx7", 97}, - {"mvfx8", 98},{"mvfx9", 99}, {"mvfx10", 100},{"mvfx11", 101}, - {"mvfx12", 102},{"mvfx13", 103},{"mvfx14", 104},{"mvfx15", 105}, - {"mvdx0", 110}, {"mvdx1", 111}, {"mvdx2", 112}, {"mvdx3", 113}, - {"mvdx4", 114}, {"mvdx5", 115}, {"mvdx6", 116}, {"mvdx7", 117}, - {"mvdx8", 118}, {"mvdx9", 119}, {"mvdx10", 120},{"mvdx11", 121}, - {"mvdx12", 122},{"mvdx13", 123},{"mvdx14", 124},{"mvdx15", 125}, - {"mvax0", 130}, {"mvax1", 131}, {"mvax2", 132}, {"mvax3", 133}, - {"dspsc", ARM_EXT_MAVERICKSC_REG}, - /* FIXME: At some point we need to add VFP register names. */ - /* Array terminator. */ - {NULL, 0} -}; - -#define BAD_ARGS _("Bad arguments to instruction") +#define BAD_ARGS _("bad arguments to instruction") #define BAD_PC _("r15 not allowed here") -#define BAD_COND _("Instruction is not conditional") +#define BAD_COND _("instruction is not conditional") #define ERR_NO_ACCUM _("acc0 expected") static struct hash_control * arm_ops_hsh = NULL; static struct hash_control * arm_tops_hsh = NULL; static struct hash_control * arm_cond_hsh = NULL; static struct hash_control * arm_shift_hsh = NULL; -static struct hash_control * arm_reg_hsh = NULL; static struct hash_control * arm_psr_hsh = NULL; /* This table describes all the machine specific pseudo-ops the assembler @@ -1718,8 +2063,8 @@ static void s_thumb_func PARAMS ((int)); static void s_thumb_set PARAMS ((int)); static void arm_s_text PARAMS ((int)); static void arm_s_data PARAMS ((int)); -#ifdef OBJ_ELF static void arm_s_section PARAMS ((int)); +#ifdef OBJ_ELF static void s_arm_elf_cons PARAMS ((int)); #endif @@ -1743,11 +2088,11 @@ const pseudo_typeS md_pseudo_table[] = /* Allow for the effect of section changes. */ { "text", arm_s_text, 0 }, { "data", arm_s_data, 0 }, -#ifdef OBJ_ELF { "section", arm_s_section, 0 }, { "section.s", arm_s_section, 0 }, { "sect", arm_s_section, 0 }, { "sect.s", arm_s_section, 0 }, +#ifdef OBJ_ELF { "word", s_arm_elf_cons, 4 }, { "long", s_arm_elf_cons, 4 }, { "file", dwarf2_directive_file, 0 }, @@ -1761,6 +2106,12 @@ const pseudo_typeS md_pseudo_table[] = { 0, 0, 0 } }; +/* Other internal functions. */ +static int arm_parse_extension PARAMS ((char *, int *)); +static int arm_parse_cpu PARAMS ((char *)); +static int arm_parse_arch PARAMS ((char *)); +static int arm_parse_fpu PARAMS ((char *)); + /* Stuff needed to resolve the label ambiguity As: ... @@ -1814,14 +2165,14 @@ add_to_lit_pool () break; if (literals[lit_count].exp.X_op == inst.reloc.exp.X_op - && inst.reloc.exp.X_op == O_symbol - && (literals[lit_count].exp.X_add_number + && inst.reloc.exp.X_op == O_symbol + && (literals[lit_count].exp.X_add_number == inst.reloc.exp.X_add_number) - && (literals[lit_count].exp.X_add_symbol + && (literals[lit_count].exp.X_add_symbol == inst.reloc.exp.X_add_symbol) - && (literals[lit_count].exp.X_op_symbol + && (literals[lit_count].exp.X_op_symbol == inst.reloc.exp.X_op_symbol)) - break; + break; lit_count++; } @@ -1830,7 +2181,7 @@ add_to_lit_pool () { if (next_literal_pool_place >= MAX_LITERAL_POOL_SIZE) { - inst.error = _("Literal Pool Overflow"); + inst.error = _("literal pool overflow"); return FAIL; } @@ -1876,7 +2227,7 @@ symbol_locate (symbolP, name, segment, valu, frag) S_SET_SEGMENT (symbolP, segment); S_SET_VALUE (symbolP, valu); - symbol_clear_list_pointers(symbolP); + symbol_clear_list_pointers (symbolP); symbol_set_frag (symbolP, frag); @@ -1972,7 +2323,7 @@ static void s_req (a) int a ATTRIBUTE_UNUSED; { - as_bad (_("Invalid syntax for .req directive.")); + as_bad (_("invalid syntax for .req directive")); } static void @@ -2047,10 +2398,10 @@ s_align (unused) temp = get_absolute_expression (); if (temp > max_alignment) - as_bad (_("Alignment too large: %d. assumed."), temp = max_alignment); + as_bad (_("alignment too large: %d assumed"), temp = max_alignment); else if (temp < 0) { - as_bad (_("Alignment negative. 0 assumed.")); + as_bad (_("alignment negative. 0 assumed.")); temp = 0; } @@ -2134,7 +2485,7 @@ s_thumb_set (equiv) if (*input_line_pointer != ',') { *end_name = 0; - as_bad (_("Expected comma after name \"%s\""), name); + as_bad (_("expected comma after name \"%s\""), name); *end_name = delim; ignore_rest_of_line (); return; @@ -2234,16 +2585,19 @@ arm_s_data (ignore) #endif } -#ifdef OBJ_ELF static void arm_s_section (ignore) int ignore; { s_ltorg (0); +#ifdef OBJ_ELF obj_elf_section (ignore); -} #endif +#ifdef OBJ_COFF + obj_coff_section (ignore); +#endif +} static void opcode_select (width) @@ -2267,15 +2621,15 @@ opcode_select (width) case 32: if (thumb_mode) { - if ((cpu_variant & ARM_ANY) == ARM_EXT_V4T) + if ((cpu_variant & ARM_ALL) == ARM_EXT_V4T) as_bad (_("selected processor does not support ARM opcodes")); thumb_mode = 0; if (!need_pass_2) - frag_align (2, 0, 0); + frag_align (2, 0, 0); - record_alignment (now_seg, 1); + record_alignment (now_seg, 1); } break; @@ -2321,12 +2675,12 @@ s_code (unused) static void end_of_line (str) - char * str; + char *str; { skip_whitespace (str); - if (* str != '\0') - inst.error = _("Garbage following instruction"); + if (*str != '\0' && !inst.error) + inst.error = _("garbage following instruction"); } static int @@ -2364,7 +2718,7 @@ reg_required_here (str, shift) int reg; char * start = * str; - if ((reg = arm_reg_parse (str)) != FAIL && int_register (reg)) + if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_RN].htab)) != FAIL) { if (shift >= 0) inst.instruction |= reg << shift; @@ -2376,7 +2730,7 @@ reg_required_here (str, shift) /* In the few cases where we might be able to accept something else this error can be overridden. */ - sprintf (buff, _("Register expected, not '%.100s'"), start); + sprintf (buff, _("register expected, not '%.100s'"), start); inst.error = buff; return FAIL; @@ -2457,36 +2811,41 @@ psr_required_here (str) static int co_proc_number (str) - char ** str; + char **str; { int processor, pchar; + char *start; - skip_whitespace (* str); + skip_whitespace (*str); + start = *str; /* The data sheet seems to imply that just a number on its own is valid here, but the RISC iX assembler seems to accept a prefix 'p'. We will accept either. */ - if (**str == 'p' || **str == 'P') - (*str)++; - - pchar = *(*str)++; - if (pchar >= '0' && pchar <= '9') + if ((processor = arm_reg_parse (str, all_reg_maps[REG_TYPE_CP].htab)) + == FAIL) { - processor = pchar - '0'; - if (**str >= '0' && **str <= '9') + *str = start; + + pchar = *(*str)++; + if (pchar >= '0' && pchar <= '9') { - processor = processor * 10 + *(*str)++ - '0'; - if (processor > 15) + processor = pchar - '0'; + if (**str >= '0' && **str <= '9') { - inst.error = _("Illegal co-processor number"); - return FAIL; + processor = processor * 10 + *(*str)++ - '0'; + if (processor > 15) + { + inst.error = _("illegal co-processor number"); + return FAIL; + } } } - } - else - { - inst.error = _("Bad or missing co-processor number"); - return FAIL; + else + { + inst.error = _("bad or missing co-processor number"); + return FAIL; + } } inst.instruction |= processor << 8; @@ -2531,16 +2890,15 @@ cp_reg_required_here (str, where) int reg; char * start = *str; - if ((reg = arm_reg_parse (str)) != FAIL && cp_register (reg)) + if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_CN].htab)) != FAIL) { - reg &= 15; inst.instruction |= reg << where; return reg; } /* In the few cases where we might be able to accept something else this error can be overridden. */ - inst.error = _("Co-processor register expected"); + inst.error = _("co-processor register expected"); /* Restore the start point. */ *str = start; @@ -2555,16 +2913,15 @@ fp_reg_required_here (str, where) int reg; char * start = * str; - if ((reg = arm_reg_parse (str)) != FAIL && fp_register (reg)) + if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_FN].htab)) != FAIL) { - reg &= 7; inst.instruction |= reg << where; return reg; } /* In the few cases where we might be able to accept something else this error can be overridden. */ - inst.error = _("Floating point register expected"); + inst.error = _("floating point register expected"); /* Restore the start point. */ *str = start; @@ -2620,8 +2977,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; @@ -2643,7 +3001,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; @@ -2685,7 +3043,7 @@ cp_address_required_here (str) skip_whitespace (p); - if (*p == '!') + if (wb_ok && *p == '!') { if (reg == REG_PC) { @@ -2760,7 +3118,7 @@ do_mrs (str) skip = 8; else { - inst.error = _("{C|S}PSR expected"); + inst.error = _("CPSR or SPSR expected"); return; } @@ -2841,7 +3199,7 @@ do_msr (str) if (value == (unsigned) FAIL) { - inst.error = _("Invalid constant"); + inst.error = _("invalid constant"); return; } @@ -3095,13 +3453,13 @@ ld_mode_required_here (string) } else /* [Rn] */ { - skip_whitespace (str); + skip_whitespace (str); - if (* str == '!') - { - str ++; - inst.instruction |= WRITE_BACK; - } + if (* str == '!') + { + str ++; + inst.instruction |= WRITE_BACK; + } inst.instruction |= INDEX_UP | HWOFFSET_IMM; pre_inc = 1; @@ -3331,7 +3689,7 @@ do_co_reg2c (str) /* Unpredictable result if rd or rn is R15. */ if (rd == REG_PC || rn == REG_PC) as_tsktsk - (_("Warning: Instruction unpredictable when using r15")); + (_("Warning: instruction unpredictable when using r15")); if (skip_past_comma (& str) == FAIL || cp_reg_required_here (& str, 0) == FAIL) @@ -3393,7 +3751,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; @@ -3529,6 +3887,28 @@ do_co_reg2 (str) end_of_line (str); } +/* ARM v5TEJ. Jump to Jazelle code. */ +static void +do_bxj (str) + char * str; +{ + int reg; + + skip_whitespace (str); + + if ((reg = reg_required_here (&str, 0)) == FAIL) + { + inst.error = BAD_ARGS; + return; + } + + /* Note - it is not illegal to do a "bxj pc". Useless, but not illegal. */ + if (reg == REG_PC) + as_tsktsk (_("use of r15 in bxj is not really useful")); + + end_of_line (str); +} + /* THUMB V5 breakpoint instruction (argument parse) BKPT . */ @@ -3650,10 +4030,10 @@ do_blx (str) { /* This must be is BLX , no condition allowed. */ if (inst.instruction != COND_ALWAYS) - { - inst.error = BAD_COND; + { + inst.error = BAD_COND; return; - } + } inst.instruction = 0xfafffffe; @@ -3711,7 +4091,7 @@ do_t_blx (str) BKPT <16 bit unsigned immediate> Instruction is not conditional. The bit pattern given in insns[] has the COND_ALWAYS condition, - and it is an error if the caller tried to override that. */ + and it is an error if the caller tried to override that. */ static void do_bkpt (str) @@ -3758,7 +4138,7 @@ do_bkpt (str) MIAxycc acc0,Rm,Rs. */ static void -do_mia (str) +do_xsc_mia (str) char * str; { int rs; @@ -3788,7 +4168,7 @@ do_mia (str) MARcc acc0,RdLo,RdHi. */ static void -do_mar (str) +do_xsc_mar (str) char * str; { int rdlo, rdhi; @@ -3817,7 +4197,7 @@ do_mar (str) MRAcc RdLo,RdHi,acc0. */ static void -do_mra (str) +do_xsc_mra (str) char * str; { int rdlo; @@ -3954,14 +4334,14 @@ do_ldrd (str) || (rn = ld_mode_required_here (& str)) == FAIL) { if (!inst.error) - inst.error = BAD_ARGS; + inst.error = BAD_ARGS; return; } /* inst.instruction has now been zapped with Rd and the addressing mode. */ if (rd & 1) /* Unpredictable result if Rd is odd. */ { - inst.error = _("Destination register must be even"); + inst.error = _("destination register must be even"); return; } @@ -4079,6 +4459,8 @@ walk_no_bignums (sp) return 0; } +static int in_my_get_expression = 0; + static int my_get_expression (ep, str) expressionS * ep; @@ -4089,7 +4471,17 @@ my_get_expression (ep, str) save_in = input_line_pointer; input_line_pointer = *str; + in_my_get_expression = 1; seg = expression (ep); + in_my_get_expression = 0; + + if (ep->X_op == O_illegal) + { + /* We found a bad expression in md_operand(). */ + *str = input_line_pointer; + input_line_pointer = save_in; + return 1; + } #ifdef OBJ_AOUT if (seg != absolute_section @@ -4114,7 +4506,7 @@ my_get_expression (ep, str) || (ep->X_op_symbol && walk_no_bignums (ep->X_op_symbol))))) { - inst.error = _("Invalid constant"); + inst.error = _("invalid constant"); *str = input_line_pointer; input_line_pointer = save_in; return 1; @@ -4125,6 +4517,20 @@ my_get_expression (ep, str) return 0; } +/* We handle all bad expressions here, so that we can report the faulty + instruction in the error message. */ +void +md_operand (expr) + expressionS *expr; +{ + if (in_my_get_expression) + { + expr->X_op = O_illegal; + if (inst.error == NULL) + inst.error = _("bad expression"); + } +} + /* UNRESTRICT should be one if is permitted for this instruction. */ @@ -4144,7 +4550,7 @@ decode_shift (str, unrestrict) if (p == * str) { - inst.error = _("Shift expression expected"); + inst.error = _("shift expression expected"); return FAIL; } @@ -4155,7 +4561,7 @@ decode_shift (str, unrestrict) if (shift == NULL) { - inst.error = _("Shift expression expected"); + inst.error = _("shift expression expected"); return FAIL; } @@ -4210,13 +4616,13 @@ decode_shift (str, unrestrict) about this though. */ if (num == 0) { - as_warn (_("Shift of 0 ignored.")); + as_warn (_("shift of 0 ignored.")); shift = & shift_names[0]; assert (shift->properties->index == SHIFT_LSL); } else { - inst.error = _("Invalid immediate shift"); + inst.error = _("invalid immediate shift"); return FAIL; } } @@ -4371,7 +4777,7 @@ data_op2 (str) if (expr.X_op != O_constant) { - inst.error = _("Constant expression expected"); + inst.error = _("constant expression expected"); return FAIL; } @@ -4380,7 +4786,7 @@ data_op2 (str) || (expr.X_add_number & 1) != 0 || ((unsigned) inst.reloc.exp.X_add_number) > 255) { - inst.error = _("Invalid constant"); + inst.error = _("invalid constant"); return FAIL; } inst.instruction |= INST_IMMEDIATE; @@ -4400,7 +4806,7 @@ data_op2 (str) inst.reloc.exp.X_add_number)) == FAIL) { - inst.error = _("Invalid constant"); + inst.error = _("invalid constant"); return FAIL; } } @@ -4413,7 +4819,7 @@ data_op2 (str) } (*str)++; - inst.error = _("Register or shift expression expected"); + inst.error = _("register or shift expression expected"); return FAIL; } } @@ -4466,11 +4872,11 @@ fp_op2 (str) return SUCCESS; } - inst.error = _("Invalid floating point immediate expression"); + inst.error = _("invalid floating point immediate expression"); return FAIL; } inst.error = - _("Floating point register or immediate expression expected"); + _("floating point register or immediate expression expected"); return FAIL; } } @@ -4682,7 +5088,7 @@ do_ldst (str) if (skip_past_comma (&str) == FAIL) { - inst.error = _("Address expected"); + inst.error = _("address expected"); return; } @@ -4771,6 +5177,12 @@ do_ldst (str) } else if (*str == '=') { + if ((inst.instruction & LOAD_BIT) == 0) + { + inst.error = _("invalid pseudo operation"); + return; + } + /* Parse an "ldr Rd, =expr" instruction; this is another pseudo op. */ str++; @@ -4782,36 +5194,52 @@ do_ldst (str) if (inst.reloc.exp.X_op != O_constant && inst.reloc.exp.X_op != O_symbol) { - inst.error = _("Constant expression expected"); + inst.error = _("constant expression expected"); return; } - if (inst.reloc.exp.X_op == O_constant - && (value = validate_immediate (inst.reloc.exp.X_add_number)) != FAIL) - { - /* This can be done with a mov instruction. */ - inst.instruction &= LITERAL_MASK; - inst.instruction |= INST_IMMEDIATE | (OPCODE_MOV << DATA_OP_SHIFT); - inst.instruction |= (value & 0xfff); - end_of_line (str); - return; - } - else + if (inst.reloc.exp.X_op == O_constant) { - /* Insert into literal pool. */ - if (add_to_lit_pool () == FAIL) + value = validate_immediate (inst.reloc.exp.X_add_number); + + if (value != FAIL) + { + /* This can be done with a mov instruction. */ + inst.instruction &= LITERAL_MASK; + inst.instruction |= (INST_IMMEDIATE + | (OPCODE_MOV << DATA_OP_SHIFT)); + inst.instruction |= value & 0xfff; + end_of_line (str); + return; + } + + value = validate_immediate (~inst.reloc.exp.X_add_number); + + if (value != FAIL) { - if (!inst.error) - inst.error = _("literal pool insertion failed"); + /* This can be done with a mvn instruction. */ + inst.instruction &= LITERAL_MASK; + inst.instruction |= (INST_IMMEDIATE + | (OPCODE_MVN << DATA_OP_SHIFT)); + inst.instruction |= value & 0xfff; + end_of_line (str); return; } + } - /* Change the instruction exp to point to the pool. */ - inst.reloc.type = BFD_RELOC_ARM_LITERAL; - inst.reloc.pc_rel = 1; - inst.instruction |= (REG_PC << 16); - pre_inc = 1; + /* Insert into literal pool. */ + if (add_to_lit_pool () == FAIL) + { + if (!inst.error) + inst.error = _("literal pool insertion failed"); + return; } + + /* Change the instruction exp to point to the pool. */ + inst.reloc.type = BFD_RELOC_ARM_LITERAL; + inst.reloc.pc_rel = 1; + inst.instruction |= (REG_PC << 16); + pre_inc = 1; } else { @@ -4850,7 +5278,7 @@ do_ldstt (str) if (skip_past_comma (& str) == FAIL) { - inst.error = _("Address expected"); + inst.error = _("address expected"); return; } @@ -4992,7 +5420,7 @@ do_ldstv4 (str) if (skip_past_comma (& str) == FAIL) { - inst.error = _("Address expected"); + inst.error = _("address expected"); return; } @@ -5083,6 +5511,12 @@ do_ldstv4 (str) } else if (*str == '=') { + if ((inst.instruction & LOAD_BIT) == 0) + { + inst.error = _("invalid pseudo operation"); + return; + } + /* XXX Does this work correctly for half-word/byte ops? */ /* Parse an "ldr Rd, =expr" instruction; this is another pseudo op. */ str++; @@ -5095,7 +5529,7 @@ do_ldstv4 (str) if (inst.reloc.exp.X_op != O_constant && inst.reloc.exp.X_op != O_symbol) { - inst.error = _("Constant expression expected"); + inst.error = _("constant expression expected"); return; } @@ -5112,7 +5546,7 @@ do_ldstv4 (str) end_of_line (str); return; } - + value = validate_immediate (~ inst.reloc.exp.X_add_number); if (value != FAIL) @@ -5196,7 +5630,7 @@ reg_list (strp) if (reg <= cur_reg) { - inst.error = _("Bad range in register list"); + inst.error = _("bad range in register list"); return FAIL; } @@ -5204,7 +5638,7 @@ reg_list (strp) { if (range & (1 << i)) as_tsktsk - (_("Warning: Duplicated register (r%d) in register list"), + (_("Warning: duplicated register (r%d) in register list"), i); else range |= 1 << i; @@ -5213,10 +5647,10 @@ reg_list (strp) } if (range & (1 << reg)) - as_tsktsk (_("Warning: Duplicated register (r%d) in register list"), + as_tsktsk (_("Warning: duplicated register (r%d) in register list"), reg); else if (reg <= cur_reg) - as_tsktsk (_("Warning: Register range not in ascending order")); + as_tsktsk (_("Warning: register range not in ascending order")); range |= 1 << reg; cur_reg = reg; @@ -5228,7 +5662,7 @@ reg_list (strp) if (*str++ != '}') { - inst.error = _("Missing `}'"); + inst.error = _("missing `}'"); return FAIL; } } @@ -5255,7 +5689,7 @@ reg_list (strp) regno &= -regno; regno = (1 << regno) - 1; as_tsktsk - (_("Warning: Duplicated register (r%d) in register list"), + (_("Warning: duplicated register (r%d) in register list"), regno); } @@ -5476,7 +5910,7 @@ do_bx (str) /* Note - it is not illegal to do a "bx pc". Useless, but not illegal. */ if (reg == REG_PC) - as_tsktsk (_("Use of r15 in bx in ARM mode is not really useful")); + as_tsktsk (_("use of r15 in bx in ARM mode is not really useful")); end_of_line (str); } @@ -5567,7 +6001,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; @@ -5674,7 +6108,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; @@ -5710,7 +6144,7 @@ do_fpa_ldmstm (str) if (inst.reloc.exp.X_op != O_constant) { - inst.error = _("Constant value required for number of registers"); + inst.error = _("constant value required for number of registers"); return; } @@ -5739,7 +6173,7 @@ do_fpa_ldmstm (str) abort (); } - if (inst.instruction & (CP_T_Pre | CP_T_UD)) /* ed/fd format. */ + if (inst.instruction & (CP_T_Pre | CP_T_UD)) /* ea/fd format. */ { int reg; int write_back; @@ -5779,7 +6213,7 @@ do_fpa_ldmstm (str) if (reg == REG_PC) { inst.error = - _("R15 not allowed as base register with write-back"); + _("r15 not allowed as base register with write-back"); return; } } @@ -5813,7 +6247,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; @@ -5952,43 +6386,944 @@ 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; - } - break; + case VFP_REG_Sd: + inst.instruction |= ((reg >> 1) << 12) | ((reg & 1) << 22); + break; - case THUMB_REG_HI: - if (reg < 8) - { - inst.error = _("hi register required"); - return FAIL; - } - break; + case VFP_REG_Sn: + inst.instruction |= ((reg >> 1) << 16) | ((reg & 1) << 7); + break; - default: + case VFP_REG_Sm: + inst.instruction |= ((reg >> 1) << 0) | ((reg & 1) << 5); + break; + + default: + abort (); + } + 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_SN].expected); + + /* Restore the start point. */ + *str = start; + return FAIL; +} + +static int +vfp_dp_reg_required_here (str, pos) + char **str; + enum vfp_dp_reg_pos pos; +{ + int reg; + char *start = *str; + + if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_DN].htab)) != FAIL) + { + switch (pos) + { + case VFP_REG_Dd: + inst.instruction |= reg << 12; + break; + + case VFP_REG_Dn: + inst.instruction |= reg << 16; + break; + + case VFP_REG_Dm: + inst.instruction |= reg << 0; + break; + + default: + abort (); + } + 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); + + /* Restore the start point. */ + *str = start; + return FAIL; +} + +static void +do_vfp_sp_monadic (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_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_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) + { + if (! inst.error) + inst.error = BAD_ARGS; + return; + } + + end_of_line (str); + return; +} + +static void +do_vfp_sp_dyadic (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_sp_reg_required_here (&str, VFP_REG_Sn) == FAIL + || 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_dp_dyadic (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_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; + } + + end_of_line (str); + 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; } @@ -6101,11 +7436,11 @@ thumb_add_sub (str, subtract) int offset = inst.reloc.exp.X_add_number; if (subtract) - offset = -offset; + offset = - offset; if (offset < 0) { - offset = -offset; + offset = - offset; subtract = 1; /* Quick check, in case offset is MIN_INT. */ @@ -6115,7 +7450,9 @@ thumb_add_sub (str, subtract) return; } } - else + /* Note - you cannot convert a subtract of 0 into an + add of 0 because the carry flag is set differently. */ + else if (offset > 0) subtract = 0; if (Rd == REG_SP) @@ -6254,7 +7591,7 @@ thumb_shift (str, shift) if (shift_value > 32 || (shift_value == 32 && shift == THUMB_LSL)) { - inst.error = _("Invalid immediate for shift"); + inst.error = _("invalid immediate for shift"); return; } @@ -6413,6 +7750,12 @@ thumb_load_store (str, load_store, size) } else if (*str == '=') { + if (load_store != THUMB_LOAD) + { + inst.error = _("invalid pseudo operation"); + return; + } + /* Parse an "ldr Rd, =expr" instruction; this is another pseudo op. */ str++; @@ -6478,12 +7821,12 @@ thumb_load_store (str, load_store, size) } else if (Rb == REG_PC && load_store != THUMB_LOAD) { - inst.error = _("R15 based store not allowed"); + inst.error = _("r15 based store not allowed"); return; } else if (Ro != FAIL) { - inst.error = _("Invalid base register for register offset"); + inst.error = _("invalid base register for register offset"); return; } @@ -6536,7 +7879,7 @@ thumb_load_store (str, load_store, size) if (offset & ~(0x1f << size)) { - inst.error = _("Invalid offset"); + inst.error = _("invalid offset"); return; } inst.instruction |= (offset >> size) << 6; @@ -6563,233 +7906,387 @@ thumb_load_store (str, load_store, size) end_of_line (str); } -/* Given a register and a register type, return 1 if - the register is of the given type, else return 0. */ +/* A register must be given at this point. + + Shift is the place to put it in inst.instruction. + + Restores input start point on err. + Returns the reg#, or FAIL. */ static int -cirrus_valid_reg (reg, regtype) - int reg; - enum cirrus_regtype regtype; +mav_reg_required_here (str, shift, regtype) + char ** str; + int shift; + enum arm_reg_type regtype; { - switch (regtype) + int reg; + char *start = *str; + + if ((reg = arm_reg_parse (str, all_reg_maps[regtype].htab)) != FAIL) { - case CIRRUS_REGTYPE_ANY: - return 1; + if (shift >= 0) + inst.instruction |= reg << shift; + + return reg; + } - case CIRRUS_REGTYPE_MVF: - return cirrus_mvf_register (reg); + /* Restore the start point. */ + *str = start; - case CIRRUS_REGTYPE_MVFX: - return cirrus_mvfx_register (reg); + /* In the few cases where we might be able to accept something else + this error can be overridden. */ + inst.error = _(all_reg_maps[regtype].expected); - case CIRRUS_REGTYPE_MVD: - return cirrus_mvd_register (reg); + return FAIL; +} - case CIRRUS_REGTYPE_MVDX: - return cirrus_mvdx_register (reg); +/* Cirrus Maverick Instructions. */ - case CIRRUS_REGTYPE_MVAX: - return cirrus_mvax_register (reg); +/* Wrapper functions. */ - case CIRRUS_REGTYPE_DSPSC: - return ARM_EXT_MAVERICKsc_register (reg); - } +static void +do_mav_binops_1a (str) + char * str; +{ + do_mav_binops (str, MAV_MODE1, REG_TYPE_RN, REG_TYPE_MVF); +} - return 0; +static void +do_mav_binops_1b (str) + char * str; +{ + do_mav_binops (str, MAV_MODE1, REG_TYPE_RN, REG_TYPE_MVD); } -/* A register must be given at this point. +static void +do_mav_binops_1c (str) + char * str; +{ + do_mav_binops (str, MAV_MODE1, REG_TYPE_RN, REG_TYPE_MVDX); +} - If the register is a Cirrus register, convert it's reg# appropriately. +static void +do_mav_binops_1d (str) + char * str; +{ + do_mav_binops (str, MAV_MODE1, REG_TYPE_MVF, REG_TYPE_MVF); +} - Shift is the place to put it in inst.instruction. +static void +do_mav_binops_1e (str) + char * str; +{ + do_mav_binops (str, MAV_MODE1, REG_TYPE_MVD, REG_TYPE_MVD); +} - regtype is type register type expected, and is: - CIRRUS_REGTYPE_MVF - CIRRUS_REGTYPE_MVFX - CIRRUS_REGTYPE_MVD - CIRRUS_REGTYPE_MVDX - CIRRUS_REGTYPE_MVAX - CIRRUS_REGTYPE_DSPSC +static void +do_mav_binops_1f (str) + char * str; +{ + do_mav_binops (str, MAV_MODE1, REG_TYPE_MVD, REG_TYPE_MVF); +} + +static void +do_mav_binops_1g (str) + char * str; +{ + do_mav_binops (str, MAV_MODE1, REG_TYPE_MVF, REG_TYPE_MVD); +} + +static void +do_mav_binops_1h (str) + char * str; +{ + do_mav_binops (str, MAV_MODE1, REG_TYPE_MVF, REG_TYPE_MVFX); +} + +static void +do_mav_binops_1i (str) + char * str; +{ + do_mav_binops (str, MAV_MODE1, REG_TYPE_MVD, REG_TYPE_MVFX); +} + +static void +do_mav_binops_1j (str) + char * str; +{ + do_mav_binops (str, MAV_MODE1, REG_TYPE_MVF, REG_TYPE_MVDX); +} + +static void +do_mav_binops_1k (str) + char * str; +{ + do_mav_binops (str, MAV_MODE1, REG_TYPE_MVD, REG_TYPE_MVDX); +} + +static void +do_mav_binops_1l (str) + char * str; +{ + do_mav_binops (str, MAV_MODE1, REG_TYPE_MVFX, REG_TYPE_MVF); +} + +static void +do_mav_binops_1m (str) + char * str; +{ + do_mav_binops (str, MAV_MODE1, REG_TYPE_MVFX, REG_TYPE_MVD); +} + +static void +do_mav_binops_1n (str) + char * str; +{ + do_mav_binops (str, MAV_MODE1, REG_TYPE_MVFX, REG_TYPE_MVFX); +} + +static void +do_mav_binops_1o (str) + char * str; +{ + do_mav_binops (str, MAV_MODE1, REG_TYPE_MVDX, REG_TYPE_MVDX); +} + +static void +do_mav_binops_2a (str) + char * str; +{ + do_mav_binops (str, MAV_MODE2, REG_TYPE_MVF, REG_TYPE_RN); +} + +static void +do_mav_binops_2b (str) + char * str; +{ + do_mav_binops (str, MAV_MODE2, REG_TYPE_MVD, REG_TYPE_RN); +} + +static void +do_mav_binops_2c (str) + char * str; +{ + do_mav_binops (str, MAV_MODE2, REG_TYPE_MVDX, REG_TYPE_RN); +} - Restores input start point on err. - Returns the reg#, or FAIL. */ +static void +do_mav_binops_3a (str) + char * str; +{ + do_mav_binops (str, MAV_MODE3, REG_TYPE_MVAX, REG_TYPE_MVFX); +} -static int -cirrus_reg_required_here (str, shift, regtype) - char ** str; - int shift; - enum cirrus_regtype regtype; +static void +do_mav_binops_3b (str) + char * str; { - static char buff [135]; /* XXX */ - int reg; - char * start = * str; + do_mav_binops (str, MAV_MODE3, REG_TYPE_MVFX, REG_TYPE_MVAX); +} - if ((reg = arm_reg_parse (str)) != FAIL - && (int_register (reg) - || cirrus_register (reg))) - { - int orig_reg = reg; +static void +do_mav_binops_3c (str) + char * str; +{ + do_mav_binops (str, MAV_MODE3, REG_TYPE_MVAX, REG_TYPE_MVDX); +} - /* Calculate actual register # for opcode. */ - if (cirrus_register (reg) - && !ARM_EXT_MAVERICKsc_register (reg)) /* Leave this one as is. */ - { - if (reg >= 130) - reg -= 130; - else if (reg >= 110) - reg -= 110; - else if (reg >= 90) - reg -= 90; - else if (reg >= 70) - reg -= 70; - else if (reg >= 50) - reg -= 50; - } +static void +do_mav_binops_3d (str) + char * str; +{ + do_mav_binops (str, MAV_MODE3, REG_TYPE_MVDX, REG_TYPE_MVAX); +} - if (!cirrus_valid_reg (orig_reg, regtype)) - { - sprintf (buff, _("invalid register type at '%.100s'"), start); - inst.error = buff; - return FAIL; - } +static void +do_mav_triple_4a (str) + char * str; +{ + do_mav_triple (str, MAV_MODE4, REG_TYPE_MVFX, REG_TYPE_MVFX, REG_TYPE_RN); +} - if (shift >= 0) - inst.instruction |= reg << shift; +static void +do_mav_triple_4b (str) + char * str; +{ + do_mav_triple (str, MAV_MODE4, REG_TYPE_MVDX, REG_TYPE_MVDX, REG_TYPE_RN); +} - return orig_reg; - } +static void +do_mav_triple_5a (str) + char * str; +{ + do_mav_triple (str, MAV_MODE5, REG_TYPE_RN, REG_TYPE_MVF, REG_TYPE_MVF); +} - /* Restore the start point, we may have got a reg of the wrong class. */ - *str = start; - - /* In the few cases where we might be able to accept something else - this error can be overridden. */ - sprintf (buff, _("Cirrus register expected, not '%.100s'"), start); - inst.error = buff; - - return FAIL; +static void +do_mav_triple_5b (str) + char * str; +{ + do_mav_triple (str, MAV_MODE5, REG_TYPE_RN, REG_TYPE_MVD, REG_TYPE_MVD); } -/* Cirrus Instructions. */ +static void +do_mav_triple_5c (str) + char * str; +{ + do_mav_triple (str, MAV_MODE5, REG_TYPE_RN, REG_TYPE_MVFX, REG_TYPE_MVFX); +} -/* Wrapper functions. */ +static void +do_mav_triple_5d (str) + char * str; +{ + do_mav_triple (str, MAV_MODE5, REG_TYPE_RN, REG_TYPE_MVDX, REG_TYPE_MVDX); +} static void -do_c_binops_1 (str) +do_mav_triple_5e (str) char * str; { - do_c_binops (str, CIRRUS_MODE1); + do_mav_triple (str, MAV_MODE5, REG_TYPE_MVF, REG_TYPE_MVF, REG_TYPE_MVF); } static void -do_c_binops_2 (str) +do_mav_triple_5f (str) char * str; { - do_c_binops (str, CIRRUS_MODE2); + do_mav_triple (str, MAV_MODE5, REG_TYPE_MVD, REG_TYPE_MVD, REG_TYPE_MVD); } static void -do_c_binops_3 (str) +do_mav_triple_5g (str) char * str; { - do_c_binops (str, CIRRUS_MODE3); + do_mav_triple (str, MAV_MODE5, REG_TYPE_MVFX, REG_TYPE_MVFX, REG_TYPE_MVFX); } static void -do_c_triple_4 (str) +do_mav_triple_5h (str) char * str; { - do_c_triple (str, CIRRUS_MODE4); + do_mav_triple (str, MAV_MODE5, REG_TYPE_MVDX, REG_TYPE_MVDX, REG_TYPE_MVDX); } static void -do_c_triple_5 (str) +do_mav_quad_6a (str) char * str; { - do_c_triple (str, CIRRUS_MODE5); + do_mav_quad (str, MAV_MODE6, REG_TYPE_MVAX, REG_TYPE_MVFX, REG_TYPE_MVFX, + REG_TYPE_MVFX); } static void -do_c_quad_6 (str) +do_mav_quad_6b (str) char * str; { - do_c_quad (str, CIRRUS_MODE6); + do_mav_quad (str, MAV_MODE6, REG_TYPE_MVAX, REG_TYPE_MVAX, REG_TYPE_MVFX, + REG_TYPE_MVFX); } +/* cfmvsc32 DSPSC,MVFX[15:0]. */ static void -do_c_dspsc_1 (str) +do_mav_dspsc_1 (str) char * str; { - do_c_dspsc (str, CIRRUS_MODE1); + skip_whitespace (str); + + /* cfmvsc32. */ + if (mav_reg_required_here (&str, -1, REG_TYPE_DSPSC) == FAIL + || skip_past_comma (&str) == FAIL + || mav_reg_required_here (&str, 16, REG_TYPE_MVFX) == FAIL) + { + if (!inst.error) + inst.error = BAD_ARGS; + + return; + } + + end_of_line (str); } +/* cfmv32sc MVFX[15:0],DSPSC. */ static void -do_c_dspsc_2 (str) +do_mav_dspsc_2 (str) char * str; { - do_c_dspsc (str, CIRRUS_MODE2); + skip_whitespace (str); + + /* cfmv32sc. */ + if (mav_reg_required_here (&str, 0, REG_TYPE_MVFX) == FAIL + || skip_past_comma (&str) == FAIL + || mav_reg_required_here (&str, -1, REG_TYPE_DSPSC) == FAIL) + { + if (!inst.error) + inst.error = BAD_ARGS; + + return; + } + + end_of_line (str); } static void -do_c_shift_1 (str) +do_mav_shift_1 (str) char * str; { - do_c_shift (str, CIRRUS_MODE1); + do_mav_shift (str, REG_TYPE_MVFX, REG_TYPE_MVFX); } static void -do_c_shift_2 (str) +do_mav_shift_2 (str) char * str; { - do_c_shift (str, CIRRUS_MODE2); + do_mav_shift (str, REG_TYPE_MVDX, REG_TYPE_MVDX); } static void -do_c_ldst_1 (str) +do_mav_ldst_1 (str) char * str; { - do_c_ldst (str, CIRRUS_MODE1); + do_mav_ldst (str, REG_TYPE_MVF); } static void -do_c_ldst_2 (str) +do_mav_ldst_2 (str) char * str; { - do_c_ldst (str, CIRRUS_MODE2); + do_mav_ldst (str, REG_TYPE_MVD); } static void -do_c_ldst_3 (str) +do_mav_ldst_3 (str) char * str; { - do_c_ldst (str, CIRRUS_MODE3); + do_mav_ldst (str, REG_TYPE_MVFX); } static void -do_c_ldst_4 (str) +do_mav_ldst_4 (str) char * str; { - do_c_ldst (str, CIRRUS_MODE4); + do_mav_ldst (str, REG_TYPE_MVDX); } /* Isnsn like "foo X,Y". */ static void -do_c_binops (str, mode) +do_mav_binops (str, mode, reg0, reg1) char * str; int mode; + enum arm_reg_type reg0; + enum arm_reg_type reg1; { - int shift1, shift2; + int shift0, shift1; - shift1 = mode & 0xff; - shift2 = (mode >> 8) & 0xff; + shift0 = mode & 0xff; + shift1 = (mode >> 8) & 0xff; skip_whitespace (str); - if (cirrus_reg_required_here (&str, shift1, CIRRUS_REGTYPE_ANY) == FAIL + if (mav_reg_required_here (&str, shift0, reg0) == FAIL || skip_past_comma (&str) == FAIL - || cirrus_reg_required_here (&str, shift2, CIRRUS_REGTYPE_ANY) == FAIL) + || mav_reg_required_here (&str, shift1, reg1) == FAIL) { if (!inst.error) inst.error = BAD_ARGS; @@ -6801,23 +8298,26 @@ do_c_binops (str, mode) /* Isnsn like "foo X,Y,Z". */ static void -do_c_triple (str, mode) +do_mav_triple (str, mode, reg0, reg1, reg2) char * str; int mode; + enum arm_reg_type reg0; + enum arm_reg_type reg1; + enum arm_reg_type reg2; { - int shift1, shift2, shift3; + int shift0, shift1, shift2; - shift1 = mode & 0xff; - shift2 = (mode >> 8) & 0xff; - shift3 = (mode >> 16) & 0xff; + shift0 = mode & 0xff; + shift1 = (mode >> 8) & 0xff; + shift2 = (mode >> 16) & 0xff; skip_whitespace (str); - if (cirrus_reg_required_here (&str, shift1, CIRRUS_REGTYPE_ANY) == FAIL + if (mav_reg_required_here (&str, shift0, reg0) == FAIL || skip_past_comma (&str) == FAIL - || cirrus_reg_required_here (&str, shift2, CIRRUS_REGTYPE_ANY) == FAIL + || mav_reg_required_here (&str, shift1, reg1) == FAIL || skip_past_comma (&str) == FAIL - || cirrus_reg_required_here (&str, shift3, CIRRUS_REGTYPE_ANY) == FAIL) + || mav_reg_required_here (&str, shift2, reg2) == FAIL) { if (!inst.error) inst.error = BAD_ARGS; @@ -6830,31 +8330,30 @@ do_c_triple (str, mode) where W=MVAX[0:3] and X,Y,Z=MVFX[0:15]. */ static void -do_c_quad (str, mode) +do_mav_quad (str, mode, reg0, reg1, reg2, reg3) char * str; int mode; + enum arm_reg_type reg0; + enum arm_reg_type reg1; + enum arm_reg_type reg2; + enum arm_reg_type reg3; { - int shift1, shift2, shift3, shift4; - enum cirrus_regtype rt; - - rt = (inst.instruction << 4 == 0xe2006000 - || inst.instruction << 4 == 0xe3006000) ? CIRRUS_REGTYPE_MVAX - : CIRRUS_REGTYPE_MVFX; + int shift0, shift1, shift2, shift3; - shift1 = mode & 0xff; - shift2 = (mode >> 8) & 0xff; - shift3 = (mode >> 16) & 0xff; - shift4 = (mode >> 24) & 0xff; + shift0= mode & 0xff; + shift1 = (mode >> 8) & 0xff; + shift2 = (mode >> 16) & 0xff; + shift3 = (mode >> 24) & 0xff; skip_whitespace (str); - if (cirrus_reg_required_here (&str, shift1, CIRRUS_REGTYPE_MVAX) == FAIL + if (mav_reg_required_here (&str, shift0, reg0) == FAIL || skip_past_comma (&str) == FAIL - || cirrus_reg_required_here (&str, shift2, rt) == FAIL + || mav_reg_required_here (&str, shift1, reg1) == FAIL || skip_past_comma (&str) == FAIL - || cirrus_reg_required_here (&str, shift3, CIRRUS_REGTYPE_MVFX) == FAIL + || mav_reg_required_here (&str, shift2, reg2) == FAIL || skip_past_comma (&str) == FAIL - || cirrus_reg_required_here (&str, shift4, CIRRUS_REGTYPE_MVFX) == FAIL) + || mav_reg_required_here (&str, shift3, reg3) == FAIL) { if (!inst.error) inst.error = BAD_ARGS; @@ -6863,56 +8362,15 @@ do_c_quad (str, mode) end_of_line (str); } -/* cfmvsc32 DSPSC,MVFX[15:0]. - cfmv32sc MVFX[15:0],DSPSC. */ - -static void -do_c_dspsc (str, mode) - char * str; - int mode; -{ - int error; - - skip_whitespace (str); - - error = 0; - - if (mode == CIRRUS_MODE1) - { - /* cfmvsc32. */ - if (cirrus_reg_required_here (&str, -1, CIRRUS_REGTYPE_DSPSC) == FAIL - || skip_past_comma (&str) == FAIL - || cirrus_reg_required_here (&str, 16, CIRRUS_REGTYPE_MVFX) == FAIL) - error = 1; - } - else - { - /* cfmv32sc. */ - if (cirrus_reg_required_here (&str, 0, CIRRUS_REGTYPE_MVFX) == FAIL - || skip_past_comma (&str) == FAIL - || cirrus_reg_required_here (&str, -1, CIRRUS_REGTYPE_DSPSC) == FAIL) - error = 1; - } - - if (error) - { - if (!inst.error) - inst.error = BAD_ARGS; - } - else - { - end_of_line (str); - } -} - -/* Cirrus shift immediate instructions. +/* Maverick shift immediate instructions. cfsh32 MVFX[15:0],MVFX[15:0],Shift[6:0]. cfsh64 MVDX[15:0],MVDX[15:0],Shift[6:0]. */ static void -do_c_shift (str, mode) +do_mav_shift (str, reg0, reg1) char * str; - int mode; + enum arm_reg_type reg0; + enum arm_reg_type reg1; { int error; int imm, neg = 0; @@ -6921,15 +8379,9 @@ do_c_shift (str, mode) error = 0; - if (cirrus_reg_required_here (&str, 12, - (mode == CIRRUS_MODE1) - ? CIRRUS_REGTYPE_MVFX - : CIRRUS_REGTYPE_MVDX) == FAIL + if (mav_reg_required_here (&str, 12, reg0) == FAIL || skip_past_comma (&str) == FAIL - || cirrus_reg_required_here (&str, 16, - (mode == CIRRUS_MODE1) - ? CIRRUS_REGTYPE_MVFX - : CIRRUS_REGTYPE_MVDX) == FAIL + || mav_reg_required_here (&str, 16, reg1) == FAIL || skip_past_comma (&str) == FAIL) { if (!inst.error) @@ -6982,7 +8434,7 @@ do_c_shift (str, mode) } static int -cirrus_parse_offset (str, negative) +mav_parse_offset (str, negative) char ** str; int *negative; { @@ -7022,37 +8474,31 @@ cirrus_parse_offset (str, negative) return *negative ? -offset : offset; } -/* Cirrus load/store instructions. +/* Maverick load/store instructions. CRd,[Rn,]{!}. CRd,[Rn],. */ static void -do_c_ldst (str, mode) +do_mav_ldst (str, reg0) char * str; - int mode; + enum arm_reg_type reg0; { int offset, negative; - enum cirrus_regtype rt; - - rt = mode == CIRRUS_MODE1 ? CIRRUS_REGTYPE_MVF - : mode == CIRRUS_MODE2 ? CIRRUS_REGTYPE_MVD - : mode == CIRRUS_MODE3 ? CIRRUS_REGTYPE_MVFX - : mode == CIRRUS_MODE4 ? CIRRUS_REGTYPE_MVDX : CIRRUS_REGTYPE_MVF; skip_whitespace (str); - if (cirrus_reg_required_here (& str, 12, rt) == FAIL - || skip_past_comma (& str) == FAIL + if (mav_reg_required_here (&str, 12, reg0) == FAIL + || skip_past_comma (&str) == FAIL || *str++ != '[' - || reg_required_here (& str, 16) == FAIL) + || reg_required_here (&str, 16) == FAIL) goto fail_ldst; - if (skip_past_comma (& str) == SUCCESS) + if (skip_past_comma (&str) == SUCCESS) { /* You are here: "]{!}". */ inst.instruction |= PRE_INDEX; - offset = cirrus_parse_offset (&str, &negative); + offset = mav_parse_offset (&str, &negative); if (inst.error) return; @@ -7079,7 +8525,7 @@ do_c_ldst (str, mode) } if (skip_past_comma (&str) == FAIL - || (offset = cirrus_parse_offset (&str, &negative), inst.error)) + || (offset = mav_parse_offset (&str, &negative), inst.error)) goto fail_ldst; inst.instruction |= CP_T_WB; /* Post indexed, set bit W. */ @@ -7300,7 +8746,7 @@ do_t_ldmstm (str) return; if (*str != '!') - as_warn (_("Inserted missing '!': load/store multiple always writes back base register")); + as_warn (_("inserted missing '!': load/store multiple always writes back base register")); else str++; @@ -7316,7 +8762,7 @@ do_t_ldmstm (str) { /* This really doesn't seem worth it. */ inst.reloc.type = BFD_RELOC_NONE; - inst.error = _("Expression too complex"); + inst.error = _("expression too complex"); return; } @@ -7368,7 +8814,7 @@ do_t_lds (str) || *str++ != ']') { if (! inst.error) - inst.error = _("Syntax: ldrs[b] Rd, [Rb, Ro]"); + inst.error = _("syntax: ldrs[b] Rd, [Rb, Ro]"); return; } @@ -7416,7 +8862,7 @@ do_t_push_pop (str) { /* This really doesn't seem worth it. */ inst.reloc.type = BFD_RELOC_NONE; - inst.error = _("Expression too complex"); + inst.error = _("expression too complex"); return; } @@ -7513,10 +8959,11 @@ do_t_adr (str) } static void -insert_reg (entry) - int entry; +insert_reg (r, htab) + const struct reg_entry *r; + struct hash_control *htab; { - int len = strlen (reg_table[entry].name) + 2; + int len = strlen (r->name) + 2; char * buf = (char *) xmalloc (len); char * buf2 = (char *) xmalloc (len); int i = 0; @@ -7525,21 +8972,35 @@ insert_reg (entry) buf[i++] = REGISTER_PREFIX; #endif - strcpy (buf + i, reg_table[entry].name); + strcpy (buf + i, r->name); for (i = 0; buf[i]; i++) buf2[i] = TOUPPER (buf[i]); buf2[i] = '\0'; - hash_insert (arm_reg_hsh, buf, (PTR) & reg_table[entry]); - hash_insert (arm_reg_hsh, buf2, (PTR) & reg_table[entry]); + hash_insert (htab, buf, (PTR) r); + hash_insert (htab, buf2, (PTR) r); +} + +static void +build_reg_hsh (map) + struct reg_map *map; +{ + const struct reg_entry *r; + + if ((map->htab = hash_new ()) == NULL) + as_fatal (_("virtual memory exhausted")); + + for (r = map->names; r->name != NULL; r++) + insert_reg (r, map->htab); } static void -insert_reg_alias (str, regnum) +insert_reg_alias (str, regnum, htab) char *str; int regnum; + struct hash_control *htab; { struct reg_entry *new = (struct reg_entry *) xmalloc (sizeof (struct reg_entry)); @@ -7549,7 +9010,93 @@ insert_reg_alias (str, regnum) new->name = name; new->number = regnum; - hash_insert (arm_reg_hsh, name, (PTR) new); + hash_insert (htab, name, (PTR) new); +} + +/* Look for the .req directive. This is of the form: + + newname .req existing_name + + If we find one, or if it looks sufficiently like one that we want to + handle any error here, return non-zero. Otherwise return zero. */ +static int +create_register_alias (newname, p) + char *newname; + char *p; +{ + char *q; + char c; + + q = p; + skip_whitespace (q); + + c = *p; + *p = '\0'; + + if (*q && !strncmp (q, ".req ", 5)) + { + char *copy_of_str; + char *r; + +#ifdef IGNORE_OPCODE_CASE + newname = original_case_string; +#endif + copy_of_str = newname; + + q += 4; + skip_whitespace (q); + + for (r = q; *r != '\0'; r++) + if (*r == ' ') + break; + + if (r != q) + { + enum arm_reg_type new_type, old_type; + int old_regno; + char d = *r; + + *r = '\0'; + old_type = arm_reg_parse_any (q); + *r = d; + + new_type = arm_reg_parse_any (newname); + + if (new_type == REG_TYPE_MAX) + { + if (old_type != REG_TYPE_MAX) + { + old_regno = arm_reg_parse (&q, all_reg_maps[old_type].htab); + insert_reg_alias (newname, old_regno, + all_reg_maps[old_type].htab); + } + else + as_warn (_("register '%s' does not exist\n"), q); + } + else if (old_type == REG_TYPE_MAX) + { + as_warn (_("ignoring redefinition of register alias '%s' to non-existant register '%s'"), + copy_of_str, q); + } + else + { + /* Do not warn about redefinitions to the same alias. */ + if (new_type != old_type + || (arm_reg_parse (&q, all_reg_maps[old_type].htab) + != arm_reg_parse (&q, all_reg_maps[new_type].htab))) + as_warn (_("ignoring redefinition of register alias '%s'"), + copy_of_str); + + } + } + else + as_warn (_("ignoring incomplete .req pseuso op")); + + *p = c; + return 1; + } + *p = c; + return 0; } static void @@ -7574,7 +9121,7 @@ build_arm_ops_hsh () for (i = 0; i < sizeof (insns) / sizeof (struct asm_opcode); i++) { - CONST struct asm_opcode *insn = insns + i; + const struct asm_opcode *insn = insns + i; if (insn->cond_offset != 0) { @@ -7620,9 +9167,8 @@ md_begin () || (arm_tops_hsh = hash_new ()) == NULL || (arm_cond_hsh = hash_new ()) == NULL || (arm_shift_hsh = hash_new ()) == NULL - || (arm_reg_hsh = hash_new ()) == NULL || (arm_psr_hsh = hash_new ()) == NULL) - as_fatal (_("Virtual memory exhausted")); + as_fatal (_("virtual memory exhausted")); build_arm_ops_hsh (); for (i = 0; i < sizeof (tinsns) / sizeof (struct thumb_opcode); i++) @@ -7634,11 +9180,55 @@ md_begin () for (i = 0; i < sizeof (psrs) / sizeof (struct asm_psr); i++) hash_insert (arm_psr_hsh, psrs[i].template, (PTR) (psrs + i)); - for (i = 0; reg_table[i].name; i++) - insert_reg (i); + for (i = (int) REG_TYPE_FIRST; i < (int) REG_TYPE_MAX; i++) + build_reg_hsh (all_reg_maps + i); set_constant_flonums (); + /* Set the cpu variant based on the command-line options. We prefer + -mcpu= over -march= if both are set (as for GCC); and we prefer + -mfpu= over any other way of setting the floating point unit. + Use of legacy options with new options are faulted. */ + if (legacy_cpu != -1) + { + if (mcpu_cpu_opt != -1 || march_cpu_opt != -1) + as_bad (_("use of old and new-style options to set CPU type")); + + mcpu_cpu_opt = legacy_cpu; + } + else if (mcpu_cpu_opt == -1) + mcpu_cpu_opt = march_cpu_opt; + + if (legacy_fpu != -1) + { + if (mfpu_opt != -1) + as_bad (_("use of old and new-style options to set FPU type")); + + mfpu_opt = legacy_fpu; + } + else if (mfpu_opt == -1) + { + if (mcpu_fpu_opt != -1) + mfpu_opt = mcpu_fpu_opt; + else + mfpu_opt = march_fpu_opt; + } + + if (mfpu_opt == -1) + { + if (mcpu_cpu_opt == -1) + mfpu_opt = FPU_DEFAULT; + else if (mcpu_cpu_opt & ARM_EXT_V5) + mfpu_opt = FPU_ARCH_VFP_V2; + else + mfpu_opt = FPU_ARCH_FPA; + } + + if (mcpu_cpu_opt == -1) + mcpu_cpu_opt = CPU_DEFAULT; + + cpu_variant = mcpu_cpu_opt | mfpu_opt; + #if defined OBJ_COFF || defined OBJ_ELF { unsigned int flags = 0; @@ -7648,7 +9238,12 @@ 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) /* VFP layout only. */ + flags |= F_SOFT_FLOAT; + /* Using VFP conventions (even if soft-float). */ + if (cpu_variant & FPU_VFP_EXT_NONE) flags |= F_VFP_FLOAT; + bfd_set_private_flags (stdoutput, flags); @@ -7690,11 +9285,10 @@ md_begin () default: mach = bfd_mach_arm_4; break; - } /* Catch special cases. */ - if (cpu_variant & ARM_EXT_XSCALE) + if (cpu_variant & ARM_CEXT_XSCALE) mach = bfd_mach_arm_XScale; else if (cpu_variant & ARM_EXT_V5E) mach = bfd_mach_arm_5TE; @@ -7818,7 +9412,7 @@ md_atof (type, litP, sizeP) default: *sizeP = 0; - return _("Bad call to MD_ATOF()"); + return _("bad call to MD_ATOF()"); } t = atof_ieee (input_line_pointer, type, words); @@ -7836,14 +9430,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; @@ -7924,8 +9525,9 @@ md_undefined_symbol (name) advance the pointer. */ static int -arm_reg_parse (ccp) +arm_reg_parse (ccp, htab) register char ** ccp; + struct hash_control *htab; { char * start = * ccp; char c; @@ -7951,7 +9553,7 @@ arm_reg_parse (ccp) c = *p++; *--p = 0; - reg = (struct reg_entry *) hash_find (arm_reg_hsh, start); + reg = (struct reg_entry *) hash_find (htab, start); *p = c; if (reg) @@ -7963,6 +9565,22 @@ arm_reg_parse (ccp) return FAIL; } +/* Search for the following register name in each of the possible reg name + tables. Return the classification if found, or REG_TYPE_MAX if not + present. */ +static enum arm_reg_type +arm_reg_parse_any (cp) + char *cp; +{ + int i; + + for (i = (int) REG_TYPE_FIRST; i < (int) REG_TYPE_MAX; i++) + if (arm_reg_parse (&cp, all_reg_maps[i].htab) != FAIL) + return (enum arm_reg_type) i; + + return REG_TYPE_MAX; +} + void md_apply_fix3 (fixP, valP, seg) fixS * fixP; @@ -8060,7 +9678,7 @@ md_apply_fix3 (fixP, valP, seg) else { as_bad_where (fixP->fx_file, fixP->fx_line, - _("Unable to compute ADRL instructions for PC offset of 0x%lx"), + _("unable to compute ADRL instructions for PC offset of 0x%lx"), value); break; } @@ -8170,7 +9788,7 @@ md_apply_fix3 (fixP, valP, seg) { if (((unsigned long) value) > 0xff) as_bad_where (fixP->fx_file, fixP->fx_line, - _("Invalid swi expression")); + _("invalid swi expression")); newval = md_chars_to_number (buf, THUMB_SIZE) & 0xff00; newval |= value; md_number_to_chars (buf, newval, THUMB_SIZE); @@ -8179,7 +9797,7 @@ md_apply_fix3 (fixP, valP, seg) { if (((unsigned long) value) > 0x00ffffff) as_bad_where (fixP->fx_file, fixP->fx_line, - _("Invalid swi expression")); + _("invalid swi expression")); newval = md_chars_to_number (buf, INSN_SIZE) & 0xff000000; newval |= value; md_number_to_chars (buf, newval, INSN_SIZE); @@ -8189,7 +9807,7 @@ md_apply_fix3 (fixP, valP, seg) case BFD_RELOC_ARM_MULTI: if (((unsigned long) value) > 0xffff) as_bad_where (fixP->fx_file, fixP->fx_line, - _("Invalid expression in load/store multiple")); + _("invalid expression in load/store multiple")); newval = value | md_chars_to_number (buf, INSN_SIZE); md_number_to_chars (buf, newval, INSN_SIZE); break; @@ -8242,7 +9860,7 @@ md_apply_fix3 (fixP, valP, seg) if (! fixP->fx_done) #endif as_bad_where (fixP->fx_file, fixP->fx_line, - _("gas can't handle same-section branch dest >= 0x04000000")); + _("GAS can't handle same-section branch dest >= 0x04000000")); } value >>= 2; @@ -8284,7 +9902,7 @@ md_apply_fix3 (fixP, valP, seg) value += diff; if ((value & ~0xff) && ((value & ~0xff) != ~0xff)) as_bad_where (fixP->fx_file, fixP->fx_line, - _("Branch out of range")); + _("branch out of range")); newval = (newval & 0xff00) | ((value & 0x1ff) >> 1); } md_number_to_chars (buf, newval, THUMB_SIZE); @@ -8300,7 +9918,7 @@ md_apply_fix3 (fixP, valP, seg) value += diff; if ((value & ~0x7ff) && ((value & ~0x7ff) != ~0x7ff)) as_bad_where (fixP->fx_file, fixP->fx_line, - _("Branch out of range")); + _("branch out of range")); newval = (newval & 0xf800) | ((value & 0xfff) >> 1); } md_number_to_chars (buf, newval, THUMB_SIZE); @@ -8321,21 +9939,19 @@ md_apply_fix3 (fixP, valP, seg) value = fixP->fx_offset; #endif value += diff; + if ((value & ~0x3fffff) && ((value & ~0x3fffff) != ~0x3fffff)) as_bad_where (fixP->fx_file, fixP->fx_line, - _("Branch with link out of range")); + _("branch with link out of range")); newval = (newval & 0xf800) | ((value & 0x7fffff) >> 12); newval2 = (newval2 & 0xf800) | ((value & 0xfff) >> 1); if (fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BLX) - /* Remove bit zero of the adjusted offset. Bit zero can only be - set if the upper insn is at a half-word boundary, since the - destination address, an ARM instruction, must always be on a - word boundary. The semantics of the BLX (1) instruction, however, - are that bit zero in the offset must always be zero, and the - corresponding bit one in the target address will be set from bit - one of the source address. */ - newval2 &= ~1; + /* For a BLX instruction, make sure that the relocation is rounded up + to a word boundary. This follows the semantics of the instruction + which specifies that bit 1 of the target address will come from bit + 1 of the base address. */ + newval2 = (newval2 + 1) & ~ 1; md_number_to_chars (buf, newval, THUMB_SIZE); md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE); } @@ -8399,7 +10015,7 @@ md_apply_fix3 (fixP, valP, seg) sign = value >= 0; if (value < -1023 || value > 1023 || (value & 3)) as_bad_where (fixP->fx_file, fixP->fx_line, - _("Illegal value for co-processor offset")); + _("illegal value for co-processor offset")); if (value < 0) value = -value; newval = md_chars_to_number (buf, INSN_SIZE) & 0xff7fff00; @@ -8423,13 +10039,13 @@ md_apply_fix3 (fixP, valP, seg) if ((fixP->fx_frag->fr_address + fixP->fx_where + value) & 3) as_bad_where (fixP->fx_file, fixP->fx_line, - _("Invalid offset, target not word aligned (0x%08X)"), + _("invalid offset, target not word aligned (0x%08X)"), (unsigned int) (fixP->fx_frag->fr_address + fixP->fx_where + value)); if ((value + 2) & ~0x3fe) as_bad_where (fixP->fx_file, fixP->fx_line, - _("Invalid offset, value too big (0x%08lX)"), value); + _("invalid offset, value too big (0x%08lX)"), value); /* Round up, since pc will be rounded down. */ newval |= (value + 2) >> 2; @@ -8438,28 +10054,28 @@ md_apply_fix3 (fixP, valP, seg) case 9: /* SP load/store. */ if (value & ~0x3fc) as_bad_where (fixP->fx_file, fixP->fx_line, - _("Invalid offset, value too big (0x%08lX)"), value); + _("invalid offset, value too big (0x%08lX)"), value); newval |= value >> 2; break; case 6: /* Word load/store. */ if (value & ~0x7c) as_bad_where (fixP->fx_file, fixP->fx_line, - _("Invalid offset, value too big (0x%08lX)"), value); + _("invalid offset, value too big (0x%08lX)"), value); newval |= value << 4; /* 6 - 2. */ break; case 7: /* Byte load/store. */ if (value & ~0x1f) as_bad_where (fixP->fx_file, fixP->fx_line, - _("Invalid offset, value too big (0x%08lX)"), value); + _("invalid offset, value too big (0x%08lX)"), value); newval |= value << 6; break; case 8: /* Halfword load/store. */ if (value & ~0x3e) as_bad_where (fixP->fx_file, fixP->fx_line, - _("Invalid offset, value too big (0x%08lX)"), value); + _("invalid offset, value too big (0x%08lX)"), value); newval |= value << 5; /* 6 - 1. */ break; @@ -8498,7 +10114,7 @@ md_apply_fix3 (fixP, valP, seg) { if (value & ~0x1fc) as_bad_where (fixP->fx_file, fixP->fx_line, - _("Invalid immediate for stack address calculation")); + _("invalid immediate for stack address calculation")); newval = subtract ? T_OPCODE_SUB_ST : T_OPCODE_ADD_ST; newval |= value >> 2; } @@ -8507,7 +10123,7 @@ md_apply_fix3 (fixP, valP, seg) if (subtract || value & ~0x3fc) as_bad_where (fixP->fx_file, fixP->fx_line, - _("Invalid immediate for address calculation (value = 0x%08lX)"), + _("invalid immediate for address calculation (value = 0x%08lX)"), (unsigned long) value); newval = (rs == REG_PC ? T_OPCODE_ADD_PC : T_OPCODE_ADD_SP); newval |= rd << 8; @@ -8517,7 +10133,7 @@ md_apply_fix3 (fixP, valP, seg) { if (value & ~0xff) as_bad_where (fixP->fx_file, fixP->fx_line, - _("Invalid 8bit immediate")); + _("invalid 8bit immediate")); newval = subtract ? T_OPCODE_SUB_I8 : T_OPCODE_ADD_I8; newval |= (rd << 8) | value; } @@ -8525,7 +10141,7 @@ md_apply_fix3 (fixP, valP, seg) { if (value & ~0x7) as_bad_where (fixP->fx_file, fixP->fx_line, - _("Invalid 3bit immediate")); + _("invalid 3bit immediate")); newval = subtract ? T_OPCODE_SUB_I3 : T_OPCODE_ADD_I3; newval |= rd | (rs << 3) | (value << 6); } @@ -8541,7 +10157,7 @@ md_apply_fix3 (fixP, valP, seg) case 0x05: /* 8bit immediate CMP. */ if (value < 0 || value > 255) as_bad_where (fixP->fx_file, fixP->fx_line, - _("Invalid immediate: %ld is too large"), + _("invalid immediate: %ld is too large"), (long) value); newval |= value; break; @@ -8556,7 +10172,7 @@ md_apply_fix3 (fixP, valP, seg) /* 5bit shift value (0..31). */ if (value < 0 || value > 31) as_bad_where (fixP->fx_file, fixP->fx_line, - _("Illegal Thumb shift value: %ld"), (long) value); + _("illegal Thumb shift value: %ld"), (long) value); newval = md_chars_to_number (buf, THUMB_SIZE) & 0xf03f; newval |= value << 6; md_number_to_chars (buf, newval, THUMB_SIZE); @@ -8570,7 +10186,7 @@ md_apply_fix3 (fixP, valP, seg) case BFD_RELOC_NONE: default: as_bad_where (fixP->fx_file, fixP->fx_line, - _("Bad relocation fixup type (%d)"), fixP->fx_r_type); + _("bad relocation fixup type (%d)"), fixP->fx_r_type); } } @@ -8641,7 +10257,7 @@ tc_gen_reloc (section, fixp) /* If this is called then the a literal has been referenced across a section boundary - possibly due to an implicit dump. */ as_bad_where (fixp->fx_file, fixp->fx_line, - _("Literal referenced across section boundary (Implicit dump?)")); + _("literal referenced across section boundary (Implicit dump?)")); return NULL; #ifdef OBJ_ELF @@ -8654,7 +10270,7 @@ tc_gen_reloc (section, fixp) case BFD_RELOC_ARM_IMMEDIATE: as_bad_where (fixp->fx_file, fixp->fx_line, - _("Internal_relocation (type %d) not fixed up (IMMEDIATE)"), + _("internal relocation (type %d) not fixed up (IMMEDIATE)"), fixp->fx_r_type); return NULL; @@ -8665,7 +10281,7 @@ tc_gen_reloc (section, fixp) case BFD_RELOC_ARM_OFFSET_IMM: as_bad_where (fixp->fx_file, fixp->fx_line, - _("Internal_relocation (type %d) not fixed up (OFFSET_IMM)"), + _("internal_relocation (type %d) not fixed up (OFFSET_IMM)"), fixp->fx_r_type); return NULL; @@ -8689,7 +10305,7 @@ tc_gen_reloc (section, fixp) default: type = _(""); break; } as_bad_where (fixp->fx_file, fixp->fx_line, - _("Cannot represent %s relocation in this object file format"), + _("cannot represent %s relocation in this object file format"), type); return NULL; } @@ -8710,7 +10326,7 @@ tc_gen_reloc (section, fixp) if (reloc->howto == NULL) { as_bad_where (fixp->fx_file, fixp->fx_line, - _("Can not represent %s relocation in this object file format"), + _("cannot represent %s relocation in this object file format"), bfd_get_reloc_code_name (code)); return NULL; } @@ -8733,13 +10349,14 @@ md_estimate_size_before_relax (fragP, segtype) } static void -output_inst PARAMS ((void)) +output_inst (str) + const char *str; { char * to = NULL; if (inst.error) { - as_bad (inst.error); + as_bad ("%s -- `%s'", inst.error, str); return; } @@ -8774,17 +10391,15 @@ void md_assemble (str) char * str; { - char c; - char * p; - char * q; - char * start; + char c; + char *p; + char *start; /* Align the instruction. This may not be the right thing to do but ... */ #if 0 arm_align (2, 0); #endif - listing_prev_line (); /* Defined in listing.h. */ /* Align the previous label if needed. */ if (last_label_seen != NULL) @@ -8807,7 +10422,7 @@ md_assemble (str) if (p == str) { - as_bad (_("No operator -- statement `%s'\n"), str); + as_bad (_("no operator -- statement `%s'\n"), str); return; } @@ -8825,14 +10440,14 @@ md_assemble (str) /* Check that this instruction is supported for this CPU. */ if (thumb_mode == 1 && (opcode->variant & cpu_variant) == 0) { - as_bad (_("selected processor does not support this opcode")); + as_bad (_("selected processor does not support `%s'"), str); return; } inst.instruction = opcode->value; inst.size = opcode->size; (*opcode->parms) (p); - output_inst (); + output_inst (str); return; } } @@ -8842,96 +10457,65 @@ md_assemble (str) c = *p; *p = '\0'; - opcode = (CONST struct asm_opcode *) hash_find (arm_ops_hsh, str); + opcode = (const struct asm_opcode *) hash_find (arm_ops_hsh, str); *p = c; if (opcode) { /* Check that this instruction is supported for this CPU. */ - if ((opcode->variant & cpu_variant) == 0) - { - as_bad (_("selected processor does not support this opcode")); - return; - } - - inst.instruction = opcode->value; - inst.size = INSN_SIZE; - (*opcode->parms) (p); - output_inst (); - return; - } - } - - /* It wasn't an instruction, but it might be a register alias of the form - alias .req reg. */ - q = p; - skip_whitespace (q); - - c = *p; - *p = '\0'; - - if (*q && !strncmp (q, ".req ", 4)) - { - int reg; - char * copy_of_str; - char * r; - -#ifdef IGNORE_OPCODE_CASE - str = original_case_string; -#endif - copy_of_str = str; - - q += 4; - skip_whitespace (q); - - for (r = q; *r != '\0'; r++) - if (*r == ' ') - break; - - if (r != q) - { - int regnum; - char d = *r; - - *r = '\0'; - regnum = arm_reg_parse (& q); - *r = d; - - reg = arm_reg_parse (& str); - - if (reg == FAIL) + if ((opcode->variant & cpu_variant) == 0) { - if (regnum != FAIL) - insert_reg_alias (str, regnum); - else - as_warn (_("register '%s' does not exist\n"), q); + as_bad (_("selected processor does not support `%s'"), str); + return; } - else if (regnum != FAIL) - { - if (reg != regnum) - as_warn (_("ignoring redefinition of register alias '%s'"), - copy_of_str); - /* Do not warn about redefinitions to the same alias. */ - } - else - as_warn (_("ignoring redefinition of register alias '%s' to non-existant register '%s'"), - copy_of_str, q); + inst.instruction = opcode->value; + inst.size = INSN_SIZE; + (*opcode->parms) (p); + output_inst (str); + return; } - else - as_warn (_("ignoring incomplete .req pseuso op")); - - *p = c; - return; } - *p = c; + /* It wasn't an instruction, but it might be a register alias of the form + alias .req reg. */ + if (create_register_alias (str, p)) + return; + as_bad (_("bad instruction `%s'"), start); } /* md_parse_option Invocation line includes a switch not recognized by the base assembler. - See if it's a processor-specific option. These are: + See if it's a processor-specific option. + + This routine is somewhat complicated by the need for backwards + compatibility (since older releases of gcc can't be changed). + The new options try to make the interface as compatible as + possible with GCC. + + New options (supported) are: + + -mcpu= Assemble for selected processor + -march= Assemble for selected architecture + -mfpu= Assemble for selected FPU. + -EB/-mbig-endian Big-endian + -EL/-mlittle-endian Little-endian + -k Generate PIC code + -mthumb Start in Thumb mode + -mthumb-interwork Code supports ARM/Thumb interworking + + For now we will also provide support for + + -mapcs-32 32-bit Program counter + -mapcs-26 26-bit Program counter + -macps-float Floats passed in FP registers + -mapcs-reentrant Reentrant code + -matpcs + (sometime these will probably be replaced with -mapcs= + and -matpcs=) + + The remaining options are only supported for back-wards compatibility. Cpu variants, the arm part is optional: -m[arm]1 Currently not supported. -m[arm]2, -m[arm]250 Arm 2 and Arm 250 processor @@ -8940,7 +10524,6 @@ md_assemble (str) -m[arm]7[xx][t][[d]m] Arm 7 processors -m[arm]8[10] Arm 8 processors -m[arm]9[20][tdmi] Arm 9 processors - -marm9e Allow Cirrus/DSP instructions -mstrongarm[110[0]] StrongARM processors -mxscale XScale processors -m[arm]v[2345[t[e]]] Arm architectures @@ -8948,384 +10531,567 @@ 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 - -EL little endian cpu - ARM Procedure Calling Standard: - -mapcs-32 32 bit APCS - -mapcs-26 26 bit APCS - -mapcs-float Pass floats in float regs - -mapcs-reentrant Position independent code - -mthumb-interwork Code supports Arm/Thumb interworking - -matpcs ARM/Thumb Procedure Call Standard - -moabi Old ELF ABI */ - -const char * md_shortopts = "m:k"; -struct option md_longopts[] = -{ + The following CPU names are recognized: + arm1, arm2, arm250, arm3, arm6, arm600, arm610, arm620, + arm7, arm7m, arm7d, arm7dm, arm7di, arm7dmi, arm70, arm700, + arm700i, arm710 arm710t, arm720, arm720t, arm740t, arm710c, + arm7100, arm7500, arm7500fe, arm7tdmi, arm8, arm810, arm9, + arm920, arm920t, arm940t, arm946, arm966, arm9tdmi, arm9e, + arm10t arm10e, arm1020t, arm1020e, arm10200e, + strongarm, strongarm110, strongarm1100, strongarm1110, xscale. + + */ + +CONST char * md_shortopts = "m:k"; + #ifdef ARM_BI_ENDIAN #define OPTION_EB (OPTION_MD_BASE + 0) - {"EB", no_argument, NULL, OPTION_EB}, #define OPTION_EL (OPTION_MD_BASE + 1) - {"EL", no_argument, NULL, OPTION_EL}, -#ifdef OBJ_ELF -#define OPTION_OABI (OPTION_MD_BASE +2) - {"oabi", no_argument, NULL, OPTION_OABI}, +#else +#if TARGET_BYTES_BIG_ENDIAN +#define OPTION_EB (OPTION_MD_BASE + 0) +#else +#define OPTION_EL (OPTION_MD_BASE + 1) +#endif +#endif + +struct option md_longopts[] = +{ +#ifdef OPTION_EB + {"EB", no_argument, NULL, OPTION_EB}, #endif +#ifdef OPTION_EL + {"EL", no_argument, NULL, OPTION_EL}, #endif {NULL, no_argument, NULL, 0} }; size_t md_longopts_size = sizeof (md_longopts); -int -md_parse_option (c, arg) - int c; - char * arg; +struct arm_option_table { - char * str = arg; + char *option; /* Option name to match. */ + char *help; /* Help information. */ + int *var; /* Variable to change. */ + int value; /* What to change it to. */ + char *deprecated; /* If non-null, print this message. */ +}; - switch (c) +struct arm_option_table arm_opts[] = +{ + {"k", N_("generate PIC code"), &pic_code, 1, NULL}, + {"mthumb", N_("assemble Thumb code"), &thumb_mode, 1, NULL}, + {"mthumb-interwork", N_("support ARM/Thumb interworking"), + &support_interwork, 1, NULL}, + {"moabi", N_("use old ABI (ELF only)"), &target_oabi, 1, NULL}, + {"mapcs-32", N_("code uses 32-bit program counter"), &uses_apcs_26, 0, NULL}, + {"mapcs-26", N_("code uses 26-bit program counter"), &uses_apcs_26, 1, NULL}, + {"mapcs-float", N_("floating point args are in fp regs"), &uses_apcs_float, + 1, NULL}, + {"mapcs-reentrant", N_("re-entrant code"), &pic_code, 1, NULL}, + {"matpcs", N_("code is ATPCS conformant"), &atpcs, 1, NULL}, + {"mbig-endian", N_("assemble for big-endian"), &target_big_endian, 1, NULL}, + {"mlittle-endian", N_("assemble for little-endian"), &target_big_endian, 1, + NULL}, + + /* These are recognized by the assembler, but have no affect on code. */ + {"mapcs-frame", N_("use frame pointer"), NULL, 0, NULL}, + {"mapcs-stack-check", N_("use stack size checking"), NULL, 0, NULL}, + + /* DON'T add any new processors to this list -- we want the whole list + to go away... Add them to the processors table instead. */ + {"marm1", NULL, &legacy_cpu, ARM_ARCH_V1, N_("use -mcpu=arm1")}, + {"m1", NULL, &legacy_cpu, ARM_ARCH_V1, N_("use -mcpu=arm1")}, + {"marm2", NULL, &legacy_cpu, ARM_ARCH_V2, N_("use -mcpu=arm2")}, + {"m2", NULL, &legacy_cpu, ARM_ARCH_V2, N_("use -mcpu=arm2")}, + {"marm250", NULL, &legacy_cpu, ARM_ARCH_V2S, N_("use -mcpu=arm250")}, + {"m250", NULL, &legacy_cpu, ARM_ARCH_V2S, N_("use -mcpu=arm250")}, + {"marm3", NULL, &legacy_cpu, ARM_ARCH_V2S, N_("use -mcpu=arm3")}, + {"m3", NULL, &legacy_cpu, ARM_ARCH_V2S, N_("use -mcpu=arm3")}, + {"marm6", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm6")}, + {"m6", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm6")}, + {"marm600", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm600")}, + {"m600", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm600")}, + {"marm610", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm610")}, + {"m610", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm610")}, + {"marm620", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm620")}, + {"m620", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm620")}, + {"marm7", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7")}, + {"m7", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7")}, + {"marm70", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm70")}, + {"m70", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm70")}, + {"marm700", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm700")}, + {"m700", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm700")}, + {"marm700i", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm700i")}, + {"m700i", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm700i")}, + {"marm710", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm710")}, + {"m710", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm710")}, + {"marm710c", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm710c")}, + {"m710c", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm710c")}, + {"marm720", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm720")}, + {"m720", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm720")}, + {"marm7d", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7d")}, + {"m7d", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7d")}, + {"marm7di", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7di")}, + {"m7di", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7di")}, + {"marm7m", NULL, &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7m")}, + {"m7m", NULL, &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7m")}, + {"marm7dm", NULL, &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7dm")}, + {"m7dm", NULL, &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7dm")}, + {"marm7dmi", NULL, &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7dmi")}, + {"m7dmi", NULL, &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7dmi")}, + {"marm7100", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7100")}, + {"m7100", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7100")}, + {"marm7500", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7500")}, + {"m7500", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7500")}, + {"marm7500fe", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7500fe")}, + {"m7500fe", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7500fe")}, + {"marm7t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm7tdmi")}, + {"m7t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm7tdmi")}, + {"marm7tdmi", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm7tdmi")}, + {"m7tdmi", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm7tdmi")}, + {"marm710t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm710t")}, + {"m710t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm710t")}, + {"marm720t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm720t")}, + {"m720t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm720t")}, + {"marm740t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm740t")}, + {"m740t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm740t")}, + {"marm8", NULL, &legacy_cpu, ARM_ARCH_V4, N_("use -mcpu=arm8")}, + {"m8", NULL, &legacy_cpu, ARM_ARCH_V4, N_("use -mcpu=arm8")}, + {"marm810", NULL, &legacy_cpu, ARM_ARCH_V4, N_("use -mcpu=arm810")}, + {"m810", NULL, &legacy_cpu, ARM_ARCH_V4, N_("use -mcpu=arm810")}, + {"marm9", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm9")}, + {"m9", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm9")}, + {"marm9tdmi", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm9tdmi")}, + {"m9tdmi", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm9tdmi")}, + {"marm920", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm920")}, + {"m920", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm920")}, + {"marm940", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm940")}, + {"m940", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm940")}, + {"mstrongarm", NULL, &legacy_cpu, ARM_ARCH_V4, N_("use -mcpu=strongarm")}, + {"mstrongarm110", NULL, &legacy_cpu, ARM_ARCH_V4, + N_("use -mcpu=strongarm110")}, + {"mstrongarm1100", NULL, &legacy_cpu, ARM_ARCH_V4, + N_("use -mcpu=strongarm1100")}, + {"mstrongarm1110", NULL, &legacy_cpu, ARM_ARCH_V4, + N_("use -mcpu=strongarm1110")}, + {"mxscale", NULL, &legacy_cpu, ARM_ARCH_XSCALE, N_("use -mcpu=xscale")}, + {"mall", NULL, &legacy_cpu, ARM_ANY, N_("use -mcpu=all")}, + + /* Architecture variants -- don't add any more to this list either. */ + {"mv2", NULL, &legacy_cpu, ARM_ARCH_V2, N_("use -march=armv2")}, + {"marmv2", NULL, &legacy_cpu, ARM_ARCH_V2, N_("use -march=armv2")}, + {"mv2a", NULL, &legacy_cpu, ARM_ARCH_V2S, N_("use -march=armv2a")}, + {"marmv2a", NULL, &legacy_cpu, ARM_ARCH_V2S, N_("use -march=armv2a")}, + {"mv3", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -march=armv3")}, + {"marmv3", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -march=armv3")}, + {"mv3m", NULL, &legacy_cpu, ARM_ARCH_V3M, N_("use -march=armv3m")}, + {"marmv3m", NULL, &legacy_cpu, ARM_ARCH_V3M, N_("use -march=armv3m")}, + {"mv4", NULL, &legacy_cpu, ARM_ARCH_V4, N_("use -march=armv4")}, + {"marmv4", NULL, &legacy_cpu, ARM_ARCH_V4, N_("use -march=armv4")}, + {"mv4t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -march=armv4t")}, + {"marmv4t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -march=armv4t")}, + {"mv5", NULL, &legacy_cpu, ARM_ARCH_V5, N_("use -march=armv5")}, + {"marmv5", NULL, &legacy_cpu, ARM_ARCH_V5, N_("use -march=armv5")}, + {"mv5t", NULL, &legacy_cpu, ARM_ARCH_V5T, N_("use -march=armv5t")}, + {"marmv5t", NULL, &legacy_cpu, ARM_ARCH_V5T, N_("use -march=armv5t")}, + {"mv5e", NULL, &legacy_cpu, ARM_ARCH_V5TE, N_("use -march=armv5te")}, + {"marmv5e", NULL, &legacy_cpu, ARM_ARCH_V5TE, N_("use -march=armv5te")}, + + /* Floating point variants -- don't add any more to this list either. */ + {"mfpe-old", NULL, &legacy_fpu, FPU_ARCH_FPE, N_("use -mfpu=fpe")}, + {"mfpa10", NULL, &legacy_fpu, FPU_ARCH_FPA, N_("use -mfpu=fpa10")}, + {"mfpa11", NULL, &legacy_fpu, FPU_ARCH_FPA, N_("use -mfpu=fpa11")}, + {"mno-fpu", NULL, &legacy_fpu, 0, + N_("use either -mfpu=softfpa or -mfpu=softvfp")}, + + {NULL, NULL, NULL, 0, NULL} +}; + +struct arm_cpu_option_table +{ + char *name; + int value; + /* For some CPUs we assume an FPU unless the user explicitly sets + -mfpu=... */ + int default_fpu; +}; + +/* This list should, at a minimum, contain all the cpu names + recognized by GCC. */ +static struct arm_cpu_option_table arm_cpus[] = +{ + {"all", ARM_ANY, FPU_ARCH_FPA}, + {"arm1", ARM_ARCH_V1, FPU_ARCH_FPA}, + {"arm2", ARM_ARCH_V2, FPU_ARCH_FPA}, + {"arm250", ARM_ARCH_V2S, FPU_ARCH_FPA}, + {"arm3", ARM_ARCH_V2S, FPU_ARCH_FPA}, + {"arm6", ARM_ARCH_V3, FPU_ARCH_FPA}, + {"arm60", ARM_ARCH_V3, FPU_ARCH_FPA}, + {"arm600", ARM_ARCH_V3, FPU_ARCH_FPA}, + {"arm610", ARM_ARCH_V3, FPU_ARCH_FPA}, + {"arm620", ARM_ARCH_V3, FPU_ARCH_FPA}, + {"arm7", ARM_ARCH_V3, FPU_ARCH_FPA}, + {"arm7m", ARM_ARCH_V3M, FPU_ARCH_FPA}, + {"arm7d", ARM_ARCH_V3, FPU_ARCH_FPA}, + {"arm7dm", ARM_ARCH_V3M, FPU_ARCH_FPA}, + {"arm7di", ARM_ARCH_V3, FPU_ARCH_FPA}, + {"arm7dmi", ARM_ARCH_V3M, FPU_ARCH_FPA}, + {"arm70", ARM_ARCH_V3, FPU_ARCH_FPA}, + {"arm700", ARM_ARCH_V3, FPU_ARCH_FPA}, + {"arm700i", ARM_ARCH_V3, FPU_ARCH_FPA}, + {"arm710", ARM_ARCH_V3, FPU_ARCH_FPA}, + {"arm710t", ARM_ARCH_V4T, FPU_ARCH_FPA}, + {"arm720", ARM_ARCH_V3, FPU_ARCH_FPA}, + {"arm720t", ARM_ARCH_V4T, FPU_ARCH_FPA}, + {"arm740t", ARM_ARCH_V4T, FPU_ARCH_FPA}, + {"arm710c", ARM_ARCH_V3, FPU_ARCH_FPA}, + {"arm7100", ARM_ARCH_V3, FPU_ARCH_FPA}, + {"arm7500", ARM_ARCH_V3, FPU_ARCH_FPA}, + {"arm7500fe", ARM_ARCH_V3, FPU_ARCH_FPA}, + {"arm7t", ARM_ARCH_V4T, FPU_ARCH_FPA}, + {"arm7tdmi", ARM_ARCH_V4T, FPU_ARCH_FPA}, + {"arm8", ARM_ARCH_V4, FPU_ARCH_FPA}, + {"arm810", ARM_ARCH_V4, FPU_ARCH_FPA}, + {"strongarm", ARM_ARCH_V4, FPU_ARCH_FPA}, + {"strongarm1", ARM_ARCH_V4, FPU_ARCH_FPA}, + {"strongarm110", ARM_ARCH_V4, FPU_ARCH_FPA}, + {"strongarm1100", ARM_ARCH_V4, FPU_ARCH_FPA}, + {"strongarm1110", ARM_ARCH_V4, FPU_ARCH_FPA}, + {"arm9", ARM_ARCH_V4T, FPU_ARCH_FPA}, + {"arm920", ARM_ARCH_V4T, FPU_ARCH_FPA}, + {"arm920t", ARM_ARCH_V4T, FPU_ARCH_FPA}, + {"arm922t", ARM_ARCH_V4T, FPU_ARCH_FPA}, + {"arm940t", ARM_ARCH_V4T, FPU_ARCH_FPA}, + {"arm9tdmi", ARM_ARCH_V4T, FPU_ARCH_FPA}, + /* For V5 or later processors we default to using VFP; but the user + should really set the FPU type explicitly. */ + {"arm9e-r0", ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2}, + {"arm9e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2}, + {"arm926ej", ARM_ARCH_V5TEJ, FPU_ARCH_VFP_V2}, + {"arm946e-r0", ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2}, + {"arm946e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2}, + {"arm966e-r0", ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2}, + {"arm966e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2}, + {"arm10t", ARM_ARCH_V5T, FPU_ARCH_VFP_V1}, + {"arm10e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2}, + {"arm1020", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2}, + {"arm1020t", ARM_ARCH_V5T, FPU_ARCH_VFP_V1}, + {"arm1020e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2}, + /* ??? XSCALE is really an architecture. */ + {"xscale", ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2}, + {"i80200", ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2}, + /* Maverick */ + {"ep9312", ARM_ARCH_V4T | ARM_CEXT_MAVERICK, FPU_NONE}, + {NULL, 0, 0} +}; + +struct arm_arch_option_table +{ + char *name; + int value; + int default_fpu; +}; + +/* This list should, at a minimum, contain all the architecture names + recognized by GCC. */ +static struct arm_arch_option_table arm_archs[] = +{ + {"all", ARM_ANY, FPU_ARCH_FPA}, + {"armv1", ARM_ARCH_V1, FPU_ARCH_FPA}, + {"armv2", ARM_ARCH_V2, FPU_ARCH_FPA}, + {"armv2a", ARM_ARCH_V2S, FPU_ARCH_FPA}, + {"armv2s", ARM_ARCH_V2S, FPU_ARCH_FPA}, + {"armv3", ARM_ARCH_V3, FPU_ARCH_FPA}, + {"armv3m", ARM_ARCH_V3M, FPU_ARCH_FPA}, + {"armv4", ARM_ARCH_V4, FPU_ARCH_FPA}, + {"armv4xm", ARM_ARCH_V4xM, FPU_ARCH_FPA}, + {"armv4t", ARM_ARCH_V4T, FPU_ARCH_FPA}, + {"armv4txm", ARM_ARCH_V4TxM, FPU_ARCH_FPA}, + {"armv5", ARM_ARCH_V5, FPU_ARCH_VFP}, + {"armv5t", ARM_ARCH_V5T, FPU_ARCH_VFP}, + {"armv5txm", ARM_ARCH_V5TxM, FPU_ARCH_VFP}, + {"armv5te", ARM_ARCH_V5TE, FPU_ARCH_VFP}, + {"armv5texp", ARM_ARCH_V5TExP, FPU_ARCH_VFP}, + {"armv5tej", ARM_ARCH_V5TEJ, FPU_ARCH_VFP}, + {"xscale", ARM_ARCH_XSCALE, FPU_ARCH_VFP}, + {NULL, 0, 0} +}; + +/* ISA extensions in the co-processor space. */ +struct arm_arch_extension_table +{ + char *name; + int value; +}; + +static struct arm_arch_extension_table arm_extensions[] = +{ + {"maverick", ARM_CEXT_MAVERICK}, + {"xscale", ARM_CEXT_XSCALE}, + {NULL, 0} +}; + +struct arm_fpu_option_table +{ + char *name; + int value; +}; + +/* This list should, at a minimum, contain all the fpu names + recognized by GCC. */ +static struct arm_fpu_option_table arm_fpus[] = +{ + {"softfpa", FPU_NONE}, + {"fpe", FPU_ARCH_FPE}, + {"fpe2", FPU_ARCH_FPE}, + {"fpe3", FPU_ARCH_FPA}, /* Third release supports LFM/SFM. */ + {"fpa", FPU_ARCH_FPA}, + {"fpa10", FPU_ARCH_FPA}, + {"fpa11", FPU_ARCH_FPA}, + {"arm7500fe", FPU_ARCH_FPA}, + {"softvfp", FPU_ARCH_VFP}, + {"softvfp+vfp", FPU_ARCH_VFP_V2}, + {"vfp", FPU_ARCH_VFP_V2}, + {"vfp9", FPU_ARCH_VFP_V2}, + {"vfp10", FPU_ARCH_VFP_V2}, + {"vfp10-r0", FPU_ARCH_VFP_V1}, + {"vfpxd", FPU_ARCH_VFP_V1xD}, + {"arm1020t", FPU_ARCH_VFP_V1}, + {"arm1020e", FPU_ARCH_VFP_V2}, + {NULL, 0} +}; + +struct arm_long_option_table +{ + char *option; /* Substring to match. */ + char *help; /* Help information. */ + int (*func) PARAMS ((char *subopt)); /* Function to decode sub-option. */ + char *deprecated; /* If non-null, print this message. */ +}; + +static int +arm_parse_extension (str, opt_p) + char *str; + int *opt_p; +{ + while (str != NULL && *str != 0) { -#ifdef ARM_BI_ENDIAN - case OPTION_EB: - target_big_endian = 1; - break; - case OPTION_EL: - target_big_endian = 0; - break; -#endif + struct arm_arch_extension_table *opt; + char *ext; + int optlen; - case 'm': - switch (*str) + if (*str != '+') { - case 'f': - if (streq (str, "fpa10") || streq (str, "fpa11")) - cpu_variant = (cpu_variant & ~FPU_ANY) | FPU_ARCH_FPA; - else if (streq (str, "fpe-old")) - cpu_variant = (cpu_variant & ~FPU_ANY) | FPU_ARCH_FPE; - else - goto bad; - break; + as_bad (_("invalid architectural extension")); + return 0; + } - case 'n': - if (streq (str, "no-fpu")) - cpu_variant &= ~FPU_ANY; - break; + str++; + ext = strchr (str, '+'); -#ifdef OBJ_ELF - case 'o': - if (streq (str, "oabi")) - target_oabi = true; - break; -#endif + if (ext != NULL) + optlen = ext - str; + else + optlen = strlen (str); - case 't': - /* Limit assembler to generating only Thumb instructions: */ - if (streq (str, "thumb")) - { - cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_EXT_V4T; - cpu_variant = (cpu_variant & ~FPU_ANY) | FPU_NONE; - thumb_mode = 1; - } - else if (streq (str, "thumb-interwork")) - { - if ((cpu_variant & ARM_EXT_V4T) == 0) - cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_ARCH_V4T; -#if defined OBJ_COFF || defined OBJ_ELF - support_interwork = true; -#endif - } - else - goto bad; - break; + if (optlen == 0) + { + as_bad (_("missing architectural extension")); + return 0; + } - default: - if (streq (str, "all")) - { - cpu_variant = ARM_ALL | FPU_DEFAULT; - return 1; - } -#if defined OBJ_COFF || defined OBJ_ELF - if (! strncmp (str, "apcs-", 5)) - { - /* GCC passes on all command line options starting "-mapcs-..." - to us, so we must parse them here. */ + for (opt = arm_extensions; opt->name != NULL; opt++) + if (strncmp (opt->name, str, optlen) == 0) + { + *opt_p |= opt->value; + break; + } - str += 5; + if (opt->name == NULL) + { + as_bad (_("unknown architectural extnsion `%s'"), str); + return 0; + } - if (streq (str, "32")) - { - uses_apcs_26 = false; - return 1; - } - else if (streq (str, "26")) - { - uses_apcs_26 = true; - return 1; - } - else if (streq (str, "frame")) - { - /* Stack frames are being generated - does not affect - linkage of code. */ - return 1; - } - else if (streq (str, "stack-check")) - { - /* Stack checking is being performed - does not affect - linkage, but does require that the functions - __rt_stkovf_split_small and __rt_stkovf_split_big be - present in the final link. */ + str = ext; + }; - return 1; - } - else if (streq (str, "float")) - { - /* Floating point arguments are being passed in the floating - point registers. This does affect linking, since this - version of the APCS is incompatible with the version that - passes floating points in the integer registers. */ + return 1; +} - uses_apcs_float = true; - return 1; - } - else if (streq (str, "reentrant")) - { - /* Reentrant code has been generated. This does affect - linking, since there is no point in linking reentrant/ - position independent code with absolute position code. */ - pic_code = true; - return 1; - } +static int +arm_parse_cpu (str) + char *str; +{ + struct arm_cpu_option_table *opt; + char *ext = strchr (str, '+'); + int optlen; - as_bad (_("Unrecognised APCS switch -m%s"), arg); - return 0; - } + if (ext != NULL) + optlen = ext - str; + else + optlen = strlen (str); - if (! strcmp (str, "atpcs")) - { - atpcs = true; - return 1; - } -#endif - /* Strip off optional "arm". */ - if (! strncmp (str, "arm", 3)) - str += 3; + if (optlen == 0) + { + as_bad (_("missing cpu name `%s'"), str); + return 0; + } - switch (*str) - { - case '1': - if (streq (str, "1")) - cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_1; - else - goto bad; - break; + for (opt = arm_cpus; opt->name != NULL; opt++) + if (strncmp (opt->name, str, optlen) == 0) + { + mcpu_cpu_opt = opt->value; + mcpu_fpu_opt = opt->default_fpu; - case '2': - if (streq (str, "2")) - cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_2; - else if (streq (str, "250")) - cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_250; - else - goto bad; - break; + if (ext != NULL) + return arm_parse_extension (ext, &mcpu_cpu_opt); - case '3': - if (streq (str, "3")) - cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_3; - else - goto bad; - break; + return 1; + } - case '6': - switch (strtol (str, NULL, 10)) - { - case 6: - case 60: - case 600: - case 610: - case 620: - cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_6; - break; - default: - goto bad; - } - break; + as_bad (_("unknown cpu `%s'"), str); + return 0; +} - case '7': - /* Eat the processor name. */ - switch (strtol (str, & str, 10)) - { - case 7: - case 70: - case 700: - case 710: - case 720: - case 7100: - case 7500: - break; - default: - goto bad; - } - cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_7; - for (; *str; str++) - { - switch (*str) - { - case 't': - cpu_variant |= ARM_ARCH_V4T; - break; +static int +arm_parse_arch (str) + char *str; +{ + struct arm_arch_option_table *opt; + char *ext = strchr (str, '+'); + int optlen; - case 'm': - cpu_variant |= ARM_EXT_V3M; - break; + if (ext != NULL) + optlen = ext - str; + else + optlen = strlen (str); - case 'f': /* fe => fp enabled cpu. */ - if (str[1] == 'e') - ++ str; - else - goto bad; + if (optlen == 0) + { + as_bad (_("missing architecture name `%s'"), str); + return 0; + } - case 'c': /* Left over from 710c processor name. */ - case 'd': /* Debug. */ - case 'i': /* Embedded ICE. */ - /* Included for completeness in ARM processor naming. */ - break; - default: - goto bad; - } - } - break; + for (opt = arm_archs; opt->name != NULL; opt++) + if (strcmp (opt->name, str) == 0) + { + march_cpu_opt = opt->value; + march_fpu_opt = opt->default_fpu; - case '8': - if (streq (str, "8") || streq (str, "810")) - cpu_variant = (cpu_variant & ~ARM_ANY) - | ARM_8 | ARM_ARCH_V4; - else - goto bad; - break; + if (ext != NULL) + return arm_parse_extension (ext, &march_cpu_opt); - case '9': - if (streq (str, "9")) - cpu_variant = (cpu_variant & ~ARM_ANY) - | ARM_9 | ARM_ARCH_V4T; - else if (streq (str, "920")) - cpu_variant = (cpu_variant & ~ARM_ANY) - | ARM_9 | ARM_ARCH_V4; - else if (streq (str, "920t")) - cpu_variant = (cpu_variant & ~ARM_ANY) - | ARM_9 | ARM_ARCH_V4T; - else if (streq (str, "9tdmi")) - cpu_variant = (cpu_variant & ~ARM_ANY) - | ARM_9 | ARM_ARCH_V4T; - else if (streq (str, "9e")) - cpu_variant = (cpu_variant & ~ARM_ANY) - | ARM_9 | ARM_ARCH_V4T | ARM_EXT_MAVERICK; - else - goto bad; - break; + return 1; + } - case 's': - if (streq (str, "strongarm") - || streq (str, "strongarm110") - || streq (str, "strongarm1100")) - cpu_variant = (cpu_variant & ~ARM_ANY) - | ARM_8 | ARM_ARCH_V4; - else - goto bad; - break; + as_bad (_("unknown architecture `%s'\n"), str); + return 0; +} - case 'x': - if (streq (str, "xscale")) - cpu_variant = (cpu_variant & ~ARM_ANY) - | ARM_9 | ARM_ARCH_XSCALE; - else - goto bad; - break; - - case 'v': - /* Select variant based on architecture rather than - processor. */ - switch (*++str) - { - case '2': - switch (*++str) - { - case 'a': - cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_3; - break; - case 0: - cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_2; - break; - default: - as_bad (_("Invalid architecture variant -m%s"), arg); - break; - } - break; +static int +arm_parse_fpu (str) + char *str; +{ + struct arm_fpu_option_table *opt; - case '3': - cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_7; + for (opt = arm_fpus; opt->name != NULL; opt++) + if (strcmp (opt->name, str) == 0) + { + mfpu_opt = opt->value; + return 1; + } - switch (*++str) - { - case 'm': cpu_variant |= ARM_EXT_V3M; break; - case 0: break; - default: - as_bad (_("Invalid architecture variant -m%s"), arg); - break; - } - break; + as_bad (_("unknown floating point format `%s'\n"), str); + return 0; +} - case '4': - cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_7 | ARM_ARCH_V4; +struct arm_long_option_table arm_long_opts[] = +{ + {"mcpu=", N_("\t assemble for CPU "), + arm_parse_cpu, NULL}, + {"march=", N_("\t assemble for architecture "), + arm_parse_arch, NULL}, + {"mfpu=", N_("\t assemble for FPU architecture "), + arm_parse_fpu, NULL}, + {NULL, NULL, 0, NULL} +}; - switch (*++str) - { - case 't': cpu_variant |= ARM_EXT_V4T; break; - case 0: break; - default: - as_bad (_("Invalid architecture variant -m%s"), arg); - break; - } - break; +int +md_parse_option (c, arg) + int c; + char * arg; +{ + struct arm_option_table *opt; + struct arm_long_option_table *lopt; - case '5': - cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_9 | ARM_ARCH_V5; - switch (*++str) - { - case 't': cpu_variant |= ARM_EXT_V4T; break; - case 'e': cpu_variant |= ARM_EXT_V5E; break; - case 0: break; - default: - as_bad (_("Invalid architecture variant -m%s"), arg); - break; - } - break; + switch (c) + { +#ifdef OPTION_EB + case OPTION_EB: + target_big_endian = 1; + break; +#endif - default: - as_bad (_("Invalid architecture variant -m%s"), arg); - break; - } - break; +#ifdef OPTION_EL + case OPTION_EL: + target_big_endian = 0; + break; +#endif - default: - bad: - as_bad (_("Invalid processor variant -m%s"), arg); - return 0; + case 'a': + /* Listing option. Just ignore these, we don't support additional + ones. */ + return 0; + + default: + for (opt = arm_opts; opt->option != NULL; opt++) + { + if (c == opt->option[0] + && ((arg == NULL && opt->option[1] == 0) + || strcmp (arg, opt->option + 1) == 0)) + { +#if WARN_DEPRECATED + /* If the option is deprecated, tell the user. */ + if (opt->deprecated != NULL) + as_tsktsk (_("option `-%c%s' is deprecated: %s"), c, + arg ? arg : "", _(opt->deprecated)); +#endif + + if (opt->var != NULL) + *opt->var = opt->value; + + return 1; } } - break; -#if defined OBJ_ELF || defined OBJ_COFF - case 'k': - pic_code = 1; - break; + for (lopt = arm_long_opts; lopt->option != NULL; lopt++) + { + /* These options are expected to have an argument. */ + if (c == lopt->option[0] + && arg != NULL + && strncmp (arg, lopt->option + 1, + strlen (lopt->option + 1)) == 0) + { +#if WARN_DEPRECATED + /* If the option is deprecated, tell the user. */ + if (lopt->deprecated != NULL) + as_tsktsk (_("option `-%c%s' is deprecated: %s"), c, arg, + _(lopt->deprecated)); #endif - default: + /* Call the sup-option parser. */ + return (*lopt->func)(arg + strlen (lopt->option) - 1); + } + } + + as_bad (_("unrecognized option `-%c%s'"), c, arg ? arg : ""); return 0; } @@ -9336,33 +11102,27 @@ void md_show_usage (fp) FILE * fp; { + struct arm_option_table *opt; + struct arm_long_option_table *lopt; + + fprintf (fp, _(" ARM-specific assembler options:\n")); + + for (opt = arm_opts; opt->option != NULL; opt++) + if (opt->help != NULL) + fprintf (fp, " -%-23s%s\n", opt->option, _(opt->help)); + + for (lopt = arm_long_opts; lopt->option != NULL; lopt++) + if (lopt->help != NULL) + fprintf (fp, " -%s%s\n", lopt->option, _(lopt->help)); + +#ifdef OPTION_EB fprintf (fp, _("\ - ARM Specific Assembler Options:\n\ - -m[arm][] select processor variant\n\ - -m[arm]v[2|2a|3|3m|4|4t|5[t][e]] select architecture variant\n\ - -marm9e allow Cirrus/DSP instructions\n\ - -mthumb only allow Thumb instructions\n\ - -mthumb-interwork mark the assembled code as supporting interworking\n\ - -mall allow any instruction\n\ - -mfpa10, -mfpa11 select floating point architecture\n\ - -mfpe-old don't allow floating-point multiple instructions\n\ - -mno-fpu don't allow any floating-point instructions.\n\ - -k generate PIC code.\n")); -#if defined OBJ_COFF || defined OBJ_ELF - fprintf (fp, _("\ - -mapcs-32, -mapcs-26 specify which ARM Procedure Calling Standard to use\n\ - -matpcs use ARM/Thumb Procedure Calling Standard\n\ - -mapcs-float floating point args are passed in FP regs\n\ - -mapcs-reentrant the code is position independent/reentrant\n")); -#endif -#ifdef OBJ_ELF - fprintf (fp, _("\ - -moabi support the old ELF ABI\n")); + -EB assemble code for a big-endian cpu\n")); #endif -#ifdef ARM_BI_ENDIAN + +#ifdef OPTION_EL fprintf (fp, _("\ - -EB assemble code for a big endian cpu\n\ - -EL assemble code for a little endian cpu\n")); + -EL assemble code for a little-endian cpu\n")); #endif } @@ -9456,7 +11216,6 @@ arm_cleanup () /* Put it at the end of text section. */ subseg_set (text_section, 0); s_ltorg (0); - listing_prev_line (); } void @@ -9488,7 +11247,7 @@ arm_frob_label (sym) lsl r3, r3, #2 ldr r2, [r3, r2] mov pc, r2 - + .Lbbb: .word .Lxxx .Lccc: .word .Lyyy ..etc... @@ -9498,7 +11257,7 @@ arm_frob_label (sym) The second instruction converts a table index into a byte offset. The third instruction gets the jump address out of the table. The fourth instruction performs the jump. - + If the address stored at .Laaa is that of a symbol which has the Thumb_Func bit set, then the linker will arrange for this address to have the bottom bit set, which in turn would mean that the @@ -9547,7 +11306,7 @@ arm_adjust_symtab () as_bad (_("%s: unexpected function type: %d"), S_GET_NAME (sym), S_GET_STORAGE_CLASS (sym)); } - else switch (S_GET_STORAGE_CLASS (sym)) + else switch (S_GET_STORAGE_CLASS (sym)) { case C_EXT: S_SET_STORAGE_CLASS (sym, C_THUMBEXT); @@ -9849,17 +11608,17 @@ arm_handle_align (fragP) int bytes, fix, noop_size; char * p; const char * noop; - + if (fragP->fr_type != rs_align_code) return; bytes = fragP->fr_next->fr_address - fragP->fr_address - fragP->fr_fix; p = fragP->fr_literal + fragP->fr_fix; fix = 0; - + if (bytes > MAX_MEM_FOR_RS_ALIGN_CODE) bytes &= MAX_MEM_FOR_RS_ALIGN_CODE; - + if (fragP->tc_frag_data) { if (target_big_endian) @@ -9876,7 +11635,7 @@ arm_handle_align (fragP) noop = arm_noop; noop_size = sizeof (arm_noop); } - + if (bytes & (noop_size - 1)) { fix = bytes & (noop_size - 1); @@ -9892,7 +11651,7 @@ arm_handle_align (fragP) bytes -= noop_size; fix += noop_size; } - + fragP->fr_fix += fix; fragP->fr_var = noop_size; } @@ -9911,7 +11670,7 @@ arm_frag_align_code (n, max) to support alignments greater than 32 bytes. */ if (max > MAX_MEM_FOR_RS_ALIGN_CODE) as_fatal (_("alignments greater than 32 bytes not supported in .text sections.")); - + p = frag_var (rs_align_code, MAX_MEM_FOR_RS_ALIGN_CODE, 1,