include/opcode/
* mips.h (mips_operand_type): Add OP_ENTRY_EXIT_LIST and OP_SAVE_RESTORE_LIST. (decode_mips16_operand): Declare. opcodes/ * mips16-opc.c: Include mips-formats.h. (reg_0_map, reg_29_map, reg_31_map, reg_m16_map, reg32r_map): New static arrays. (decode_mips16_operand): New function. * mips-dis.c (mips16_to_32_reg_map, mips16_reg_names): Delete. (print_insn_arg): Handle OP_ENTRY_EXIT list. Abort for OP_SAVE_RESTORE_LIST. (print_mips16_insn_arg): Change interface. Use mips_operand structures. Delete GET_OP_S. Move GET_OP definition to... (print_insn_mips16): ...here. Call init_print_arg_state. Update the call to print_mips16_insn_arg.
This commit is contained in:
parent
ab90248154
commit
c3c0747817
5 changed files with 338 additions and 456 deletions
|
@ -1,3 +1,9 @@
|
||||||
|
2013-07-14 Richard Sandiford <rdsandiford@googlemail.com>
|
||||||
|
|
||||||
|
* mips.h (mips_operand_type): Add OP_ENTRY_EXIT_LIST and
|
||||||
|
OP_SAVE_RESTORE_LIST.
|
||||||
|
(decode_mips16_operand): Declare.
|
||||||
|
|
||||||
2013-07-14 Richard Sandiford <rdsandiford@googlemail.com>
|
2013-07-14 Richard Sandiford <rdsandiford@googlemail.com>
|
||||||
|
|
||||||
* mips.h (mips_operand_type, mips_reg_operand_type): New enums.
|
* mips.h (mips_operand_type, mips_reg_operand_type): New enums.
|
||||||
|
|
|
@ -375,6 +375,13 @@ enum mips_operand_type {
|
||||||
size determines whether the 16-bit or 32-bit encoding is required. */
|
size determines whether the 16-bit or 32-bit encoding is required. */
|
||||||
OP_LWM_SWM_LIST,
|
OP_LWM_SWM_LIST,
|
||||||
|
|
||||||
|
/* The register list for an emulated MIPS16 ENTRY or EXIT instruction. */
|
||||||
|
OP_ENTRY_EXIT_LIST,
|
||||||
|
|
||||||
|
/* The register list and frame size for a MIPS16 SAVE or RESTORE
|
||||||
|
instruction. */
|
||||||
|
OP_SAVE_RESTORE_LIST,
|
||||||
|
|
||||||
/* A 10-bit field VVVVVNNNNN used for octobyte and quadhalf instructions:
|
/* A 10-bit field VVVVVNNNNN used for octobyte and quadhalf instructions:
|
||||||
|
|
||||||
V Meaning
|
V Meaning
|
||||||
|
@ -1680,6 +1687,7 @@ extern int bfd_mips_num_opcodes;
|
||||||
FP_D (never used)
|
FP_D (never used)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
extern const struct mips_operand *decode_mips16_operand (char, bfd_boolean);
|
||||||
extern const struct mips_opcode mips16_opcodes[];
|
extern const struct mips_opcode mips16_opcodes[];
|
||||||
extern const int bfd_mips16_num_opcodes;
|
extern const int bfd_mips16_num_opcodes;
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,17 @@
|
||||||
|
2013-07-14 Richard Sandiford <rdsandiford@googlemail.com>
|
||||||
|
|
||||||
|
* mips16-opc.c: Include mips-formats.h.
|
||||||
|
(reg_0_map, reg_29_map, reg_31_map, reg_m16_map, reg32r_map): New
|
||||||
|
static arrays.
|
||||||
|
(decode_mips16_operand): New function.
|
||||||
|
* mips-dis.c (mips16_to_32_reg_map, mips16_reg_names): Delete.
|
||||||
|
(print_insn_arg): Handle OP_ENTRY_EXIT list.
|
||||||
|
Abort for OP_SAVE_RESTORE_LIST.
|
||||||
|
(print_mips16_insn_arg): Change interface. Use mips_operand
|
||||||
|
structures. Delete GET_OP_S. Move GET_OP definition to...
|
||||||
|
(print_insn_mips16): ...here. Call init_print_arg_state.
|
||||||
|
Update the call to print_mips16_insn_arg.
|
||||||
|
|
||||||
2013-07-14 Richard Sandiford <rdsandiford@googlemail.com>
|
2013-07-14 Richard Sandiford <rdsandiford@googlemail.com>
|
||||||
|
|
||||||
* mips-formats.h: New file.
|
* mips-formats.h: New file.
|
||||||
|
|
|
@ -51,15 +51,6 @@ struct mips_cp0sel_name
|
||||||
const char * const name;
|
const char * const name;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The mips16 registers. */
|
|
||||||
static const unsigned int mips16_to_32_reg_map[] =
|
|
||||||
{
|
|
||||||
16, 17, 2, 3, 4, 5, 6, 7
|
|
||||||
};
|
|
||||||
|
|
||||||
#define mips16_reg_names(rn) mips_gpr_names[mips16_to_32_reg_map[rn]]
|
|
||||||
|
|
||||||
|
|
||||||
static const char * const mips_gpr_names_numeric[32] =
|
static const char * const mips_gpr_names_numeric[32] =
|
||||||
{
|
{
|
||||||
"$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
|
"$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
|
||||||
|
@ -1128,6 +1119,54 @@ print_insn_arg (struct disassemble_info *info,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OP_ENTRY_EXIT_LIST:
|
||||||
|
{
|
||||||
|
const char *sep;
|
||||||
|
unsigned int amask, smask;
|
||||||
|
|
||||||
|
sep = "";
|
||||||
|
amask = (uval >> 3) & 7;
|
||||||
|
if (amask > 0 && amask < 5)
|
||||||
|
{
|
||||||
|
infprintf (is, "%s", mips_gpr_names[4]);
|
||||||
|
if (amask > 1)
|
||||||
|
infprintf (is, "-%s", mips_gpr_names[amask + 3]);
|
||||||
|
sep = ",";
|
||||||
|
}
|
||||||
|
|
||||||
|
smask = (uval >> 1) & 3;
|
||||||
|
if (smask == 3)
|
||||||
|
{
|
||||||
|
infprintf (is, "%s??", sep);
|
||||||
|
sep = ",";
|
||||||
|
}
|
||||||
|
else if (smask > 0)
|
||||||
|
{
|
||||||
|
infprintf (is, "%s%s", sep, mips_gpr_names[16]);
|
||||||
|
if (smask > 1)
|
||||||
|
infprintf (is, "-%s", mips_gpr_names[smask + 15]);
|
||||||
|
sep = ",";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uval & 1)
|
||||||
|
{
|
||||||
|
infprintf (is, "%s%s", sep, mips_gpr_names[31]);
|
||||||
|
sep = ",";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (amask == 5 || amask == 6)
|
||||||
|
{
|
||||||
|
infprintf (is, "%s%s", sep, mips_fpr_names[0]);
|
||||||
|
if (amask == 6)
|
||||||
|
infprintf (is, "-%s", mips_fpr_names[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_SAVE_RESTORE_LIST:
|
||||||
|
/* Should be handled by the caller due to extend behavior. */
|
||||||
|
abort ();
|
||||||
|
|
||||||
case OP_MDMX_IMM_REG:
|
case OP_MDMX_IMM_REG:
|
||||||
{
|
{
|
||||||
unsigned int vsel;
|
unsigned int vsel;
|
||||||
|
@ -1351,22 +1390,22 @@ print_insn_mips (bfd_vma memaddr,
|
||||||
/* Disassemble an operand for a mips16 instruction. */
|
/* Disassemble an operand for a mips16 instruction. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
print_mips16_insn_arg (char type,
|
print_mips16_insn_arg (struct disassemble_info *info,
|
||||||
const struct mips_opcode *op,
|
struct mips_print_arg_state *state,
|
||||||
int l,
|
const struct mips_opcode *opcode,
|
||||||
bfd_boolean use_extend,
|
char type, bfd_vma memaddr,
|
||||||
int extend,
|
unsigned insn, bfd_boolean use_extend,
|
||||||
bfd_vma memaddr,
|
unsigned extend, bfd_boolean is_offset)
|
||||||
struct disassemble_info *info)
|
|
||||||
{
|
{
|
||||||
const fprintf_ftype infprintf = info->fprintf_func;
|
const fprintf_ftype infprintf = info->fprintf_func;
|
||||||
void *is = info->stream;
|
void *is = info->stream;
|
||||||
|
const struct mips_operand *operand, *ext_operand;
|
||||||
|
unsigned int uval;
|
||||||
|
bfd_vma baseaddr;
|
||||||
|
|
||||||
|
if (!use_extend)
|
||||||
|
extend = 0;
|
||||||
|
|
||||||
#define GET_OP(insn, field) \
|
|
||||||
(((insn) >> MIPS16OP_SH_##field) & MIPS16OP_MASK_##field)
|
|
||||||
#define GET_OP_S(insn, field) \
|
|
||||||
((GET_OP (insn, field) ^ ((MIPS16OP_MASK_##field >> 1) + 1)) \
|
|
||||||
- ((MIPS16OP_MASK_##field >> 1) + 1))
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case ',':
|
case ',':
|
||||||
|
@ -1375,428 +1414,67 @@ print_mips16_insn_arg (char type,
|
||||||
infprintf (is, "%c", type);
|
infprintf (is, "%c", type);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'y':
|
|
||||||
case 'w':
|
|
||||||
infprintf (is, "%s", mips16_reg_names (GET_OP (l, RY)));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'x':
|
|
||||||
case 'v':
|
|
||||||
infprintf (is, "%s", mips16_reg_names (GET_OP (l, RX)));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'z':
|
|
||||||
infprintf (is, "%s", mips16_reg_names (GET_OP (l, RZ)));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'Z':
|
|
||||||
infprintf (is, "%s", mips16_reg_names (GET_OP (l, MOVE32Z)));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '0':
|
|
||||||
infprintf (is, "%s", mips_gpr_names[0]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'S':
|
|
||||||
infprintf (is, "%s", mips_gpr_names[29]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'P':
|
|
||||||
infprintf (is, "$pc");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'R':
|
|
||||||
infprintf (is, "%s", mips_gpr_names[31]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'X':
|
|
||||||
infprintf (is, "%s", mips_gpr_names[GET_OP (l, REGR32)]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'Y':
|
|
||||||
infprintf (is, "%s", mips_gpr_names[MIPS16OP_EXTRACT_REG32R (l)]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '<':
|
|
||||||
case '>':
|
|
||||||
case '[':
|
|
||||||
case ']':
|
|
||||||
case '4':
|
|
||||||
case '5':
|
|
||||||
case 'H':
|
|
||||||
case 'W':
|
|
||||||
case 'D':
|
|
||||||
case 'j':
|
|
||||||
case '6':
|
|
||||||
case '8':
|
|
||||||
case 'V':
|
|
||||||
case 'C':
|
|
||||||
case 'U':
|
|
||||||
case 'k':
|
|
||||||
case 'K':
|
|
||||||
case 'p':
|
|
||||||
case 'q':
|
|
||||||
case 'A':
|
|
||||||
case 'B':
|
|
||||||
case 'E':
|
|
||||||
{
|
|
||||||
int immed, nbits, shift, signedp, extbits, pcrel, extu, branch;
|
|
||||||
|
|
||||||
shift = 0;
|
|
||||||
signedp = 0;
|
|
||||||
extbits = 16;
|
|
||||||
pcrel = 0;
|
|
||||||
extu = 0;
|
|
||||||
branch = 0;
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case '<':
|
|
||||||
nbits = 3;
|
|
||||||
immed = GET_OP (l, RZ);
|
|
||||||
extbits = 5;
|
|
||||||
extu = 1;
|
|
||||||
break;
|
|
||||||
case '>':
|
|
||||||
nbits = 3;
|
|
||||||
immed = GET_OP (l, RX);
|
|
||||||
extbits = 5;
|
|
||||||
extu = 1;
|
|
||||||
break;
|
|
||||||
case '[':
|
|
||||||
nbits = 3;
|
|
||||||
immed = GET_OP (l, RZ);
|
|
||||||
extbits = 6;
|
|
||||||
extu = 1;
|
|
||||||
break;
|
|
||||||
case ']':
|
|
||||||
nbits = 3;
|
|
||||||
immed = GET_OP (l, RX);
|
|
||||||
extbits = 6;
|
|
||||||
extu = 1;
|
|
||||||
break;
|
|
||||||
case '4':
|
|
||||||
nbits = 4;
|
|
||||||
immed = GET_OP (l, IMM4);
|
|
||||||
signedp = 1;
|
|
||||||
extbits = 15;
|
|
||||||
break;
|
|
||||||
case '5':
|
|
||||||
nbits = 5;
|
|
||||||
immed = GET_OP (l, IMM5);
|
|
||||||
info->insn_type = dis_dref;
|
|
||||||
info->data_size = 1;
|
|
||||||
break;
|
|
||||||
case 'H':
|
|
||||||
nbits = 5;
|
|
||||||
shift = 1;
|
|
||||||
immed = GET_OP (l, IMM5);
|
|
||||||
info->insn_type = dis_dref;
|
|
||||||
info->data_size = 2;
|
|
||||||
break;
|
|
||||||
case 'W':
|
|
||||||
nbits = 5;
|
|
||||||
shift = 2;
|
|
||||||
immed = GET_OP (l, IMM5);
|
|
||||||
if ((op->pinfo & MIPS16_INSN_READ_PC) == 0
|
|
||||||
&& (op->pinfo & MIPS16_INSN_READ_SP) == 0)
|
|
||||||
{
|
|
||||||
info->insn_type = dis_dref;
|
|
||||||
info->data_size = 4;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'D':
|
|
||||||
nbits = 5;
|
|
||||||
shift = 3;
|
|
||||||
immed = GET_OP (l, IMM5);
|
|
||||||
info->insn_type = dis_dref;
|
|
||||||
info->data_size = 8;
|
|
||||||
break;
|
|
||||||
case 'j':
|
|
||||||
nbits = 5;
|
|
||||||
immed = GET_OP (l, IMM5);
|
|
||||||
signedp = 1;
|
|
||||||
break;
|
|
||||||
case '6':
|
|
||||||
nbits = 6;
|
|
||||||
immed = GET_OP (l, IMM6);
|
|
||||||
break;
|
|
||||||
case '8':
|
|
||||||
nbits = 8;
|
|
||||||
immed = GET_OP (l, IMM8);
|
|
||||||
break;
|
|
||||||
case 'V':
|
|
||||||
nbits = 8;
|
|
||||||
shift = 2;
|
|
||||||
immed = GET_OP (l, IMM8);
|
|
||||||
/* FIXME: This might be lw, or it might be addiu to $sp or
|
|
||||||
$pc. We assume it's load. */
|
|
||||||
info->insn_type = dis_dref;
|
|
||||||
info->data_size = 4;
|
|
||||||
break;
|
|
||||||
case 'C':
|
|
||||||
nbits = 8;
|
|
||||||
shift = 3;
|
|
||||||
immed = GET_OP (l, IMM8);
|
|
||||||
info->insn_type = dis_dref;
|
|
||||||
info->data_size = 8;
|
|
||||||
break;
|
|
||||||
case 'U':
|
|
||||||
nbits = 8;
|
|
||||||
immed = GET_OP (l, IMM8);
|
|
||||||
extu = 1;
|
|
||||||
break;
|
|
||||||
case 'k':
|
|
||||||
nbits = 8;
|
|
||||||
immed = GET_OP (l, IMM8);
|
|
||||||
signedp = 1;
|
|
||||||
break;
|
|
||||||
case 'K':
|
|
||||||
nbits = 8;
|
|
||||||
shift = 3;
|
|
||||||
immed = GET_OP (l, IMM8);
|
|
||||||
signedp = 1;
|
|
||||||
break;
|
|
||||||
case 'p':
|
|
||||||
nbits = 8;
|
|
||||||
immed = GET_OP (l, IMM8);
|
|
||||||
signedp = 1;
|
|
||||||
pcrel = 1;
|
|
||||||
branch = 1;
|
|
||||||
break;
|
|
||||||
case 'q':
|
|
||||||
nbits = 11;
|
|
||||||
immed = GET_OP (l, IMM11);
|
|
||||||
signedp = 1;
|
|
||||||
pcrel = 1;
|
|
||||||
branch = 1;
|
|
||||||
break;
|
|
||||||
case 'A':
|
|
||||||
nbits = 8;
|
|
||||||
shift = 2;
|
|
||||||
immed = GET_OP (l, IMM8);
|
|
||||||
pcrel = 1;
|
|
||||||
/* FIXME: This can be lw or la. We assume it is lw. */
|
|
||||||
info->insn_type = dis_dref;
|
|
||||||
info->data_size = 4;
|
|
||||||
break;
|
|
||||||
case 'B':
|
|
||||||
nbits = 5;
|
|
||||||
shift = 3;
|
|
||||||
immed = GET_OP (l, IMM5);
|
|
||||||
pcrel = 1;
|
|
||||||
info->insn_type = dis_dref;
|
|
||||||
info->data_size = 8;
|
|
||||||
break;
|
|
||||||
case 'E':
|
|
||||||
nbits = 5;
|
|
||||||
shift = 2;
|
|
||||||
immed = GET_OP (l, IMM5);
|
|
||||||
pcrel = 1;
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
abort ();
|
operand = decode_mips16_operand (type, FALSE);
|
||||||
}
|
if (!operand)
|
||||||
|
|
||||||
if (! use_extend)
|
|
||||||
{
|
{
|
||||||
if (signedp && immed >= (1 << (nbits - 1)))
|
/* xgettext:c-format */
|
||||||
immed -= 1 << nbits;
|
infprintf (is, _("# internal error, undefined operand in `%s %s'"),
|
||||||
immed <<= shift;
|
opcode->name, opcode->args);
|
||||||
if ((type == '<' || type == '>' || type == '[' || type == ']')
|
return;
|
||||||
&& immed == 0)
|
|
||||||
immed = 8;
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (operand->type == OP_SAVE_RESTORE_LIST)
|
||||||
{
|
{
|
||||||
if (extbits == 16)
|
/* Handle this case here because of the complex interation
|
||||||
immed |= ((extend & 0x1f) << 11) | (extend & 0x7e0);
|
with the EXTEND opcode. */
|
||||||
else if (extbits == 15)
|
unsigned int amask, nargs, nstatics, nsreg, smask, frame_size, i, j;
|
||||||
immed |= ((extend & 0xf) << 11) | (extend & 0x7f0);
|
const char *sep;
|
||||||
else
|
|
||||||
immed = ((extend >> 6) & 0x1f) | (extend & 0x20);
|
|
||||||
immed &= (1 << extbits) - 1;
|
|
||||||
if (! extu && immed >= (1 << (extbits - 1)))
|
|
||||||
immed -= 1 << extbits;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! pcrel)
|
amask = extend & 0xf;
|
||||||
infprintf (is, "%d", immed);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bfd_vma baseaddr;
|
|
||||||
|
|
||||||
if (branch)
|
|
||||||
{
|
|
||||||
immed *= 2;
|
|
||||||
baseaddr = memaddr + 2;
|
|
||||||
}
|
|
||||||
else if (use_extend)
|
|
||||||
baseaddr = memaddr - 2;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int status;
|
|
||||||
bfd_byte buffer[2];
|
|
||||||
|
|
||||||
baseaddr = memaddr;
|
|
||||||
|
|
||||||
/* If this instruction is in the delay slot of a jr
|
|
||||||
instruction, the base address is the address of the
|
|
||||||
jr instruction. If it is in the delay slot of jalr
|
|
||||||
instruction, the base address is the address of the
|
|
||||||
jalr instruction. This test is unreliable: we have
|
|
||||||
no way of knowing whether the previous word is
|
|
||||||
instruction or data. */
|
|
||||||
status = (*info->read_memory_func) (memaddr - 4, buffer, 2,
|
|
||||||
info);
|
|
||||||
if (status == 0
|
|
||||||
&& (((info->endian == BFD_ENDIAN_BIG
|
|
||||||
? bfd_getb16 (buffer)
|
|
||||||
: bfd_getl16 (buffer))
|
|
||||||
& 0xf800) == 0x1800))
|
|
||||||
baseaddr = memaddr - 4;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
status = (*info->read_memory_func) (memaddr - 2, buffer,
|
|
||||||
2, info);
|
|
||||||
if (status == 0
|
|
||||||
&& (((info->endian == BFD_ENDIAN_BIG
|
|
||||||
? bfd_getb16 (buffer)
|
|
||||||
: bfd_getl16 (buffer))
|
|
||||||
& 0xf81f) == 0xe800))
|
|
||||||
baseaddr = memaddr - 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
info->target = (baseaddr & ~((1 << shift) - 1)) + immed;
|
|
||||||
if (pcrel && branch
|
|
||||||
&& info->flavour == bfd_target_unknown_flavour)
|
|
||||||
/* For gdb disassembler, maintain odd address. */
|
|
||||||
info->target |= 1;
|
|
||||||
(*info->print_address_func) (info->target, info);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'a':
|
|
||||||
case 'i':
|
|
||||||
{
|
|
||||||
if (! use_extend)
|
|
||||||
extend = 0;
|
|
||||||
l = ((l & 0x1f) << 23) | ((l & 0x3e0) << 13) | (extend << 2);
|
|
||||||
if (type == 'a' && info->flavour == bfd_target_unknown_flavour)
|
|
||||||
/* For gdb disassembler, maintain odd address. */
|
|
||||||
l |= 1;
|
|
||||||
}
|
|
||||||
info->target = ((memaddr + 4) & ~(bfd_vma) 0x0fffffff) | l;
|
|
||||||
(*info->print_address_func) (info->target, info);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'l':
|
|
||||||
case 'L':
|
|
||||||
{
|
|
||||||
int need_comma, amask, smask;
|
|
||||||
|
|
||||||
need_comma = 0;
|
|
||||||
|
|
||||||
l = GET_OP (l, IMM6);
|
|
||||||
|
|
||||||
amask = (l >> 3) & 7;
|
|
||||||
|
|
||||||
if (amask > 0 && amask < 5)
|
|
||||||
{
|
|
||||||
infprintf (is, "%s", mips_gpr_names[4]);
|
|
||||||
if (amask > 1)
|
|
||||||
infprintf (is, "-%s", mips_gpr_names[amask + 3]);
|
|
||||||
need_comma = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
smask = (l >> 1) & 3;
|
|
||||||
if (smask == 3)
|
|
||||||
{
|
|
||||||
infprintf (is, "%s??", need_comma ? "," : "");
|
|
||||||
need_comma = 1;
|
|
||||||
}
|
|
||||||
else if (smask > 0)
|
|
||||||
{
|
|
||||||
infprintf (is, "%s%s", need_comma ? "," : "", mips_gpr_names[16]);
|
|
||||||
if (smask > 1)
|
|
||||||
infprintf (is, "-%s", mips_gpr_names[smask + 15]);
|
|
||||||
need_comma = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (l & 1)
|
|
||||||
{
|
|
||||||
infprintf (is, "%s%s", need_comma ? "," : "", mips_gpr_names[31]);
|
|
||||||
need_comma = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (amask == 5 || amask == 6)
|
|
||||||
{
|
|
||||||
infprintf (is, "%s$f0", need_comma ? "," : "");
|
|
||||||
if (amask == 6)
|
|
||||||
infprintf (is, "-$f1");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'm':
|
|
||||||
case 'M':
|
|
||||||
/* MIPS16e save/restore. */
|
|
||||||
{
|
|
||||||
int need_comma = 0;
|
|
||||||
int amask, args, statics;
|
|
||||||
int nsreg, smask;
|
|
||||||
int framesz;
|
|
||||||
int i, j;
|
|
||||||
|
|
||||||
l = l & 0x7f;
|
|
||||||
if (use_extend)
|
|
||||||
l |= extend << 16;
|
|
||||||
|
|
||||||
amask = (l >> 16) & 0xf;
|
|
||||||
if (amask == MIPS16_ALL_ARGS)
|
if (amask == MIPS16_ALL_ARGS)
|
||||||
{
|
{
|
||||||
args = 4;
|
nargs = 4;
|
||||||
statics = 0;
|
nstatics = 0;
|
||||||
}
|
}
|
||||||
else if (amask == MIPS16_ALL_STATICS)
|
else if (amask == MIPS16_ALL_STATICS)
|
||||||
{
|
{
|
||||||
args = 0;
|
nargs = 0;
|
||||||
statics = 4;
|
nstatics = 4;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
args = amask >> 2;
|
nargs = amask >> 2;
|
||||||
statics = amask & 3;
|
nstatics = amask & 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args > 0) {
|
sep = "";
|
||||||
|
if (nargs > 0)
|
||||||
|
{
|
||||||
infprintf (is, "%s", mips_gpr_names[4]);
|
infprintf (is, "%s", mips_gpr_names[4]);
|
||||||
if (args > 1)
|
if (nargs > 1)
|
||||||
infprintf (is, "-%s", mips_gpr_names[4 + args - 1]);
|
infprintf (is, "-%s", mips_gpr_names[4 + nargs - 1]);
|
||||||
need_comma = 1;
|
sep = ",";
|
||||||
}
|
}
|
||||||
|
|
||||||
framesz = (((l >> 16) & 0xf0) | (l & 0x0f)) * 8;
|
frame_size = ((extend & 0xf0) | (insn & 0x0f)) * 8;
|
||||||
if (framesz == 0 && !use_extend)
|
if (frame_size == 0 && !use_extend)
|
||||||
framesz = 128;
|
frame_size = 128;
|
||||||
|
infprintf (is, "%s%d", sep, frame_size);
|
||||||
|
|
||||||
infprintf (is, "%s%d", need_comma ? "," : "", framesz);
|
if (insn & 0x40) /* $ra */
|
||||||
|
|
||||||
if (l & 0x40) /* $ra */
|
|
||||||
infprintf (is, ",%s", mips_gpr_names[31]);
|
infprintf (is, ",%s", mips_gpr_names[31]);
|
||||||
|
|
||||||
nsreg = (l >> 24) & 0x7;
|
nsreg = (extend >> 8) & 0x7;
|
||||||
smask = 0;
|
smask = 0;
|
||||||
if (l & 0x20) /* $s0 */
|
if (insn & 0x20) /* $s0 */
|
||||||
smask |= 1 << 0;
|
smask |= 1 << 0;
|
||||||
if (l & 0x10) /* $s1 */
|
if (insn & 0x10) /* $s1 */
|
||||||
smask |= 1 << 1;
|
smask |= 1 << 1;
|
||||||
if (nsreg > 0) /* $s2-$s8 */
|
if (nsreg > 0) /* $s2-$s8 */
|
||||||
smask |= ((1 << nsreg) - 1) << 2;
|
smask |= ((1 << nsreg) - 1) << 2;
|
||||||
|
|
||||||
/* Find first set static reg bit. */
|
|
||||||
for (i = 0; i < 9; i++)
|
for (i = 0; i < 9; i++)
|
||||||
{
|
|
||||||
if (smask & (1 << i))
|
if (smask & (1 << i))
|
||||||
{
|
{
|
||||||
infprintf (is, ",%s", mips_gpr_names[i == 8 ? 30 : (16 + i)]);
|
infprintf (is, ",%s", mips_gpr_names[i == 8 ? 30 : (16 + i)]);
|
||||||
|
@ -1807,25 +1485,88 @@ print_mips16_insn_arg (char type,
|
||||||
infprintf (is, "-%s", mips_gpr_names[j == 8 ? 30 : (16 + j)]);
|
infprintf (is, "-%s", mips_gpr_names[j == 8 ? 30 : (16 + j)]);
|
||||||
i = j + 1;
|
i = j + 1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* Statics $ax - $a3. */
|
/* Statics $ax - $a3. */
|
||||||
if (statics == 1)
|
if (nstatics == 1)
|
||||||
infprintf (is, ",%s", mips_gpr_names[7]);
|
infprintf (is, ",%s", mips_gpr_names[7]);
|
||||||
else if (statics > 0)
|
else if (nstatics > 0)
|
||||||
infprintf (is, ",%s-%s",
|
infprintf (is, ",%s-%s",
|
||||||
mips_gpr_names[7 - statics + 1],
|
mips_gpr_names[7 - nstatics + 1],
|
||||||
mips_gpr_names[7]);
|
mips_gpr_names[7]);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
if (is_offset && operand->type == OP_INT)
|
||||||
/* xgettext:c-format */
|
{
|
||||||
infprintf (is,
|
const struct mips_int_operand *int_op;
|
||||||
_("# internal disassembler error, "
|
|
||||||
"unrecognised modifier (%c)"),
|
int_op = (const struct mips_int_operand *) operand;
|
||||||
type);
|
info->insn_type = dis_dref;
|
||||||
abort ();
|
info->data_size = 1 << int_op->shift;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (operand->size == 26)
|
||||||
|
/* In this case INSN is the first two bytes of the instruction
|
||||||
|
and EXTEND is the second two bytes. */
|
||||||
|
uval = ((insn & 0x1f) << 21) | ((insn & 0x3e0) << 11) | extend;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Calculate the full field value. */
|
||||||
|
uval = mips_extract_operand (operand, insn);
|
||||||
|
if (use_extend)
|
||||||
|
{
|
||||||
|
ext_operand = decode_mips16_operand (type, TRUE);
|
||||||
|
if (ext_operand != operand)
|
||||||
|
{
|
||||||
|
operand = ext_operand;
|
||||||
|
if (operand->size == 16)
|
||||||
|
uval |= ((extend & 0x1f) << 11) | (extend & 0x7e0);
|
||||||
|
else if (operand->size == 15)
|
||||||
|
uval |= ((extend & 0xf) << 11) | (extend & 0x7f0);
|
||||||
|
else
|
||||||
|
uval = ((extend >> 6) & 0x1f) | (extend & 0x20);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
baseaddr = memaddr + 2;
|
||||||
|
if (operand->type == OP_PCREL)
|
||||||
|
{
|
||||||
|
const struct mips_pcrel_operand *pcrel_op;
|
||||||
|
|
||||||
|
pcrel_op = (const struct mips_pcrel_operand *) operand;
|
||||||
|
if (!pcrel_op->include_isa_bit && use_extend)
|
||||||
|
baseaddr = memaddr - 2;
|
||||||
|
else if (!pcrel_op->include_isa_bit)
|
||||||
|
{
|
||||||
|
bfd_byte buffer[2];
|
||||||
|
|
||||||
|
/* If this instruction is in the delay slot of a JR
|
||||||
|
instruction, the base address is the address of the
|
||||||
|
JR instruction. If it is in the delay slot of a JALR
|
||||||
|
instruction, the base address is the address of the
|
||||||
|
JALR instruction. This test is unreliable: we have
|
||||||
|
no way of knowing whether the previous word is
|
||||||
|
instruction or data. */
|
||||||
|
if (info->read_memory_func (memaddr - 4, buffer, 2, info) == 0
|
||||||
|
&& (((info->endian == BFD_ENDIAN_BIG
|
||||||
|
? bfd_getb16 (buffer)
|
||||||
|
: bfd_getl16 (buffer))
|
||||||
|
& 0xf800) == 0x1800))
|
||||||
|
baseaddr = memaddr - 4;
|
||||||
|
else if (info->read_memory_func (memaddr - 2, buffer, 2,
|
||||||
|
info) == 0
|
||||||
|
&& (((info->endian == BFD_ENDIAN_BIG
|
||||||
|
? bfd_getb16 (buffer)
|
||||||
|
: bfd_getl16 (buffer))
|
||||||
|
& 0xf81f) == 0xe800))
|
||||||
|
baseaddr = memaddr - 2;
|
||||||
|
else
|
||||||
|
baseaddr = memaddr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print_insn_arg (info, state, opcode, operand, baseaddr, uval);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1859,6 +1600,7 @@ print_insn_mips16 (bfd_vma memaddr, struct disassemble_info *info)
|
||||||
bfd_boolean use_extend;
|
bfd_boolean use_extend;
|
||||||
int extend = 0;
|
int extend = 0;
|
||||||
const struct mips_opcode *op, *opend;
|
const struct mips_opcode *op, *opend;
|
||||||
|
struct mips_print_arg_state state;
|
||||||
void *is = info->stream;
|
void *is = info->stream;
|
||||||
|
|
||||||
info->bytes_per_chunk = 2;
|
info->bytes_per_chunk = 2;
|
||||||
|
@ -1869,6 +1611,8 @@ print_insn_mips16 (bfd_vma memaddr, struct disassemble_info *info)
|
||||||
info->target = 0;
|
info->target = 0;
|
||||||
info->target2 = 0;
|
info->target2 = 0;
|
||||||
|
|
||||||
|
#define GET_OP(insn, field) \
|
||||||
|
(((insn) >> MIPS16OP_SH_##field) & MIPS16OP_MASK_##field)
|
||||||
/* Decode PLT entry's GOT slot address word. */
|
/* Decode PLT entry's GOT slot address word. */
|
||||||
if (is_mips16_plt_tail (info, memaddr))
|
if (is_mips16_plt_tail (info, memaddr))
|
||||||
{
|
{
|
||||||
|
@ -1979,6 +1723,7 @@ print_insn_mips16 (bfd_vma memaddr, struct disassemble_info *info)
|
||||||
if (op->args[0] != '\0')
|
if (op->args[0] != '\0')
|
||||||
infprintf (is, "\t");
|
infprintf (is, "\t");
|
||||||
|
|
||||||
|
init_print_arg_state (&state);
|
||||||
for (s = op->args; *s != '\0'; s++)
|
for (s = op->args; *s != '\0'; s++)
|
||||||
{
|
{
|
||||||
if (*s == ','
|
if (*s == ','
|
||||||
|
@ -1997,8 +1742,8 @@ print_insn_mips16 (bfd_vma memaddr, struct disassemble_info *info)
|
||||||
++s;
|
++s;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
print_mips16_insn_arg (*s, op, insn, use_extend, extend, memaddr,
|
print_mips16_insn_arg (info, &state, op, *s, memaddr, insn,
|
||||||
info);
|
use_extend, extend, s[1] == '(');
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Figure out branch instruction type and delay slot information. */
|
/* Figure out branch instruction type and delay slot information. */
|
||||||
|
@ -2018,7 +1763,6 @@ print_insn_mips16 (bfd_vma memaddr, struct disassemble_info *info)
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#undef GET_OP_S
|
|
||||||
#undef GET_OP
|
#undef GET_OP
|
||||||
|
|
||||||
if (use_extend)
|
if (use_extend)
|
||||||
|
|
|
@ -23,6 +23,116 @@
|
||||||
#include "sysdep.h"
|
#include "sysdep.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "opcode/mips.h"
|
#include "opcode/mips.h"
|
||||||
|
#include "mips-formats.h"
|
||||||
|
|
||||||
|
static unsigned char reg_0_map[] = { 0 };
|
||||||
|
static unsigned char reg_29_map[] = { 29 };
|
||||||
|
static unsigned char reg_31_map[] = { 31 };
|
||||||
|
static unsigned char reg_m16_map[] = { 16, 17, 2, 3, 4, 5, 6, 7 };
|
||||||
|
static unsigned char reg32r_map[] = {
|
||||||
|
0, 8, 16, 24,
|
||||||
|
1, 9, 17, 25,
|
||||||
|
2, 10, 18, 26,
|
||||||
|
3, 11, 19, 27,
|
||||||
|
4, 12, 20, 28,
|
||||||
|
5, 13, 21, 29,
|
||||||
|
6, 14, 22, 30,
|
||||||
|
7, 15, 23, 31
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Return the meaning of operand character TYPE, or null if it isn't
|
||||||
|
recognized. If the operand is affected by the EXTEND instruction,
|
||||||
|
EXTENDED_P selects between the extended and unextended forms.
|
||||||
|
The extended forms all have an lsb of 0. */
|
||||||
|
|
||||||
|
const struct mips_operand *
|
||||||
|
decode_mips16_operand (char type, bfd_boolean extended_p)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case '0': MAPPED_REG (0, 0, GP, reg_0_map);
|
||||||
|
|
||||||
|
case 'L': SPECIAL (6, 5, ENTRY_EXIT_LIST);
|
||||||
|
case 'M': SPECIAL (7, 0, SAVE_RESTORE_LIST);
|
||||||
|
case 'P': SPECIAL (0, 0, PC);
|
||||||
|
case 'R': MAPPED_REG (0, 0, GP, reg_31_map);
|
||||||
|
case 'S': MAPPED_REG (0, 0, GP, reg_29_map);
|
||||||
|
case 'X': REG (5, 0, GP);
|
||||||
|
case 'Y': MAPPED_REG (5, 3, GP, reg32r_map);
|
||||||
|
case 'Z': MAPPED_REG (3, 0, GP, reg_m16_map);
|
||||||
|
|
||||||
|
case 'a': JUMP (26, 0, 2);
|
||||||
|
case 'e': UINT (11, 0);
|
||||||
|
case 'i': JALX (26, 0, 2);
|
||||||
|
case 'l': SPECIAL (6, 5, ENTRY_EXIT_LIST);
|
||||||
|
case 'm': SPECIAL (7, 0, SAVE_RESTORE_LIST);
|
||||||
|
case 'v': MAPPED_REG (3, 8, GP, reg_m16_map);
|
||||||
|
case 'w': MAPPED_REG (3, 5, GP, reg_m16_map);
|
||||||
|
case 'x': MAPPED_REG (3, 8, GP, reg_m16_map);
|
||||||
|
case 'y': MAPPED_REG (3, 5, GP, reg_m16_map);
|
||||||
|
case 'z': MAPPED_REG (3, 2, GP, reg_m16_map);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extended_p)
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case '<': UINT (5, 0);
|
||||||
|
case '>': UINT (5, 0);
|
||||||
|
case '[': UINT (6, 0);
|
||||||
|
case ']': UINT (6, 0);
|
||||||
|
|
||||||
|
case '4': SINT (15, 0);
|
||||||
|
case '5': SINT (16, 0);
|
||||||
|
case '6': SINT (16, 0);
|
||||||
|
case '8': SINT (16, 0);
|
||||||
|
|
||||||
|
case 'A': PCREL (16, 0, 2, 0, TRUE, FALSE, FALSE);
|
||||||
|
case 'B': PCREL (16, 0, 3, 0, TRUE, FALSE, FALSE);
|
||||||
|
case 'C': SINT (16, 0);
|
||||||
|
case 'D': SINT (16, 0);
|
||||||
|
case 'E': PCREL (16, 0, 2, 0, TRUE, FALSE, FALSE);
|
||||||
|
case 'H': SINT (16, 0);
|
||||||
|
case 'K': SINT (16, 0);
|
||||||
|
case 'U': UINT (16, 0);
|
||||||
|
case 'V': SINT (16, 0);
|
||||||
|
case 'W': SINT (16, 0);
|
||||||
|
|
||||||
|
case 'j': SINT (16, 0);
|
||||||
|
case 'k': SINT (16, 0);
|
||||||
|
case 'p': BRANCH (16, 0, 1);
|
||||||
|
case 'q': BRANCH (16, 0, 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case '<': INT_ADJ (3, 2, 8, 0, FALSE);
|
||||||
|
case '>': INT_ADJ (3, 8, 8, 0, FALSE);
|
||||||
|
case '[': INT_ADJ (3, 2, 8, 0, FALSE);
|
||||||
|
case ']': INT_ADJ (3, 8, 8, 0, FALSE);
|
||||||
|
|
||||||
|
case '4': SINT (4, 0);
|
||||||
|
case '5': UINT (5, 0);
|
||||||
|
case '6': UINT (6, 5);
|
||||||
|
case '8': UINT (8, 0);
|
||||||
|
|
||||||
|
case 'A': PCREL (8, 0, 2, 2, FALSE, FALSE, FALSE);
|
||||||
|
case 'B': PCREL (5, 0, 3, 3, FALSE, FALSE, FALSE);
|
||||||
|
case 'C': INT_ADJ (8, 0, 255, 3, FALSE); /* (0 .. 255) << 3 */
|
||||||
|
case 'D': INT_ADJ (5, 0, 31, 3, FALSE); /* (0 .. 31) << 3 */
|
||||||
|
case 'E': PCREL (5, 0, 2, 2, FALSE, FALSE, FALSE);
|
||||||
|
case 'H': INT_ADJ (5, 0, 31, 1, FALSE); /* (0 .. 31) << 1 */
|
||||||
|
case 'K': INT_ADJ (8, 0, 127, 3, FALSE); /* (-128 .. 127) << 3 */
|
||||||
|
case 'U': UINT (8, 0);
|
||||||
|
case 'V': INT_ADJ (8, 0, 255, 2, FALSE); /* (0 .. 255) << 2 */
|
||||||
|
case 'W': INT_ADJ (5, 0, 31, 2, FALSE); /* (0 .. 31) << 2 */
|
||||||
|
|
||||||
|
case 'j': SINT (5, 0);
|
||||||
|
case 'k': SINT (8, 0);
|
||||||
|
case 'p': BRANCH (8, 0, 1);
|
||||||
|
case 'q': BRANCH (11, 0, 1);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* This is the opcodes table for the mips16 processor. The format of
|
/* This is the opcodes table for the mips16 processor. The format of
|
||||||
this table is intentionally identical to the one in mips-opc.c.
|
this table is intentionally identical to the one in mips-opc.c.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue