include/opcode/
authorRichard Sandiford <rdsandiford@googlemail.com>
Sun, 14 Jul 2013 13:36:51 +0000 (13:36 +0000)
committerRichard Sandiford <rdsandiford@googlemail.com>
Sun, 14 Jul 2013 13:36:51 +0000 (13:36 +0000)
* 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
include/opcode/mips.h
opcodes/ChangeLog
opcodes/mips-dis.c
opcodes/mips16-opc.c

index fc991a0..25f88be 100644 (file)
@@ -1,5 +1,11 @@
 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>
+
        * mips.h (mips_operand_type, mips_reg_operand_type): New enums.
        (mips_operand, mips_int_operand, mips_mapped_int_operand)
        (mips_msb_operand, mips_reg_operand, mips_reg_pair_operand)
index 2d77b95..e2f72e0 100644 (file)
@@ -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;
 
index 17cc1c6..5ac2b28 100644 (file)
@@ -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.
index cd7c633..03333bf 100644 (file)
@@ -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)
index 1e03402..62d3e7f 100644 (file)
 #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.