2009-04-09 Catherine Moore <clm@codesourcery.com>

* config/tc-mips.c (mips_fix_24k): Declare.
        (check_for_24k_errata): New.
        (mips_cleanup): Call check_for_24k_errata.
        (start_noreorder): Likewise.
        (md_mips_end): Likewise.
        (s_change_sec): Likewise.
        (s_change_section): Likewise.
        (append_insn): Call check_for_24k_errata.  Prevent
        ERET/DERET instructions from being moved into delay
        slots.
        (OPTION_FIX_24K): New.
        (OPTION_NO_FIX_24k) New.
        (md_longopts): Add "mfix-24k" and "mno-fix-24k".
        (md_parse_option): Handle fix-24k options.
        (md_show_usage): Display fix-24k options.
        * doc/c-mips.texi: Document.
        * testsuite/gas/mips/mips.exp: Run new tests.
        * testsuite/gas/mips/eret.s: New test.
        * testsuite/gas/mips/eret.d: New test output.
        * testsuite/gas/mips/eret.l: New test output.
This commit is contained in:
Catherine Moore
2009-04-09 15:55:59 +00:00
parent ef699244c2
commit 6a32d87432
7 changed files with 232 additions and 3 deletions

View File

@ -1,3 +1,26 @@
2009-04-09 Catherine Moore <clm@codesourcery.com>
* config/tc-mips.c (mips_fix_24k): Declare.
(check_for_24k_errata): New.
(mips_cleanup): Call check_for_24k_errata.
(start_noreorder): Likewise.
(md_mips_end): Likewise.
(s_change_sec): Likewise.
(s_change_section): Likewise.
(append_insn): Call check_for_24k_errata. Prevent
ERET/DERET instructions from being moved into delay
slots.
(OPTION_FIX_24K): New.
(OPTION_NO_FIX_24k) New.
(md_longopts): Add "mfix-24k" and "mno-fix-24k".
(md_parse_option): Handle fix-24k options.
(md_show_usage): Display fix-24k options.
* doc/c-mips.texi: Document.
* testsuite/gas/mips/mips.exp: Run new tests.
* testsuite/gas/mips/eret.s: New test.
* testsuite/gas/mips/eret.d: New test output.
* testsuite/gas/mips/eret.l: New test output.
2009-04-09 Adam Nemet <anemet@caviumnetworks.com> 2009-04-09 Adam Nemet <anemet@caviumnetworks.com>
* config/tc-mips.c (mips_dwarf2_addr_size): Use HAVE_64BIT_OBJECTS * config/tc-mips.c (mips_dwarf2_addr_size): Use HAVE_64BIT_OBJECTS

View File

