* mips.h: Assign 'm'/'M' codes to MIPS16e save/restore
authorThiemo Seufer <ths@networkno.de>
Mon, 14 Nov 2005 02:25:39 +0000 (02:25 +0000)
committerThiemo Seufer <ths@networkno.de>
Mon, 14 Nov 2005 02:25:39 +0000 (02:25 +0000)
        instructions.  Define MIPS16_ALL_ARGS and MIPS16_ALL_STATICS for
        save/restore encoding of the args field.

        * mips16-opc.c: Add MIPS16e save/restore opcodes.
        * mips-dis.c (print_mips16_insn_arg): Handle printing of 'm'/'M'
        codes for save/restore.

        * config/tc-mips.c (mips16_ip): Add handling of 'm' and 'M' codes
        for the MIPS16e save/restore instructions.

        * gas/mips/mips.exp: Run new save/restore tests.
        * gas/testsuite/gas/mips/mips16e-save.s: New test for generating
        different styles of save/restore instructions.
        * gas/testsuite/gas/mips/mips16e-save.d: New.

gas/ChangeLog
gas/config/tc-mips.c
gas/testsuite/ChangeLog
gas/testsuite/gas/mips/mips.exp
gas/testsuite/gas/mips/mips16e-save.d [new file with mode: 0644]
gas/testsuite/gas/mips/mips16e-save.s [new file with mode: 0644]
include/opcode/ChangeLog
include/opcode/mips.h
opcodes/ChangeLog
opcodes/mips-dis.c
opcodes/mips16-opc.c

index dc73bd3..4fda943 100644 (file)
@@ -1,3 +1,8 @@
+2005-11-14  David Ung  <davidu@mips.com>
+
+       * config/tc-mips.c (mips16_ip): Add handling of 'm' and 'M' codes
+       for the MIPS16e save/restore instructions.
+
 2005-11-11  Jan Beulich  <jbeulich@novell.com>
 
        * doc/Makefile.am: Make asconfig.texi writeable before trying
index 391f0be..4f1afea 100644 (file)
@@ -9303,6 +9303,8 @@ do_msbd:
     }
 }
 
