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

David Ung davidu@mips.com
Thu Oct 20 13:54:00 GMT 2005


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



More information about the Binutils mailing list