334 lines
12 KiB
Diff
334 lines
12 KiB
Diff
diff -uNrbB binutils-2.13.2.1/gas/as.c binutils/gas/as.c
|
|
--- binutils-2.13.2.1/gas/as.c 2002-12-20 22:19:05.000000000 +0100
|
|
+++ binutils/gas/as.c 2004-03-31 22:47:52.000000000 +0200
|
|
@@ -212,6 +212,7 @@
|
|
#else
|
|
fprintf (stderr, _("GNU assembler version %s (%s)"), VERSION, TARGET_ALIAS);
|
|
#endif
|
|
+ fprintf (stderr, _(" with Broadcom modifications"));
|
|
fprintf (stderr, "\n");
|
|
}
|
|
|
|
@@ -529,10 +530,11 @@
|
|
case OPTION_VERSION:
|
|
/* This output is intended to follow the GNU standards document. */
|
|
#ifdef BFD_ASSEMBLER
|
|
- printf (_("GNU assembler %s\n"), BFD_VERSION_STRING);
|
|
+ printf (_("GNU assembler %s"), BFD_VERSION_STRING);
|
|
#else
|
|
- printf (_("GNU assembler %s\n"), VERSION);
|
|
+ printf (_("GNU assembler %s"), VERSION);
|
|
#endif
|
|
+ printf (_(" with Broadcom modifications\n"));
|
|
printf (_("Copyright 2002 Free Software Foundation, Inc.\n"));
|
|
printf (_("\
|
|
This program is free software; you may redistribute it under the terms of\n\
|
|
diff -uNrbB binutils-2.13.2.1/gas/config/tc-mips.c binutils/gas/config/tc-mips.c
|
|
--- binutils-2.13.2.1/gas/config/tc-mips.c 2002-11-05 23:03:40.000000000 +0100
|
|
+++ binutils/gas/config/tc-mips.c 2004-03-31 22:47:54.000000000 +0200
|
|
@@ -106,6 +106,13 @@
|
|
|
|
extern int target_big_endian;
|
|
|
|
+/* WA_BCM4710A0 */
|
|
+#if BCM4710A0
|
|
+static int wa_bcm4710a0 = 1;
|
|
+#else
|
|
+#define wa_bcm4710a0 0
|
|
+#endif
|
|
+
|
|
/* The name of the readonly data section. */
|
|
#define RDATA_SECTION_NAME (OUTPUT_FLAVOR == bfd_target_aout_flavour \
|
|
? ".data" \
|
|
@@ -2130,6 +2137,8 @@
|
|
|| (pinfo & INSN_COND_BRANCH_DELAY))
|
|
{
|
|
if (mips_optimize < 2
|
|
+ /* WA_BCM4710A0: Shortcut the whole conditional and always add nops */
|
|
+ || wa_bcm4710a0 == 1
|
|
/* If we have seen .set volatile or .set nomove, don't
|
|
optimize. */
|
|
|| mips_opts.nomove != 0
|
|
@@ -2342,6 +2351,11 @@
|
|
instruction at the destination, put it in the delay
|
|
slot, and bump the destination address. */
|
|
emit_nop ();
|
|
+
|
|
+ /* WA_BCM4710A0: Add another nop */
|
|
+ if (wa_bcm4710a0)
|
|
+ emit_nop ();
|
|
+
|
|
/* Update the previous insn information. */
|
|
prev_prev_insn = *ip;
|
|
prev_insn.insn_mo = &dummy_opcode;
|
|
@@ -2456,6 +2470,11 @@
|
|
into the delay slot, and increment the branch to jump to
|
|
the next instruction. */
|
|
emit_nop ();
|
|
+
|
|
+ /* WA_BCM4710A0: Add another nop */
|
|
+ if (wa_bcm4710a0)
|
|
+ emit_nop ();
|
|
+
|
|
/* Update the previous insn information. */
|
|
prev_prev_insn = *ip;
|
|
prev_insn.insn_mo = &dummy_opcode;
|
|
@@ -2500,6 +2519,167 @@
|
|
}
|
|
else if (place == NULL)
|
|
{
|
|
+ if(wa_bcm4710a0) {
|
|
+ /* We took care above of adding noops when reordering, now
|
|
+ need to do the same when not reordering. Unless this
|
|
+ is already a nop.
|
|
+ This means swapping the insn in the delay slot with the
|
|
+ jump and adding the nops. */
|
|
+
|
|
+#define MIPS_INSN_MOVE 0x00000021
|
|
+#define MIPS_INSN_MOVE2 0x00000025
|
|
+#define GLIBC_SET_GP 0x04100000
|
|
+
|
|
+ if (prev_pinfo & (INSN_UNCOND_BRANCH_DELAY | INSN_COND_BRANCH_DELAY | INSN_COND_BRANCH_LIKELY)) {
|
|
+
|
|
+ /* Special case for glibc SET_GP macro */
|
|
+ if (prev_insn.insn_opcode == GLIBC_SET_GP) {
|
|
+ as_warn (_("bcm4710a0: NOT adding nop to glibc SET_GP macro (0x%lx %s)"),
|
|
+ prev_insn.insn_opcode, prev_insn.insn_mo->name);
|
|
+ goto skip_nop;
|
|
+ }
|
|
+
|
|
+ /* If it is a nop or just a move, let it go. XXX: we should add a flag to
|
|
+ pinfo to let us know which insn's are ok, i.e. they don't
|
|
+ cause any stalls. */
|
|
+ if ((ip->insn_opcode != 0)
|
|
+ && ((ip->insn_opcode & ip->insn_mo->mask) != MIPS_INSN_MOVE)
|
|
+ && ((ip->insn_opcode & ip->insn_mo->mask) != MIPS_INSN_MOVE2)) {
|
|
+
|
|
+ int wreg = 0, wrsh = 0, rs = 0, rt = 0;
|
|
+ unsigned long wrmsk = 0, temp;
|
|
+ char *prev_f;
|
|
+
|
|
+ /* Bad case: we cannot move a trap */
|
|
+ if (pinfo & INSN_TRAP) {
|
|
+ as_warn (_("bcm4710a0: Current insn (%s) is a trap, cannot swap with %s"),
|
|
+ ip->insn_mo->name, prev_insn.insn_mo->name);
|
|
+ goto skip_swap;
|
|
+ }
|
|
+
|
|
+ /* Another bad case: we cannot move stuff after a branch likely */
|
|
+ if (pinfo & INSN_COND_BRANCH_LIKELY) {
|
|
+ as_warn (_("bcm4710a0: Current insn (%s) cannot be swaped with branch likely %s"),
|
|
+ ip->insn_mo->name, prev_insn.insn_mo->name);
|
|
+ goto skip_swap;
|
|
+ }
|
|
+ /* Also, we cannot move if there is a cc conflict */
|
|
+ if ((pinfo & INSN_WRITE_COND_CODE) && (prev_pinfo & INSN_READ_COND_CODE)) {
|
|
+ as_warn (_("bcm4710a0: Current insn (%s) writes CC, cannot swap with %s which reads CC"),
|
|
+ ip->insn_mo->name, prev_insn.insn_mo->name);
|
|
+ goto skip_swap;
|
|
+ }
|
|
+
|
|
+ /* or a hi conflict */
|
|
+ if ((pinfo & INSN_WRITE_HI) && (prev_pinfo & INSN_READ_HI)) {
|
|
+ as_warn (_("bcm4710a0: Current insn (%s) writes HI, cannot swap with %s which reads HI"),
|
|
+ ip->insn_mo->name, prev_insn.insn_mo->name);
|
|
+ goto skip_swap;
|
|
+ }
|
|
+
|
|
+ /* or a lo conflict */
|
|
+ if ((pinfo & INSN_WRITE_LO) && (prev_pinfo & INSN_READ_LO)) {
|
|
+ as_warn (_("bcm4710a0: Current insn (%s) writes LO, cannot swap with %s which reads LO"),
|
|
+ ip->insn_mo->name, prev_insn.insn_mo->name);
|
|
+ goto skip_swap;
|
|
+ }
|
|
+
|
|
+ /* Which register if any is modified by the current insn? */
|
|
+ if (pinfo & INSN_WRITE_GPR_D) {
|
|
+ wreg = (ip->insn_opcode >> OP_SH_RD) & OP_MASK_RD;
|
|
+ wrsh = OP_SH_RD;
|
|
+ wrmsk = OP_MASK_RD;
|
|
+ } else if (pinfo & INSN_WRITE_GPR_T) {
|
|
+ wreg = (ip->insn_opcode >> OP_SH_RT) & OP_MASK_RT;
|
|
+ wrsh = OP_SH_RT;
|
|
+ wrmsk = OP_MASK_RT;
|
|
+ } else if (pinfo & INSN_WRITE_GPR_31)
|
|
+ wreg = RA;
|
|
+
|
|
+ if (wreg) {
|
|
+ /* Is that reg used by the previous insn? */
|
|
+ if (prev_pinfo & INSN_READ_GPR_S)
|
|
+ rs = (prev_insn.insn_opcode >> OP_SH_RS) & OP_MASK_RS;
|
|
+ if (prev_pinfo & INSN_READ_GPR_T)
|
|
+ rt = (prev_insn.insn_opcode >> OP_SH_RT) & OP_MASK_RT;
|
|
+ if ((wreg != rs) && (wreg != rt)) {
|
|
+ /* Nope, We *can* do the swap */
|
|
+ wreg = 0;
|
|
+ } else {
|
|
+ /* Cannot swap without some more surgery,
|
|
+ but do not swap at all if it is $at */
|
|
+ if (wreg == AT) {
|
|
+ as_warn (_("bcm4710a0: Current insn (%s) uses reg%d, cannot swap with %s"),
|
|
+ ip->insn_mo->name, wreg, prev_insn.insn_mo->name);
|
|
+ goto skip_swap;
|
|
+ }
|
|
+ /* or if $at is not avaliable */
|
|
+ if (mips_opts.noat) {
|
|
+ as_warn (_("bcm4710a0: .set noat in effect, cannot swap %s with %s"),
|
|
+ ip->insn_mo->name, prev_insn.insn_mo->name);
|
|
+ goto skip_swap;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Swap the previous insn (a jump) and the current one */
|
|
+ assert (prev_insn_frag != NULL);
|
|
+ prev_f = prev_insn_frag->fr_literal + prev_insn_where;
|
|
+ memcpy (&temp, f, 4);
|
|
+ if (wreg) {
|
|
+ /* Modify the instruction to use at */
|
|
+ temp = (temp & ~(wrmsk << wrsh)) | (AT << wrsh);
|
|
+ }
|
|
+ memcpy (f, prev_f, 4);
|
|
+ memcpy (prev_f, &temp, 4);
|
|
+ if (prev_insn_fixp[0]) {
|
|
+ prev_insn_fixp[0]->fx_frag = frag_now;
|
|
+ prev_insn_fixp[0]->fx_where = f - frag_now->fr_literal;
|
|
+ }
|
|
+ if (prev_insn_fixp[1]) {
|
|
+ prev_insn_fixp[1]->fx_frag = frag_now;
|
|
+ prev_insn_fixp[1]->fx_where = f - frag_now->fr_literal;
|
|
+ }
|
|
+ if (prev_insn_fixp[2]) {
|
|
+ prev_insn_fixp[2]->fx_frag = frag_now;
|
|
+ prev_insn_fixp[2]->fx_where = f - frag_now->fr_literal;
|
|
+ }
|
|
+ if (fixp[0]) {
|
|
+ fixp[0]->fx_frag = prev_insn_frag;
|
|
+ fixp[0]->fx_where = prev_insn_where;
|
|
+ }
|
|
+ if (fixp[1]) {
|
|
+ fixp[1]->fx_frag = prev_insn_frag;
|
|
+ fixp[1]->fx_where = prev_insn_where;
|
|
+ }
|
|
+ if (fixp[2]) {
|
|
+ fixp[2]->fx_frag = prev_insn_frag;
|
|
+ fixp[2]->fx_where = prev_insn_where;
|
|
+ }
|
|
+ /* Now put a nop or move after the jump ... */
|
|
+ if (wreg) {
|
|
+ /* A move if we modified the insn we moved. */
|
|
+ md_number_to_chars (frag_more (4),
|
|
+ (MIPS_INSN_MOVE | (wreg << OP_SH_RD) | (AT << OP_SH_RS)),
|
|
+ 4);
|
|
+ } else {
|
|
+ emit_nop ();
|
|
+ }
|
|
+ }
|
|
+skip_swap:
|
|
+ /* And another nop */
|
|
+ emit_nop ();
|
|
+ }
|
|
+skip_nop:
|
|
+ /* Remember stuff that is not normally remembered in the not-reordering
|
|
+ case so we can swap with next insn */
|
|
+ prev_insn_fixp[0] = fixp[0];
|
|
+ prev_insn_fixp[1] = fixp[1];
|
|
+ prev_insn_fixp[2] = fixp[2];
|
|
+ prev_insn_frag = frag_now;
|
|
+ prev_insn_where = f - frag_now->fr_literal;
|
|
+ }
|
|
+
|
|
/* We need to record a bit of information even when we are not
|
|
reordering, in order to determine the base address for mips16
|
|
PC relative relocs. */
|
|
@@ -10003,8 +10183,14 @@
|
|
{"mdmx", no_argument, NULL, OPTION_MDMX},
|
|
#define OPTION_NO_MDMX (OPTION_MD_BASE + 36)
|
|
{"no-mdmx", no_argument, NULL, OPTION_NO_MDMX},
|
|
+#define OPTION_M4710A0 (OPTION_MD_BASE + 37)
|
|
+ {"m4710a0", no_argument, NULL, OPTION_M4710A0},
|
|
+#define OPTION_NO_M4710A0 (OPTION_MD_BASE + 38)
|
|
+ {"no-m4710a0", no_argument, NULL, OPTION_NO_M4710A0},
|
|
+ {"mno-4710a0", no_argument, NULL, OPTION_NO_M4710A0},
|
|
+ {"m4710a0kern", no_argument, NULL, OPTION_NO_M4710A0},
|
|
#ifdef OBJ_ELF
|
|
-#define OPTION_ELF_BASE (OPTION_MD_BASE + 37)
|
|
+#define OPTION_ELF_BASE (OPTION_MD_BASE + 39)
|
|
#define OPTION_CALL_SHARED (OPTION_ELF_BASE + 0)
|
|
{"KPIC", no_argument, NULL, OPTION_CALL_SHARED},
|
|
{"call_shared", no_argument, NULL, OPTION_CALL_SHARED},
|
|
@@ -10213,6 +10399,16 @@
|
|
case OPTION_NO_M3900:
|
|
break;
|
|
|
|
+#if BCM4710A0
|
|
+ case OPTION_M4710A0:
|
|
+ wa_bcm4710a0 = 1;
|
|
+ break;
|
|
+
|
|
+ case OPTION_NO_M4710A0:
|
|
+ wa_bcm4710a0 = 0;
|
|
+ break;
|
|
+#endif
|
|
+
|
|
case OPTION_MDMX:
|
|
mips_opts.ase_mdmx = 1;
|
|
break;
|
|
diff -uNrbB binutils-2.13.2.1/gas/config.in binutils/gas/config.in
|
|
--- binutils-2.13.2.1/gas/config.in 2002-07-14 03:14:19.000000000 +0200
|
|
+++ binutils/gas/config.in 2004-03-31 22:47:52.000000000 +0200
|
|
@@ -271,3 +271,5 @@
|
|
/* Define if errno is not declared in system header files. */
|
|
#undef NEED_DECLARATION_ERRNO
|
|
|
|
+/* Define to 1 for BCM4710A0 compiler workarounds */
|
|
+#undef BCM4710A0
|
|
diff -uNrbB binutils-2.13.2.1/gas/configure binutils/gas/configure
|
|
--- binutils-2.13.2.1/gas/configure 2002-10-30 18:07:37.000000000 +0100
|
|
+++ binutils/gas/configure 2004-03-31 22:47:52.000000000 +0200
|
|
@@ -32,6 +32,8 @@
|
|
ac_help="$ac_help
|
|
--enable-build-warnings Enable build-time compiler warnings if gcc is used"
|
|
ac_help="$ac_help
|
|
+ --with-bcm4710a0 enable BCM4710A0 compiler workarounds"
|
|
+ac_help="$ac_help
|
|
--disable-nls do not use Native Language Support"
|
|
ac_help="$ac_help
|
|
--with-included-gettext use the GNU gettext library included here"
|
|
@@ -2936,6 +2938,18 @@
|
|
;;
|
|
esac
|
|
|
|
+# Enable BCM4710A0 compiler workarounds
|
|
+# Check whether --with-bcm4710a0 or --without-bcm4710a0 was given.
|
|
+if test "${with_bcm4710a0+set}" = set; then
|
|
+ withval="$with_bcm4710a0"
|
|
+ case "${withval}" in
|
|
+ yes) cat >> confdefs.h <<\EOF
|
|
+#define BCM4710A0 1
|
|
+EOF
|
|
+ ;;
|
|
+esac
|
|
+fi
|
|
+
|
|
# Getting this done right is going to be a bitch. Each configuration specified
|
|
# with --enable-targets=... should be checked for environment, format, cpu, and
|
|
# bfd_gas setting.
|
|
diff -uNrbB binutils-2.13.2.1/gas/configure.in binutils/gas/configure.in
|
|
--- binutils-2.13.2.1/gas/configure.in 2002-10-30 18:07:32.000000000 +0100
|
|
+++ binutils/gas/configure.in 2004-03-31 22:47:52.000000000 +0200
|
|
@@ -762,6 +762,13 @@
|
|
;;
|
|
esac
|
|
|
|
+# With BCM4710A0 compiler workarounds
|
|
+AC_ARG_WITH(bcm4710a0,
|
|
+[ --with-bcm4710a0 enable BCM4710A0 compiler workarounds],
|
|
+[case "${withval}" in
|
|
+ yes) AC_DEFINE(BCM4710A0, 1, [BCM4710A0 support?]) ;;
|
|
+esac])
|
|
+
|
|
# Getting this done right is going to be a bitch. Each configuration specified
|
|
# with --enable-targets=... should be checked for environment, format, cpu, and
|
|
# bfd_gas setting.
|