command line (e.g., by -march). */
static int file_ase_smartmips;
-#define ISA_SUPPORT_SMARTMIPS (mips_opts.isa == ISA_MIPS32 \
- || mips_opts.isa == ISA_MIPS32R2)
+#define ISA_SUPPORTS_SMARTMIPS (mips_opts.isa == ISA_MIPS32 \
+ || mips_opts.isa == ISA_MIPS32R2)
/* True if -mdsp was passed or implied by arguments passed on the
command line (e.g., by -march). */
static int file_ase_dsp;
+#define ISA_SUPPORTS_DSP_ASE (mips_opts.isa == ISA_MIPS32R2 \
+ || mips_opts.isa == ISA_MIPS64R2)
+
/* True if -mmt was passed or implied by arguments passed on the
command line (e.g., by -march). */
static int file_ase_mt;
+#define ISA_SUPPORTS_MT_ASE (mips_opts.isa == ISA_MIPS32R2 \
+ || mips_opts.isa == ISA_MIPS64R2)
+
/* The argument of the -march= flag. The architecture we are assembling. */
static int file_mips_arch = CPU_UNKNOWN;
static const char *mips_arch_string;
#define ABI_NEEDS_32BIT_REGS(ABI) ((ABI) == O32_ABI)
/* Likewise 64-bit registers. */
-#define ABI_NEEDS_64BIT_REGS(ABI) \
- ((ABI) == N32_ABI \
- || (ABI) == N64_ABI \
+#define ABI_NEEDS_64BIT_REGS(ABI) \
+ ((ABI) == N32_ABI \
+ || (ABI) == N64_ABI \
|| (ABI) == O64_ABI)
-/* Return true if ISA supports 64 bit gp register instructions. */
-#define ISA_HAS_64BIT_REGS(ISA) ( \
- (ISA) == ISA_MIPS3 \
- || (ISA) == ISA_MIPS4 \
- || (ISA) == ISA_MIPS5 \
- || (ISA) == ISA_MIPS64 \
- || (ISA) == ISA_MIPS64R2 \
- )
+/* Return true if ISA supports 64 bit wide gp registers. */
+#define ISA_HAS_64BIT_REGS(ISA) \
+ ((ISA) == ISA_MIPS3 \
+ || (ISA) == ISA_MIPS4 \
+ || (ISA) == ISA_MIPS5 \
+ || (ISA) == ISA_MIPS64 \
+ || (ISA) == ISA_MIPS64R2)
+
+/* Return true if ISA supports 64 bit wide float registers. */
+#define ISA_HAS_64BIT_FPRS(ISA) \
+ ((ISA) == ISA_MIPS3 \
+ || (ISA) == ISA_MIPS4 \
+ || (ISA) == ISA_MIPS5 \
+ || (ISA) == ISA_MIPS32R2 \
+ || (ISA) == ISA_MIPS64 \
+ || (ISA) == ISA_MIPS64R2)
/* Return true if ISA supports 64-bit right rotate (dror et al.)
instructions. */
-#define ISA_HAS_DROR(ISA) ( \
- (ISA) == ISA_MIPS64R2 \
- )
+#define ISA_HAS_DROR(ISA) \
+ ((ISA) == ISA_MIPS64R2)
/* Return true if ISA supports 32-bit right rotate (ror et al.)
instructions. */
-#define ISA_HAS_ROR(ISA) ( \
- (ISA) == ISA_MIPS32R2 \
- || (ISA) == ISA_MIPS64R2 \
- || mips_opts.ase_smartmips \
- )
+#define ISA_HAS_ROR(ISA) \
+ ((ISA) == ISA_MIPS32R2 \
+ || (ISA) == ISA_MIPS64R2 \
+ || mips_opts.ase_smartmips)
+
+/* Return true if ISA supports single-precision floats in odd registers. */
+#define ISA_HAS_ODD_SINGLE_FPR(ISA) \
+ ((ISA) == ISA_MIPS32 \
+ || (ISA) == ISA_MIPS32R2 \
+ || (ISA) == ISA_MIPS64 \
+ || (ISA) == ISA_MIPS64R2)
+
+/* Return true if ISA supports move to/from high part of a 64-bit
+ floating-point register. */
+#define ISA_HAS_MXHC1(ISA) \
+ ((ISA) == ISA_MIPS32R2 \
+ || (ISA) == ISA_MIPS64R2)
#define HAVE_32BIT_GPRS \
- (mips_opts.gp32 || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+ (mips_opts.gp32 || !ISA_HAS_64BIT_REGS (mips_opts.isa))
#define HAVE_32BIT_FPRS \
- (mips_opts.fp32 || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+ (mips_opts.fp32 || !ISA_HAS_64BIT_FPRS (mips_opts.isa))
-#define HAVE_64BIT_GPRS (! HAVE_32BIT_GPRS)
-#define HAVE_64BIT_FPRS (! HAVE_32BIT_FPRS)
+#define HAVE_64BIT_GPRS (!HAVE_32BIT_GPRS)
+#define HAVE_64BIT_FPRS (!HAVE_32BIT_FPRS)
#define HAVE_NEWABI (mips_abi == N32_ABI || mips_abi == N64_ABI)
struct mips_cpu_info
{
const char *name; /* CPU or ISA name. */
- int is_isa; /* Is this an ISA? (If 0, a CPU.) */
+ int flags; /* ASEs available, or ISA flag. */
int isa; /* ISA level. */
int cpu; /* CPU number (default CPU if ISA). */
};
+#define MIPS_CPU_IS_ISA 0x0001 /* Is this an ISA? (If 0, a CPU.) */
+#define MIPS_CPU_ASE_SMARTMIPS 0x0002 /* CPU implements SmartMIPS ASE */
+#define MIPS_CPU_ASE_DSP 0x0004 /* CPU implements DSP ASE */
+#define MIPS_CPU_ASE_MT 0x0008 /* CPU implements MT ASE */
+#define MIPS_CPU_ASE_MIPS3D 0x0010 /* CPU implements MIPS-3D ASE */
+#define MIPS_CPU_ASE_MDMX 0x0020 /* CPU implements MDMX ASE */
+
static const struct mips_cpu_info *mips_parse_cpu (const char *, const char *);
static const struct mips_cpu_info *mips_cpu_info_from_isa (int);
static const struct mips_cpu_info *mips_cpu_info_from_arch (int);
#undef CONFLICT
}
-/* This function is called once, at assembler startup time. It should
- set up all the tables, etc. that the MD part of the assembler will need. */
+struct regname {
+ const char *name;
+ unsigned int num;
+};
+
+#define RTYPE_MASK 0x1ff00
+#define RTYPE_NUM 0x00100
+#define RTYPE_FPU 0x00200
+#define RTYPE_FCC 0x00400
+#define RTYPE_VEC 0x00800
+#define RTYPE_GP 0x01000
+#define RTYPE_CP0 0x02000
+#define RTYPE_PC 0x04000
+#define RTYPE_ACC 0x08000
+#define RTYPE_CCC 0x10000
+#define RNUM_MASK 0x000ff
+#define RWARN 0x80000
+
+#define GENERIC_REGISTER_NUMBERS \
+ {"$0", RTYPE_NUM | 0}, \
+ {"$1", RTYPE_NUM | 1}, \
+ {"$2", RTYPE_NUM | 2}, \
+ {"$3", RTYPE_NUM | 3}, \
+ {"$4", RTYPE_NUM | 4}, \
+ {"$5", RTYPE_NUM | 5}, \
+ {"$6", RTYPE_NUM | 6}, \
+ {"$7", RTYPE_NUM | 7}, \
+ {"$8", RTYPE_NUM | 8}, \
+ {"$9", RTYPE_NUM | 9}, \
+ {"$10", RTYPE_NUM | 10}, \
+ {"$11", RTYPE_NUM | 11}, \
+ {"$12", RTYPE_NUM | 12}, \
+ {"$13", RTYPE_NUM | 13}, \
+ {"$14", RTYPE_NUM | 14}, \
+ {"$15", RTYPE_NUM | 15}, \
+ {"$16", RTYPE_NUM | 16}, \
+ {"$17", RTYPE_NUM | 17}, \
+ {"$18", RTYPE_NUM | 18}, \
+ {"$19", RTYPE_NUM | 19}, \
+ {"$20", RTYPE_NUM | 20}, \
+ {"$21", RTYPE_NUM | 21}, \
+ {"$22", RTYPE_NUM | 22}, \
+ {"$23", RTYPE_NUM | 23}, \
+ {"$24", RTYPE_NUM | 24}, \
+ {"$25", RTYPE_NUM | 25}, \
+ {"$26", RTYPE_NUM | 26}, \
+ {"$27", RTYPE_NUM | 27}, \
+ {"$28", RTYPE_NUM | 28}, \
+ {"$29", RTYPE_NUM | 29}, \
+ {"$30", RTYPE_NUM | 30}, \
+ {"$31", RTYPE_NUM | 31}
+
+#define FPU_REGISTER_NAMES \
+ {"$f0", RTYPE_FPU | 0}, \
+ {"$f1", RTYPE_FPU | 1}, \
+ {"$f2", RTYPE_FPU | 2}, \
+ {"$f3", RTYPE_FPU | 3}, \
+ {"$f4", RTYPE_FPU | 4}, \
+ {"$f5", RTYPE_FPU | 5}, \
+ {"$f6", RTYPE_FPU | 6}, \
+ {"$f7", RTYPE_FPU | 7}, \
+ {"$f8", RTYPE_FPU | 8}, \
+ {"$f9", RTYPE_FPU | 9}, \
+ {"$f10", RTYPE_FPU | 10}, \
+ {"$f11", RTYPE_FPU | 11}, \
+ {"$f12", RTYPE_FPU | 12}, \
+ {"$f13", RTYPE_FPU | 13}, \
+ {"$f14", RTYPE_FPU | 14}, \
+ {"$f15", RTYPE_FPU | 15}, \
+ {"$f16", RTYPE_FPU | 16}, \
+ {"$f17", RTYPE_FPU | 17}, \
+ {"$f18", RTYPE_FPU | 18}, \
+ {"$f19", RTYPE_FPU | 19}, \
+ {"$f20", RTYPE_FPU | 20}, \
+ {"$f21", RTYPE_FPU | 21}, \
+ {"$f22", RTYPE_FPU | 22}, \
+ {"$f23", RTYPE_FPU | 23}, \
+ {"$f24", RTYPE_FPU | 24}, \
+ {"$f25", RTYPE_FPU | 25}, \
+ {"$f26", RTYPE_FPU | 26}, \
+ {"$f27", RTYPE_FPU | 27}, \
+ {"$f28", RTYPE_FPU | 28}, \
+ {"$f29", RTYPE_FPU | 29}, \
+ {"$f30", RTYPE_FPU | 30}, \
+ {"$f31", RTYPE_FPU | 31}
+
+#define FPU_CONDITION_CODE_NAMES \
+ {"$fcc0", RTYPE_FCC | 0}, \
+ {"$fcc1", RTYPE_FCC | 1}, \
+ {"$fcc2", RTYPE_FCC | 2}, \
+ {"$fcc3", RTYPE_FCC | 3}, \
+ {"$fcc4", RTYPE_FCC | 4}, \
+ {"$fcc5", RTYPE_FCC | 5}, \
+ {"$fcc6", RTYPE_FCC | 6}, \
+ {"$fcc7", RTYPE_FCC | 7}
+
+#define COPROC_CONDITION_CODE_NAMES \
+ {"$cc0", RTYPE_FCC | RTYPE_CCC | 0}, \
+ {"$cc1", RTYPE_FCC | RTYPE_CCC | 1}, \
+ {"$cc2", RTYPE_FCC | RTYPE_CCC | 2}, \
+ {"$cc3", RTYPE_FCC | RTYPE_CCC | 3}, \
+ {"$cc4", RTYPE_FCC | RTYPE_CCC | 4}, \
+ {"$cc5", RTYPE_FCC | RTYPE_CCC | 5}, \
+ {"$cc6", RTYPE_FCC | RTYPE_CCC | 6}, \
+ {"$cc7", RTYPE_FCC | RTYPE_CCC | 7}
+
+#define N32N64_SYMBOLIC_REGISTER_NAMES \
+ {"$a4", RTYPE_GP | 8}, \
+ {"$a5", RTYPE_GP | 9}, \
+ {"$a6", RTYPE_GP | 10}, \
+ {"$a7", RTYPE_GP | 11}, \
+ {"$ta0", RTYPE_GP | 8}, /* alias for $a4 */ \
+ {"$ta1", RTYPE_GP | 9}, /* alias for $a5 */ \
+ {"$ta2", RTYPE_GP | 10}, /* alias for $a6 */ \
+ {"$ta3", RTYPE_GP | 11}, /* alias for $a7 */ \
+ {"$t0", RTYPE_GP | 12}, \
+ {"$t1", RTYPE_GP | 13}, \
+ {"$t2", RTYPE_GP | 14}, \
+ {"$t3", RTYPE_GP | 15}
+
+#define O32_SYMBOLIC_REGISTER_NAMES \
+ {"$t0", RTYPE_GP | 8}, \
+ {"$t1", RTYPE_GP | 9}, \
+ {"$t2", RTYPE_GP | 10}, \
+ {"$t3", RTYPE_GP | 11}, \
+ {"$t4", RTYPE_GP | 12}, \
+ {"$t5", RTYPE_GP | 13}, \
+ {"$t6", RTYPE_GP | 14}, \
+ {"$t7", RTYPE_GP | 15}, \
+ {"$ta0", RTYPE_GP | 12}, /* alias for $t4 */ \
+ {"$ta1", RTYPE_GP | 13}, /* alias for $t5 */ \
+ {"$ta2", RTYPE_GP | 14}, /* alias for $t6 */ \
+ {"$ta3", RTYPE_GP | 15} /* alias for $t7 */
+
+/* Remaining symbolic register names */
+#define SYMBOLIC_REGISTER_NAMES \
+ {"$zero", RTYPE_GP | 0}, \
+ {"$at", RTYPE_GP | 1}, \
+ {"$AT", RTYPE_GP | 1}, \
+ {"$v0", RTYPE_GP | 2}, \
+ {"$v1", RTYPE_GP | 3}, \
+ {"$a0", RTYPE_GP | 4}, \
+ {"$a1", RTYPE_GP | 5}, \
+ {"$a2", RTYPE_GP | 6}, \
+ {"$a3", RTYPE_GP | 7}, \
+ {"$s0", RTYPE_GP | 16}, \
+ {"$s1", RTYPE_GP | 17}, \
+ {"$s2", RTYPE_GP | 18}, \
+ {"$s3", RTYPE_GP | 19}, \
+ {"$s4", RTYPE_GP | 20}, \
+ {"$s5", RTYPE_GP | 21}, \
+ {"$s6", RTYPE_GP | 22}, \
+ {"$s7", RTYPE_GP | 23}, \
+ {"$t8", RTYPE_GP | 24}, \
+ {"$t9", RTYPE_GP | 25}, \
+ {"$k0", RTYPE_GP | 26}, \
+ {"$kt0", RTYPE_GP | 26}, \
+ {"$k1", RTYPE_GP | 27}, \
+ {"$kt1", RTYPE_GP | 27}, \
+ {"$gp", RTYPE_GP | 28}, \
+ {"$sp", RTYPE_GP | 29}, \
+ {"$s8", RTYPE_GP | 30}, \
+ {"$fp", RTYPE_GP | 30}, \
+ {"$ra", RTYPE_GP | 31}
+
+#define MIPS16_SPECIAL_REGISTER_NAMES \
+ {"$pc", RTYPE_PC | 0}
+
+#define MDMX_VECTOR_REGISTER_NAMES \
+ /* {"$v0", RTYPE_VEC | 0}, clash with REG 2 above */ \
+ /* {"$v1", RTYPE_VEC | 1}, clash with REG 3 above */ \
+ {"$v2", RTYPE_VEC | 2}, \
+ {"$v3", RTYPE_VEC | 3}, \
+ {"$v4", RTYPE_VEC | 4}, \
+ {"$v5", RTYPE_VEC | 5}, \
+ {"$v6", RTYPE_VEC | 6}, \
+ {"$v7", RTYPE_VEC | 7}, \
+ {"$v8", RTYPE_VEC | 8}, \
+ {"$v9", RTYPE_VEC | 9}, \
+ {"$v10", RTYPE_VEC | 10}, \
+ {"$v11", RTYPE_VEC | 11}, \
+ {"$v12", RTYPE_VEC | 12}, \
+ {"$v13", RTYPE_VEC | 13}, \
+ {"$v14", RTYPE_VEC | 14}, \
+ {"$v15", RTYPE_VEC | 15}, \
+ {"$v16", RTYPE_VEC | 16}, \
+ {"$v17", RTYPE_VEC | 17}, \
+ {"$v18", RTYPE_VEC | 18}, \
+ {"$v19", RTYPE_VEC | 19}, \
+ {"$v20", RTYPE_VEC | 20}, \
+ {"$v21", RTYPE_VEC | 21}, \
+ {"$v22", RTYPE_VEC | 22}, \
+ {"$v23", RTYPE_VEC | 23}, \
+ {"$v24", RTYPE_VEC | 24}, \
+ {"$v25", RTYPE_VEC | 25}, \
+ {"$v26", RTYPE_VEC | 26}, \
+ {"$v27", RTYPE_VEC | 27}, \
+ {"$v28", RTYPE_VEC | 28}, \
+ {"$v29", RTYPE_VEC | 29}, \
+ {"$v30", RTYPE_VEC | 30}, \
+ {"$v31", RTYPE_VEC | 31}
+
+#define MIPS_DSP_ACCUMULATOR_NAMES \
+ {"$ac0", RTYPE_ACC | 0}, \
+ {"$ac1", RTYPE_ACC | 1}, \
+ {"$ac2", RTYPE_ACC | 2}, \
+ {"$ac3", RTYPE_ACC | 3}
+
+static const struct regname reg_names[] = {
+ GENERIC_REGISTER_NUMBERS,
+ FPU_REGISTER_NAMES,
+ FPU_CONDITION_CODE_NAMES,
+ COPROC_CONDITION_CODE_NAMES,
+
+ /* The $txx registers depends on the abi,
+ these will be added later into the symbol table from
+ one of the tables below once mips_abi is set after
+ parsing of arguments from the command line. */
+ SYMBOLIC_REGISTER_NAMES,
+
+ MIPS16_SPECIAL_REGISTER_NAMES,
+ MDMX_VECTOR_REGISTER_NAMES,
+ MIPS_DSP_ACCUMULATOR_NAMES,
+ {0, 0}
+};
+
+static const struct regname reg_names_o32[] = {
+ O32_SYMBOLIC_REGISTER_NAMES,
+ {0, 0}
+};
+
+static const struct regname reg_names_n32n64[] = {
+ N32N64_SYMBOLIC_REGISTER_NAMES,
+ {0, 0}
+};
+
+static int
+reg_lookup (char **s, unsigned int types, unsigned int *regnop)
+{
+ symbolS *symbolP;
+ char *e;
+ char save_c;
+ int reg = -1;
+
+ /* Find end of name. */
+ e = *s;
+ if (is_name_beginner (*e))
+ ++e;
+ while (is_part_of_name (*e))
+ ++e;
+
+ /* Terminate name. */
+ save_c = *e;
+ *e = '\0';
+
+ /* Look for a register symbol. */
+ if ((symbolP = symbol_find (*s)) && S_GET_SEGMENT (symbolP) == reg_section)
+ {
+ int r = S_GET_VALUE (symbolP);
+ if (r & types)
+ reg = r & RNUM_MASK;
+ else if ((types & RTYPE_VEC) && (r & ~1) == (RTYPE_GP | 2))
+ /* Convert GP reg $v0/1 to MDMX reg $v0/1! */
+ reg = (r & RNUM_MASK) - 2;
+ }
+ /* Else see if this is a register defined in an itbl entry. */
+ else if ((types & RTYPE_GP) && itbl_have_entries)
+ {
+ char *n = *s;
+ unsigned long r;
+
+ if (*n == '$')
+ ++n;
+ if (itbl_get_reg_val (n, &r))
+ reg = r & RNUM_MASK;
+ }
+
+ /* Advance to next token if a register was recognised. */
+ if (reg >= 0)
+ *s = e;
+ else if (types & RWARN)
+ as_warn ("Unrecognized register name `%s'", *s);
+
+ *e = save_c;
+ if (regnop)
+ *regnop = reg;
+ return reg >= 0;
+}
+
+/* This function is called once, at assembler startup time. It should set up
+ all the tables, etc. that the MD part of the assembler will need. */
void
md_begin (void)
/* We add all the general register names to the symbol table. This
helps us detect invalid uses of them. */
- for (i = 0; i < 32; i++)
- {
- char buf[5];
-
- sprintf (buf, "$%d", i);
- symbol_table_insert (symbol_new (buf, reg_section, i,
+ for (i = 0; reg_names[i].name; i++)
+ symbol_table_insert (symbol_new (reg_names[i].name, reg_section,
+ reg_names[i].num, // & RNUM_MASK,
+ &zero_address_frag));
+ if (HAVE_NEWABI)
+ for (i = 0; reg_names_n32n64[i].name; i++)
+ symbol_table_insert (symbol_new (reg_names_n32n64[i].name, reg_section,
+ reg_names_n32n64[i].num, // & RNUM_MASK,
&zero_address_frag));
- }
- symbol_table_insert (symbol_new ("$ra", reg_section, RA,
- &zero_address_frag));
- symbol_table_insert (symbol_new ("$fp", reg_section, FP,
- &zero_address_frag));
- symbol_table_insert (symbol_new ("$sp", reg_section, SP,
- &zero_address_frag));
- symbol_table_insert (symbol_new ("$gp", reg_section, GP,
- &zero_address_frag));
- symbol_table_insert (symbol_new ("$at", reg_section, AT,
- &zero_address_frag));
- symbol_table_insert (symbol_new ("$kt0", reg_section, KT0,
- &zero_address_frag));
- symbol_table_insert (symbol_new ("$kt1", reg_section, KT1,
- &zero_address_frag));
- symbol_table_insert (symbol_new ("$zero", reg_section, ZERO,
- &zero_address_frag));
- symbol_table_insert (symbol_new ("$pc", reg_section, -1,
- &zero_address_frag));
-
- /* If we don't add these register names to the symbol table, they
- may end up being added as regular symbols by operand(), and then
- make it to the object file as undefined in case they're not
- regarded as local symbols. They're local in o32, since `$' is a
- local symbol prefix, but not in n32 or n64. */
- for (i = 0; i < 8; i++)
- {
- char buf[6];
-
- sprintf (buf, "$fcc%i", i);
- symbol_table_insert (symbol_new (buf, reg_section, -1,
+ else
+ for (i = 0; reg_names_o32[i].name; i++)
+ symbol_table_insert (symbol_new (reg_names_o32[i].name, reg_section,
+ reg_names_o32[i].num, // & RNUM_MASK,
&zero_address_frag));
- }
mips_no_prev_insn ();
bfd_set_gp_size (stdoutput, g_switch_value);
+#ifdef OBJ_ELF
if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
{
/* On a native system other than VxWorks, sections must be aligned
bfd_set_section_flags (stdoutput, sec, flags);
bfd_set_section_alignment (stdoutput, sec, HAVE_NEWABI ? 3 : 2);
-#ifdef OBJ_ELF
mips_regmask_frag = frag_more (sizeof (Elf32_External_RegInfo));
-#endif
}
else
{
bfd_set_section_flags (stdoutput, sec, flags);
bfd_set_section_alignment (stdoutput, sec, 3);
-#ifdef OBJ_ELF
/* Set up the option header. */
{
Elf_Internal_Options opthdr;
mips_regmask_frag = frag_more (sizeof (Elf64_External_RegInfo));
}
-#endif
}
if (ECOFF_DEBUGGING)
SEC_HAS_CONTENTS | SEC_READONLY);
(void) bfd_set_section_alignment (stdoutput, sec, 2);
}
-#ifdef OBJ_ELF
else if (OUTPUT_FLAVOR == bfd_target_elf_flavour && mips_flag_pdr)
{
pdr_seg = subseg_new (".pdr", (subsegT) 0);
| SEC_DEBUGGING);
(void) bfd_set_section_alignment (stdoutput, pdr_seg, 2);
}
-#endif
subseg_set (seg, subseg);
}
}
+#endif /* OBJ_ELF */
if (! ECOFF_DEBUGGING)
md_obj_begin ();
if ((address_expr->X_add_number & 3) != 0)
as_bad (_("jump to misaligned address (0x%lx)"),
(unsigned long) address_expr->X_add_number);
- if (address_expr->X_add_number & ~0xfffffff)
- as_warn (_("jump address range overflow (0x%lx)"),
- (unsigned long) address_expr->X_add_number);
ip->insn_opcode |= (address_expr->X_add_number >> 2) & 0x3ffffff;
break;
if ((address_expr->X_add_number & 3) != 0)
as_bad (_("jump to misaligned address (0x%lx)"),
(unsigned long) address_expr->X_add_number);
- if (address_expr->X_add_number & ~0xfffffff)
- as_warn (_("jump address range overflow (0x%lx)"),
- (unsigned long) address_expr->X_add_number);
ip->insn_opcode |=
(((address_expr->X_add_number & 0x7c0000) << 3)
| ((address_expr->X_add_number & 0xf800000) >> 7)
|| mo->pinfo == INSN_MACRO
|| !OPCODE_IS_MEMBER (mo,
(mips_opts.isa
- | (file_ase_mips16 ? INSN_MIPS16 : 0)
+ | (mips_opts.mips16 ? INSN_MIPS16 : 0)
| (mips_opts.ase_smartmips ? INSN_SMARTMIPS : 0)),
mips_opts.arch)
|| (mips_opts.arch == CPU_R4650 && (mo->pinfo & FP_D) != 0))
{ 0,0,0,0 }
};
+/* Check whether an odd floating-point register is allowed. */
+static int
+mips_oddfpreg_ok (const struct mips_opcode *insn, int argnum)
+{
+ const char *s = insn->name;
+
+ if (insn->pinfo == INSN_MACRO)
+ /* Let a macro pass, we'll catch it later when it is expanded. */
+ return 1;
+
+ if (ISA_HAS_ODD_SINGLE_FPR (mips_opts.isa))
+ {
+ /* Allow odd registers for single-precision ops. */
+ switch (insn->pinfo & (FP_S | FP_D))
+ {
+ case FP_S:
+ case 0:
+ return 1; /* both single precision - ok */
+ case FP_D:
+ return 0; /* both double precision - fail */
+ default:
+ break;
+ }
+
+ /* Cvt.w.x and cvt.x.w allow an odd register for a 'w' or 's' operand. */
+ s = strchr (insn->name, '.');
+ if (argnum == 2)
+ s = s != NULL ? strchr (s + 1, '.') : NULL;
+ return (s != NULL && (s[1] == 'w' || s[1] == 's'));
+ }
+
+ /* Single-precision coprocessor loads and moves are OK too. */
+ if ((insn->pinfo & FP_S)
+ && (insn->pinfo & (INSN_COPROC_MEMORY_DELAY | INSN_STORE_MEMORY
+ | INSN_LOAD_COPROC_DELAY | INSN_COPROC_MOVE_DELAY)))
+ return 1;
+
+ return 0;
+}
+
/* This routine assembles an instruction into its binary format. As a
side effect, it sets one of the global variables imm_reloc or
offset_reloc to the type of relocation to do if one of the operands
char *s_reset;
char save_c = 0;
offsetT min_range, max_range;
+ int argnum;
+ unsigned int rtype;
insn_error = NULL;
if (OPCODE_IS_MEMBER (insn,
(mips_opts.isa
+ /* We don't check for mips_opts.mips16 here since
+ we want to allow jalx if -mips16 was specified
+ on the command line. */
| (file_ase_mips16 ? INSN_MIPS16 : 0)
| (mips_opts.ase_mdmx ? INSN_MDMX : 0)
| (mips_opts.ase_dsp ? INSN_DSP : 0)
create_insn (ip, insn);
insn_error = NULL;
+ argnum = 1;
for (args = insn->args;; ++args)
{
int is_mdmx;
s = expr_end;
continue;
- case 'T': /* Coprocessor register */
+ case 'T': /* Coprocessor register. */
/* +T is for disassembly only; never match. */
break;
- case 't': /* Coprocessor register number */
+ case 't': /* Coprocessor register number. */
if (s[0] == '$' && ISDIGIT (s[1]))
{
++s;
s = expr_end;
continue;
- case 'P': /* Performance register */
+ case 'P': /* Performance register. */
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
if (imm_expr.X_add_number != 0 && imm_expr.X_add_number != 1)
s = expr_end;
continue;
+ case 'G': /* Coprocessor destination register. */
+ if (((ip->insn_opcode >> OP_SH_OP) & OP_MASK_OP) == OP_OP_COP0)
+ ok = reg_lookup (&s, RTYPE_NUM | RTYPE_CP0, ®no);
+ else
+ ok = reg_lookup (&s, RTYPE_NUM | RTYPE_GP, ®no);
+ ip->insn_opcode |= regno << OP_SH_RD;
+ if (ok)
+ {
+ lastregno = regno;
+ continue;
+ }
+ else
+ break;
+
case 'b': /* base register */
case 'd': /* destination register */
case 's': /* source register */
case 'v': /* both dest and source */
case 'w': /* both dest and target */
case 'E': /* coprocessor target register */
- case 'G': /* coprocessor destination register */
case 'K': /* 'rdhwr' destination register */
case 'x': /* ignore register name */
case 'z': /* must be zero register */
case 'U': /* destination register (clo/clz). */
case 'g': /* coprocessor destination register */
- s_reset = s;
- if (s[0] == '$')
+ s_reset = s;
+ if (*args == 'E' || *args == 'K')
+ ok = reg_lookup (&s, RTYPE_NUM, ®no);
+ else
+ {
+ ok = reg_lookup (&s, RTYPE_NUM | RTYPE_GP, ®no);
+ if (regno == AT && ! mips_opts.noat)
+ as_warn ("Used $at without \".set noat\"");
+ }
+ if (ok)
{
- if (ISDIGIT (s[1]))
- {
- ++s;
- regno = 0;
- do
- {
- regno *= 10;
- regno += *s - '0';
- ++s;
- }
- while (ISDIGIT (*s));
- if (regno > 31)
- as_bad (_("Invalid register number (%d)"), regno);
- }
- else if (*args == 'E' || *args == 'G' || *args == 'K')
- goto notreg;
- else
- {
- if (s[1] == 'r' && s[2] == 'a')
- {
- s += 3;
- regno = RA;
- }
- else if (s[1] == 'f' && s[2] == 'p')
- {
- s += 3;
- regno = FP;
- }
- else if (s[1] == 's' && s[2] == 'p')
- {
- s += 3;
- regno = SP;
- }
- else if (s[1] == 'g' && s[2] == 'p')
- {
- s += 3;
- regno = GP;
- }
- else if (s[1] == 'a' && s[2] == 't')
- {
- s += 3;
- regno = AT;
- }
- else if (s[1] == 'k' && s[2] == 't' && s[3] == '0')
- {
- s += 4;
- regno = KT0;
- }
- else if (s[1] == 'k' && s[2] == 't' && s[3] == '1')
- {
- s += 4;
- regno = KT1;
- }
- else if (s[1] == 'z' && s[2] == 'e' && s[3] == 'r' && s[4] == 'o')
- {
- s += 5;
- regno = ZERO;
- }
- else if (itbl_have_entries)
- {
- char *p, *n;
- unsigned long r;
-
- p = s + 1; /* advance past '$' */
- n = itbl_get_field (&p); /* n is name */
-
- /* See if this is a register defined in an
- itbl entry. */
- if (itbl_get_reg_val (n, &r))
- {
- /* Get_field advances to the start of
- the next field, so we need to back
- rack to the end of the last field. */
- if (p)
- s = p - 1;
- else
- s = strchr (s, '\0');
- regno = r;
- }
- else
- goto notreg;
- }
- else
- goto notreg;
- }
- if (regno == AT
- && ! mips_opts.noat
- && *args != 'E'
- && *args != 'G'
- && *args != 'K')
- as_warn (_("Used $at without \".set noat\""));
c = *args;
if (*s == ' ')
++s;
lastregno = regno;
continue;
}
- notreg:
switch (*args++)
{
case 'r':
case 'R': /* floating point source register */
case 'V':
case 'W':
+ rtype = RTYPE_FPU;
+ if (is_mdmx
+ || (mips_opts.ase_mdmx
+ && (ip->insn_mo->pinfo & FP_D)
+ && (ip->insn_mo->pinfo & (INSN_COPROC_MOVE_DELAY
+ | INSN_COPROC_MEMORY_DELAY
+ | INSN_LOAD_COPROC_DELAY
+ | INSN_LOAD_MEMORY_DELAY
+ | INSN_STORE_MEMORY))))
+ rtype |= RTYPE_VEC;
s_reset = s;
- /* Accept $fN for FP and MDMX register numbers, and in
- addition accept $vN for MDMX register numbers. */
- if ((s[0] == '$' && s[1] == 'f' && ISDIGIT (s[2]))
- || (is_mdmx != 0 && s[0] == '$' && s[1] == 'v'
- && ISDIGIT (s[2])))
+ if (reg_lookup (&s, rtype, ®no))
{
- s += 2;
- regno = 0;
- do
- {
- regno *= 10;
- regno += *s - '0';
- ++s;
- }
- while (ISDIGIT (*s));
-
- if (regno > 31)
- as_bad (_("Invalid float register number (%d)"), regno);
-
if ((regno & 1) != 0
&& HAVE_32BIT_FPRS
- && ! (strcmp (str, "mtc1") == 0
- || strcmp (str, "mfc1") == 0
- || strcmp (str, "lwc1") == 0
- || strcmp (str, "swc1") == 0
- || strcmp (str, "l.s") == 0
- || strcmp (str, "s.s") == 0
- || strcmp (str, "mftc1") == 0
- || strcmp (str, "mfthc1") == 0
- || strcmp (str, "cftc1") == 0
- || strcmp (str, "mttc1") == 0
- || strcmp (str, "mtthc1") == 0
- || strcmp (str, "cttc1") == 0))
+ && ! mips_oddfpreg_ok (ip->insn_mo, argnum))
as_warn (_("Float register should be even, was %d"),
regno);
case 'N': /* 3 bit branch condition code */
case 'M': /* 3 bit compare condition code */
- if (strncmp (s, "$fcc", 4) != 0)
+ rtype = RTYPE_CCC;
+ if (ip->insn_mo->pinfo & (FP_D| FP_S))
+ rtype |= RTYPE_FCC;
+ if (!reg_lookup (&s, rtype, ®no))
break;
- s += 4;
- regno = 0;
- do
- {
- regno *= 10;
- regno += *s - '0';
- ++s;
- }
- while (ISDIGIT (*s));
- if (regno > 7)
- as_bad (_("Invalid condition code register $fcc%d"), regno);
if ((strcmp(str + strlen(str) - 3, ".ps") == 0
|| strcmp(str + strlen(str) - 5, "any2f") == 0
|| strcmp(str + strlen(str) - 5, "any2t") == 0)
argsstart = s;
for (;;)
{
+ bfd_boolean ok;
+
assert (strcmp (insn->name, str) == 0);
+ if (OPCODE_IS_MEMBER (insn, mips_opts.isa, mips_opts.arch))
+ ok = TRUE;
+ else
+ ok = FALSE;
+
+ if (! ok)
+ {
+ if (insn + 1 < &mips16_opcodes[bfd_mips16_num_opcodes]
+ && strcmp (insn->name, insn[1].name) == 0)
+ {
+ ++insn;
+ continue;
+ }
+ else
+ {
+ if (!insn_error)
+ {
+ static char buf[100];
+ sprintf (buf,
+ _("opcode not supported on this processor: %s (%s)"),
+ mips_cpu_info_from_arch (mips_opts.arch)->name,
+ mips_cpu_info_from_isa (mips_opts.isa)->name);
+ insn_error = buf;
+ }
+ return;
+ }
+ }
+
create_insn (ip, insn);
imm_expr.X_op = O_absent;
imm_reloc[0] = BFD_RELOC_UNUSED;
case 'R':
case 'X':
case 'Y':
- if (s[0] != '$')
- break;
- s_reset = s;
- if (ISDIGIT (s[1]))
+ s_reset = s;
+ if (!reg_lookup (&s, RTYPE_NUM | RTYPE_GP, ®no))
{
- ++s;
- regno = 0;
- do
- {
- regno *= 10;
- regno += *s - '0';
- ++s;
- }
- while (ISDIGIT (*s));
- if (regno > 31)
- {
- as_bad (_("invalid register number (%d)"), regno);
- regno = 2;
- }
- }
- else
- {
- if (s[1] == 'r' && s[2] == 'a')
- {
- s += 3;
- regno = RA;
- }
- else if (s[1] == 'f' && s[2] == 'p')
- {
- s += 3;
- regno = FP;
- }
- else if (s[1] == 's' && s[2] == 'p')
- {
- s += 3;
- regno = SP;
- }
- else if (s[1] == 'g' && s[2] == 'p')
- {
- s += 3;
- regno = GP;
- }
- else if (s[1] == 'a' && s[2] == 't')
- {
- s += 3;
- regno = AT;
- }
- else if (s[1] == 'k' && s[2] == 't' && s[3] == '0')
- {
- s += 4;
- regno = KT0;
- }
- else if (s[1] == 'k' && s[2] == 't' && s[3] == '1')
- {
- s += 4;
- regno = KT1;
- }
- else if (s[1] == 'z' && s[2] == 'e' && s[3] == 'r' && s[4] == 'o')
+ if (c == 'v' || c == 'w')
{
- s += 5;
- regno = ZERO;
+ if (c == 'v')
+ ip->insn_opcode |= lastregno << MIPS16OP_SH_RX;
+ else
+ ip->insn_opcode |= lastregno << MIPS16OP_SH_RY;
+ ++args;
+ continue;
}
- else
- break;
+ break;
}
if (*s == ' ')
mask = 7 << 3;
while (*s != '\0')
{
- int freg, reg1, reg2;
+ unsigned int freg, reg1, reg2;
while (*s == ' ' || *s == ',')
++s;
- if (*s != '$')
- {
- as_bad (_("can't parse register list"));
- break;
- }
- ++s;
- if (*s != 'f')
+ if (reg_lookup (&s, RTYPE_GP | RTYPE_NUM, ®1))
freg = 0;
+ else if (reg_lookup (&s, RTYPE_FPU, ®1))
+ freg = 1;
else
{
- freg = 1;
- ++s;
- }
- reg1 = 0;
- while (ISDIGIT (*s))
- {
- reg1 *= 10;
- reg1 += *s - '0';
- ++s;
+ as_bad (_("can't parse register list"));
+ break;
}
if (*s == ' ')
++s;
else
{
++s;
- if (*s != '$')
- break;
- ++s;
- if (freg)
+ if (!reg_lookup (&s, freg ? RTYPE_FPU
+ : (RTYPE_GP | RTYPE_NUM), ®2))
{
- if (*s == 'f')
- ++s;
- else
- {
- as_bad (_("invalid register list"));
- break;
- }
- }
- reg2 = 0;
- while (ISDIGIT (*s))
- {
- reg2 *= 10;
- reg2 += *s - '0';
- ++s;
+ as_bad (_("invalid register list"));
+ break;
}
}
if (freg && reg1 == 0 && reg2 == 0 && c == 'L')
continue;
}
- if (*s != '$')
+ if (! reg_lookup (&s, RTYPE_GP | RTYPE_NUM, ®1))
{
as_bad (_("can't parse register list"));
break;
}
- ++s;
- reg1 = 0;
- while (ISDIGIT (*s))
- {
- reg1 *= 10;
- reg1 += *s - '0';
- ++s;
- }
- SKIP_SPACE_TABS (s);
+ while (*s == ' ')
+ ++s;
+
if (*s != '-')
reg2 = reg1;
else
{
++s;
- if (*s != '$')
+ if (! reg_lookup (&s, RTYPE_GP | RTYPE_NUM, ®2)
+ || reg2 < reg1)
{
as_bad (_("can't parse register list"));
break;
}
- ++s;
- reg2 = 0;
- while (ISDIGIT (*s))
- {
- reg2 *= 10;
- reg2 += *s - '0';
- ++s;
- }
}
while (reg1 <= reg2)
|| !ISA_HAS_64BIT_REGS (mips_opts.isa));
}
- /* ??? GAS treats single-float processors as though they had 64-bit
- float registers (although it complains when double-precision
- instructions are used). As things stand, saying they have 32-bit
- registers would lead to spurious "register must be even" messages.
- So here we assume float registers are always the same size as
- integer ones, unless the user says otherwise. */
- if (file_mips_fp32 < 0)
- file_mips_fp32 = file_mips_gp32;
+ switch (file_mips_fp32)
+ {
+ default:
+ case -1:
+ /* No user specified float register size.
+ ??? GAS treats single-float processors as though they had 64-bit
+ float registers (although it complains when double-precision
+ instructions are used). As things stand, saying they have 32-bit
+ registers would lead to spurious "register must be even" messages.
+ So here we assume float registers are never smaller than the
+ integer ones. */
+ if (file_mips_gp32 == 0)
+ /* 64-bit integer registers implies 64-bit float registers. */
+ file_mips_fp32 = 0;
+ else if ((mips_opts.ase_mips3d > 0 || mips_opts.ase_mdmx > 0)
+ && ISA_HAS_64BIT_FPRS (mips_opts.isa))
+ /* -mips3d and -mdmx imply 64-bit float registers, if possible. */
+ file_mips_fp32 = 0;
+ else
+ /* 32-bit float registers. */
+ file_mips_fp32 = 1;
+ break;
+
+ /* The user specified the size of the float registers. Check if it
+ agrees with the ABI and ISA. */
+ case 0:
+ if (!ISA_HAS_64BIT_FPRS (mips_opts.isa))
+ as_bad (_("-mfp64 used with a 32-bit fpu"));
+ else if (ABI_NEEDS_32BIT_REGS (mips_abi)
+ && !ISA_HAS_MXHC1 (mips_opts.isa))
+ as_warn (_("-mfp64 used with a 32-bit ABI"));
+ break;
+ case 1:
+ if (ABI_NEEDS_64BIT_REGS (mips_abi))
+ as_warn (_("-mfp32 used with a 64-bit ABI"));
+ break;
+ }
/* End of GCC-shared inference code. */
if (mips_opts.mips16 == -1)
mips_opts.mips16 = (CPU_HAS_MIPS16 (file_mips_arch)) ? 1 : 0;
if (mips_opts.ase_mips3d == -1)
- mips_opts.ase_mips3d = (CPU_HAS_MIPS3D (file_mips_arch)) ? 1 : 0;
+ mips_opts.ase_mips3d = ((CPU_HAS_MIPS3D (file_mips_arch)
+ || (arch_info->flags & MIPS_CPU_ASE_MIPS3D))
+ && file_mips_fp32 == 0) ? 1 : 0;
+ if (mips_opts.ase_mips3d && file_mips_fp32 == 1)
+ as_bad (_("-mfp32 used with -mips3d"));
+
if (mips_opts.ase_mdmx == -1)
- mips_opts.ase_mdmx = (CPU_HAS_MDMX (file_mips_arch)) ? 1 : 0;
+ mips_opts.ase_mdmx = ((CPU_HAS_MDMX (file_mips_arch)
+ || (arch_info->flags & MIPS_CPU_ASE_MDMX))
+ && file_mips_fp32 == 0) ? 1 : 0;
+ if (mips_opts.ase_mdmx && file_mips_fp32 == 1)
+ as_bad (_("-mfp32 used with -mdmx"));
+
+ if (mips_opts.ase_smartmips == -1)
+ mips_opts.ase_smartmips = (arch_info->flags & MIPS_CPU_ASE_SMARTMIPS) ? 1 : 0;
+ if (mips_opts.ase_smartmips && !ISA_SUPPORTS_SMARTMIPS)
+ as_warn ("%s ISA does not support SmartMIPS",
+ mips_cpu_info_from_isa (mips_opts.isa)->name);
+
if (mips_opts.ase_dsp == -1)
- mips_opts.ase_dsp = (CPU_HAS_DSP (file_mips_arch)) ? 1 : 0;
+ mips_opts.ase_dsp = (arch_info->flags & MIPS_CPU_ASE_DSP) ? 1 : 0;
+ if (mips_opts.ase_dsp && !ISA_SUPPORTS_DSP_ASE)
+ as_warn ("%s ISA does not support DSP ASE",
+ mips_cpu_info_from_isa (mips_opts.isa)->name);
+
if (mips_opts.ase_mt == -1)
- mips_opts.ase_mt = (CPU_HAS_MT (file_mips_arch)) ? 1 : 0;
+ mips_opts.ase_mt = (arch_info->flags & MIPS_CPU_ASE_MT) ? 1 : 0;
+ if (mips_opts.ase_mt && !ISA_SUPPORTS_MT_ASE)
+ as_warn ("%s ISA does not support MT ASE",
+ mips_cpu_info_from_isa (mips_opts.isa)->name);
file_mips_isa = mips_opts.isa;
file_ase_mips16 = mips_opts.mips16;
{
mips_opts.nobopt = 1;
}
+ else if (strcmp (name, "gp=default") == 0)
+ mips_opts.gp32 = file_mips_gp32;
+ else if (strcmp (name, "gp=32") == 0)
+ mips_opts.gp32 = 1;
+ else if (strcmp (name, "gp=64") == 0)
+ {
+ if (!ISA_HAS_64BIT_REGS (mips_opts.isa))
+ as_warn ("%s isa does not support 64-bit registers",
+ mips_cpu_info_from_isa (mips_opts.isa)->name);
+ mips_opts.gp32 = 0;
+ }
+ else if (strcmp (name, "fp=default") == 0)
+ mips_opts.fp32 = file_mips_fp32;
+ else if (strcmp (name, "fp=32") == 0)
+ mips_opts.fp32 = 1;
+ else if (strcmp (name, "fp=64") == 0)
+ {
+ if (!ISA_HAS_64BIT_FPRS (mips_opts.isa))
+ as_warn ("%s isa does not support 64-bit floating point registers",
+ mips_cpu_info_from_isa (mips_opts.isa)->name);
+ mips_opts.fp32 = 0;
+ }
else if (strcmp (name, "mips16") == 0
|| strcmp (name, "MIPS-16") == 0)
mips_opts.mips16 = 1;
mips_opts.mips16 = 0;
else if (strcmp (name, "smartmips") == 0)
{
- if (!ISA_SUPPORT_SMARTMIPS)
+ if (!ISA_SUPPORTS_SMARTMIPS)
as_warn ("%s ISA does not support SmartMIPS ASE",
mips_cpu_info_from_isa (mips_opts.isa)->name);
mips_opts.ase_smartmips = 1;
else if (strcmp (name, "nomdmx") == 0)
mips_opts.ase_mdmx = 0;
else if (strcmp (name, "dsp") == 0)
- mips_opts.ase_dsp = 1;
+ {
+ if (!ISA_SUPPORTS_DSP_ASE)
+ as_warn ("%s ISA does not support DSP ASE",
+ mips_cpu_info_from_isa (mips_opts.isa)->name);
+ mips_opts.ase_dsp = 1;
+ }
else if (strcmp (name, "nodsp") == 0)
mips_opts.ase_dsp = 0;
else if (strcmp (name, "mt") == 0)
- mips_opts.ase_mt = 1;
+ {
+ if (!ISA_SUPPORTS_MT_ASE)
+ as_warn ("%s ISA does not support MT ASE",
+ mips_cpu_info_from_isa (mips_opts.isa)->name);
+ mips_opts.ase_mt = 1;
+ }
else if (strcmp (name, "nomt") == 0)
mips_opts.ase_mt = 0;
else if (strncmp (name, "mips", 4) == 0 || strncmp (name, "arch=", 5) == 0)
int
tc_get_register (int frame)
{
- int reg;
+ unsigned int reg;
SKIP_WHITESPACE ();
- if (*input_line_pointer++ != '$')
- {
- as_warn (_("expected `$'"));
- reg = ZERO;
- }
- else if (ISDIGIT (*input_line_pointer))
- {
- reg = get_absolute_expression ();
- if (reg < 0 || reg >= 32)
- {
- as_warn (_("Bad register number"));
- reg = ZERO;
- }
- }
- else
- {
- if (strncmp (input_line_pointer, "ra", 2) == 0)
- {
- reg = RA;
- input_line_pointer += 2;
- }
- else if (strncmp (input_line_pointer, "fp", 2) == 0)
- {
- reg = FP;
- input_line_pointer += 2;
- }
- else if (strncmp (input_line_pointer, "sp", 2) == 0)
- {
- reg = SP;
- input_line_pointer += 2;
- }
- else if (strncmp (input_line_pointer, "gp", 2) == 0)
- {
- reg = GP;
- input_line_pointer += 2;
- }
- else if (strncmp (input_line_pointer, "at", 2) == 0)
- {
- reg = AT;
- input_line_pointer += 2;
- }
- else if (strncmp (input_line_pointer, "kt0", 3) == 0)
- {
- reg = KT0;
- input_line_pointer += 3;
- }
- else if (strncmp (input_line_pointer, "kt1", 3) == 0)
- {
- reg = KT1;
- input_line_pointer += 3;
- }
- else if (strncmp (input_line_pointer, "zero", 4) == 0)
- {
- reg = ZERO;
- input_line_pointer += 4;
- }
- else
- {
- as_warn (_("Unrecognized register name"));
- reg = ZERO;
- while (ISALNUM(*input_line_pointer))
- input_line_pointer++;
- }
- }
+ if (! reg_lookup (&input_line_pointer, RWARN | RTYPE_NUM | RTYPE_GP, ®))
+ reg = 0;
if (frame)
{
mips_frame_reg = reg != 0 ? reg : SP;
if (mips_32bitmode)
elf_elfheader (stdoutput)->e_flags |= EF_MIPS_32BITMODE;
+
+#if 0 /* XXX FIXME */
+ /* 32 bit code with 64 bit FP registers. */
+ if (!file_mips_fp32 && ABI_NEEDS_32BIT_REGS (mips_abi))
+ elf_elfheader (stdoutput)->e_flags |= ???;
+#endif
}
#endif /* OBJ_ELF || OBJ_MAYBE_ELF */
static const struct mips_cpu_info mips_cpu_info_table[] =
{
/* Entries for generic ISAs */
- { "mips1", 1, ISA_MIPS1, CPU_R3000 },
- { "mips2", 1, ISA_MIPS2, CPU_R6000 },
- { "mips3", 1, ISA_MIPS3, CPU_R4000 },
- { "mips4", 1, ISA_MIPS4, CPU_R8000 },
- { "mips5", 1, ISA_MIPS5, CPU_MIPS5 },
- { "mips32", 1, ISA_MIPS32, CPU_MIPS32 },
- { "mips32r2", 1, ISA_MIPS32R2, CPU_MIPS32R2 },
- { "mips64", 1, ISA_MIPS64, CPU_MIPS64 },
- { "mips64r2", 1, ISA_MIPS64R2, CPU_MIPS64R2 },
+ { "mips1", MIPS_CPU_IS_ISA, ISA_MIPS1, CPU_R3000 },
+ { "mips2", MIPS_CPU_IS_ISA, ISA_MIPS2, CPU_R6000 },
+ { "mips3", MIPS_CPU_IS_ISA, ISA_MIPS3, CPU_R4000 },
+ { "mips4", MIPS_CPU_IS_ISA, ISA_MIPS4, CPU_R8000 },
+ { "mips5", MIPS_CPU_IS_ISA, ISA_MIPS5, CPU_MIPS5 },
+ { "mips32", MIPS_CPU_IS_ISA, ISA_MIPS32, CPU_MIPS32 },
+ { "mips32r2", MIPS_CPU_IS_ISA, ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "mips64", MIPS_CPU_IS_ISA, ISA_MIPS64, CPU_MIPS64 },
+ { "mips64r2", MIPS_CPU_IS_ISA, ISA_MIPS64R2, CPU_MIPS64R2 },
/* MIPS I */
- { "r3000", 0, ISA_MIPS1, CPU_R3000 },
- { "r2000", 0, ISA_MIPS1, CPU_R3000 },
- { "r3900", 0, ISA_MIPS1, CPU_R3900 },
+ { "r3000", 0, ISA_MIPS1, CPU_R3000 },
+ { "r2000", 0, ISA_MIPS1, CPU_R3000 },
+ { "r3900", 0, ISA_MIPS1, CPU_R3900 },
/* MIPS II */
- { "r6000", 0, ISA_MIPS2, CPU_R6000 },
+ { "r6000", 0, ISA_MIPS2, CPU_R6000 },
/* MIPS III */
- { "r4000", 0, ISA_MIPS3, CPU_R4000 },
- { "r4010", 0, ISA_MIPS2, CPU_R4010 },
- { "vr4100", 0, ISA_MIPS3, CPU_VR4100 },
- { "vr4111", 0, ISA_MIPS3, CPU_R4111 },
- { "vr4120", 0, ISA_MIPS3, CPU_VR4120 },
- { "vr4130", 0, ISA_MIPS3, CPU_VR4120 },
- { "vr4181", 0, ISA_MIPS3, CPU_R4111 },
- { "vr4300", 0, ISA_MIPS3, CPU_R4300 },
- { "r4400", 0, ISA_MIPS3, CPU_R4400 },
- { "r4600", 0, ISA_MIPS3, CPU_R4600 },
- { "orion", 0, ISA_MIPS3, CPU_R4600 },
- { "r4650", 0, ISA_MIPS3, CPU_R4650 },
+ { "r4000", 0, ISA_MIPS3, CPU_R4000 },
+ { "r4010", 0, ISA_MIPS2, CPU_R4010 },
+ { "vr4100", 0, ISA_MIPS3, CPU_VR4100 },
+ { "vr4111", 0, ISA_MIPS3, CPU_R4111 },
+ { "vr4120", 0, ISA_MIPS3, CPU_VR4120 },
+ { "vr4130", 0, ISA_MIPS3, CPU_VR4120 },
+ { "vr4181", 0, ISA_MIPS3, CPU_R4111 },
+ { "vr4300", 0, ISA_MIPS3, CPU_R4300 },
+ { "r4400", 0, ISA_MIPS3, CPU_R4400 },
+ { "r4600", 0, ISA_MIPS3, CPU_R4600 },
+ { "orion", 0, ISA_MIPS3, CPU_R4600 },
+ { "r4650", 0, ISA_MIPS3, CPU_R4650 },
/* MIPS IV */
- { "r8000", 0, ISA_MIPS4, CPU_R8000 },
- { "r10000", 0, ISA_MIPS4, CPU_R10000 },
- { "r12000", 0, ISA_MIPS4, CPU_R12000 },
- { "vr5000", 0, ISA_MIPS4, CPU_R5000 },
- { "vr5400", 0, ISA_MIPS4, CPU_VR5400 },
- { "vr5500", 0, ISA_MIPS4, CPU_VR5500 },
- { "rm5200", 0, ISA_MIPS4, CPU_R5000 },
- { "rm5230", 0, ISA_MIPS4, CPU_R5000 },
- { "rm5231", 0, ISA_MIPS4, CPU_R5000 },
- { "rm5261", 0, ISA_MIPS4, CPU_R5000 },
- { "rm5721", 0, ISA_MIPS4, CPU_R5000 },
- { "rm7000", 0, ISA_MIPS4, CPU_RM7000 },
- { "rm9000", 0, ISA_MIPS4, CPU_RM9000 },
+ { "r8000", 0, ISA_MIPS4, CPU_R8000 },
+ { "r10000", 0, ISA_MIPS4, CPU_R10000 },
+ { "r12000", 0, ISA_MIPS4, CPU_R12000 },
+ { "vr5000", 0, ISA_MIPS4, CPU_R5000 },
+ { "vr5400", 0, ISA_MIPS4, CPU_VR5400 },
+ { "vr5500", 0, ISA_MIPS4, CPU_VR5500 },
+ { "rm5200", 0, ISA_MIPS4, CPU_R5000 },
+ { "rm5230", 0, ISA_MIPS4, CPU_R5000 },
+ { "rm5231", 0, ISA_MIPS4, CPU_R5000 },
+ { "rm5261", 0, ISA_MIPS4, CPU_R5000 },
+ { "rm5721", 0, ISA_MIPS4, CPU_R5000 },
+ { "rm7000", 0, ISA_MIPS4, CPU_RM7000 },
+ { "rm9000", 0, ISA_MIPS4, CPU_RM9000 },
/* MIPS 32 */
- { "4kc", 0, ISA_MIPS32, CPU_MIPS32 },
- { "4km", 0, ISA_MIPS32, CPU_MIPS32 },
- { "4kp", 0, ISA_MIPS32, CPU_MIPS32 },
-
- /* MIPS32 Release 2 */
- { "m4k", 0, ISA_MIPS32R2, CPU_MIPS32R2 },
- { "24k", 0, ISA_MIPS32R2, CPU_MIPS32R2 },
- { "24kc", 0, ISA_MIPS32R2, CPU_MIPS32R2 },
- { "24kf", 0, ISA_MIPS32R2, CPU_MIPS32R2 },
- { "24kx", 0, ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "4kc", 0, ISA_MIPS32, CPU_MIPS32 },
+ { "4km", 0, ISA_MIPS32, CPU_MIPS32 },
+ { "4kp", 0, ISA_MIPS32, CPU_MIPS32 },
+ { "4ksc", MIPS_CPU_ASE_SMARTMIPS, ISA_MIPS32, CPU_MIPS32 },
+
+ /* MIPS 32 Release 2 */
+ { "4kec", 0, ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "4kem", 0, ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "4kep", 0, ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "4ksd", MIPS_CPU_ASE_SMARTMIPS, ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "m4k", 0, ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "m4kp", 0, ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "24k", 0, ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "24kc", 0, ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "24kf", 0, ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "24kx", 0, ISA_MIPS32R2, CPU_MIPS32R2 },
+ /* 24ke is a 24k with DSP ASE, other ASEs are optional. */
+ { "24ke", MIPS_CPU_ASE_DSP, ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "24kec", MIPS_CPU_ASE_DSP, ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "24kef", MIPS_CPU_ASE_DSP, ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "24kex", MIPS_CPU_ASE_DSP, ISA_MIPS32R2, CPU_MIPS32R2 },
+ /* 34k is a 24k with MT ASE, other ASEs are optional. */
+ { "34kc", MIPS_CPU_ASE_MT, ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "34kf", MIPS_CPU_ASE_MT, ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "34kx", MIPS_CPU_ASE_MT, ISA_MIPS32R2, CPU_MIPS32R2 },
/* MIPS 64 */
- { "5kc", 0, ISA_MIPS64, CPU_MIPS64 },
- { "5kf", 0, ISA_MIPS64, CPU_MIPS64 },
- { "20kc", 0, ISA_MIPS64, CPU_MIPS64 },
+ { "5kc", 0, ISA_MIPS64, CPU_MIPS64 },
+ { "5kf", 0, ISA_MIPS64, CPU_MIPS64 },
+ { "20kc", MIPS_CPU_ASE_MIPS3D, ISA_MIPS64, CPU_MIPS64 },
+
+ /* MIPS 64 Release 2 */
+ { "25kf", MIPS_CPU_ASE_MIPS3D, ISA_MIPS64R2, CPU_MIPS64R2 },
/* Broadcom SB-1 CPU core */
- { "sb1", 0, ISA_MIPS64, CPU_SB1 },
+ { "sb1", 0, ISA_MIPS64, CPU_SB1 },
/* End marker */
{ NULL, 0, 0, 0 }
int i;
for (i = 0; mips_cpu_info_table[i].name != NULL; i++)
- if (mips_cpu_info_table[i].is_isa
+ if ((mips_cpu_info_table[i].flags & MIPS_CPU_IS_ISA)
&& isa == mips_cpu_info_table[i].isa)
return (&mips_cpu_info_table[i]);
cfi_add_CFA_def_cfa_register (SP);
}
+int
+tc_mips_regname_to_dw2regnum (char *regname)
+{
+ unsigned int regnum = -1;
+ unsigned int reg;
+
+ if (reg_lookup (®name, RTYPE_GP | RTYPE_NUM, ®))
+ regnum = reg;
+
+ return regnum;
+}