+#define SKIP_SPACE_TABS(S) { while (*(S) == ' ' || *(S) == '\t') ++(S); }
+
 /* This routine assembles an instruction into its binary format when
    assembling for the mips16.  As a side effect, it sets one of the
    global variables imm_reloc or offset_reloc to the type of
@@ -9836,6 +9838,184 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
              }
            continue;
 
+           case 'm':           /* Register list for save insn.  */
+           case 'M':           /* Register list for restore insn.  */
+             {
+               int opcode = 0;
+               int framesz = 0, seen_framesz = 0;
+               int args = 0, statics = 0, sregs = 0;
+
+               while (*s != '\0')
+                 {
+                   unsigned int reg1, reg2;
+
+                   SKIP_SPACE_TABS (s);
+                   while (*s == ',')
+                     ++s;
+                   SKIP_SPACE_TABS (s);
+
+                   my_getExpression (&imm_expr, s);
+                   if (imm_expr.X_op == O_constant)
+                     {
+                       /* Handle the frame size.  */
+                       if (seen_framesz)
+                         {
+                           as_bad (_("more than one frame size in list"));
+                           break;
+                         }
+                       seen_framesz = 1;
+                       framesz = imm_expr.X_add_number;
+                       imm_expr.X_op = O_absent;
+                       s = expr_end;
+                       continue;
+                     }
+
+                   if (*s != '$')
+                     {
+                       as_bad (_("can't parse register list"));
+                       break;
+                     }
+                   ++s;
+
+                   reg1 = 0;
+                   while (ISDIGIT (*s))
+                     {
+                       reg1 *= 10;
+                       reg1 += *s - '0';
+                       ++s;
+                     }
+                   SKIP_SPACE_TABS (s);
+                   if (*s != '-')
+                     reg2 = reg1;
+                   else
+                     {
+                       ++s;
+                       if (*s != '$')
+                         {
+                           as_bad (_("can't parse register list"));
+                           break;
+                         }
+                       ++s;
+                       reg2 = 0;
+                       while (ISDIGIT (*s))
+                         {
+                           reg2 *= 10;
+                           reg2 += *s - '0';
+                           ++s;
+                         }
+                     }
+
+                   while (reg1 <= reg2)
+                     {
+                       if (reg1 >= 4 && reg1 <= 7)
+                         {
+                           if (c == 'm' && !seen_framesz)
+                               /* args $a0-$a3 */
+                               args |= 1 << (reg1 - 4);
+                           else
+                               /* statics $a0-$a3 */
+                               statics |= 1 << (reg1 - 4);
+                         }
+                       else if ((reg1 >= 16 && reg1 <= 23) || reg1 == 30)
+                         {
+                           /* $s0-$s8 */
+                           sregs |= 1 << ((reg1 == 30) ? 8 : (reg1 - 16));
+                         }
+                       else if (reg1 == 31)
+                         {
+                           /* Add $ra to insn.  */
+                           opcode |= 0x40;
+                         }
+                       else
+                         {
+                           as_bad (_("unexpected register in list"));
+                           break;
+                         }
+                       if (++reg1 == 24)
+                         reg1 = 30;
+                     }
+                 }
+
+               /* Encode args/statics combination.  */
+               if (args & statics)
+                 as_bad (_("arg/static registers overlap"));
+               else if (args == 0xf)
+                 /* All $a0-$a3 are args.  */
+                 opcode |= MIPS16_ALL_ARGS << 16;
+               else if (statics == 0xf)
+                 /* All $a0-$a3 are statics.  */
+                 opcode |= MIPS16_ALL_STATICS << 16;
+               else 
+                 {
+                   int narg = 0, nstat = 0;
+
+                   /* Count arg registers.  */
+                   while (args & 0x1)
+                     {
+                       args >>= 1;
+                       narg++;
+                     }
+                   if (args != 0)
+                     as_bad (_("invalid arg register list"));
+
+                   /* Count static registers.  */
+                   while (statics & 0x8)
+                     {
+                       statics = (statics << 1) & 0xf;
+                       nstat++;
+                     }
+                   if (statics != 0) 
+                     as_bad (_("invalid static register list"));
+
+                   /* Encode args/statics.  */
+                   opcode |= ((narg << 2) | nstat) << 16;
+                 }
+
+               /* Encode $s0/$s1.  */
+               if (sregs & (1 << 0))           /* $s0 */
+                 opcode |= 0x20;
+               if (sregs & (1 << 1))           /* $s1 */
+                 opcode |= 0x10;
+               sregs >>= 2;
+
+               if (sregs != 0)
+                 {
+                   /* Count regs $s2-$s8.  */
+                   int nsreg = 0;
+                   while (sregs & 1)
+                     {
+                       sregs >>= 1;
+                       nsreg++;
+                     }
+                   if (sregs != 0)
+                     as_bad (_("invalid static register list"));
+                   /* Encode $s2-$s8. */
+                   opcode |= nsreg << 24;
+                 }
+
+               /* Encode frame size.  */
+               if (!seen_framesz)
+                 as_bad (_("missing frame size"));
+               else if ((framesz & 7) != 0 || framesz < 0
+                        || framesz > 0xff * 8)
+                 as_bad (_("invalid frame size"));
+               else if (framesz != 128 || (opcode >> 16) != 0)
+                 {
+                   framesz /= 8;
+                   opcode |= (((framesz & 0xf0) << 16)
+                            | (framesz & 0x0f));
+                 }
+
+               /* Finally build the instruction.  */
+               if ((opcode >> 16) != 0 || framesz == 0)
+                 {
+                   ip->use_extend = TRUE;
+                   ip->extend = opcode >> 16;
+                 }
+               ip->insn_opcode |= opcode & 0x7f;
+             }
+           continue;
+
            case 'e':           /* extend code */
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
index eb0881e..275efde 100644 (file)
@@ -1,3 +1,10 @@
+2005-11-14  David Ung  <davidu@mips.com>
+
+       * gas/mips/mips.exp: Run new save/restore tests.
+       * gas/testsuite/gas/mips/mips16e-save.s: New test for generating
+       different styles of save/restore instructions.
+       * gas/testsuite/gas/mips/mips16e-save.d: New.
+
 2005-11-10  Jan Beulich  <jbeulich@novell.com>
 
        * gas/i386/intelbad.d: Add tests for ill registers in brackets.
index c787e4f..174aea4 100644 (file)
@@ -771,5 +771,8 @@ if { [istarget mips*-*-*] } then {
            run_dump_test "mips16-dwarf2-n32"
        }
     }
-    if { !$no_mips16 } { run_dump_test "mips16e-jrc" }
+    if { !$no_mips16 } { 
+        run_dump_test "mips16e-jrc"
+        run_dump_test "mips16e-save"
+    }
 }
