[Patch] MIPS: Add mips16e save/restore instruction support.

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

[Patch] MIPS: Add mips16e save/restore instruction support.

David Ung

This patch adds the MIPS16e save/restore instructions to the opcode
table, dissambler and gas.  The codes "m" and "M" are created for the
new args field for save and restore  respetively.
Test case also attached.  For detailed description of these instruction,
please refer to the MIPS16e ASE Reference manuals.
Support in GCC to generate these instructions will be post to
gcc-patches when mainline reopens again.
gas regressions ok.  

David.

        * mips.h: Assign 'm'/'M' codes to MIPS16e save/restore instructions.

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

Index: include/opcode/mips.h
===================================================================
RCS file: /cvs/src/src/include/opcode/mips.h,v
retrieving revision 1.45
diff -c -p -b -r1.45 mips.h
*** include/opcode/mips.h 6 Sep 2005 18:42:58 -0000 1.45
--- include/opcode/mips.h 20 Oct 2005 13:37:44 -0000
*************** extern int bfd_mips_num_opcodes;
*** 928,933 ****
--- 928,935 ----
     "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)
     */
 
  /* For the mips16, we use the same opcode table format and a few of

Index: opcodes/mips16-opc.c
===================================================================
RCS file: /cvs/src/src/opcodes/mips16-opc.c,v
retrieving revision 1.9
diff -c -p -b -r1.9 mips16-opc.c
*** opcodes/mips16-opc.c 23 Aug 2005 11:06:10 -0000 1.9
--- opcodes/mips16-opc.c 20 Oct 2005 13:42:42 -0000
*************** const struct mips_opcode mips16_opcodes[
*** 226,231 ****
--- 226,233 ----
  {"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 },

Index: gas/config/tc-mips.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-mips.c,v
retrieving revision 1.324
diff -c -p -b -r1.324 tc-mips.c
*** gas/config/tc-mips.c 19 Oct 2005 18:47:09 -0000 1.324
--- gas/config/tc-mips.c 20 Oct 2005 13:36:38 -0000
*************** mips16_ip (char *str, struct mips_cl_ins
*** 9836,9841 ****
--- 9836,10013 ----
       }
     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, astatics = 0, sregs = 0;
+
+ while (*s != '\0')
+  {
+    unsigned int reg1, reg2;
+
+    while (*s == ' ' || *s == ',')
+      ++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;
+      }
+    if (*s == ' ')
+      ++s;
+    if (*s != '-')
+      reg2 = reg1;
+    else
+      {
+ ++s;
+ if (*s == '$')
+  ++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
+ /* a-static $a0-$a3 */
+ astatics |= 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/astatic combination.  */
+ if (args & astatics)
+  as_bad ("arg/static registers overlap");
+ else if (args == 0xf)
+  /* All $a0-$a3 are args.  */
+  opcode |= 0xe << 16;
+ else if (astatics == 0xf)
+  /* All $a0-$a3 are a-statics.  */
+  opcode |= 0xb << 16;
+ else
+  {
+    int narg = 0, nastat = 0;
+
+    /* Count arg registers.  */
+    while (args & 0x1)
+      {
+ args >>= 1;
+ narg++;
+      }
+    if (args != 0)
+      as_bad ("invalid arg register list");
+
+    /* Count astatic registers.  */
+    while (astatics & 0x8)
+      {
+ astatics = (astatics << 1) & 0xf;
+ nastat++;
+      }
+    if (astatics != 0)
+      as_bad ("invalid a-static register list");
+
+    /* Encode args/astatic.  */
+    opcode |= ((narg << 2) | nastat) << 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: opcodes/mips-dis.c
===================================================================
RCS file: /cvs/src/src/opcodes/mips-dis.c,v
retrieving revision 1.54
diff -c -p -b -r1.54 mips-dis.c
*** opcodes/mips-dis.c 6 Sep 2005 18:46:57 -0000 1.54
--- opcodes/mips-dis.c 20 Oct 2005 13:41:50 -0000
*************** print_mips16_insn_arg (char type,
*** 1656,1661 ****
--- 1656,1747 ----
        }
        break;
 
+     case 'm':
+     case 'M':
+       /* MIPS16e save/restore.  */
+       {
+ int need_comma = 0;
+ int amask, args, astatic;
+ int nsreg, smask;
+ int framesz;
+ int i, j;
+
+ l = l & 0x7f;
+ if (use_extend)
+  l |= extend << 16;
+
+ amask = (l >> 16) & 0xf;
+ if (amask == 0xe)
+  {
+    args = 4;
+    astatic = 0;
+  }
+ else if (amask == 0x0b)
+  {
+    args = 0;
+    astatic = 4;
+  }
+ else
+  {
+    args = amask >> 2;
+    astatic = 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 (astatic == 1)
+  (*info->fprintf_func) (info->stream, ",%s", mips_gpr_names[7]);
+ else if (astatic > 0)
+  (*info->fprintf_func) (info->stream, ",%s-%s",
+ mips_gpr_names[7 - astatic + 1],
+ mips_gpr_names[7]);
+       }
+       break;
+
      default:
        /* xgettext:c-format */
        (*info->fprintf_func)

Index: gas/testsuite/gas/mips/mips.exp
===================================================================
RCS file: /cvs/src/src/gas/testsuite/gas/mips/mips.exp,v
retrieving revision 1.110
diff -c -p -b -r1.110 mips.exp
*** gas/testsuite/gas/mips/mips.exp 19 Oct 2005 18:47:09 -0000 1.110
--- gas/testsuite/gas/mips/mips.exp 20 Oct 2005 13:39:56 -0000
*************** if { [istarget mips*-*-*] } then {
*** 771,775 ****
     run_dump_test "mips16-dwarf2-n32"
  }
      }
!     if { !$no_mips16 } { run_dump_test "mips16e-jrc" }
  }
