aboutsummaryrefslogtreecommitdiff
path: root/opcodes
diff options
context:
space:
mode:
authorRichard Sandiford <rdsandiford@googlemail.com>2013-07-14 13:36:51 +0000
committerRichard Sandiford <rdsandiford@googlemail.com>2013-07-14 13:36:51 +0000
commitc3c0747817f456c7d4a5d8884b304c2095bdf5ab (patch)
tree24deb899ff002df6b658f19744194eb896a197b8 /opcodes
parentab90248154ba05dc800c480712c3cb03eb33b135 (diff)
downloadgdb-c3c0747817f456c7d4a5d8884b304c2095bdf5ab.zip
gdb-c3c0747817f456c7d4a5d8884b304c2095bdf5ab.tar.gz
gdb-c3c0747817f456c7d4a5d8884b304c2095bdf5ab.tar.bz2
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.
Diffstat (limited to 'opcodes')
-rw-r--r--opcodes/ChangeLog14
-rw-r--r--opcodes/mips-dis.c664
-rw-r--r--opcodes/mips16-opc.c110
3 files changed, 328 insertions, 460 deletions
diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog
index 17cc1c6..5ac2b28 100644
--- a/opcodes/ChangeLog
+++ b/opcodes/ChangeLog
@@ -1,5 +1,19 @@
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>
+
* mips-formats.h: New file.
* mips-opc.c: Include mips-formats.h.
(reg_0_map): New static array.
diff --git a/opcodes/mips-dis.c b/opcodes/mips-dis.c
index cd7c633..03333bf 100644
--- a/opcodes/mips-dis.c
+++ b/opcodes/mips-dis.c
@@ -51,15 +51,6 @@ struct mips_cp0sel_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] =
{
"$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
@@ -1128,6 +1119,54 @@ print_insn_arg (struct disassemble_info *info,
}
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:
{
unsigned int vsel;
@@ -1351,22 +1390,22 @@ print_insn_mips (bfd_vma memaddr,
/* Disassemble an operand for a mips16 instruction. */
static void
-print_mips16_insn_arg (char type,
- const struct mips_opcode *op,
- int l,
- bfd_boolean use_extend,
- int extend,
- bfd_vma memaddr,
- struct disassemble_info *info)
+print_mips16_insn_arg (struct disassemble_info *info,
+ struct mips_print_arg_state *state,
+ const struct mips_opcode *opcode,
+ char type, bfd_vma memaddr,
+ unsigned insn, bfd_boolean use_extend,
+ unsigned extend, bfd_boolean is_offset)
{
const fprintf_ftype infprintf = info->fprintf_func;
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)
{
case ',':
@@ -1375,457 +1414,159 @@ print_mips16_insn_arg (char type,
infprintf (is, "%c", type);
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;
+ default:
+ operand = decode_mips16_operand (type, FALSE);
+ if (!operand)
+ {
+ /* xgettext:c-format */
+ infprintf (is, _("# internal error, undefined operand in `%s %s'"),
+ opcode->name, opcode->args);
+ return;
+ }
- case 'R':
- infprintf (is, "%s", mips_gpr_names[31]);
- break;
+ if (operand->type == OP_SAVE_RESTORE_LIST)
+ {
+ /* Handle this case here because of the complex interation
+ with the EXTEND opcode. */
+ unsigned int amask, nargs, nstatics, nsreg, smask, frame_size, i, j;
+ const char *sep;
- case 'X':
- infprintf (is, "%s", mips_gpr_names[GET_OP (l, REGR32)]);
- break;
+ amask = extend & 0xf;
+ if (amask == MIPS16_ALL_ARGS)
+ {
+ nargs = 4;
+ nstatics = 0;
+ }
+ else if (amask == MIPS16_ALL_STATICS)
+ {
+ nargs = 0;
+ nstatics = 4;
+ }
+ else
+ {
+ nargs = amask >> 2;
+ nstatics = amask & 3;
+ }
- case 'Y':
- infprintf (is, "%s", mips_gpr_names[MIPS16OP_EXTRACT_REG32R (l)]);
- break;
+ sep = "";
+ if (nargs > 0)
+ {
+ infprintf (is, "%s", mips_gpr_names[4]);
+ if (nargs > 1)
+ infprintf (is, "-%s", mips_gpr_names[4 + nargs - 1]);
+ sep = ",";
+ }
- 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)
+ frame_size = ((extend & 0xf0) | (insn & 0x0f)) * 8;
+ if (frame_size == 0 && !use_extend)
+ frame_size = 128;
+ infprintf (is, "%s%d", sep, frame_size);
+
+ if (insn & 0x40) /* $ra */
+ infprintf (is, ",%s", mips_gpr_names[31]);
+
+ nsreg = (extend >> 8) & 0x7;
+ smask = 0;
+ if (insn & 0x20) /* $s0 */
+ smask |= 1 << 0;
+ if (insn & 0x10) /* $s1 */
+ smask |= 1 << 1;
+ if (nsreg > 0) /* $s2-$s8 */
+ smask |= ((1 << nsreg) - 1) << 2;
+
+ for (i = 0; i < 9; i++)
+ if (smask & (1 << i))
{
- info->insn_type = dis_dref;
- info->data_size = 4;
+ infprintf (is, ",%s", mips_gpr_names[i == 8 ? 30 : (16 + i)]);
+ /* Skip over string of set bits. */
+ for (j = i; smask & (2 << j); j++)
+ continue;
+ if (j > i)
+ infprintf (is, "-%s", mips_gpr_names[j == 8 ? 30 : (16 + j)]);
+ i = j + 1;
}
- 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:
- abort ();
- }
+ /* Statics $ax - $a3. */
+ if (nstatics == 1)
+ infprintf (is, ",%s", mips_gpr_names[7]);
+ else if (nstatics > 0)
+ infprintf (is, ",%s-%s",
+ mips_gpr_names[7 - nstatics + 1],
+ mips_gpr_names[7]);
+ break;
+ }
- if (! use_extend)
- {
- if (signedp && immed >= (1 << (nbits - 1)))
- immed -= 1 << nbits;
- immed <<= shift;
- if ((type == '<' || type == '>' || type == '[' || type == ']')
- && immed == 0)
- immed = 8;
- }
- else
- {
- if (extbits == 16)
- immed |= ((extend & 0x1f) << 11) | (extend & 0x7e0);
- else if (extbits == 15)
- immed |= ((extend & 0xf) << 11) | (extend & 0x7f0);
- else
- immed = ((extend >> 6) & 0x1f) | (extend & 0x20);
- immed &= (1 << extbits) - 1;
- if (! extu && immed >= (1 << (extbits - 1)))
- immed -= 1 << extbits;
- }
+ if (is_offset && operand->type == OP_INT)
+ {
+ const struct mips_int_operand *int_op;
- if (! pcrel)
- infprintf (is, "%d", immed);
- else
- {
- bfd_vma baseaddr;
+ int_op = (const struct mips_int_operand *) operand;
+ info->insn_type = dis_dref;
+ info->data_size = 1 << int_op->shift;
+ }
- 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
+ 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;
- }
- }
- 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)
- {
- args = 4;
- statics = 0;
- }
- else if (amask == MIPS16_ALL_STATICS)
- {
- args = 0;
- statics = 4;
- }
- else
- {
- args = amask >> 2;
- statics = amask & 3;
- }
-
- if (args > 0) {
- infprintf (is, "%s", mips_gpr_names[4]);
- if (args > 1)
- infprintf (is, "-%s", mips_gpr_names[4 + args - 1]);
- need_comma = 1;
- }
+ baseaddr = memaddr - 2;
+ else
+ baseaddr = memaddr;
+ }
+ }
- framesz = (((l >> 16) & 0xf0) | (l & 0x0f)) * 8;
- if (framesz == 0 && !use_extend)
- framesz = 128;
-
- infprintf (is, "%s%d", need_comma ? "," : "", framesz);
-
- if (l & 0x40) /* $ra */
- infprintf (is, ",%s", mips_gpr_names[31]);
-
- nsreg = (l >> 24) & 0x7;
- smask = 0;
- if (l & 0x20) /* $s0 */
- smask |= 1 << 0;
- if (l & 0x10) /* $s1 */
- smask |= 1 << 1;
- if (nsreg > 0) /* $s2-$s8 */
- smask |= ((1 << nsreg) - 1) << 2;
-
- /* Find first set static reg bit. */
- for (i = 0; i < 9; i++)
- {
- if (smask & (1 << i))
- {
- infprintf (is, ",%s", mips_gpr_names[i == 8 ? 30 : (16 + i)]);
- /* Skip over string of set bits. */
- for (j = i; smask & (2 << j); j++)
- continue;
- if (j > i)
- infprintf (is, "-%s", mips_gpr_names[j == 8 ? 30 : (16 + j)]);
- i = j + 1;
- }
- }
-
- /* Statics $ax - $a3. */
- if (statics == 1)
- infprintf (is, ",%s", mips_gpr_names[7]);
- else if (statics > 0)
- infprintf (is, ",%s-%s",
- mips_gpr_names[7 - statics + 1],
- mips_gpr_names[7]);
- }
+ print_insn_arg (info, state, opcode, operand, baseaddr, uval);
break;
-
- default:
- /* xgettext:c-format */
- infprintf (is,
- _("# internal disassembler error, "
- "unrecognised modifier (%c)"),
- type);
- abort ();
}
}
@@ -1859,6 +1600,7 @@ print_insn_mips16 (bfd_vma memaddr, struct disassemble_info *info)
bfd_boolean use_extend;
int extend = 0;
const struct mips_opcode *op, *opend;
+ struct mips_print_arg_state state;
void *is = info->stream;
info->bytes_per_chunk = 2;
@@ -1869,6 +1611,8 @@ print_insn_mips16 (bfd_vma memaddr, struct disassemble_info *info)
info->target = 0;
info->target2 = 0;
+#define GET_OP(insn, field) \
+ (((insn) >> MIPS16OP_SH_##field) & MIPS16OP_MASK_##field)
/* Decode PLT entry's GOT slot address word. */
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')
infprintf (is, "\t");
+ init_print_arg_state (&state);
for (s = op->args; *s != '\0'; s++)
{
if (*s == ','
@@ -1997,8 +1742,8 @@ print_insn_mips16 (bfd_vma memaddr, struct disassemble_info *info)
++s;
continue;
}
- print_mips16_insn_arg (*s, op, insn, use_extend, extend, memaddr,
- info);
+ print_mips16_insn_arg (info, &state, op, *s, memaddr, insn,
+ use_extend, extend, s[1] == '(');
}
/* 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;
}
}
-#undef GET_OP_S
#undef GET_OP
if (use_extend)
diff --git a/opcodes/mips16-opc.c b/opcodes/mips16-opc.c
index 1e03402..62d3e7f 100644
--- a/opcodes/mips16-opc.c
+++ b/opcodes/mips16-opc.c
@@ -23,6 +23,116 @@
#include "sysdep.h"
#include <stdio.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 table is intentionally identical to the one in mips-opc.c.