"$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31"
};
+static const char * const msa_control_names[32] =
+{
+ "msa_ir", "msa_csr", "msa_access", "msa_save",
+ "msa_modify", "msa_request", "msa_map", "msa_unmap",
+ "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
+ "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
+ "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31"
+};
+
struct mips_abi_choice
{
const char * name;
{ "mips32r2", 1, bfd_mach_mipsisa32r2, CPU_MIPS32R2,
ISA_MIPS32R2,
(ASE_SMARTMIPS | ASE_DSP | ASE_DSPR2 | ASE_EVA | ASE_MIPS3D
- | ASE_MT | ASE_MCU | ASE_VIRT),
+ | ASE_MT | ASE_MCU | ASE_VIRT | ASE_MSA),
mips_cp0_names_mips3264r2,
mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
mips_hwr_names_mips3264r2 },
{ "mips64r2", 1, bfd_mach_mipsisa64r2, CPU_MIPS64R2,
ISA_MIPS64R2,
(ASE_MIPS3D | ASE_DSP | ASE_DSPR2 | ASE_DSP64 | ASE_EVA | ASE_MT
- | ASE_MDMX | ASE_MCU | ASE_VIRT | ASE_VIRT64),
+ | ASE_MCU | ASE_VIRT | ASE_VIRT64 | ASE_MSA | ASE_MSA64),
mips_cp0_names_mips3264r2,
mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
mips_hwr_names_mips3264r2 },
return;
}
+ if (CONST_STRNEQ (option, "msa"))
+ {
+ mips_ase |= ASE_MSA;
+ if ((mips_isa & INSN_ISA_MASK) == ISA_MIPS64R2)
+ mips_ase |= ASE_MSA64;
+ return;
+ }
+
if (CONST_STRNEQ (option, "virt"))
{
mips_ase |= ASE_VIRT;
case OP_REG_HW:
info->fprintf_func (info->stream, "%s", mips_hwr_names[regno]);
break;
+
+ case OP_REG_VF:
+ info->fprintf_func (info->stream, "$vf%d", regno);
+ break;
+
+ case OP_REG_VI:
+ info->fprintf_func (info->stream, "$vi%d", regno);
+ break;
+
+ case OP_REG_R5900_I:
+ info->fprintf_func (info->stream, "$I");
+ break;
+
+ case OP_REG_R5900_Q:
+ info->fprintf_func (info->stream, "$Q");
+ break;
+
+ case OP_REG_R5900_R:
+ info->fprintf_func (info->stream, "$R");
+ break;
+
+ case OP_REG_R5900_ACC:
+ info->fprintf_func (info->stream, "$ACC");
+ break;
+
+ case OP_REG_MSA:
+ info->fprintf_func (info->stream, "$w%d", regno);
+ break;
+
+ case OP_REG_MSA_CTRL:
+ info->fprintf_func (info->stream, "%s", msa_control_names[regno]);
+ break;
+
}
}
\f
memset (state, 0, sizeof (*state));
}
+/* Print OP_VU0_SUFFIX or OP_VU0_MATCH_SUFFIX operand OPERAND,
+ whose value is given by UVAL. */
+
+static void
+print_vu0_channel (struct disassemble_info *info,
+ const struct mips_operand *operand, unsigned int uval)
+{
+ if (operand->size == 4)
+ info->fprintf_func (info->stream, "%s%s%s%s",
+ uval & 8 ? "x" : "",
+ uval & 4 ? "y" : "",
+ uval & 2 ? "z" : "",
+ uval & 1 ? "w" : "");
+ else if (operand->size == 2)
+ info->fprintf_func (info->stream, "%c", "xyzw"[uval]);
+ else
+ abort ();
+}
+
/* Print operand OPERAND of OPCODE, using STATE to track inter-operand state.
UVAL is the encoding of the operand (shifted into bit 0) and BASE_PC is
the base address for OP_PCREL operands. */
break;
case OP_REG:
+ case OP_OPTIONAL_REG:
{
const struct mips_reg_operand *reg_op;
reg_op = (const struct mips_reg_operand *) operand;
- if (reg_op->reg_map)
- uval = reg_op->reg_map[uval];
+ uval = mips_decode_reg_operand (reg_op, uval);
print_reg (info, opcode, reg_op->reg_type, uval);
state->last_reg_type = reg_op->reg_type;
case OP_PC:
infprintf (is, "$pc");
break;
+
+ case OP_VU0_SUFFIX:
+ case OP_VU0_MATCH_SUFFIX:
+ print_vu0_channel (info, operand, uval);
+ break;
+
+ case OP_IMM_INDEX:
+ infprintf (is, "[%d]", uval);
+ break;
+
+ case OP_REG_INDEX:
+ infprintf (is, "[");
+ print_reg (info, opcode, OP_REG_GP, uval);
+ infprintf (is, "]");
+ break;
}
}
infprintf (is, "%c", *s);
break;
+ case '#':
+ ++s;
+ infprintf (is, "%c%c", *s, *s);
+ break;
+
default:
operand = decode_operand (s);
if (!operand)
/* Figure out instruction type and branch delay information. */
if ((op->pinfo & INSN_UNCOND_BRANCH_DELAY) != 0)
{
- if ((op->pinfo & (INSN_WRITE_GPR_31
- | INSN_WRITE_GPR_D)) != 0)
+ if ((op->pinfo & (INSN_WRITE_GPR_31 | INSN_WRITE_1)) != 0)
info->insn_type = dis_jsr;
else
info->insn_type = dis_branch;
info->insn_type = dis_dref;
infprintf (is, "%s", op->name);
+ if (op->pinfo2 & INSN2_VU0_CHANNEL_SUFFIX)
+ {
+ unsigned int uval;
+
+ infprintf (is, ".");
+ uval = mips_extract_operand (&mips_vu0_channel_mask, word);
+ print_vu0_channel (info, &mips_vu0_channel_mask, uval);
+ }
if (op->args[0])
{
}
}
- print_insn_arg (info, state, opcode, operand, baseaddr, uval);
+ print_insn_arg (info, state, opcode, operand, baseaddr + 1, uval);
break;
}
}
/* Figure out branch instruction type and delay slot information. */
if ((op->pinfo & INSN_UNCOND_BRANCH_DELAY) != 0)
info->branch_delay_insns = 1;
- if ((op->pinfo & (INSN_UNCOND_BRANCH_DELAY
- | MIPS16_INSN_UNCOND_BRANCH)) != 0)
+ if ((op->pinfo & INSN_UNCOND_BRANCH_DELAY) != 0
+ || (op->pinfo2 & INSN2_UNCOND_BRANCH) != 0)
{
if ((op->pinfo & INSN_WRITE_GPR_31) != 0)
info->insn_type = dis_jsr;
else
info->insn_type = dis_branch;
}
- else if ((op->pinfo & MIPS16_INSN_COND_BRANCH) != 0)
+ else if ((op->pinfo2 & INSN2_COND_BRANCH) != 0)
info->insn_type = dis_condbranch;
return length;
if (((op->pinfo & INSN_UNCOND_BRANCH_DELAY)
| (op->pinfo2 & INSN2_UNCOND_BRANCH)) != 0)
{
- if ((op->pinfo & (INSN_WRITE_GPR_31 | INSN_WRITE_GPR_T)) != 0)
+ if ((op->pinfo & (INSN_WRITE_GPR_31 | INSN_WRITE_1)) != 0)
info->insn_type = dis_jsr;
else
info->insn_type = dis_branch;
The following MIPS specific disassembler options are supported for use\n\
with the -M switch (multiple options should be separated by commas):\n"));
+ fprintf (stream, _("\n\
+ msa Recognize MSA instructions.\n"));
+
fprintf (stream, _("\n\
virt Recognize the virtualization ASE instructions.\n"));