From 0499d65b9bc3522c3275f1945beb3d40e6f7a1ca Mon Sep 17 00:00:00 2001 From: Thiemo Seufer Date: Mon, 14 Nov 2005 02:25:39 +0000 Subject: [PATCH] * 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. --- gas/ChangeLog | 5 + gas/config/tc-mips.c | 180 ++++++++++++++++++++++++++ gas/testsuite/ChangeLog | 7 + gas/testsuite/gas/mips/mips.exp | 5 +- gas/testsuite/gas/mips/mips16e-save.d | 43 ++++++ gas/testsuite/gas/mips/mips16e-save.s | 55 ++++++++ include/opcode/ChangeLog | 6 + include/opcode/mips.h | 9 +- opcodes/ChangeLog | 6 + opcodes/mips-dis.c | 86 ++++++++++++ opcodes/mips16-opc.c | 2 + 11 files changed, 402 insertions(+), 2 deletions(-) create mode 100644 gas/testsuite/gas/mips/mips16e-save.d create mode 100644 gas/testsuite/gas/mips/mips16e-save.s diff --git a/gas/ChangeLog b/gas/ChangeLog index dc73bd37a45..4fda943344e 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,8 @@ +2005-11-14 David Ung + + * config/tc-mips.c (mips16_ip): Add handling of 'm' and 'M' codes + for the MIPS16e save/restore instructions. + 2005-11-11 Jan Beulich * doc/Makefile.am: Make asconfig.texi writeable before trying diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c index 391f0bebbdd..4f1afeacc69 100644 --- a/gas/config/tc-mips.c +++ b/gas/config/tc-mips.c @@ -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); diff --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog index eb0881ecf10..275efde107b 100644 --- a/gas/testsuite/ChangeLog +++ b/gas/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2005-11-14 David Ung + + * 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 * gas/i386/intelbad.d: Add tests for ill registers in brackets. diff --git a/gas/testsuite/gas/mips/mips.exp b/gas/testsuite/gas/mips/mips.exp index c787e4fb88a..174aea483a6 100644 --- a/gas/testsuite/gas/mips/mips.exp +++ b/gas/testsuite/gas/mips/mips.exp @@ -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 index 00000000000..7bc0b9959a5 --- /dev/null +++ b/gas/testsuite/gas/mips/mips16e-save.d @@ -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 : + 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 index 00000000000..b982cc7afbf --- /dev/null +++ b/gas/testsuite/gas/mips/mips16e-save.s @@ -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 + diff --git a/include/opcode/ChangeLog b/include/opcode/ChangeLog index a282a622261..c9a4a1257d0 100644 --- a/include/opcode/ChangeLog +++ b/include/opcode/ChangeLog @@ -1,3 +1,9 @@ +2005-11-14 David Ung + + * 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 Contribute the following changes: diff --git a/include/opcode/mips.h b/include/opcode/mips.h index e46ba2c0996..4bec5edcc8c 100644 --- a/include/opcode/mips.h +++ b/include/opcode/mips.h @@ -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. */ diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog index aa14a3d125a..aebe716dc51 100644 --- a/opcodes/ChangeLog +++ b/opcodes/ChangeLog @@ -1,3 +1,9 @@ +2005-11-14 David Ung + + * 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 * m68k-dis.c (print_insn_m68k): Only match FPU insns with diff --git a/opcodes/mips-dis.c b/opcodes/mips-dis.c index 21f20fb5035..9a48d86d2d1 100644 --- a/opcodes/mips-dis.c +++ b/opcodes/mips-dis.c @@ -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) diff --git a/opcodes/mips16-opc.c b/opcodes/mips16-opc.c index 0459582e20f..4e5ae44752f 100644 --- a/opcodes/mips16-opc.c +++ b/opcodes/mips16-opc.c @@ -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 }, -- 2.30.2