--- 771,778 ----
     run_dump_test "mips16-dwarf2-n32"
  }
      }
!     if { !$no_mips16 } {
!         run_dump_test "mips16e-jrc"
!         run_dump_test "mips16e-save"
!     }
  }

Index: gas/testsuite/gas/mips/mips16e-save.s
===================================================================
# 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: gas/testsuite/gas/mips/mips16e-save.s
===================================================================
#objdump: -dr -mmips:isa32 -mmips:16
#as: -march=mips32 -mips16
#name: mips16e save/restore
.*:     file format .*
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

Reply | Threaded
Open this post in threaded view
|

Re: [Patch] MIPS: Add mips16e save/restore instruction support.

Thiemo Seufer
David Ung wrote:
>
> This patch adds the MIPS16e save/restore instructions to the opcode
> table, dissambler and gas.
[snip]

> Index: gas/config/tc-mips.c
> ===================================================================
> RCS file: /cvs/src/src/gas/config/tc-mips.c,v
> retrieving revision 1.324
> diff -c -p -b -r1.324 tc-mips.c
> *** gas/config/tc-mips.c 19 Oct 2005 18:47:09 -0000 1.324
> --- gas/config/tc-mips.c 20 Oct 2005 13:36:38 -0000
> *************** mips16_ip (char *str, struct mips_cl_ins
> *** 9836,9841 ****
> --- 9836,10013 ----
>        }
>      continue;
>  
> +    case 'm': /* register list for save insn */
> +    case 'M': /* register list for restore insn */

Comment formatting.

