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:
Richard Sandiford 2013-07-14 13:36:51 +00:00
parent ab90248154
commit c3c0747817
5 changed files with 338 additions and 456 deletions

View file

@ -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.

View file

@ -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;

View file

@ -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.

View 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)

View file

@ -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.