This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[patch] [MIPS] Implement Errata for 24K and 24KE
- From: Catherine Moore <clm at codesourcery dot com>
- To: binutils at sourceware dot org
- Cc: Catherine Moore <clm at codesourcery dot com>
- Date: Wed, 08 Apr 2009 17:11:53 -0400
- Subject: [patch] [MIPS] Implement Errata for 24K and 24KE
This patch implements the errata for the 24K and 24KE. The errata calls for a NOP to be emitted
after an ERET/DERET instruction followed by a branch. If the ERET/DERET is in a noreorder section,
then a warning will be issued instead. This functionality requires the -mfix-24k option.
In addition, there was an error in the delay slot handling in append_insn. The code failed to
exclude an ERET or DERET instuction from being moved into a delay slot. That failure is also
corrected with this patch.
Does this look okay to install?
Thanks,
Catherine
2009-04-08 Catherine Moore <clm@codesourcery.com>
gas/
* 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.
Index: config/tc-mips.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-mips.c,v
retrieving revision 1.403
diff -p -r1.403 tc-mips.c
*** config/tc-mips.c 3 Feb 2009 18:16:03 -0000 1.403
--- config/tc-mips.c 8 Apr 2009 21:02:02 -0000
*************** static int mips_fix_vr4120;
*** 760,765 ****
--- 760,768 ----
/* ...likewise -mfix-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
`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
*************** reg_lookup (char **s, unsigned int types
*** 1789,1794 ****
--- 1792,1885 ----
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;
+ }
+ else
+ {
+ 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;
+
+ }
+
/* Return TRUE if opcode MO is valid on the currently selected ISA and
architecture. If EXPANSIONP is TRUE then this check is done while
expanding a macro. Use is_opcode_valid_16 for MIPS16 opcodes. */
*************** md_begin (void)
*** 2074,2079 ****
--- 2165,2173 ----
void
md_mips_end (void)
{
+ if (mips_fix_24k)
+ check_for_24k_errata ((struct mips_cl_insn *) &history[0], -1);
+
if (! ECOFF_DEBUGGING)
md_obj_end ();
}
*************** append_insn (struct mips_cl_insn *ip, ex
*** 2705,2710 ****
--- 2799,2805 ----
bfd_reloc_code_real_type *reloc_type)
{
unsigned long prev_pinfo, pinfo;
+ int hndx_24k = 0;
relax_stateT prev_insn_frag_type = 0;
bfd_boolean relaxed_branch = FALSE;
segment_info_type *si = seg_info (now_seg);
*************** append_insn (struct mips_cl_insn *ip, ex
*** 3238,3244 ****
|| (mips_opts.mips16 && history[0].fixp[0])
/* If the previous instruction is a sync, sync.l, or
sync.p, we can not swap. */
! || (prev_pinfo & INSN_SYNC))
{
if (mips_opts.mips16
&& (pinfo & INSN_UNCOND_BRANCH_DELAY)
--- 3333,3343 ----
|| (mips_opts.mips16 && history[0].fixp[0])
/* If the previous instruction is a sync, sync.l, or
sync.p, we can not swap. */
! || (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
&& (pinfo & INSN_UNCOND_BRANCH_DELAY)
*************** append_insn (struct mips_cl_insn *ip, ex
*** 3258,3263 ****
--- 3357,3364 ----
slot, and bump the destination address. */
insert_into_history (0, 1, ip);
emit_nop ();
+ if (mips_fix_24k)
+ hndx_24k++;
}
if (mips_relax.sequence)
*************** append_insn (struct mips_cl_insn *ip, ex
*** 3297,3303 ****
/* If that was an unconditional branch, forget the previous
insn information. */
if (pinfo & INSN_UNCOND_BRANCH_DELAY)
! mips_no_prev_insn ();
}
else if (pinfo & INSN_COND_BRANCH_LIKELY)
{
--- 3398,3411 ----
/* If that was an unconditional branch, forget the previous
insn information. */
if (pinfo & INSN_UNCOND_BRANCH_DELAY)
! {
! /* 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)
{
*************** append_insn (struct mips_cl_insn *ip, ex
*** 3307,3312 ****
--- 3415,3422 ----
the next instruction. */
insert_into_history (0, 1, ip);
emit_nop ();
+ if (mips_fix_24k)
+ hndx_24k++;
}
else
insert_into_history (0, 1, ip);
*************** append_insn (struct mips_cl_insn *ip, ex
*** 3314,3319 ****
--- 3424,3433 ----
else
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. */
mips_clear_insn_labels ();
}
*************** start_noreorder (void)
*** 3400,3405 ****
--- 3514,3522 ----
static void
end_noreorder (void)
{
+ if (mips_fix_24k)
+ check_for_24k_errata (NULL, 0);
+
mips_opts.noreorder--;
if (mips_opts.noreorder == 0 && prev_nop_frag != NULL)
{
*************** enum options
*** 11175,11181 ****
OPTION_M3900,
OPTION_NO_M3900,
OPTION_M7000_HILO_FIX,
! OPTION_MNO_7000_HILO_FIX,
OPTION_FIX_VR4120,
OPTION_NO_FIX_VR4120,
OPTION_FIX_VR4130,
--- 11292,11300 ----
OPTION_M3900,
OPTION_NO_M3900,
OPTION_M7000_HILO_FIX,
! OPTION_MNO_7000_HILO_FIX,
! OPTION_FIX_24K,
! OPTION_NO_FIX_24K,
OPTION_FIX_VR4120,
OPTION_NO_FIX_VR4120,
OPTION_FIX_VR4130,
*************** struct option md_longopts[] =
*** 11268,11273 ****
--- 11387,11394 ----
{"mno-fix-vr4120", no_argument, NULL, OPTION_NO_FIX_VR4120},
{"mfix-vr4130", no_argument, NULL, OPTION_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. */
{"trap", no_argument, NULL, OPTION_TRAP},
*************** md_parse_option (int c, char *arg)
*** 11521,11526 ****
--- 11642,11655 ----
mips_opts.ase_smartmips = 0;
break;
+ case OPTION_FIX_24K:
+ mips_fix_24k = 1;
+ break;
+
+ case OPTION_NO_FIX_24K:
+ mips_fix_24k = 0;
+ break;
+
case OPTION_FIX_VR4120:
mips_fix_vr4120 = 1;
break;
*************** s_change_sec (int sec)
*** 12468,12473 ****
--- 12597,12606 ----
#endif
mips_emit_delays ();
+
+ if (mips_fix_24k)
+ check_for_24k_errata ((struct mips_cl_insn *) &history[0], -1);
+
switch (sec)
{
case 't':
*************** s_change_section (int ignore ATTRIBUTE_U
*** 12526,12531 ****
--- 12659,12667 ----
if (!IS_ELF)
return;
+ if (mips_fix_24k)
+ check_for_24k_errata ((struct mips_cl_insn *) &history[0], -1);
+
section_name = input_line_pointer;
c = get_symbol_end ();
if (c)
*************** MIPS options:\n\
*** 15457,15462 ****
--- 15593,15599 ----
fprintf (stream, _("\
-mfix-vr4120 work around certain VR4120 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\
-mfp32 use 32-bit FPRs, regardless of the chosen ISA\n\
-msym32 assume all symbols have 32-bit values\n\
Index: doc/c-mips.texi
===================================================================
RCS file: /cvs/src/src/gas/doc/c-mips.texi,v
retrieving revision 1.47
diff -p -r1.47 c-mips.texi
*** doc/c-mips.texi 3 Feb 2009 18:16:03 -0000 1.47
--- doc/c-mips.texi 8 Apr 2009 21:02:02 -0000
*************** all problems in hand-written assembler c
*** 182,187 ****
--- 182,191 ----
@itemx -no-mfix-vr4130
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
@itemx -no-m4010
Generate code for the LSI @sc{r4010} chip. This tells the assembler to
Index: testsuite/gas/mips/eret.d
===================================================================
RCS file: testsuite/gas/mips/eret.d
diff -N testsuite/gas/mips/eret.d
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/gas/mips/eret.d 8 Apr 2009 21:02:03 -0000
***************
*** 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
Index: testsuite/gas/mips/eret.l
===================================================================
RCS file: testsuite/gas/mips/eret.l
diff -N testsuite/gas/mips/eret.l
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/gas/mips/eret.l 8 Apr 2009 21:02:03 -0000
***************
*** 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\.
Index: testsuite/gas/mips/eret.s
===================================================================
RCS file: testsuite/gas/mips/eret.s
diff -N testsuite/gas/mips/eret.s
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/gas/mips/eret.s 8 Apr 2009 21:02:03 -0000
***************
*** 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
Index: testsuite/gas/mips/mips.exp
===================================================================
RCS file: /cvs/src/src/gas/testsuite/gas/mips/mips.exp,v
retrieving revision 1.149
diff -p -r1.149 mips.exp
*** testsuite/gas/mips/mips.exp 3 Feb 2009 18:16:04 -0000 1.149
--- testsuite/gas/mips/mips.exp 8 Apr 2009 21:02:03 -0000
*************** if { [istarget mips*-*-vxworks*] } {
*** 436,441 ****
--- 436,444 ----
} else {
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-xgot" }
run_list_test_arches "jal-range" "-32" [mips_arch_list_matching mips1]