> +      {
> + int opcode = 0;
> + int framesz = 0, seen_framesz = 0;
> + int args = 0, astatics = 0, sregs = 0;
> +
> + while (*s != '\0')
> +  {
> +    unsigned int reg1, reg2;
> +
> +    while (*s == ' ' || *s == ',')
> +      ++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");

Should be i18n: as_bad (_("... , there are more such instances further
down.

[snip]
> + /* Encode args/astatic combination.  */
> + if (args & astatics)
> +  as_bad ("arg/static registers overlap");
> + else if (args == 0xf)
> +  /* All $a0-$a3 are args.  */
> +  opcode |= 0xe << 16;
> + else if (astatics == 0xf)
> +  /* All $a0-$a3 are a-statics.  */

Now, how is it called, "astatic", "static" or "a-static"? Consistent
naming would be good. I also dislike the magic constants showing up
here.


Thiemo
Reply | Threaded
Open this post in threaded view
|

Re: [Patch] MIPS: Add mips16e save/restore instruction support.

David Ung


> > +    case 'm': /* register list for save insn */
> > +    case 'M': /* register list for restore insn */
>
> Comment formatting.

ok..  although I thought I was consistent with the 'l','L' cases from
above.
anyway, I have reformatted it.

> > + if (seen_framesz)
> > +  {
> > +    as_bad ("more than one frame size in list");
>
> Should be i18n: as_bad (_("... , there are more such instances further
> down.

ok.

> > + /* Encode args/astatic combination.  */
> > + if (args & astatics)
> > +  as_bad ("arg/static registers overlap");
> > + else if (args == 0xf)
> > +  /* All $a0-$a3 are args.  */
> > +  opcode |= 0xe << 16;
> > + else if (astatics == 0xf)
> > +  /* All $a0-$a3 are a-statics.  */
>
> Now, how is it called, "astatic", "static" or "a-static"? Consistent
> naming would be good. I also dislike the magic constants showing up
> here.

ok, only "statics" is used for both variable and comments now.
I've also now put the magic constants into opcodes/mips.h as
MIPS16_ALL_ARGS amd MIPS16_ALL_STATICS.
new patch below.  regressions ok.

David.

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

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

Index: include/opcode/mips.h
===================================================================
RCS file: /cvs/src/src/include/opcode/mips.h,v
retrieving revision 1.45
diff -c -p -b -r1.45 mips.h
*** include/opcode/mips.h       6 Sep 2005 18:42:58 -0000       1.45
--- include/opcode/mips.h       20 Oct 2005 13:37:44 -0000
*************** extern int bfd_mips_num_opcodes;
*** 928,933 ****
--- 928,935 ----
     "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: opcodes/mips16-opc.c
===================================================================
RCS file: /cvs/src/src/opcodes/mips16-opc.c,v
retrieving revision 1.9
diff -c -p -b -r1.9 mips16-opc.c
*** opcodes/mips16-opc.c        23 Aug 2005 11:06:10 -0000      1.9
--- opcodes/mips16-opc.c        20 Oct 2005 13:42:42 -0000
*************** const struct mips_opcode mips16_opcodes[
*** 226,231 ****
--- 226,233 ----
  {"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 },

Index: gas/config/tc-mips.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-mips.c,v
retrieving revision 1.325
diff -c -p -b -r1.325 tc-mips.c
*** gas/config/tc-mips.c 1 Nov 2005 01:59:28 -0000 1.325
--- gas/config/tc-mips.c 3 Nov 2005 17:39:48 -0000
*************** mips16_ip (char *str, struct mips_cl_ins
*** 9836,9841 ****
--- 9836,10013 ----
       }
     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;
+
+    while (*s == ' ' || *s == ',')
+      ++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;
+      }
+    if (*s == ' ')
+      ++s;
+    if (*s != '-')
+      reg2 = reg1;
+    else
+      {
+ ++s;
+ if (*s == '$')
+  ++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/tatics 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: opcodes/mips-dis.c
===================================================================
RCS file: /cvs/src/src/opcodes/mips-dis.c,v
retrieving revision 1.54
diff -c -p -b -r1.54 mips-dis.c
*** opcodes/mips-dis.c 6 Sep 2005 18:46:57 -0000 1.54
--- opcodes/mips-dis.c 3 Nov 2005 17:42:27 -0000
*************** print_mips16_insn_arg (char type,
*** 1656,1661 ****
--- 1656,1747 ----
        }
        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: gas/testsuite/gas/mips/mips.exp
===================================================================
RCS file: /cvs/src/src/gas/testsuite/gas/mips/mips.exp,v
retrieving revision 1.110
diff -c -p -b -r1.110 mips.exp
*** gas/testsuite/gas/mips/mips.exp     19 Oct 2005 18:47:09 -0000      1.110
--- gas/testsuite/gas/mips/mips.exp     20 Oct 2005 13:39:56 -0000
*************** if { [istarget mips*-*-*] } then {
*** 771,775 ****
            run_dump_test "mips16-dwarf2-n32"
        }
      }
!     if { !$no_mips16 } { run_dump_test "mips16e-jrc" }
  }
--- 771,778 ----
            run_dump_test "mips16-dwarf2-n32"
        }
      }
!     if { !$no_mips16 } {
!         run_dump_test "mips16e-jrc"
!         run_dump_test "mips16e-save"
!     }
  }

Index: gas/testsuite/gas/mips/mips16e-save.s
===================================================================
# 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: gas/testsuite/gas/mips/mips16e-save.s
===================================================================
#objdump: -dr -mmips:isa32 -mmips:16
#as: -march=mips32 -mips16
#name: mips16e save/restore
.*:     file format .*
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

Reply | Threaded
Open this post in threaded view
|

Re: [Patch] MIPS: Add mips16e save/restore instruction support.

Thiemo Seufer
David Ung wrote:
[snip]

> *** gas/config/tc-mips.c 1 Nov 2005 01:59:28 -0000 1.325
> --- gas/config/tc-mips.c 3 Nov 2005 17:39:48 -0000
> *************** mips16_ip (char *str, struct mips_cl_ins
> *** 9836,9841 ****
> --- 9836,10013 ----
>        }
>      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;
> +
> +    while (*s == ' ' || *s == ',')
> +      ++s;

This could also see \t, and multiple ',' are an error, I think.

        SKIP_WHITESPACE ();
        if (*s == ',')
          ++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;
> +      }
> +    if (*s == ' ')
> +      ++s;

        SKIP_WHITESPACE();

> +    if (*s != '-')
> +      reg2 = reg1;
> +    else
> +      {
> + ++s;
> + if (*s == '$')
> +  ++s;

Is this '$' really meant to be optional?

> + 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/tatics combination.  */

Typo.

[snip]
> *** opcodes/mips-dis.c 6 Sep 2005 18:46:57 -0000 1.54
> --- opcodes/mips-dis.c 3 Nov 2005 17:42:27 -0000
> *************** print_mips16_insn_arg (char type,
[snip]
> +  (*info->fprintf_func) (info->stream, "-%s",
> + mips_gpr_names[j == 8 ? 30 : (16 + j)]);
> + i = j + 1;
> +      }
> +  }
> +
> + /* Statics $ax - $a3.  */

$ax ?


Thiemo
Reply | Threaded
Open this post in threaded view
|

Re: [Patch] MIPS: Add mips16e save/restore instruction support.

David Ung

> > +
> > + while (*s != '\0')
> > +  {
> > +    unsigned int reg1, reg2;
> > +
> > +    while (*s == ' ' || *s == ',')
> > +      ++s;
>
> This could also see \t, and multiple ',' are an error, I think.
>
> SKIP_WHITESPACE ();
> if (*s == ',')
>  ++s;

SKIP_WHITESPACE only skips ' ', not \t and it only skip one ' '.
The above code won't handle " , ".  Ideally it should look like
 
#define SKIP_SPACE_TABS(S) { while (*S == ' ' || *S == '\t') ++S; }

  SKIP_SPACE_TABS (s);
  if (*s == ',')
    ++s;
  SKIP_SPACE_TABS (s);

> > +    if (*s != '-')
> > +      reg2 = reg1;
> > +    else
> > +      {
> > + ++s;
> > + if (*s == '$')
> > +  ++s;
>
> Is this '$' really meant to be optional?

The manual uses names like a0-a3. So I guess making it strictly having $
on hard register numbers would be ok.

> > *** opcodes/mips-dis.c 6 Sep 2005 18:46:57 -0000 1.54
> > --- opcodes/mips-dis.c 3 Nov 2005 17:42:27 -0000
> > *************** print_mips16_insn_arg (char type,
> [snip]
> > +  (*info->fprintf_func) (info->stream, "-%s",
> > + mips_gpr_names[j == 8 ? 30 : (16 + j)]);
> > + i = j + 1;
> > +      }
> > +  }
> > +
> > + /* Statics $ax - $a3.  */
>
> $ax ?

This is correct.  For statics, it goes backwards starting from $a3
towards $a0.

revised patch attached.

David.

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

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

Index: include/opcode/mips.h
===================================================================
RCS file: /cvs/src/src/include/opcode/mips.h,v
retrieving revision 1.45
diff -c -p -b -r1.45 mips.h
*** include/opcode/mips.h       6 Sep 2005 18:42:58 -0000       1.45
--- include/opcode/mips.h       20 Oct 2005 13:37:44 -0000
*************** extern int bfd_mips_num_opcodes;
*** 928,933 ****
--- 928,935 ----
     "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: opcodes/mips16-opc.c
===================================================================
RCS file: /cvs/src/src/opcodes/mips16-opc.c,v
retrieving revision 1.9
diff -c -p -b -r1.9 mips16-opc.c
*** opcodes/mips16-opc.c        23 Aug 2005 11:06:10 -0000      1.9
--- opcodes/mips16-opc.c        20 Oct 2005 13:42:42 -0000
*************** const struct mips_opcode mips16_opcodes[
*** 226,231 ****
--- 226,233 ----
  {"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 },

Index: gas/config/tc-mips.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-mips.c,v
retrieving revision 1.325
diff -c -p -b -r1.325 tc-mips.c
*** gas/config/tc-mips.c 1 Nov 2005 01:59:28 -0000 1.325
--- gas/config/tc-mips.c 9 Nov 2005 14:31:25 -0000
*************** do_msbd:
*** 9303,9308 ****
--- 9303,9310 ----
      }
  }
 
+ #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
*************** mips16_ip (char *str, struct mips_cl_ins
*** 9836,9841 ****
--- 9838,10021 ----
       }
     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: opcodes/mips-dis.c
===================================================================
RCS file: /cvs/src/src/opcodes/mips-dis.c,v
retrieving revision 1.54
diff -c -p -b -r1.54 mips-dis.c
*** opcodes/mips-dis.c  6 Sep 2005 18:46:57 -0000       1.54
--- opcodes/mips-dis.c  3 Nov 2005 17:42:27 -0000
*************** print_mips16_insn_arg (char type,
*** 1656,1661 ****
--- 1656,1747 ----
        }
        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: gas/testsuite/gas/mips/mips.exp
===================================================================
RCS file: /cvs/src/src/gas/testsuite/gas/mips/mips.exp,v
retrieving revision 1.110
diff -c -p -b -r1.110 mips.exp
*** gas/testsuite/gas/mips/mips.exp     19 Oct 2005 18:47:09 -0000      1.110
--- gas/testsuite/gas/mips/mips.exp     20 Oct 2005 13:39:56 -0000
*************** if { [istarget mips*-*-*] } then {
*** 771,775 ****
            run_dump_test "mips16-dwarf2-n32"
        }
      }
!     if { !$no_mips16 } { run_dump_test "mips16e-jrc" }
  }
--- 771,778 ----
            run_dump_test "mips16-dwarf2-n32"
        }
      }
!     if { !$no_mips16 } {
!         run_dump_test "mips16e-jrc"
!         run_dump_test "mips16e-save"
!     }
  }

Index: gas/testsuite/gas/mips/mips16e-save.s
===================================================================
# 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: gas/testsuite/gas/mips/mips16e-save.d
===================================================================
#objdump: -dr -mmips:isa32 -mmips:16
#as: -march=mips32 -mips16
#name: mips16e save/restore
.*:     file format .*
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

Reply | Threaded
Open this post in threaded view
|

Re: [Patch] MIPS: Add mips16e save/restore instruction support.

Thiemo Seufer
David Ung wrote:
[snip]

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

Approved and applied with minimal changes:

[snip]
> + #define SKIP_SPACE_TABS(S) { while (*S == ' ' || *S == '\t') ++S; }
> +

Parentheses around the argument uses.

[snip]
> Index: gas/testsuite/gas/mips/mips16e-save.d
> ===================================================================
> #objdump: -dr -mmips:isa32 -mmips:16
> #as: -march=mips32 -mips16
> #name: mips16e save/restore
> .*:     file format .*

File format of .*mips.*

> Disassembly of section .text:
> 00000000 <func>:
>    0:   6481            save    8

An whitespace regex [ ]+, which is a bit more robust.


