2009-04-09 Catherine Moore <clm@codesourcery.com>
authorCatherine Moore <clm@redhat.com>
Thu, 9 Apr 2009 15:55:59 +0000 (15:55 +0000)
committerCatherine Moore <clm@redhat.com>
Thu, 9 Apr 2009 15:55:59 +0000 (15:55 +0000)
        * 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.

gas/ChangeLog
gas/config/tc-mips.c
gas/doc/c-mips.texi
gas/testsuite/gas/mips/eret.d [new file with mode: 0644]
gas/testsuite/gas/mips/eret.l [new file with mode: 0644]
gas/testsuite/gas/mips/eret.s [new file with mode: 0644]
gas/testsuite/gas/mips/mips.exp

index 5f63801..19a7697 100644 (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>
 
        * config/tc-mips.c (mips_dwarf2_addr_size): Use HAVE_64BIT_OBJECTS
index 62d4e4f..5c85845 100644 (file)
@@ -760,6 +760,9 @@ static int mips_fix_vr4120;
 /* ...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
@@ -1789,6 +1792,85 @@ reg_lookup (char **s, unsigned int types, unsigned int *regnop)
   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
    architecture.  If EXPANSIONP is TRUE then this check is done while
    expanding a macro.  Use is_opcode_valid_16 for MIPS16 opcodes.  */
@@ -2074,6 +2156,9 @@ md_begin (void)
 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 ();
 }
@@ -2705,6 +2790,7 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
             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);
@@ -3238,7 +3324,11 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
              || (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))
+             || (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)
@@ -3258,6 +3348,8 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
                     slot, and bump the destination address.  */
                  insert_into_history (0, 1, ip);
                  emit_nop ();
+                 if (mips_fix_24k)
+                   hndx_24k++;
                }
                
              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
             insn information.  */
          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)
        {
@@ -3307,6 +3406,8 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
             the next instruction.  */
          insert_into_history (0, 1, ip);
          emit_nop ();
+         if (mips_fix_24k)
+           hndx_24k++;
        }
       else
        insert_into_history (0, 1, ip);
@@ -3314,6 +3415,10 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
   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 ();
 }
@@ -3400,6 +3505,9 @@ start_noreorder (void)
 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)
     {
@@ -11175,7 +11283,9 @@ enum options
     OPTION_M3900,
     OPTION_NO_M3900,
     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_NO_FIX_VR4120,
     OPTION_FIX_VR4130,
@@ -11268,6 +11378,8 @@ struct option md_longopts[] =
   {"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},
@@ -11521,6 +11633,14 @@ md_parse_option (int c, char *arg)
       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;
@@ -12468,6 +12588,10 @@ s_change_sec (int sec)
 #endif
 
   mips_emit_delays ();
+
+  if (mips_fix_24k)
+    check_for_24k_errata ((struct mips_cl_insn *) &history[0], -1);
+
   switch (sec)
     {
     case 't':
@@ -12526,6 +12650,9 @@ s_change_section (int ignore ATTRIBUTE_UNUSED)
   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)
@@ -15457,6 +15584,7 @@ MIPS options:\n\
   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 91bd822..695176b 100644 (file)
@@ -182,6 +182,10 @@ all problems in hand-written assembler code.
 @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
diff --git a/gas/testsuite/gas/mips/eret.d b/gas/testsuite/gas/mips/eret.d
new file mode 100644 (file)
index 0000000..1c0124a
--- /dev/null
@@ -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
diff --git a/gas/testsuite/gas/mips/eret.l b/gas/testsuite/gas/mips/eret.l
new file mode 100644 (file)
index 0000000..327dd95
--- /dev/null
@@ -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\.
diff --git a/gas/testsuite/gas/mips/eret.s b/gas/testsuite/gas/mips/eret.s
new file mode 100644 (file)
index 0000000..081d01e
--- /dev/null
@@ -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
index b213aba..627232f 100644 (file)
@@ -436,6 +436,9 @@ if { [istarget mips*-*-vxworks*] } {
     } 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]