diff --git a/gas/testsuite/gas/mips/mips16e-save.d b/gas/testsuite/gas/mips/mips16e-save.d
new file mode 100644 (file)
index 0000000..7bc0b99
--- /dev/null
@@ -0,0 +1,43 @@
+#objdump: -dr -mmips:isa32 -mmips:16
+#as: -march=mips32 -mips16
+#name: mips16e save/restore
+
+.*: +file format .*mips.*
+
+Disassembly of section .text:
+00000000 <func>:
+   0:[         ]+6481[         ]+save[         ]+8
+   2:[         ]+64c2[         ]+save[         ]+16,ra
+   4:[         ]+64a3[         ]+save[         ]+24,s0
+   6:[         ]+6494[         ]+save[         ]+32,s1
+   8:[         ]+64b5[         ]+save[         ]+40,s0-s1
+   a:[         ]+64e6[         ]+save[         ]+48,ra,s0
+   c:[         ]+64d7[         ]+save[         ]+56,ra,s1
+   e:[         ]+64f8[         ]+save[         ]+64,ra,s0-s1
+  10:[         ]+64f9[         ]+save[         ]+72,ra,s0-s1
+  12:[         ]+64fa[         ]+save[         ]+80,ra,s0-s1
+  14:[         ]+64fb[         ]+save[         ]+88,ra,s0-s1
+  16:[         ]+64f0[         ]+save[         ]+128,ra,s0-s1
+  18:[         ]+f010 6481[    ]+save[         ]+136
+  1c:[         ]+f010 64c2[    ]+save[         ]+144,ra
+  20:[         ]+f010 64b3[    ]+save[         ]+152,s0-s1
+  24:[         ]+f100 6488[    ]+save[         ]+64,s2
+  28:[         ]+f600 6489[    ]+save[         ]+72,s2-s7
+  2c:[         ]+f700 648a[    ]+save[         ]+80,s2-s8
+  30:[         ]+f700 64bb[    ]+save[         ]+88,s0-s8
+  34:[         ]+f001 6488[    ]+save[         ]+64,a3
+  38:[         ]+f012 6480[    ]+save[         ]+128,a2-a3
+  3c:[         ]+f02b 6480[    ]+save[         ]+256,a0-a3
+  40:[         ]+f024 6480[    ]+save[         ]+a0,256
+  44:[         ]+f018 6480[    ]+save[         ]+a0-a1,128
+  48:[         ]+f00e 6488[    ]+save[         ]+a0-a3,64
+  4c:[         ]+f015 6480[    ]+save[         ]+a0,128,a3
+  50:[         ]+f017 6480[    ]+save[         ]+a0,128,a1-a3
+  54:[         ]+f01a 6480[    ]+save[         ]+a0-a1,128,a2-a3
+  58:[         ]+f01d 6480[    ]+save[         ]+a0-a2,128,a3
+  5c:[         ]+f71a 64f0[    ]+save[         ]+a0-a1,128,ra,s0-s8,a2-a3
+  60:[         ]+6470[         ]+restore[      ]+128,ra,s0-s1
+  62:[         ]+f010 6441[    ]+restore[      ]+136,ra
+  66:[         ]+f100 6408[    ]+restore[      ]+64,s2
+  6a:[         ]+f71b 6470[    ]+restore[      ]+128,ra,s0-s8,a0-a3
+  6e:[         ]+6500[         ]+nop
diff --git a/gas/testsuite/gas/mips/mips16e-save.s b/gas/testsuite/gas/mips/mips16e-save.s
new file mode 100644 (file)
index 0000000..b982cc7
--- /dev/null
@@ -0,0 +1,55 @@
+# Test the generation of the mips16e save instruction
+
+       .set    mips16
+       .text
+func:
+# Un-extended version
+       save    8
+       save    $31,16
+       save    $16,24
+       save    $17,32
+       save    $16-$17,40
+       save    $31,$16,48
+       save    $31,$17,56
+       save    $31,$16,$17,64
+       save    $31,$16-$17,72
+       save    80,$31,$16-$17
+       save    $31,88,$16,$17
+       save    $31,$17,128,$16
+
+# Extended version
+       save    136
+       save    $31,144
+       save    $16-$17,152
+
+       # sreg
+       save    $18,64
+       save    $18-$23,72
+       save    $18-$23,$30,80
+       save    $16-$23,$30,88
+       
+       # static areg
+       save    64,$7
+       save    128,$7,$6
+       save    256,$7,$6,$5,$4
+
+       # areg
+       save    $4,256
+       save    $4,$5,128
+       save    $4,$5,$6,$7,64
+
+       # mix areg and static areg
+       save    $4,128,$7
+       save    $4,128,$7,$6,$5
+       save    $4,$5,128,$7,$6
+       save    $4,$5,$6,128,$7
+
+       save    $4-$5,$16-$23,$30-$31,128,$6-$7
+
+       restore $16,$17,$31,128
+       restore $31,136
+       restore $18,64
+       restore $4-$5,$16-$23,$30-$31,128,$6-$7
+       
+        .p2align 4
+
index a282a62..c9a4a12 100644 (file)
@@ -1,3 +1,9 @@
+2005-11-14  David Ung  <davidu@mips.com>
+
+       * mips.h: Assign 'm'/'M' codes to MIPS16e save/restore
+       instructions.  Define MIPS16_ALL_ARGS and MIPS16_ALL_STATICS for
+       save/restore encoding of the args field.
+
 2005-10-28  Dave Brolley  <brolley@redhat.com>
 
        Contribute the following changes:
