From c3c0747817f456c7d4a5d8884b304c2095bdf5ab Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Sun, 14 Jul 2013 13:36:51 +0000 Subject: [PATCH] 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. --- include/opcode/ChangeLog | 6 + include/opcode/mips.h | 8 + opcodes/ChangeLog | 14 + opcodes/mips-dis.c | 664 ++++++++++++--------------------------- opcodes/mips16-opc.c | 110 +++++++ 5 files changed, 342 insertions(+), 460 deletions(-) diff --git a/include/opcode/ChangeLog b/include/opcode/ChangeLog index fc991a01e4c..25f88bedb3c 100644 --- a/include/opcode/ChangeLog +++ b/include/opcode/ChangeLog @@ -1,3 +1,9 @@ +2013-07-14 Richard Sandiford + + * mips.h (mips_operand_type): Add OP_ENTRY_EXIT_LIST and + OP_SAVE_RESTORE_LIST. + (decode_mips16_operand): Declare. + 2013-07-14 Richard Sandiford * mips.h (mips_operand_type, mips_reg_operand_type): New enums. diff --git a/include/opcode/mips.h b/include/opcode/mips.h index 2d77b959408..e2f72e0b019 100644 --- a/include/opcode/mips.h +++ b/include/opcode/mips.h @@ -375,6 +375,13 @@ enum mips_operand_type { size determines whether the 16-bit or 32-bit encoding is required. */ 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: V Meaning @@ -1680,6 +1687,7 @@ extern int bfd_mips_num_opcodes; FP_D (never used) */ +extern const struct mips_operand *decode_mips16_operand (char, bfd_boolean); extern const struct mips_opcode mips16_opcodes[]; extern const int bfd_mips16_num_opcodes; diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog index 17cc1c6d49c..5ac2b28307f 100644 --- a/opcodes/ChangeLog +++ b/opcodes/ChangeLog @@ -1,3 +1,17 @@ +2013-07-14 Richard Sandiford + + * 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 * mips-formats.h: New file. diff --git a/opcodes/mips-dis.c b/opcodes/mips-dis.c index cd7c63387d5..03333bfd954 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 1e034021171..62d3e7f018a 100644 --- a/opcodes/mips16-opc.c +++ b/opcodes/mips16-opc.c @@ -23,6 +23,116 @@ #include "sysdep.h" #include #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. -- 2.30.2