Thiemo
Reply | Threaded
Open this post in threaded view
|

Re: [Patch] MIPS: Add mips16e save/restore instruction support.

Thiemo Seufer
Thiemo Seufer wrote:
[snip]

> > Index: gas/testsuite/gas/mips/mips16e-save.d
> > ===================================================================
> > #objdump: -dr -mmips:isa32 -mmips:16
> > #as: -march=mips32 -mips16
> > #name: mips16e save/restore
> > .*:     file format .*
>
> File format of .*mips.*
>
> > Disassembly of section .text:
> > 00000000 <func>:
> >    0:   6481            save    8
>
> An whitespace regex [ ]+, which is a bit more robust.

I also checked in the appended patch.


Thiemo


2005-11-14  Thiemo Seufer  <[hidden email]>

        * gas/testsuite/gas/mips/mips16e-jrc.d: Tighten file format
        check, relax whitespace checking.


Index: gas/testsuite/gas/mips/mips16e-jrc.d
===================================================================
RCS file: /cvs/src/src/gas/testsuite/gas/mips/mips16e-jrc.d,v
retrieving revision 1.1
diff -u -p -r1.1 mips16e-jrc.d
--- gas/testsuite/gas/mips/mips16e-jrc.d 19 Oct 2005 18:47:09 -0000 1.1
+++ gas/testsuite/gas/mips/mips16e-jrc.d 14 Nov 2005 10:58:20 -0000
@@ -1,14 +1,16 @@
 #objdump: -dr -mmips:isa32 -mmips:16
 #as: -march=mips32 -mips16
 #name: mips16e jalrc/jrc
-.*:     file format .*
+
+.*: +file format .*mips.*
+
 Disassembly of section .text:
 00000000 <.text>:
-   0: eac0       jalrc v0
-   2: e8a0       jrc ra
-   4: 6a01       li v0,1
-   6: 6500       nop
-   8: 6500       nop
-   a: 6500       nop
-   c: 6500       nop
-   e: 6500       nop
+   0:[ ]+eac0[ ]+jalrc[ ]+v0
+   2:[ ]+e8a0[ ]+jrc[ ]+ra
+   4:[ ]+6a01[ ]+li[ ]+v0,1
+   6:[ ]+6500[ ]+nop
+   8:[ ]+6500[ ]+nop
+   a:[ ]+6500[ ]+nop
+   c:[ ]+6500[ ]+nop
+   e:[ ]+6500[ ]+nop