@ -760,6 +760,9 @@ static int mips_fix_vr4120;
/* ...likewise -mfix-vr4130. */ /* ...likewise -mfix-vr4130. */
static int mips_fix_vr4130; static int mips_fix_vr4130;
/* ...likewise -mfix-24k. */
static int mips_fix_24k;
/* We don't relax branches by default, since this causes us to expand /* We don't relax branches by default, since this causes us to expand
`la .l2 - .l1' if there's a branch between .l1 and .l2, because we `la .l2 - .l1' if there's a branch between .l1 and .l2, because we
fail to compute the offset before expanding the macro to the most fail to compute the offset before expanding the macro to the most
@ -1789,6 +1792,85 @@ reg_lookup (char **s, unsigned int types, unsigned int *regnop)
return reg >= 0; return reg >= 0;
} }
#define INSN_ERET 0x42000018
#define INSN_DERET 0x4200001f
/* Implement the ERET/DERET Errata for MIPS 24k.
If an ERET/DERET is encountered in a noreorder block,
warn if the ERET/DERET is followed by a branch instruction.
Also warn if the ERET/DERET is the last instruction in the
noreorder block.
IF an ERET/DERET is in a reorder block and is followed by a
branch instruction, insert a nop. */
static void
check_for_24k_errata (struct mips_cl_insn *insn, int eret_ndx)
{
bfd_boolean next_insn_is_branch = FALSE;
/* eret_ndx will be -1 for the last instruction in a section
and the ERET/DERET will be in insn, not history. */
if (insn
&& eret_ndx == -1
&& (insn->insn_opcode == INSN_ERET
|| insn->insn_opcode == INSN_DERET)
&& insn->noreorder_p)
{
as_warn (_("ERET and DERET must be followed by a NOP on the 24K."));
return;
}
if (history[eret_ndx].insn_opcode != INSN_ERET
&& history[eret_ndx].insn_opcode != INSN_DERET)
return;
if (!insn)
{
if (history[eret_ndx].noreorder_p)
as_warn (_("ERET and DERET must be followed by a NOP on the 24K."));
return;
}
next_insn_is_branch = ((insn->insn_opcode == INSN_ERET)
|| (insn->insn_opcode == INSN_DERET)
|| (insn->insn_mo->pinfo
& (INSN_UNCOND_BRANCH_DELAY
| INSN_COND_BRANCH_DELAY
| INSN_COND_BRANCH_LIKELY)));
if (next_insn_is_branch && history[eret_ndx].noreorder_p)
{
as_warn (_("ERET and DERET must be followed by a NOP on the 24K."));
return;
}
/* Emit nop if the next instruction is a branch. */
if (next_insn_is_branch)
{
long nop_where, br_where;
struct frag *nop_frag, *br_frag;
struct mips_cl_insn br_insn, nop_insn;
emit_nop ();
nop_insn = history[eret_ndx - 1];
nop_frag = history[eret_ndx - 1].frag;
nop_where = history[eret_ndx - 1].where;
br_insn = history[eret_ndx];
br_frag = history[eret_ndx].frag;
br_where = history[eret_ndx].where;
move_insn (&nop_insn, br_frag, br_where);
move_insn (&br_insn, nop_frag, nop_where);
history[eret_ndx-1] = br_insn;
history[eret_ndx] = nop_insn;
}
}
/* Return TRUE if opcode MO is valid on the currently selected ISA and /* Return TRUE if opcode MO is valid on the currently selected ISA and
architecture. If EXPANSIONP is TRUE then this check is done while architecture. If EXPANSIONP is TRUE then this check is done while
expanding a macro. Use is_opcode_valid_16 for MIPS16 opcodes. */ expanding a macro. Use is_opcode_valid_16 for MIPS16 opcodes. */
@ -2074,6 +2156,9 @@ md_begin (void)
void void
md_mips_end (void) md_mips_end (void)
{ {
if (mips_fix_24k)
check_for_24k_errata ((struct mips_cl_insn *) &history[0], -1);
if (! ECOFF_DEBUGGING) if (! ECOFF_DEBUGGING)
md_obj_end (); md_obj_end ();
} }
@ -2705,6 +2790,7 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
bfd_reloc_code_real_type *reloc_type) bfd_reloc_code_real_type *reloc_type)
{ {
unsigned long prev_pinfo, pinfo; unsigned long prev_pinfo, pinfo;
int hndx_24k = 0;
relax_stateT prev_insn_frag_type = 0; relax_stateT prev_insn_frag_type = 0;
bfd_boolean relaxed_branch = FALSE; bfd_boolean relaxed_branch = FALSE;
segment_info_type *si = seg_info (now_seg); segment_info_type *si = seg_info (now_seg);
@ -3238,7 +3324,11 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
|| (mips_opts.mips16 && history[0].fixp[0]) || (mips_opts.mips16 && history[0].fixp[0])
/* If the previous instruction is a sync, sync.l, or /* If the previous instruction is a sync, sync.l, or
sync.p, we can not swap. */ sync.p, we can not swap. */
|| (prev_pinfo & INSN_SYNC)) || (prev_pinfo & INSN_SYNC)
/* If the previous instruction is an ERET or
DERET, avoid the swap. */
|| (history[0].insn_opcode == INSN_ERET)
|| (history[0].insn_opcode == INSN_DERET))
{ {
if (mips_opts.mips16 if (mips_opts.mips16
&& (pinfo & INSN_UNCOND_BRANCH_DELAY) && (pinfo & INSN_UNCOND_BRANCH_DELAY)
@ -3258,6 +3348,8 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
slot, and bump the destination address. */ slot, and bump the destination address. */
insert_into_history (0, 1, ip); insert_into_history (0, 1, ip);
emit_nop (); emit_nop ();
if (mips_fix_24k)
hndx_24k++;
} }
if (mips_relax.sequence) if (mips_relax.sequence)
@ -3297,7 +3389,14 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
/* If that was an unconditional branch, forget the previous /* If that was an unconditional branch, forget the previous
insn information. */ insn information. */
if (pinfo & INSN_UNCOND_BRANCH_DELAY) if (pinfo & INSN_UNCOND_BRANCH_DELAY)
mips_no_prev_insn (); {
/* Check for eret/deret before clearing history. */
if (mips_fix_24k)
check_for_24k_errata (
(struct mips_cl_insn *) &history[hndx_24k],
hndx_24k+1);
mips_no_prev_insn ();
}
} }
else if (pinfo & INSN_COND_BRANCH_LIKELY) else if (pinfo & INSN_COND_BRANCH_LIKELY)
{ {
@ -3307,6 +3406,8 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
the next instruction. */ the next instruction. */
insert_into_history (0, 1, ip); insert_into_history (0, 1, ip);
emit_nop (); emit_nop ();
if (mips_fix_24k)
hndx_24k++;
} }
else else
insert_into_history (0, 1, ip); insert_into_history (0, 1, ip);
@ -3314,6 +3415,10 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
else else
insert_into_history (0, 1, ip); insert_into_history (0, 1, ip);
if (mips_fix_24k)
check_for_24k_errata ((struct mips_cl_insn *) &history[hndx_24k],
hndx_24k+1);
/* We just output an insn, so the next one doesn't have a label. */ /* We just output an insn, so the next one doesn't have a label. */
mips_clear_insn_labels (); mips_clear_insn_labels ();
} }
@ -3400,6 +3505,9 @@ start_noreorder (void)
static void static void
end_noreorder (void) end_noreorder (void)
{ {
if (mips_fix_24k)
check_for_24k_errata (NULL, 0);
mips_opts.noreorder--; mips_opts.noreorder--;
if (mips_opts.noreorder == 0 && prev_nop_frag != NULL) if (mips_opts.noreorder == 0 && prev_nop_frag != NULL)
{ {
@ -11176,6 +11284,8 @@ enum options
OPTION_NO_M3900, OPTION_NO_M3900,
OPTION_M7000_HILO_FIX, OPTION_M7000_HILO_FIX,
OPTION_MNO_7000_HILO_FIX, OPTION_MNO_7000_HILO_FIX,
OPTION_FIX_24K,
OPTION_NO_FIX_24K,
OPTION_FIX_VR4120, OPTION_FIX_VR4120,
OPTION_NO_FIX_VR4120, OPTION_NO_FIX_VR4120,
OPTION_FIX_VR4130, OPTION_FIX_VR4130,
@ -11268,6 +11378,8 @@ struct option md_longopts[] =
{"mno-fix-vr4120", no_argument, NULL, OPTION_NO_FIX_VR4120}, {"mno-fix-vr4120", no_argument, NULL, OPTION_NO_FIX_VR4120},
{"mfix-vr4130", no_argument, NULL, OPTION_FIX_VR4130}, {"mfix-vr4130", no_argument, NULL, OPTION_FIX_VR4130},
{"mno-fix-vr4130", no_argument, NULL, OPTION_NO_FIX_VR4130}, {"mno-fix-vr4130", no_argument, NULL, OPTION_NO_FIX_VR4130},
{"mfix-24k", no_argument, NULL, OPTION_FIX_24K},
{"mno-fix-24k", no_argument, NULL, OPTION_NO_FIX_24K},
/* Miscellaneous options. */ /* Miscellaneous options. */
{"trap", no_argument, NULL, OPTION_TRAP}, {"trap", no_argument, NULL, OPTION_TRAP},
@ -11521,6 +11633,14 @@ md_parse_option (int c, char *arg)
mips_opts.ase_smartmips = 0; mips_opts.ase_smartmips = 0;
break; break;
case OPTION_FIX_24K:
mips_fix_24k = 1;
break;
case OPTION_NO_FIX_24K:
mips_fix_24k = 0;
break;
case OPTION_FIX_VR4120: case OPTION_FIX_VR4120:
mips_fix_vr4120 = 1; mips_fix_vr4120 = 1;
break; break;
@ -12468,6 +12588,10 @@ s_change_sec (int sec)
#endif #endif
mips_emit_delays (); mips_emit_delays ();
if (mips_fix_24k)
check_for_24k_errata ((struct mips_cl_insn *) &history[0], -1);
switch (sec) switch (sec)
{ {
case 't': case 't':
@ -12526,6 +12650,9 @@ s_change_section (int ignore ATTRIBUTE_UNUSED)
if (!IS_ELF) if (!IS_ELF)
return; return;
if (mips_fix_24k)
check_for_24k_errata ((struct mips_cl_insn *) &history[0], -1);
section_name = input_line_pointer; section_name = input_line_pointer;
c = get_symbol_end (); c = get_symbol_end ();
if (c) if (c)
@ -15457,6 +15584,7 @@ MIPS options:\n\
fprintf (stream, _("\ fprintf (stream, _("\
-mfix-vr4120 work around certain VR4120 errata\n\ -mfix-vr4120 work around certain VR4120 errata\n\
-mfix-vr4130 work around VR4130 mflo/mfhi errata\n\ -mfix-vr4130 work around VR4130 mflo/mfhi errata\n\
-mfix-24k insert a nop after ERET and DERET instructions\n\
-mgp32 use 32-bit GPRs, regardless of the chosen ISA\n\ -mgp32 use 32-bit GPRs, regardless of the chosen ISA\n\
-mfp32 use 32-bit FPRs, regardless of the chosen ISA\n\ -mfp32 use 32-bit FPRs, regardless of the chosen ISA\n\
-msym32 assume all symbols have 32-bit values\n\ -msym32 assume all symbols have 32-bit values\n\

View File

@ -182,6 +182,10 @@ all problems in hand-written assembler code.
@itemx -no-mfix-vr4130 @itemx -no-mfix-vr4130
Insert nops to work around the VR4130 @samp{mflo}/@samp{mfhi} errata. Insert nops to work around the VR4130 @samp{mflo}/@samp{mfhi} errata.
@item -mfix-24k
@itemx -no-mfix-24k
Insert nops to work around the 24K @samp{eret}/@samp{deret} errata.
@item -m4010 @item -m4010
@itemx -no-m4010 @itemx -no-m4010
Generate code for the LSI @sc{r4010} chip. This tells the assembler to Generate code for the LSI @sc{r4010} chip. This tells the assembler to

View File

@ -0,0 +1,41 @@
#objdump: -d
#name: MIPS eret disassembly
#as: -mfix-24k -march=24kc --no-warn
.*\.o: file format .*mips.*
Disassembly of section \.text:
00000000 <\.text>:
0: 240c0000 li t4,0
4: 42000018 eret
8: 00000000 nop
c: 10000003 b 0x1c
10: 00000000 nop
14: 240a0003 li t2,3
18: 42000018 eret
1c: 24040000 li a0,0
20: 4200001f deret
24: 00000000 nop
28: 116afffa beq t3,t2,0x14
2c: 00000000 nop
30: 4200001f deret
34: 00000000 nop
38: 42000018 eret
3c: 00000000 nop
40: 42000018 eret
44: 00000000 nop
48: 1000fff4 b 0x1c
4c: 00000000 nop
50: 240c0004 li t4,4
54: 4200001f deret
58: 240c0003 li t4,3
5c: 42000018 eret
60: 10000005 b 0x78
64: 240c0003 li t4,3
68: 42000018 eret
6c: 00000000 nop
70: 10000001 b 0x78
74: 240c0003 li t4,3
78: 240c0003 li t4,3
7c: 42000018 eret

View File

@ -0,0 +1,3 @@
.*\.s: Assembler messages:
.*\.s:20: Warning: ERET and DERET must be followed by a NOP on the 24K\.
.*\.s:27: Warning: ERET and DERET must be followed by a NOP on the 24K\.

View File

@ -0,0 +1,27 @@
.text
li $t4, 0
eret
b 2f
1: li $t2, 3
eret
2: li $a0, 0
deret
beq $t3,$t2,1b
deret
eret
eret
b 2b
.set noreorder
li $t4, 4
deret
li $t4, 3
eret
b 1f
li $t4, 3
eret
nop
b 1f
li $t4, 3
1: li $t4, 3
eret

View File

@ -436,6 +436,9 @@ if { [istarget mips*-*-vxworks*] } {
} else { } else {
run_dump_test "jal" run_dump_test "jal"
} }
run_dump_test "eret"
run_list_test "eret" "-mfix-24k -march=24kc" "MIPS eret warnings"
if $elf { run_dump_test "jal-svr4pic" } if $elf { run_dump_test "jal-svr4pic" }
if $elf { run_dump_test "jal-xgot" } if $elf { run_dump_test "jal-xgot" }
run_list_test_arches "jal-range" "-32" [mips_arch_list_matching mips1] run_list_test_arches "jal-range" "-32" [mips_arch_list_matching mips1]