#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 \
- )
+#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 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)
+
#define HAVE_32BIT_GPRS \
(mips_opts.gp32 || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
#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 ();
char *s_reset;
char save_c = 0;
offsetT min_range, max_range;
+ int argnum;
+ unsigned int rtype;
insn_error = NULL;
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
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)
case 'R':
case 'X':
case 'Y':
- if (s[0] != '$')
- break;
- s_reset = s;
- 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);
- regno = 2;
- }
- }
- else
+ s_reset = s;
+ if (!reg_lookup (&s, RTYPE_NUM | RTYPE_GP, ®no))
{
- 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 (*s == 'f')
- ++s;
- else
- {
- as_bad (_("invalid register list"));
- break;
- }
- }
- reg2 = 0;
- while (ISDIGIT (*s))
+ if (!reg_lookup (&s, freg ? RTYPE_FPU
+ : (RTYPE_GP | RTYPE_NUM), ®2))
{
- 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)
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;
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;
+}