This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[Patch] MIPS: Add mips16e save/restore instruction support.
- From: David Ung <davidu at mips dot com>
- To: binutils at sources dot redhat dot com
- Date: Thu, 20 Oct 2005 14:54:18 +0100
- Subject: [Patch] MIPS: Add mips16e save/restore instruction support.
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