This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: [Patch] MIPS: Add mips16e save/restore instruction support.
> > +
> > + 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