This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[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]

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]