You should have received a copy of the GNU General Public License
along with GAS; see the file COPYING. If not, write to the Free
- Software Foundation, 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, USA. */
+ Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
+ 02110-1301, USA. */
#include "as.h"
#include "config.h"
#include "opcode/mips.h"
#include "itbl-ops.h"
#include "dwarf2dbg.h"
+#include "dw2gencfi.h"
#ifdef DEBUG
#define DBG(x) printf x
command line options, and based on the default architecture. */
int ase_mips3d;
int ase_mdmx;
+ int ase_dsp;
+ int ase_mt;
/* 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
static struct mips_set_options mips_opts =
{
- ISA_UNKNOWN, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, CPU_UNKNOWN, FALSE
+ ISA_UNKNOWN, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, CPU_UNKNOWN, FALSE
};
/* These variables are filled in with the masks of registers used.
command line (e.g., by -march). */
static int file_ase_mdmx;
+/* True if -mdsp was passed or implied by arguments passed on the
+ command line (e.g., by -march). */
+static int file_ase_dsp;
+
+/* True if -mmt was passed or implied by arguments passed on the
+ command line (e.g., by -march). */
+static int file_ase_mt;
+
/* The argument of the -march= flag. The architecture we are assembling. */
static int file_mips_arch = CPU_UNKNOWN;
static const char *mips_arch_string;
#define CPU_HAS_MDMX(cpu) (FALSE \
)
+/* Return true if the given CPU supports the DSP ASE. */
+#define CPU_HAS_DSP(cpu) (FALSE \
+ )
+
+/* Return true if the given CPU supports the MT ASE. */
+#define CPU_HAS_MT(cpu) (FALSE \
+ )
+
/* True if CPU has a dror instruction. */
#define CPU_HAS_DROR(CPU) ((CPU) == CPU_VR5400 || (CPU) == CPU_VR5500)
(((x) &~ (offsetT) 0x7fff) == 0 \
|| (((x) &~ (offsetT) 0x7fff) == ~ (offsetT) 0x7fff))
+/* Is the given value a zero-extended 32-bit value? Or a negated one? */
+#define IS_ZEXT_32BIT_NUM(x) \
+ (((x) &~ (offsetT) 0xffffffff) == 0 \
+ || (((x) &~ (offsetT) 0xffffffff) == ~ (offsetT) 0xffffffff))
+
/* Replace bits MASK << SHIFT of STRUCT with the equivalent bits in
VALUE << SHIFT. VALUE is evaluated exactly once. */
#define INSERT_BITS(STRUCT, VALUE, MASK, SHIFT) \
else if (mips_opts.mips16
&& ! ip->use_extend
&& *reloc_type != BFD_RELOC_MIPS16_JMP)
- {
- /* Make sure there is enough room to swap this instruction with
- a following jump instruction. */
- frag_grow (6);
+ {
+ if ((pinfo & INSN_UNCOND_BRANCH_DELAY) == 0)
+ /* Make sure there is enough room to swap this instruction with
+ a following jump instruction. */
+ frag_grow (6);
add_fixed_insn (ip);
}
else
if (mips_opts.mips16)
{
know (delay.frag == ip->frag);
- move_insn (ip, delay.frag, delay.where);
+ move_insn (ip, delay.frag, delay.where);
move_insn (&delay, ip->frag, ip->where + insn_length (ip));
}
else if (relaxed_branch)
append_insn (&insn, ep, r);
}
+/*
+ * Sign-extend 32-bit mode constants that have bit 31 set and all
+ * higher bits unset.
+ */
+static void
+normalize_constant_expr (expressionS *ex)
+{
+ if (ex->X_op == O_constant
+ && IS_ZEXT_32BIT_NUM (ex->X_add_number))
+ ex->X_add_number = (((ex->X_add_number & 0xffffffff) ^ 0x80000000)
+ - 0x80000000);
+}
+
+/*
+ * Sign-extend 32-bit mode address offsets that have bit 31 set and
+ * all higher bits unset.
+ */
+static void
+normalize_address_expr (expressionS *ex)
+{
+ if (((ex->X_op == O_constant && HAVE_32BIT_ADDRESSES)
+ || (ex->X_op == O_symbol && HAVE_32BIT_SYMBOLS))
+ && IS_ZEXT_32BIT_NUM (ex->X_add_number))
+ ex->X_add_number = (((ex->X_add_number & 0xffffffff) ^ 0x80000000)
+ - 0x80000000);
+}
+
/*
* Generate a "jalr" instruction with a relocation hint to the called
* function. This occurs in NewABI PIC code.
assert (ep->X_op == O_constant);
/* Sign-extending 32-bit constants makes their handling easier. */
- if (! dbl && ! ((ep->X_add_number & ~((bfd_vma) 0x7fffffff))
- == ~((bfd_vma) 0x7fffffff)))
- {
- if (ep->X_add_number & ~((bfd_vma) 0xffffffff))
- as_bad (_("constant too large"));
-
- ep->X_add_number = (((ep->X_add_number & 0xffffffff) ^ 0x80000000)
- - 0x80000000);
- }
+ if (!dbl)
+ normalize_constant_expr (ep);
/* Right now, this routine can only handle signed 32-bit constants. */
if (! IS_SEXT_32BIT_NUM(ep->X_add_number + 0x8000))
}
}
-static void
-normalize_constant_expr (expressionS *ex)
-{
- if (ex->X_op == O_constant && HAVE_32BIT_GPRS)
- ex->X_add_number = (((ex->X_add_number & 0xffffffff) ^ 0x80000000)
- - 0x80000000);
-}
-
/* Warn if an expression is not a constant. */
static void
if (ex->X_op == O_big)
as_bad (_("unsupported large constant"));
else if (ex->X_op != O_constant)
- as_bad (_("Instruction %s requires absolute expression"), ip->insn_mo->name);
+ as_bad (_("Instruction %s requires absolute expression"),
+ ip->insn_mo->name);
- normalize_constant_expr (ex);
+ if (HAVE_32BIT_GPRS)
+ normalize_constant_expr (ex);
}
/* Count the leading zeroes by performing a binary chop. This is a
assert (ep->X_op == O_constant);
/* Sign-extending 32-bit constants makes their handling easier. */
- if (! dbl && ! ((ep->X_add_number & ~((bfd_vma) 0x7fffffff))
- == ~((bfd_vma) 0x7fffffff)))
- {
- if (ep->X_add_number & ~((bfd_vma) 0xffffffff))
- as_bad (_("constant too large"));
-
- ep->X_add_number = (((ep->X_add_number & 0xffffffff) ^ 0x80000000)
- - 0x80000000);
- }
+ if (!dbl)
+ normalize_constant_expr (ep);
if (IS_SEXT_16BIT_NUM (ep->X_add_number))
{
/* The value is larger than 32 bits. */
- if (HAVE_32BIT_GPRS)
+ if (!dbl || HAVE_32BIT_GPRS)
{
- as_bad (_("Number (0x%lx) larger than 32 bits"),
- (unsigned long) ep->X_add_number);
+ char value[32];
+
+ sprintf_vma (value, ep->X_add_number);
+ as_bad (_("Number (0x%s) larger than 32 bits"), value);
macro_build (ep, "addiu", "t,r,j", reg, 0, BFD_RELOC_LO16);
return;
}
offset_expr.X_op = O_constant;
}
+ if (HAVE_32BIT_ADDRESSES
+ && !IS_SEXT_32BIT_NUM (offset_expr.X_add_number))
+ {
+ char value [32];
+
+ sprintf_vma (value, offset_expr.X_add_number);
+ as_bad (_("Number (0x%s) larger than 32 bits"), value);
+ }
+
/* A constant expression in PIC code can be handled just as it
is in non PIC code. */
if (offset_expr.X_op == O_constant)
{
- if (HAVE_32BIT_ADDRESSES
- && !IS_SEXT_32BIT_NUM (offset_expr.X_add_number))
- as_bad (_("constant too large"));
-
expr1.X_add_number = ((offset_expr.X_add_number + 0x8000)
& ~(bfd_vma) 0xffff);
+ normalize_address_expr (&expr1);
load_register (tempreg, &expr1, HAVE_64BIT_ADDRESSES);
if (breg != 0)
macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
offset_expr.X_op = O_constant;
}
+ if (HAVE_32BIT_ADDRESSES
+ && !IS_SEXT_32BIT_NUM (offset_expr.X_add_number))
+ {
+ char value [32];
+
+ sprintf_vma (value, offset_expr.X_add_number);
+ as_bad (_("Number (0x%s) larger than 32 bits"), value);
+ }
+
/* Even on a big endian machine $fn comes before $fn+1. We have
to adjust when loading from memory. We set coproc if we must
load $fn+1 first. */
If there is a base register, we add it to $at after the
lui instruction. If there is a constant, we always use
the last case. */
- if ((valueT) offset_expr.X_add_number <= MAX_GPREL_OFFSET
+ if (offset_expr.X_op == O_symbol
+ && (valueT) offset_expr.X_add_number <= MAX_GPREL_OFFSET
&& !nopic_need_relax (offset_expr.X_add_symbol, 1))
{
relax_start (offset_expr.X_add_symbol);
case 'G': USE_BITS (OP_MASK_EXTMSBD, OP_SH_EXTMSBD); break;
case 'H': USE_BITS (OP_MASK_EXTMSBD, OP_SH_EXTMSBD); break;
case 'I': break;
+ case 't': USE_BITS (OP_MASK_RT, OP_SH_RT); break;
+ case 'T': USE_BITS (OP_MASK_RT, OP_SH_RT);
+ USE_BITS (OP_MASK_SEL, OP_SH_SEL); break;
default:
as_bad (_("internal: bad mips opcode (unknown extension operand type `+%c'): %s %s"),
c, opc->name, opc->args);
case '%': USE_BITS (OP_MASK_VECALIGN, OP_SH_VECALIGN); break;
case '[': break;
case ']': break;
+ case '3': USE_BITS (OP_MASK_SA3, OP_SH_SA3); break;
+ case '4': USE_BITS (OP_MASK_SA4, OP_SH_SA4); break;
+ case '5': USE_BITS (OP_MASK_IMM8, OP_SH_IMM8); break;
+ case '6': USE_BITS (OP_MASK_RS, OP_SH_RS); break;
+ case '7': USE_BITS (OP_MASK_DSPACC, OP_SH_DSPACC); break;
+ case '8': USE_BITS (OP_MASK_WRDSP, OP_SH_WRDSP); break;
+ case '9': USE_BITS (OP_MASK_DSPACC_S, OP_SH_DSPACC_S);break;
+ case '0': USE_BITS (OP_MASK_DSPSFT, OP_SH_DSPSFT); break;
+ case '\'': USE_BITS (OP_MASK_RDDSP, OP_SH_RDDSP); break;
+ case ':': USE_BITS (OP_MASK_DSPSFT_7, OP_SH_DSPSFT_7);break;
+ case '@': USE_BITS (OP_MASK_IMM10, OP_SH_IMM10); break;
+ case '!': USE_BITS (OP_MASK_MT_U, OP_SH_MT_U); break;
+ case '$': USE_BITS (OP_MASK_MT_H, OP_SH_MT_H); break;
+ 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;
default:
as_bad (_("internal: bad mips opcode (unknown operand type `%c'): %s %s"),
c, opc->name, opc->args);
unsigned int limlo, limhi;
char *s_reset;
char save_c = 0;
+ offsetT min_range, max_range;
insn_error = NULL;
(mips_opts.isa
| (file_ase_mips16 ? INSN_MIPS16 : 0)
| (mips_opts.ase_mdmx ? INSN_MDMX : 0)
+ | (mips_opts.ase_dsp ? INSN_DSP : 0)
+ | (mips_opts.ase_mt ? INSN_MT : 0)
| (mips_opts.ase_mips3d ? INSN_MIPS3D : 0)),
mips_opts.arch))
ok = TRUE;
return;
break;
+ case '3': /* dsp 3-bit unsigned immediate in bit 21 */
+ my_getExpression (&imm_expr, s);
+ check_absolute_expr (ip, &imm_expr);
+ if (imm_expr.X_add_number & ~OP_MASK_SA3)
+ {
+ as_warn (_("DSP immediate not in range 0..%d (%lu)"),
+ OP_MASK_SA3, (unsigned long) imm_expr.X_add_number);
+ imm_expr.X_add_number &= OP_MASK_SA3;
+ }
+ ip->insn_opcode |= imm_expr.X_add_number << OP_SH_SA3;
+ imm_expr.X_op = O_absent;
+ s = expr_end;
+ continue;
+
+ case '4': /* dsp 4-bit unsigned immediate in bit 21 */
+ my_getExpression (&imm_expr, s);
+ check_absolute_expr (ip, &imm_expr);
+ if (imm_expr.X_add_number & ~OP_MASK_SA4)
+ {
+ as_warn (_("DSP immediate not in range 0..%d (%lu)"),
+ OP_MASK_SA4, (unsigned long) imm_expr.X_add_number);
+ imm_expr.X_add_number &= OP_MASK_SA4;
+ }
+ ip->insn_opcode |= imm_expr.X_add_number << OP_SH_SA4;
+ imm_expr.X_op = O_absent;
+ s = expr_end;
+ continue;
+
+ case '5': /* dsp 8-bit unsigned immediate in bit 16 */
+ my_getExpression (&imm_expr, s);
+ check_absolute_expr (ip, &imm_expr);
+ if (imm_expr.X_add_number & ~OP_MASK_IMM8)
+ {
+ as_warn (_("DSP immediate not in range 0..%d (%lu)"),
+ OP_MASK_IMM8, (unsigned long) imm_expr.X_add_number);
+ imm_expr.X_add_number &= OP_MASK_IMM8;
+ }
+ ip->insn_opcode |= imm_expr.X_add_number << OP_SH_IMM8;
+ imm_expr.X_op = O_absent;
+ s = expr_end;
+ continue;
+
+ case '6': /* dsp 5-bit unsigned immediate in bit 21 */
+ my_getExpression (&imm_expr, s);
+ check_absolute_expr (ip, &imm_expr);
+ if (imm_expr.X_add_number & ~OP_MASK_RS)
+ {
+ as_warn (_("DSP immediate not in range 0..%d (%lu)"),
+ OP_MASK_RS, (unsigned long) imm_expr.X_add_number);
+ imm_expr.X_add_number &= OP_MASK_RS;
+ }
+ ip->insn_opcode |= imm_expr.X_add_number << OP_SH_RS;
+ imm_expr.X_op = O_absent;
+ s = expr_end;
+ continue;
+
+ case '7': /* four dsp accumulators in bits 11,12 */
+ if (s[0] == '$' && s[1] == 'a' && s[2] == 'c' &&
+ s[3] >= '0' && s[3] <= '3')
+ {
+ regno = s[3] - '0';
+ s += 4;
+ ip->insn_opcode |= regno << OP_SH_DSPACC;
+ continue;
+ }
+ else
+ as_bad (_("Invalid dsp acc register"));
+ break;
+
+ case '8': /* dsp 6-bit unsigned immediate in bit 11 */
+ my_getExpression (&imm_expr, s);
+ check_absolute_expr (ip, &imm_expr);
+ if (imm_expr.X_add_number & ~OP_MASK_WRDSP)
+ {
+ as_warn (_("DSP immediate not in range 0..%d (%lu)"),
+ OP_MASK_WRDSP,
+ (unsigned long) imm_expr.X_add_number);
+ imm_expr.X_add_number &= OP_MASK_WRDSP;
+ }
+ ip->insn_opcode |= imm_expr.X_add_number << OP_SH_WRDSP;
+ imm_expr.X_op = O_absent;
+ s = expr_end;
+ continue;
+
+ case '9': /* four dsp accumulators in bits 21,22 */
+ if (s[0] == '$' && s[1] == 'a' && s[2] == 'c' &&
+ s[3] >= '0' && s[3] <= '3')
+ {
+ regno = s[3] - '0';
+ s += 4;
+ ip->insn_opcode |= regno << OP_SH_DSPACC_S;
+ continue;
+ }
+ else
+ as_bad (_("Invalid dsp acc register"));
+ break;
+
+ case '0': /* dsp 6-bit signed immediate in bit 20 */
+ my_getExpression (&imm_expr, s);
+ check_absolute_expr (ip, &imm_expr);
+ min_range = -((OP_MASK_DSPSFT + 1) >> 1);
+ max_range = ((OP_MASK_DSPSFT + 1) >> 1) - 1;
+ if (imm_expr.X_add_number < min_range ||
+ imm_expr.X_add_number > max_range)
+ {
+ as_warn (_("DSP immediate not in range %ld..%ld (%ld)"),
+ (long) min_range, (long) max_range,
+ (long) imm_expr.X_add_number);
+ }
+ imm_expr.X_add_number &= OP_MASK_DSPSFT;
+ ip->insn_opcode |= ((unsigned long) imm_expr.X_add_number
+ << OP_SH_DSPSFT);
+ imm_expr.X_op = O_absent;
+ s = expr_end;
+ continue;
+
+ case '\'': /* dsp 6-bit unsigned immediate in bit 16 */
+ my_getExpression (&imm_expr, s);
+ check_absolute_expr (ip, &imm_expr);
+ if (imm_expr.X_add_number & ~OP_MASK_RDDSP)
+ {
+ as_warn (_("DSP immediate not in range 0..%d (%lu)"),
+ OP_MASK_RDDSP,
+ (unsigned long) imm_expr.X_add_number);
+ imm_expr.X_add_number &= OP_MASK_RDDSP;
+ }
+ ip->insn_opcode |= imm_expr.X_add_number << OP_SH_RDDSP;
+ imm_expr.X_op = O_absent;
+ s = expr_end;
+ continue;
+
+ case ':': /* dsp 7-bit signed immediate in bit 19 */
+ my_getExpression (&imm_expr, s);
+ check_absolute_expr (ip, &imm_expr);
+ min_range = -((OP_MASK_DSPSFT_7 + 1) >> 1);
+ max_range = ((OP_MASK_DSPSFT_7 + 1) >> 1) - 1;
+ if (imm_expr.X_add_number < min_range ||
+ imm_expr.X_add_number > max_range)
+ {
+ as_warn (_("DSP immediate not in range %ld..%ld (%ld)"),
+ (long) min_range, (long) max_range,
+ (long) imm_expr.X_add_number);
+ }
+ imm_expr.X_add_number &= OP_MASK_DSPSFT_7;
+ ip->insn_opcode |= ((unsigned long) imm_expr.X_add_number
+ << OP_SH_DSPSFT_7);
+ imm_expr.X_op = O_absent;
+ s = expr_end;
+ continue;
+
+ case '@': /* dsp 10-bit signed immediate in bit 16 */
+ my_getExpression (&imm_expr, s);
+ check_absolute_expr (ip, &imm_expr);
+ min_range = -((OP_MASK_IMM10 + 1) >> 1);
+ max_range = ((OP_MASK_IMM10 + 1) >> 1) - 1;
+ if (imm_expr.X_add_number < min_range ||
+ imm_expr.X_add_number > max_range)
+ {
+ as_warn (_("DSP immediate not in range %ld..%ld (%ld)"),
+ (long) min_range, (long) max_range,
+ (long) imm_expr.X_add_number);
+ }
+ imm_expr.X_add_number &= OP_MASK_IMM10;
+ ip->insn_opcode |= ((unsigned long) imm_expr.X_add_number
+ << OP_SH_IMM10);
+ imm_expr.X_op = O_absent;
+ s = expr_end;
+ continue;
+
+ case '!': /* mt 1-bit unsigned immediate in bit 5 */
+ my_getExpression (&imm_expr, s);
+ check_absolute_expr (ip, &imm_expr);
+ if (imm_expr.X_add_number & ~OP_MASK_MT_U)
+ {
+ as_warn (_("MT immediate not in range 0..%d (%lu)"),
+ OP_MASK_MT_U, (unsigned long) imm_expr.X_add_number);
+ imm_expr.X_add_number &= OP_MASK_MT_U;
+ }
+ ip->insn_opcode |= imm_expr.X_add_number << OP_SH_MT_U;
+ imm_expr.X_op = O_absent;
+ s = expr_end;
+ continue;
+
+ case '$': /* mt 1-bit unsigned immediate in bit 4 */
+ my_getExpression (&imm_expr, s);
+ check_absolute_expr (ip, &imm_expr);
+ if (imm_expr.X_add_number & ~OP_MASK_MT_H)
+ {
+ as_warn (_("MT immediate not in range 0..%d (%lu)"),
+ OP_MASK_MT_H, (unsigned long) imm_expr.X_add_number);
+ imm_expr.X_add_number &= OP_MASK_MT_H;
+ }
+ ip->insn_opcode |= imm_expr.X_add_number << OP_SH_MT_H;
+ imm_expr.X_op = O_absent;
+ s = expr_end;
+ continue;
+
+ case '*': /* four dsp accumulators in bits 18,19 */
+ if (s[0] == '$' && s[1] == 'a' && s[2] == 'c' &&
+ s[3] >= '0' && s[3] <= '3')
+ {
+ regno = s[3] - '0';
+ s += 4;
+ ip->insn_opcode |= regno << OP_SH_MTACC_T;
+ continue;
+ }
+ else
+ as_bad (_("Invalid dsp/smartmips acc register"));
+ break;
+
+ case '&': /* four dsp accumulators in bits 13,14 */
+ if (s[0] == '$' && s[1] == 'a' && s[2] == 'c' &&
+ s[3] >= '0' && s[3] <= '3')
+ {
+ regno = s[3] - '0';
+ s += 4;
+ ip->insn_opcode |= regno << OP_SH_MTACC_D;
+ continue;
+ }
+ else
+ as_bad (_("Invalid dsp/smartmips acc register"));
+ break;
+
case ',':
if (*s++ == *args)
continue;
if (imm2_expr.X_op != O_big
&& imm2_expr.X_op != O_constant)
insn_error = _("absolute expression required");
- normalize_constant_expr (&imm2_expr);
+ if (HAVE_32BIT_GPRS)
+ normalize_constant_expr (&imm2_expr);
s = expr_end;
continue;
+ case 'T': /* Coprocessor register */
+ /* +T is for disassembly only; never match. */
+ break;
+
+ case 't': /* Coprocessor register number */
+ if (s[0] == '$' && ISDIGIT (s[1]))
+ {
+ ++s;
+ regno = 0;
+ do
+ {
+ regno *= 10;
+ regno += *s - '0';
+ ++s;
+ }
+ while (ISDIGIT (*s));
+ if (regno > 31)
+ as_bad (_("Invalid register number (%d)"), regno);
+ else
+ {
+ ip->insn_opcode |= regno << OP_SH_RT;
+ continue;
+ }
+ }
+ else
+ as_bad (_("Invalid coprocessor 0 register number"));
+ break;
+
default:
as_bad (_("internal: bad mips opcode (unknown extension operand type `+%c'): %s %s"),
*args, insn->name, insn->args);
case 'x': /* ignore register name */
case 'z': /* must be zero register */
case 'U': /* destination register (clo/clz). */
+ case 'g': /* coprocessor destination register */
s_reset = s;
if (s[0] == '$')
{
case 'd':
case 'G':
case 'K':
+ case 'g':
INSERT_OPERAND (RD, *ip, regno);
break;
case 'U':
|| strcmp (str, "lwc1") == 0
|| strcmp (str, "swc1") == 0
|| strcmp (str, "l.s") == 0
- || strcmp (str, "s.s") == 0))
+ || strcmp (str, "s.s") == 0
+ || strcmp (str, "mftc1") == 0
+ || strcmp (str, "mfthc1") == 0
+ || strcmp (str, "cftc1") == 0
+ || strcmp (str, "mttc1") == 0
+ || strcmp (str, "mtthc1") == 0
+ || strcmp (str, "cttc1") == 0))
as_warn (_("Float register should be even, was %d"),
regno);
if (imm_expr.X_op != O_big
&& imm_expr.X_op != O_constant)
insn_error = _("absolute expression required");
- normalize_constant_expr (&imm_expr);
+ if (HAVE_32BIT_GPRS)
+ normalize_constant_expr (&imm_expr);
s = expr_end;
continue;
case 'A':
my_getExpression (&offset_expr, s);
+ normalize_address_expr (&offset_expr);
*imm_reloc = BFD_RELOC_32;
s = expr_end;
continue;
{"mdmx", no_argument, NULL, OPTION_MDMX},
#define OPTION_NO_MDMX (OPTION_ASE_BASE + 5)
{"no-mdmx", no_argument, NULL, OPTION_NO_MDMX},
+#define OPTION_DSP (OPTION_ASE_BASE + 6)
+ {"mdsp", no_argument, NULL, OPTION_DSP},
+#define OPTION_NO_DSP (OPTION_ASE_BASE + 7)
+ {"mno-dsp", no_argument, NULL, OPTION_NO_DSP},
+#define OPTION_MT (OPTION_ASE_BASE + 8)
+ {"mmt", no_argument, NULL, OPTION_MT},
+#define OPTION_NO_MT (OPTION_ASE_BASE + 9)
+ {"mno-mt", no_argument, NULL, OPTION_NO_MT},
/* Old-style architecture options. Don't add more of these. */
-#define OPTION_COMPAT_ARCH_BASE (OPTION_ASE_BASE + 6)
+#define OPTION_COMPAT_ARCH_BASE (OPTION_ASE_BASE + 10)
#define OPTION_M4650 (OPTION_COMPAT_ARCH_BASE + 0)
{"m4650", no_argument, NULL, OPTION_M4650},
#define OPTION_NO_M4650 (OPTION_COMPAT_ARCH_BASE + 1)
mips_opts.ase_mdmx = 0;
break;
+ case OPTION_DSP:
+ mips_opts.ase_dsp = 1;
+ break;
+
+ case OPTION_NO_DSP:
+ mips_opts.ase_dsp = 0;
+ break;
+
+ case OPTION_MT:
+ mips_opts.ase_mt = 1;
+ break;
+
+ case OPTION_NO_MT:
+ mips_opts.ase_mt = 0;
+ break;
+
case OPTION_MIPS16:
mips_opts.mips16 = 1;
mips_no_prev_insn ();
mips_opts.ase_mips3d = (CPU_HAS_MIPS3D (file_mips_arch)) ? 1 : 0;
if (mips_opts.ase_mdmx == -1)
mips_opts.ase_mdmx = (CPU_HAS_MDMX (file_mips_arch)) ? 1 : 0;
+ if (mips_opts.ase_dsp == -1)
+ mips_opts.ase_dsp = (CPU_HAS_DSP (file_mips_arch)) ? 1 : 0;
+ if (mips_opts.ase_mt == -1)
+ mips_opts.ase_mt = (CPU_HAS_MT (file_mips_arch)) ? 1 : 0;
file_mips_isa = mips_opts.isa;
file_ase_mips16 = mips_opts.mips16;
file_ase_mips3d = mips_opts.ase_mips3d;
file_ase_mdmx = mips_opts.ase_mdmx;
+ file_ase_dsp = mips_opts.ase_dsp;
+ file_ase_mt = mips_opts.ase_mt;
mips_opts.gp32 = file_mips_gp32;
mips_opts.fp32 = file_mips_fp32;
}
/* Sort any unmatched HI16 and GOT16 relocs so that they immediately precede
- the corresponding LO16 reloc. This is called before md_apply_fix3 and
+ the corresponding LO16 reloc. This is called before md_apply_fix and
tc_gen_reloc. Unmatched relocs can only be generated by use of explicit
relocation operators.
if (*pos == l->fixp)
hi_pos = pos;
- if ((*pos)->fx_r_type == BFD_RELOC_LO16
+ if (((*pos)->fx_r_type == BFD_RELOC_LO16
+ || (*pos)->fx_r_type == BFD_RELOC_MIPS16_LO16)
&& (*pos)->fx_addsy == l->fixp->fx_addsy
&& (*pos)->fx_offset >= l->fixp->fx_offset
&& (lo_pos == NULL
/* Apply a fixup to the object file. */
void
-md_apply_fix3 (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
+md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
{
bfd_byte *buf;
long insn;
hiv = 0xffffffff;
else
hiv = 0;
- md_number_to_chars ((char *)(buf + target_big_endian ? 4 : 0),
+ md_number_to_chars ((char *)(buf + (target_big_endian ? 4 : 0)),
*valP, 4);
- md_number_to_chars ((char *)(buf + target_big_endian ? 0 : 4),
+ md_number_to_chars ((char *)(buf + (target_big_endian ? 0 : 4)),
hiv, 4);
}
}
symbolS *symbolP;
flagword flag;
- name = input_line_pointer;
- c = get_symbol_end ();
- symbolP = symbol_find_or_make (name);
- *input_line_pointer = c;
- SKIP_WHITESPACE ();
-
- /* On Irix 5, every global symbol that is not explicitly labelled as
- being a function is apparently labelled as being an object. */
- flag = BSF_OBJECT;
-
- if (! is_end_of_line[(unsigned char) *input_line_pointer])
+ do
{
- char *secname;
- asection *sec;
-
- secname = input_line_pointer;
+ name = input_line_pointer;
c = get_symbol_end ();
- sec = bfd_get_section_by_name (stdoutput, secname);
- if (sec == NULL)
- as_bad (_("%s: no such section"), secname);
+ symbolP = symbol_find_or_make (name);
+ S_SET_EXTERNAL (symbolP);
+
*input_line_pointer = c;
+ SKIP_WHITESPACE ();
- if (sec != NULL && (sec->flags & SEC_CODE) != 0)
- flag = BSF_FUNCTION;
- }
+ /* On Irix 5, every global symbol that is not explicitly labelled as
+ being a function is apparently labelled as being an object. */
+ flag = BSF_OBJECT;
+
+ if (!is_end_of_line[(unsigned char) *input_line_pointer]
+ && (*input_line_pointer != ','))
+ {
+ char *secname;
+ asection *sec;
+
+ secname = input_line_pointer;
+ c = get_symbol_end ();
+ sec = bfd_get_section_by_name (stdoutput, secname);
+ if (sec == NULL)
+ as_bad (_("%s: no such section"), secname);
+ *input_line_pointer = c;
+
+ if (sec != NULL && (sec->flags & SEC_CODE) != 0)
+ flag = BSF_FUNCTION;
+ }
- symbol_get_bfdsym (symbolP)->flags |= flag;
+ symbol_get_bfdsym (symbolP)->flags |= flag;
+
+ c = *input_line_pointer;
+ if (c == ',')
+ {
+ input_line_pointer++;
+ SKIP_WHITESPACE ();
+ if (is_end_of_line[(unsigned char) *input_line_pointer])
+ c = '\n';
+ }
+ }
+ while (c == ',');
- S_SET_EXTERNAL (symbolP);
demand_empty_rest_of_line ();
}
mips_opts.ase_mdmx = 1;
else if (strcmp (name, "nomdmx") == 0)
mips_opts.ase_mdmx = 0;
+ else if (strcmp (name, "dsp") == 0)
+ mips_opts.ase_dsp = 1;
+ else if (strcmp (name, "nodsp") == 0)
+ mips_opts.ase_dsp = 0;
+ else if (strcmp (name, "mt") == 0)
+ mips_opts.ase_mt = 1;
+ else if (strcmp (name, "nomt") == 0)
+ mips_opts.ase_mt = 0;
else if (strncmp (name, "mips", 4) == 0 || strncmp (name, "arch=", 5) == 0)
{
int reset = 0;
expressionS ex;
ex.X_op = O_symbol;
- ex.X_add_symbol = symbol_find_or_make ("_gp");
+ ex.X_add_symbol = symbol_find_or_make ("__gnu_local_gp");
ex.X_op_symbol = NULL;
ex.X_add_number = 0;
placed anywhere. Rather than break backwards compatibility by changing
this, it seems better not to force the issue, and instead keep the
original symbol. This will work with either linker behavior. */
- if ((fixp->fx_r_type == BFD_RELOC_LO16 || reloc_needs_lo_p (fixp->fx_r_type))
+ if ((fixp->fx_r_type == BFD_RELOC_LO16
+ || fixp->fx_r_type == BFD_RELOC_MIPS16_LO16
+ || reloc_needs_lo_p (fixp->fx_r_type))
&& HAVE_IN_PLACE_ADDENDS
&& (S_GET_SEGMENT (fixp->fx_addsy)->flags & SEC_MERGE) != 0)
return 0;
elf_elfheader (stdoutput)->e_flags |= EF_MIPS_CPIC;
/* Set MIPS ELF flags for ASEs. */
+ /* We may need to define a new flag for DSP ASE, and set this flag when
+ file_ase_dsp is true. */
+ /* We may need to define a new flag for MT ASE, and set this flag when
+ file_ase_mt is true. */
if (file_ase_mips16)
elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ARCH_ASE_M16;
#if 0 /* XXX FIXME */
{ "4km", 0, ISA_MIPS32, CPU_MIPS32 },
{ "4kp", 0, ISA_MIPS32, CPU_MIPS32 },
+ /* MIPS32 Release 2 */
+ { "m4k", 0, ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "24k", 0, ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "24kc", 0, ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "24kf", 0, ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "24kx", 0, ISA_MIPS32R2, CPU_MIPS32R2 },
+
/* MIPS 64 */
{ "5kc", 0, ISA_MIPS64, CPU_MIPS64 },
+ { "5kf", 0, ISA_MIPS64, CPU_MIPS64 },
{ "20kc", 0, ISA_MIPS64, CPU_MIPS64 },
/* Broadcom SB-1 CPU core */
-mips16 generate mips16 instructions\n\
-no-mips16 do not generate mips16 instructions\n"));
fprintf (stream, _("\
+-mdsp generate DSP instructions\n\
+-mno-dsp do not generate DSP instructions\n"));
+ fprintf (stream, _("\
+-mmt generate MT instructions\n\
+-mno-mt do not generate MT instructions\n"));
+ fprintf (stream, _("\
-mfix-vr4120 work around certain VR4120 errata\n\
-mfix-vr4130 work around VR4130 mflo/mfhi errata\n\
-mgp32 use 32-bit GPRs, regardless of the chosen ISA\n\
else
return 4;
}
+
+/* Standard calling conventions leave the CFA at SP on entry. */
+void
+mips_cfi_frame_initial_instructions (void)
+{
+ cfi_add_CFA_def_cfa_register (SP);
+}
+