index e46ba2c..4bec5ed 100644 (file)
@@ -928,7 +928,14 @@ extern int bfd_mips_num_opcodes;
    "A" 8 bit PC relative address * 4 (MIPS16OP_*_IMM8)
    "B" 5 bit PC relative address * 8 (MIPS16OP_*_IMM5)
    "E" 5 bit PC relative address * 4 (MIPS16OP_*_IMM5)
-   */
+   "m" 7 bit register list for save instruction (18 bit extended)
+   "M" 7 bit register list for restore instruction (18 bit extended)
+  */
+
+/* Save/restore encoding for the args field when all 4 registers are
+   either saved as arguments or saved/restored as statics.  */
+#define MIPS16_ALL_ARGS    0xe
+#define MIPS16_ALL_STATICS 0xb
 
 /* For the mips16, we use the same opcode table format and a few of
    the same flags.  However, most of the flags are different.  */
index aa14a3d..aebe716 100644 (file)
@@ -1,3 +1,9 @@
+2005-11-14  David Ung  <davidu@mips.com>
+
+       * mips16-opc.c: Add MIPS16e save/restore opcodes.
+       * mips-dis.c (print_mips16_insn_arg): Handle printing of 'm'/'M'
+       codes for save/restore.
+
 2005-11-10  Andreas Schwab  <schwab@suse.de>
 
        * m68k-dis.c (print_insn_m68k): Only match FPU insns with
index 21f20fb..9a48d86 100644 (file)
@@ -1656,6 +1656,92 @@ print_mips16_insn_arg (char type,
       }
       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) {
+          (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[4]);
+          if (args > 1)
+            (*info->fprintf_func) (info->stream, "-%s",
+                                   mips_gpr_names[4 + args - 1]);
+          need_comma = 1;
+      }
+
+      framesz = (((l >> 16) & 0xf0) | (l & 0x0f)) * 8;
+      if (framesz == 0 && !use_extend)
+        framesz = 128;
+
+      (*info->fprintf_func) (info->stream, "%s%d", 
+                             need_comma ? "," : "",
+                             framesz);
+
+      if (l & 0x40)                   /* $ra */
+        (*info->fprintf_func) (info->stream, ",%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))
+            {
+              (*info->fprintf_func) (info->stream, ",%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)
+                (*info->fprintf_func) (info->stream, "-%s",
+                                       mips_gpr_names[j == 8 ? 30 : (16 + j)]);
+              i = j + 1;
+            }
+        }
+
+      /* Statics $ax - $a3.  */
+      if (statics == 1)
+        (*info->fprintf_func) (info->stream, ",%s", mips_gpr_names[7]);
+      else if (statics > 0) 
+        (*info->fprintf_func) (info->stream, ",%s-%s", 
+                               mips_gpr_names[7 - statics + 1],
+                               mips_gpr_names[7]);
+      }
+      break;
+
     default:
       /* xgettext:c-format */
       (*info->fprintf_func)
index 0459582..4e5ae44 100644 (file)
@@ -226,6 +226,8 @@ const struct mips_opcode mips16_opcodes[] =
 {"jalrc",   "R,x",     0xe8c0, 0xf8ff, WR_31|RD_x|TRAP, 0,     0 },
 {"jrc",     "x",       0xe880, 0xf8ff, RD_x|TRAP,      0,      0 },
 {"jrc",     "R",       0xe8a0, 0xffff, RD_31|TRAP,     0,      0 },
+{"restore", "M",       0x6400, 0xff80, WR_31|RD_SP|WR_SP|TRAP, 0,      0 },
+{"save",    "m",       0x6480, 0xff80, RD_31|RD_SP|WR_SP|TRAP, 0,      0 },
 {"seb",            "x",        0xe891, 0xf8ff, WR_x|RD_x,      0,      0 },
 {"seh",            "x",        0xe8b1, 0xf8ff, WR_x|RD_x,      0,      0 },
 {"sew",            "x",        0xe8d1, 0xf8ff, WR_x|RD_x,      0,      I3 },