aboutsummaryrefslogtreecommitdiff
path: root/gas/config
diff options
context:
space:
mode:
authorThiemo Seufer <ths@networkno.de>2005-11-14 02:25:39 +0000
committerThiemo Seufer <ths@networkno.de>2005-11-14 02:25:39 +0000
commit0499d65b9bc3522c3275f1945beb3d40e6f7a1ca (patch)
tree2893f145182b936f85283320bd1c3989075cd3e4 /gas/config
parenteafa87ff3b0eadd6e13c1c42962cad9e92992c3c (diff)
downloadgdb-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.c180
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);