diff options
author | Iceberg Fu <Chao-Ying.Fu@imgtec.com> | 2013-08-15 11:22:25 +0800 |
---|---|---|
committer | Andrew Hsieh <andrewhsieh@google.com> | 2013-08-15 11:22:25 +0800 |
commit | 250ab64769fdb34c9ffebb94a8697f503747a2f8 (patch) | |
tree | 19f7b0b75f622167478fd885b901438f49097e99 /binutils-2.21/gas/config | |
parent | 831acf283992c03f08a38e560d39a0696d55ccd4 (diff) | |
download | toolchain_binutils-250ab64769fdb34c9ffebb94a8697f503747a2f8.zip toolchain_binutils-250ab64769fdb34c9ffebb94a8697f503747a2f8.tar.gz toolchain_binutils-250ab64769fdb34c9ffebb94a8697f503747a2f8.tar.bz2 |
Add MXU support to binutils-2.21/2.22/2.23
Change-Id: Ibcc5b2ab16e640f7fd3d8a0420fec1bd91a6e6fa
Diffstat (limited to 'binutils-2.21/gas/config')
-rw-r--r-- | binutils-2.21/gas/config/tc-mips.c | 718 |
1 files changed, 717 insertions, 1 deletions
diff --git a/binutils-2.21/gas/config/tc-mips.c b/binutils-2.21/gas/config/tc-mips.c index 59d6880..32919b8 100644 --- a/binutils-2.21/gas/config/tc-mips.c +++ b/binutils-2.21/gas/config/tc-mips.c @@ -198,6 +198,7 @@ struct mips_set_options int ase_dsp; int ase_dspr2; int ase_mt; + int ase_mxu; /* Whether we are assembling for the mips16 processor. 0 if we are not, 1 if we are, and -1 if the value has not been initialized. Changed by `.set mips16' and `.set nomips16', and the -mips16 and @@ -267,6 +268,7 @@ static struct mips_set_options mips_opts = { /* isa */ ISA_UNKNOWN, /* ase_mips3d */ -1, /* ase_mdmx */ -1, /* ase_smartmips */ 0, /* ase_dsp */ -1, /* ase_dspr2 */ -1, /* ase_mt */ -1, + /* ase_mxu */ -1, /* mips16 */ -1, /* noreorder */ 0, /* at */ ATREG, /* warn_about_macros */ 0, /* nomove */ 0, /* nobopt */ 0, /* noautoextend */ 0, /* gp32 */ 0, /* fp32 */ 0, /* arch */ CPU_UNKNOWN, @@ -322,6 +324,9 @@ static int file_ase_smartmips; command line (e.g., by -march). */ static int file_ase_dsp; +/* True if -mmxu was passed. */ +static int file_ase_mxu; + #define ISA_SUPPORTS_DSP_ASE (mips_opts.isa == ISA_MIPS32R2 \ || mips_opts.isa == ISA_MIPS64R2) @@ -1133,6 +1138,7 @@ struct mips_cpu_info #define MIPS_CPU_ASE_MIPS3D 0x0010 /* CPU implements MIPS-3D ASE */ #define MIPS_CPU_ASE_MDMX 0x0020 /* CPU implements MDMX ASE */ #define MIPS_CPU_ASE_DSPR2 0x0040 /* CPU implements DSP R2 ASE */ +#define MIPS_CPU_ASE_MXU 0x0080 /* CPU implements MXU ASE */ static const struct mips_cpu_info *mips_parse_cpu (const char *, const char *); static const struct mips_cpu_info *mips_cpu_info_from_isa (int); @@ -1530,12 +1536,45 @@ init_vr4120_conflicts (void) #undef CONFLICT } +struct args { + const char *opt; + char *value; +}; + +const struct args args_opt[] = { + {"WW", "0"}, + {"LW", "1"}, + {"HW", "2"}, + {"XW", "3"}, + {"0", "0"}, + {"1", "1"}, + {"2", "2"}, + {"3", "3"}, +}; +const struct args args_apt[] = { + {"AA", "0"}, + {"AS", "1"}, + {"SA", "2"}, + {"SS", "3"} +}; + +const struct args args_ept[] = { + {"ptn0", "0"}, + {"ptn1", "1"}, + {"ptn2", "2"}, + {"ptn3", "3"}, + {"ptn4", "4"}, + {"ptn5", "5"}, + {"ptn6", "6"}, + {"ptn7", "7"}, +}; + struct regname { const char *name; unsigned int num; }; -#define RTYPE_MASK 0x1ff00 +#define RTYPE_MASK 0x3ff00 #define RTYPE_NUM 0x00100 #define RTYPE_FPU 0x00200 #define RTYPE_FCC 0x00400 @@ -1545,6 +1584,7 @@ struct regname { #define RTYPE_PC 0x04000 #define RTYPE_ACC 0x08000 #define RTYPE_CCC 0x10000 +#define RTYPE_JZ 0x20000 #define RNUM_MASK 0x000ff #define RWARN 0x80000 @@ -1738,6 +1778,25 @@ struct regname { {"$ac2", RTYPE_ACC | 2}, \ {"$ac3", RTYPE_ACC | 3} +#define MIPS32_JZ_REGISTER_NAMES \ + {"xr0", RTYPE_JZ | 0}, \ + {"xr1", RTYPE_JZ | 1}, \ + {"xr2", RTYPE_JZ | 2}, \ + {"xr3", RTYPE_JZ | 3}, \ + {"xr4", RTYPE_JZ | 4}, \ + {"xr5", RTYPE_JZ | 5}, \ + {"xr6", RTYPE_JZ | 6}, \ + {"xr7", RTYPE_JZ | 7}, \ + {"xr8", RTYPE_JZ | 8}, \ + {"xr9", RTYPE_JZ | 9}, \ + {"xr10", RTYPE_JZ | 10}, \ + {"xr11", RTYPE_JZ | 11}, \ + {"xr12", RTYPE_JZ | 12}, \ + {"xr13", RTYPE_JZ | 13}, \ + {"xr14", RTYPE_JZ | 14}, \ + {"xr15", RTYPE_JZ | 15}, \ + {"xr16", RTYPE_JZ | 16} + static const struct regname reg_names[] = { GENERIC_REGISTER_NUMBERS, FPU_REGISTER_NAMES, @@ -1753,6 +1812,7 @@ static const struct regname reg_names[] = { MIPS16_SPECIAL_REGISTER_NAMES, MDMX_VECTOR_REGISTER_NAMES, MIPS_DSP_ACCUMULATOR_NAMES, + MIPS32_JZ_REGISTER_NAMES, {0, 0} }; @@ -1828,6 +1888,8 @@ is_opcode_valid (const struct mips_opcode *mo) int isa = mips_opts.isa; int fp_s, fp_d; + if (mips_opts.ase_mxu) + isa |= INSN_MXU; if (mips_opts.ase_mdmx) isa |= INSN_MDMX; if (mips_opts.ase_dsp) @@ -8549,6 +8611,70 @@ validate_mips_insn (const struct mips_opcode *opc) case '*': USE_BITS (OP_MASK_MTACC_T, OP_SH_MTACC_T); break; case '&': USE_BITS (OP_MASK_MTACC_D, OP_SH_MTACC_D); break; case 'g': USE_BITS (OP_MASK_RD, OP_SH_RD); break; + +/************** JZ SPECIAL ISA **************/ + /* m and n is used for S32M2I and S32I2M */ + case 'm': USE_BITS (OP_MASK_RA, OP_SH_RA); break; + case '=': USE_BITS (OP_MASK_XRA, OP_SH_XRA); + while (*p) + switch (*p++) + { + case ',': break; + case 'a': USE_BITS (OP_MASK_LPTN2, OP_SH_LPTN2); break; + case 'b': USE_BITS (OP_MASK_XRB, OP_SH_XRB); break; + case 'c': USE_BITS (OP_MASK_XRC, OP_SH_XRC); break; + case 'd': USE_BITS (OP_MASK_XRD, OP_SH_XRD); break; + case 'e': USE_BITS (OP_MASK_EPTN3, OP_SH_EPTN3); break; + case 'f': USE_BITS (OP_MASK_SFT4, OP_SH_SFT4); break; + case 'i': USE_BITS (OP_MASK_XIM12, OP_SH_XIM12); break; + case 'q': + case 'o': USE_BITS (OP_MASK_RPTN2, OP_SH_RPTN2); break; + case 'P': + case 'p': USE_BITS (OP_MASK_PTN, OP_SH_PTN); break; + case 'r': USE_BITS (OP_MASK_LSTRD2, OP_SH_LSTRD2); break; + case 's': USE_BITS (OP_MASK_RS, OP_SH_RS); break; + case 't': USE_BITS (OP_MASK_RT, OP_SH_RT); break; + case 'A': USE_BITS (OP_MASK_XAS, OP_SH_XAS); break; + case 'U': + case 'B': USE_BITS (OP_MASK_XIM8, OP_SH_XIM8); break; + case 'E': USE_BITS (OP_MASK_LPTN2, OP_SH_LPTN2); break; + case 'I': USE_BITS (OP_MASK_XIM10, OP_SH_XIM10); break; + case 'O': USE_BITS (OP_MASK_OPTN3, OP_SH_OPTN3); break; + case 'S': USE_BITS (OP_MASK_XRS, OP_SH_XRS); break; + case 'T': USE_BITS (OP_MASK_RT, OP_SH_RT); break; + default: + as_bad (_("internal: bad mips opcode (unknown operand type `%c'): %s %s"), c, opc->name, opc->args); + return 0; + } + break; + + case 'n': USE_BITS (OP_MASK_RD, OP_SH_RD); + while (*p) + switch(*p++) + { + case ',': break; + case 's': USE_BITS (OP_MASK_RS, OP_SH_RS); break; + case 't': USE_BITS (OP_MASK_RT, OP_SH_RT); break; + case 'R': USE_BITS (OP_MASK_RSTRD2, OP_SH_RSTRD2); break; + default: + as_bad (_("internal: bad mips opcode (unknown operand type `%c'): %s %s"), c, opc->name, opc->args); + return 0; + } + break; + + case 'y': USE_BITS (OP_MASK_XRB, OP_SH_XRB); + while (*p) + switch (*p++) + { + case ',': break; + case 'D': USE_BITS (OP_MASK_XRC, OP_SH_XRC); break; + case 's': USE_BITS (OP_MASK_RS, OP_SH_RS); break; + default: + as_bad (_("internal: bad mips opcode (unknown operand type `%c'): %s %s"), c, opc->name, opc->args); + return 0; + } + break; + default: as_bad (_("internal: bad mips opcode (unknown operand type `%c'): %s %s"), c, opc->name, opc->args); @@ -9457,9 +9583,14 @@ do_msbd: case 'z': /* must be zero register */ case 'U': /* destination register (clo/clz). */ case 'g': /* coprocessor destination register */ + /* JZ S32M2I and JZS32I2M special command */ + case 'm': + s_reset = s; if (*args == 'E' || *args == 'K') ok = reg_lookup (&s, RTYPE_NUM, ®no); + else if (*args == 'm') + ok = reg_lookup (&s, RTYPE_NUM | RTYPE_JZ, ®no); else { ok = reg_lookup (&s, RTYPE_NUM | RTYPE_GP, ®no); @@ -9548,6 +9679,11 @@ do_msbd: break; /* What about all other operands like 'i', which can be specified in the opcode table? */ + + /* JZ special command S32M2I S32I2M */ + case 'm': + INSERT_OPERAND (RA, *ip, regno); + break; } lastregno = regno; continue; @@ -10087,6 +10223,563 @@ do_msbd: s = expr_end; continue; +/************** JZ SPECIAL ISA ****************/ /* S32MTI and S32I2M is added by 'm', 'n' above */ + + case '=': + for (; ; args++) { + int i; + char tmp[8]; + char *p = tmp; + switch (*args) { + /* end of args */ + case '\0': + if (*s == '\0') + return; + break; + case ',': + if (*s++ == *args) + continue; + break; + + case 'a': + /* phrase the aptn */ + strcpy(tmp, s); + p = strtok(tmp, ","); + for (i = 0; i < 4; i++) + if (!strcmp(p, args_apt[i].opt)) { + s += 2; + strcpy(tmp, args_apt[i].value); + break; + } + if (i == 4) { + as_bad (_("bad command args = '%s'\n"), s); + internalError (); + } + s = strcat(tmp, s); + my_getExpression (&imm_expr, s); + check_absolute_expr (ip, &imm_expr); + if ((unsigned long) imm_expr.X_add_number > OP_MASK_RPTN2) + as_bad (_("Code (%c) for %s not in range (%lu)"), *args, + ip->insn_mo->name, + (unsigned long) imm_expr.X_add_number); + INSERT_OPERAND (LPTN2, *ip, imm_expr.X_add_number); + imm_expr.X_op = O_absent; + s = expr_end; + continue; + + case 'f': /* SFT4 */ + my_getExpression (&imm_expr, s); + check_absolute_expr (ip, &imm_expr); + if ((unsigned long) imm_expr.X_add_number > OP_MASK_SFT4) + as_bad (_("Code (%c) for %s not in range (%lu)"), *args, + ip->insn_mo->name, + (unsigned long) imm_expr.X_add_number); + INSERT_OPERAND (SFT4, *ip, imm_expr.X_add_number); + imm_expr.X_op = O_absent; + s = expr_end; + continue; + + case 'e': /* eptn3 */ + for (i = 0; i < 8; i++) { + if (!strcmp(args_ept[i].opt, s)) { + s = args_ept[i].value; + break; + } + } + if (i == 8) { + as_bad (_("bad command args = '%s'\n"), s); + internalError (); + } + + my_getExpression (&imm_expr, s); + check_absolute_expr (ip, &imm_expr); + if ((unsigned long) imm_expr.X_add_number > OP_MASK_EPTN3) + as_bad (_("Code (%c) for %s not in range (%lu)"), *args, + ip->insn_mo->name, + (unsigned long) imm_expr.X_add_number); + INSERT_OPERAND (EPTN3, *ip, imm_expr.X_add_number); + imm_expr.X_op = O_absent; + s = expr_end; + continue; + + + case 'i': /* s[12:2] */ + my_getExpression (&imm_expr, s); + check_absolute_expr (ip, &imm_expr); + /* the immediate must be fully divisioned by 4 */ + if ((signed long) imm_expr.X_add_number % 4 != 0 ) + as_bad (_("bad immediate = '%s'\n"), s); + /* the immediate must not be out of range */ + if ((signed long) imm_expr.X_add_number > 2044 || + (signed long)imm_expr.X_add_number < -2048) + as_bad (_("Code (%c) for %s not in range (%lu)"), *args, + ip->insn_mo->name, + (signed long) imm_expr.X_add_number); + /* the bit in the command express multiple by 4 */ + INSERT_OPERAND (XIM12, *ip, (imm_expr.X_add_number >> 2) & 0x3ff); + imm_expr.X_op = O_absent; + s = expr_end; + continue; + + case 'o': /* OPTN2 */ + case 'q': /* s16mad, OPTN2 */ + for (i = 0; i < 8; i++) + if (!strcmp(args_opt[i].opt, s)) { + s = args_opt[i].value; + break; + } + if (i == 8) { + as_bad (_("bad command args = '%s'\n"), s); + internalError (); + } + my_getExpression (&imm_expr, s); + check_absolute_expr (ip, &imm_expr); + if ((unsigned long) imm_expr.X_add_number > OP_MASK_RPTN2) + as_bad (_("Code (%c) for %s not in range (%lu)"), *args, + ip->insn_mo->name, + (unsigned long) imm_expr.X_add_number); + INSERT_OPERAND (RPTN2, *ip, imm_expr.X_add_number); + imm_expr.X_op = O_absent; + s = expr_end; + continue; + + case 'p': /* ptn */ + for (i = 0; i < 4; i++) + if (!strcmp(args_ept[i].opt, s)) { + s = args_ept[i].value; + break; + } + if (i == 4) { + as_bad (_("bad command args = '%s'\n"), s); + internalError (); + } + + my_getExpression (&imm_expr, s); + check_absolute_expr (ip, &imm_expr); + + /* the range of strd2 from 0 to 1 */ + if ((unsigned long) imm_expr.X_add_number > 0x1) + as_bad (_("Code (%c) for %s not in range (%lu)"), *args, + ip->insn_mo->name, + (unsigned long) imm_expr.X_add_number); + INSERT_OPERAND (PTN, *ip, imm_expr.X_add_number); + imm_expr.X_op = O_absent; + s = expr_end; + continue; + + case 'P': /* ptn */ + for (i = 0; i < 4; i++) + if (!strcmp(args_ept[i].opt, s)) { + s = args_ept[i].value; + break; + } + if (i == 4) { + as_bad (_("bad command args = '%s'\n"), s); + internalError (); + } + + my_getExpression (&imm_expr, s); + check_absolute_expr (ip, &imm_expr); + + /* the range of strd2 from 0 to 1 */ + if ((unsigned long) imm_expr.X_add_number > 0x3) + as_bad (_("Code (%c) for %s not in range (%lu)"), *args, + ip->insn_mo->name, + (unsigned long) imm_expr.X_add_number); + INSERT_OPERAND (PTN, *ip, imm_expr.X_add_number); + imm_expr.X_op = O_absent; + s = expr_end; + continue; + + case 'r': /* lstrd2 */ + my_getExpression (&imm_expr, s); + check_absolute_expr (ip, &imm_expr); + + /* the range of strd2 from 0 to 2 */ + if ((unsigned long) imm_expr.X_add_number > 0x2) + as_bad (_("Code (%c) for %s not in range (%lu)"), *args, + ip->insn_mo->name, + (unsigned long) imm_expr.X_add_number); + INSERT_OPERAND (LSTRD2, *ip, imm_expr.X_add_number); + imm_expr.X_op = O_absent; + s = expr_end; + continue; + + case 'A': /* special s32mad command */ + strcpy(tmp, s); + p = strtok(tmp, ","); + if (strcmp(p, "A") && strcmp(p, "S")) { + as_bad (_("bad command args = '%s'\n"), s); + internalError (); + } + if (*s == 'S') + *s = '1'; + else if (*s == 'A') + *s = '0'; + my_getExpression (&imm_expr, s); + INSERT_OPERAND (XAS, *ip, imm_expr.X_add_number); + imm_expr.X_op = O_absent; + s = expr_end; + continue; + + case 'B': /* s8[7:0] */ + my_getExpression (&imm_expr, s); + check_absolute_expr (ip, &imm_expr); + /* the immediate must not be out of range */ + if ((signed long) imm_expr.X_add_number > 127 || + (signed long)imm_expr.X_add_number < -128) + as_bad (_("Code (%c) for %s not in range (%lu)"), *args, + ip->insn_mo->name, + (signed long) imm_expr.X_add_number); + /* the bit in the command express multiple by 4 */ + INSERT_OPERAND (XIM8, *ip, imm_expr.X_add_number); + imm_expr.X_op = O_absent; + s = expr_end; + continue; + + case 'U': /* u8[7:0] */ + my_getExpression (&imm_expr, s); + check_absolute_expr (ip, &imm_expr); + /* the immediate must not be out of range */ + if ((signed long) imm_expr.X_add_number > 255 || + (signed long)imm_expr.X_add_number < -128) + as_bad (_("Code (%c) for %s not in range (%ld)"), *args, + ip->insn_mo->name, + (signed long) imm_expr.X_add_number); + /* the bit in the command express multiple by 4 */ + INSERT_OPERAND (XIM8, *ip, imm_expr.X_add_number); + imm_expr.X_op = O_absent; + s = expr_end; + continue; + + case 'E': /* phrase the s32sfl(aptn) */ + for (i = 0; i < 4; i++) + if (!strcmp(args_ept[i].opt, s)) { + s = args_ept[i].value; + break; + } + if (i == 4) { + as_bad (_("bad command args = '%s'\n"), s); + internalError (); + } + + my_getExpression (&imm_expr, s); + check_absolute_expr (ip, &imm_expr); + if ((unsigned long) imm_expr.X_add_number > 0x3) + as_bad (_("Code (%c) for %s not in range (%lu)"), *args, + ip->insn_mo->name, + (unsigned long) imm_expr.X_add_number); + INSERT_OPERAND (LPTN2, *ip, imm_expr.X_add_number); + imm_expr.X_op = O_absent; + s = expr_end; + continue; + + case 'I': /* s10[9:1] */ + my_getExpression (&imm_expr, s); + check_absolute_expr (ip, &imm_expr); + /* the immediate must be fully divisioned by 4 */ + if ((signed long) imm_expr.X_add_number % 2 != 0 ) + as_bad (_("bad immediate = '%s'\n"), s); + /* the immediate must not be out of range */ + if ((signed long) imm_expr.X_add_number > 510 || + (signed long)imm_expr.X_add_number < -512) + as_bad (_("Code (%c) for %s not in range (%lu)"), *args, + ip->insn_mo->name, + (signed long) imm_expr.X_add_number); + /* the bit in the command express multiple by 2 */ + INSERT_OPERAND (XIM10, *ip, (imm_expr.X_add_number >> 1)); + imm_expr.X_op = O_absent; + s = expr_end; + continue; + + case 'O': /* optn3 */ + for (i = 0; i < 8; i++) { + if (!strcmp(args_ept[i].opt, s)) { + s = args_ept[i].value; + break; + } + } + if (i == 8) { + as_bad (_("bad command args = '%s'\n"), s); + internalError (); + } + + my_getExpression (&imm_expr, s); + check_absolute_expr (ip, &imm_expr); + if ((unsigned long) imm_expr.X_add_number > OP_MASK_OPTN3) + as_bad (_("Code (%c) for %s not in range (%lu)"), *args, + ip->insn_mo->name, + (unsigned long) imm_expr.X_add_number); + INSERT_OPERAND (OPTN3, *ip, imm_expr.X_add_number); + imm_expr.X_op = O_absent; + s = expr_end; + continue; + + case 'S': /* s3[2:0] */ + for (i = 0; i < 4; i++) + if (!strcmp(args_ept[i].opt, s)) { + s = args_ept[i].value; + break; + } + if (i == 4) { + as_bad (_("bad command args = '%s'\n"), s); + internalError (); + } + + my_getExpression (&imm_expr, s); + check_absolute_expr (ip, &imm_expr); + if ((unsigned long) imm_expr.X_add_number > 0x4) + as_bad (_("Code (%c) for %s not in range (%lu)"), *args, + ip->insn_mo->name, + (unsigned long) imm_expr.X_add_number); + INSERT_OPERAND (XRS, *ip, imm_expr.X_add_number); + imm_expr.X_op = O_absent; + s = expr_end; + continue; + + + + case 'T': /* bits5 */ + my_getExpression (&imm_expr, s); + check_absolute_expr (ip, &imm_expr); + if ((unsigned long) imm_expr.X_add_number > OP_MASK_RT) + as_bad (_("Code (%c) for %s not in range (%lu)"), *args, + ip->insn_mo->name, + (unsigned long) imm_expr.X_add_number); + INSERT_OPERAND (RT, *ip, imm_expr.X_add_number); + imm_expr.X_op = O_absent; + s = expr_end; + continue; + + case '=': + case 'b': + case 'c': + case 'd': + case 's': + case 't': + s_reset = s; + if (*args == 's' || *args == 't') { + rtype = RTYPE_NUM | RTYPE_GP; + ok = reg_lookup (&s, rtype, ®no); + if (regno == AT && mips_opts.at) + { + if (mips_opts.at == ATREG) + as_warn (_("used $at without \".set noat\"")); + else + as_warn (_("used $%u with \".set at=$%u\""), + regno, mips_opts.at); + } + } else { + rtype = RTYPE_JZ | RTYPE_GP; + ok = reg_lookup (&s, rtype, ®no); + if (!ok) + break; + if (regno > 15) { + as_bad (_("regno out of range(%d)\n"), regno); + internalError (); + } + } + if (ok) + { + c = *args; + if (*s == ' ') + ++s; + if (args[1] != *s) + { + if (c == 'r' || c == 'v' || c == 'w') + { + regno = lastregno; + s = s_reset; + ++args; + } + } + /* Now that we have assembled one operand, we use the args string + * to figure out where it goes in the instruction. */ + switch (c) + { + /* '=' 'b' 'c' 'd' express jz special register XRA XRB XRC XRD */ + case '=': + INSERT_OPERAND (XRA, *ip, regno); + break; + case 'b': + INSERT_OPERAND (XRB, *ip, regno); + break; + case 'c': + INSERT_OPERAND (XRC, *ip, regno); + break; + case 'd': + INSERT_OPERAND (XRD, *ip, regno); + break; + /* regular register s and t*/ + case 's': + INSERT_OPERAND (RS, *ip, regno); + break; + case 't': + INSERT_OPERAND (RT, *ip, regno); + break; + } + lastregno = regno; + continue; + } + break; + default: + as_bad (_("bad char = '%c'\n"), *args); + internalError (); + } + break; + } + break; + case 'n': + for (; ; args++) { + switch (*args) { + /* end of args */ + case '\0': + if (*s == '\0') + return; + break; + case ',': + if (*s++ == *args) + continue; + break; + + case 'R': /* rstrd2 */ + my_getExpression (&imm_expr, s); + check_absolute_expr (ip, &imm_expr); + + /* the range of strd2 from 0 to 2 */ + if ((unsigned long) imm_expr.X_add_number > 0x2) + as_bad (_("Code (%c) for %s not in range (%lu)"), *args, + ip->insn_mo->name, + (unsigned long) imm_expr.X_add_number); + INSERT_OPERAND (RSTRD2, *ip, imm_expr.X_add_number); + imm_expr.X_op = O_absent; + s = expr_end; + continue; + + case 'n': + case 's': + case 't': + s_reset = s; + ok = reg_lookup (&s, RTYPE_NUM | RTYPE_GP, ®no); + if (regno == AT && mips_opts.at) + { + if (mips_opts.at == ATREG) + as_warn (_("used $at without \".set noat\"")); + else + as_warn (_("used $%u with \".set at=$%u\""), + regno, mips_opts.at); + } + if (ok) + { + c = *args; + if (*s == ' ') + ++s; + + /* Now that we have assembled one operand, we use the args string + * to figure out where it goes in the instruction. */ + switch (c) + { + case 'n': + INSERT_OPERAND (RD, *ip, regno); + break; + case 's': + INSERT_OPERAND (RS, *ip, regno); + break; + case 't': + INSERT_OPERAND (RT, *ip, regno); + break; + } + lastregno = regno; + continue; + } + break; + default: + as_bad (_("bad char = '%c'\n"), *args); + internalError (); + } + break; + } + break; + + + case 'y': + for (; ; args++) { + switch (*args) { + /* end of args */ + case '\0': + if (*s == '\0') + return; + break; + case ',': + if (*s++ == *args) + continue; + break; + + case 'y': + case 'D': + case 's': + s_reset = s; + if (*args == 's') { + rtype = RTYPE_NUM | RTYPE_GP; + ok = reg_lookup (&s, rtype, ®no); + if (regno == AT && mips_opts.at) + { + if (mips_opts.at == ATREG) + as_warn (_("used $at without \".set noat\"")); + else + as_warn (_("used $%u with \".set at=$%u\""), + regno, mips_opts.at); + } + } else { + rtype = RTYPE_JZ | RTYPE_GP; + ok = reg_lookup (&s, rtype, ®no); + if (!ok) + break; + if (regno > 15) { + as_bad (_("regno out of range(%d)\n"), regno); + internalError (); + } + } + if (ok) + { + c = *args; + if (*s == ' ') + ++s; + if (args[1] != *s) + { + if (c == 'r' || c == 'v' || c == 'w') + { + regno = lastregno; + s = s_reset; + ++args; + } + } + /* Now that we have assembled one operand, we use the args string + * to figure out where it goes in the instruction. */ + switch (c) + { + case 'y': + INSERT_OPERAND (XRB, *ip, regno); + break; + case 'D': + INSERT_OPERAND (XRC, *ip, regno); + break; + case 's': + INSERT_OPERAND (RS, *ip, regno); + break; + } + lastregno = regno; + continue; + } + break; + default: + as_bad (_("bad char = '%c'\n"), *args); + internalError (); + } + break; + } + break; + default: as_bad (_("bad char = '%c'\n"), *args); internalError (); @@ -11209,6 +11902,8 @@ enum options OPTION_NO_DSP, OPTION_MT, OPTION_NO_MT, + OPTION_MXU, + OPTION_NO_MXU, OPTION_SMARTMIPS, OPTION_NO_SMARTMIPS, OPTION_DSPR2, @@ -11301,6 +11996,8 @@ struct option md_longopts[] = {"mno-dsp", no_argument, NULL, OPTION_NO_DSP}, {"mmt", no_argument, NULL, OPTION_MT}, {"mno-mt", no_argument, NULL, OPTION_NO_MT}, + {"mmxu", no_argument, NULL, OPTION_MXU}, + {"mno-mxu", no_argument, NULL, OPTION_NO_MXU}, {"msmartmips", no_argument, NULL, OPTION_SMARTMIPS}, {"mno-smartmips", no_argument, NULL, OPTION_NO_SMARTMIPS}, {"mdspr2", no_argument, NULL, OPTION_DSPR2}, @@ -11551,6 +12248,14 @@ md_parse_option (int c, char *arg) mips_opts.ase_dsp = 0; break; + case OPTION_MXU: + mips_opts.ase_mxu = 1; + break; + + case OPTION_NO_MXU: + mips_opts.ase_mxu = 0; + break; + case OPTION_MT: mips_opts.ase_mt = 1; break; @@ -12036,6 +12741,9 @@ mips_after_parse_args (void) as_warn (_("%s ISA does not support MT ASE"), mips_cpu_info_from_isa (mips_opts.isa)->name); + if (mips_opts.ase_mxu == -1) + mips_opts.ase_mxu = (arch_info->flags & MIPS_CPU_ASE_MXU) ? 1 : 0; + file_mips_isa = mips_opts.isa; file_ase_mips16 = mips_opts.mips16; file_ase_mips3d = mips_opts.ase_mips3d; @@ -12043,6 +12751,7 @@ mips_after_parse_args (void) file_ase_smartmips = mips_opts.ase_smartmips; file_ase_dsp = mips_opts.ase_dsp; file_ase_dspr2 = mips_opts.ase_dspr2; + file_ase_mxu = mips_opts.ase_mxu; file_ase_mt = mips_opts.ase_mt; mips_opts.gp32 = file_mips_gp32; mips_opts.fp32 = file_mips_fp32; @@ -13008,6 +13717,10 @@ s_mipsset (int x ATTRIBUTE_UNUSED) } else if (strcmp (name, "nomt") == 0) mips_opts.ase_mt = 0; + else if (strcmp (name, "mxu") == 0) + mips_opts.ase_mxu = 1; + else if (strcmp (name, "nomxu") == 0) + mips_opts.ase_mxu = 0; else if (strncmp (name, "mips", 4) == 0 || strncmp (name, "arch=", 5) == 0) { int reset = 0; @@ -15590,6 +16303,9 @@ MIPS options:\n\ -mmt generate MT instructions\n\ -mno-mt do not generate MT instructions\n")); fprintf (stream, _("\ +-mmxu generate MXU instructions\n\ +-mno-mxu do not generate MXU instructions\n")); + fprintf (stream, _("\ -mfix-loongson2f-jump work around Loongson2F JUMP instructions\n\ -mfix-loongson2f-nop work around Loongson2F NOP errata\n\ -mfix-vr4120 work around certain VR4120 errata\n\ |