diff options
author | Thiemo Seufer <ths@networkno.de> | 2005-11-14 02:25:39 +0000 |
---|---|---|
committer | Thiemo Seufer <ths@networkno.de> | 2005-11-14 02:25:39 +0000 |
commit | 0499d65b9bc3522c3275f1945beb3d40e6f7a1ca (patch) | |
tree | 2893f145182b936f85283320bd1c3989075cd3e4 /gas/config | |
parent | eafa87ff3b0eadd6e13c1c42962cad9e92992c3c (diff) | |
download | gdb-0499d65b9bc3522c3275f1945beb3d40e6f7a1ca.zip gdb-0499d65b9bc3522c3275f1945beb3d40e6f7a1ca.tar.gz gdb-0499d65b9bc3522c3275f1945beb3d40e6f7a1ca.tar.bz2 |
* 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.
Diffstat (limited to 'gas/config')
-rw-r--r-- | gas/config/tc-mips.c | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c index 391f0be..4f1afea 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); |