[binutils-gdb] Add support for MSP430 silicon errata to the assembler.

Nick Clifton nickc@sourceware.org
Thu Oct 22 15:26:00 GMT 2015


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=2213f746d3ab63715c24c3197ae207486464091b

commit 2213f746d3ab63715c24c3197ae207486464091b
Author: Nick Clifton <nickc@redhat.com>
Date:   Thu Oct 22 16:25:46 2015 +0100

    Add support for MSP430 silicon errata to the assembler.
    
    	* config/tc-msp430.c (PUSH_1X_WORKAROUND): Delete.
    	(OPTION_SILICON_ERRATA): Define.
    	(OPTION_SILICON_WARN): Define.
    	(md_parse_opton): Handle silicon errata options.
    	(md_longopts): Add silicon errata options.
    	(ms_show_usage): Report silicon errata options.
    	(msp430_srcoperand): Handle silicon errata.
    	(msp430_operands): Likewise. Improve nop insertion.
    	(msp430_fix_adjustable): Update warning generation.
    	* doc/c-msp430.texi: Document silicon errata options.
    
    tests	* gas/msp430/errata_fixes.s: New test source file.
    	* gas/msp430/errata_fixes.d: New test control file.
    	* gas/msp430/errata_warns.s: New test source file.
    	* gas/msp430/errata_warns.d: New test control file.
    	* gas/msp430/errata_warns.l: New test message file.
    	* gas/msp430/msp430.exp: Run the new tests.
    	* gas/msp430/bad.l: Update expected warning messages
    	* gas/msp430/msp430.exp: Run the new tests.

Diff:
---
 gas/ChangeLog                           |  13 ++
 gas/config/tc-msp430.c                  | 336 ++++++++++++++++++++++++--------
 gas/doc/c-msp430.texi                   |  34 ++++
 gas/testsuite/ChangeLog                 |  11 ++
 gas/testsuite/gas/msp430/bad.l          |   3 +-
 gas/testsuite/gas/msp430/errata_fixes.d |  23 +++
 gas/testsuite/gas/msp430/errata_fixes.s |  24 +++
 gas/testsuite/gas/msp430/errata_warns.d |   4 +
 gas/testsuite/gas/msp430/errata_warns.l |  44 +++++
 gas/testsuite/gas/msp430/errata_warns.s |  59 ++++++
 gas/testsuite/gas/msp430/msp430.exp     |   2 +
 11 files changed, 473 insertions(+), 80 deletions(-)

diff --git a/gas/ChangeLog b/gas/ChangeLog
index 0743ff3..1b77b64 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,16 @@
+2015-10-22  Nick Clifton  <nickc@redhat.com>
+
+	* config/tc-msp430.c (PUSH_1X_WORKAROUND): Delete.
+	(OPTION_SILICON_ERRATA): Define.
+	(OPTION_SILICON_WARN): Define.
+	(md_parse_opton): Handle silicon errata options.
+	(md_longopts): Add silicon errata options.
+	(ms_show_usage): Report silicon errata options.
+	(msp430_srcoperand): Handle silicon errata.
+	(msp430_operands): Likewise. Improve nop insertion.
+	(msp430_fix_adjustable): Update warning generation.
+	* doc/c-msp430.texi: Document silicon errata options.
+
 2015-10-22  H.J. Lu  <hongjiu.lu@intel.com>
 
 	* configure.ac: Properly check
diff --git a/gas/config/tc-msp430.c b/gas/config/tc-msp430.c
index accc592..8e32189 100644
--- a/gas/config/tc-msp430.c
+++ b/gas/config/tc-msp430.c
@@ -22,7 +22,6 @@
 
 #include "as.h"
 #include <limits.h>
-#define PUSH_1X_WORKAROUND
 #include "subsegs.h"
 #include "opcode/msp430.h"
 #include "safe-ctype.h"
@@ -681,6 +680,23 @@ static bfd_boolean warn_interrupt_nops = TRUE;
 #define OPTION_MOVE_DATA 'd'
 static bfd_boolean move_data = FALSE;
 
+enum
+{
+  OPTION_SILICON_ERRATA = OPTION_MD_BASE,
+  OPTION_SILICON_ERRATA_WARN,
+} option_numbers;
+
+static unsigned int silicon_errata_fix = 0;
+static unsigned int silicon_errata_warn = 0;
+#define SILICON_ERRATA_CPU4 		(1 << 0)
+#define SILICON_ERRATA_CPU8		(1 << 1)
+#define SILICON_ERRATA_CPU11 		(1 << 2)
+#define SILICON_ERRATA_CPU12 		(1 << 3)
+#define SILICON_ERRATA_CPU13 		(1 << 4)
+#define SILICON_ERRATA_CPU19 		(1 << 5)
+#define SILICON_ERRATA_CPU42 		(1 << 6)
+#define SILICON_ERRATA_CPU42_PLUS	(1 << 7)
+
 static void
 msp430_set_arch (int option)
 {
@@ -1305,6 +1321,55 @@ md_parse_option (int c, char * arg)
 {
   switch (c)
     {
+    case OPTION_SILICON_ERRATA:
+    case OPTION_SILICON_ERRATA_WARN:
+      {
+	signed int i;
+	const struct
+	{
+	  char *       name;
+	  unsigned int length;
+	  unsigned int bitfield;
+	} erratas[] =
+	{
+	  { STRING_COMMA_LEN ("cpu4"), SILICON_ERRATA_CPU4 },
+	  { STRING_COMMA_LEN ("cpu8"), SILICON_ERRATA_CPU8 },
+	  { STRING_COMMA_LEN ("cpu11"), SILICON_ERRATA_CPU11 },
+	  { STRING_COMMA_LEN ("cpu12"), SILICON_ERRATA_CPU12 },
+	  { STRING_COMMA_LEN ("cpu13"), SILICON_ERRATA_CPU13 },
+	  { STRING_COMMA_LEN ("cpu19"), SILICON_ERRATA_CPU19 },
+	  { STRING_COMMA_LEN ("cpu42"), SILICON_ERRATA_CPU42 },
+	  { STRING_COMMA_LEN ("cpu42+"), SILICON_ERRATA_CPU42_PLUS },
+	};
+
+	do
+	  {
+	    for (i = ARRAY_SIZE (erratas); i--;)
+	      if (strncasecmp (arg, erratas[i].name, erratas[i].length) == 0)
+		{
+		  if (c == OPTION_SILICON_ERRATA)
+		    silicon_errata_fix |= erratas[i].bitfield;
+		  else
+		    silicon_errata_warn |= erratas[i].bitfield;
+		  arg += erratas[i].length;
+		  break;
+		}
+	    if (i < 0)
+	      {
+		as_warn (_("Unrecognised CPU errata name starting here: %s"), arg);
+		break;
+	      }
+	    if (*arg == 0)
+	      break;
+	    if (*arg != ',')
+	      as_warn (_("Expecting comma after CPU errata name, not: %s"), arg);
+	    else
+	      arg ++;
+	  }
+	while (*arg != 0);
+      }
+      return 1;
+
     case OPTION_MMCU:
       if (arg == NULL)
 	as_fatal (_("MCU option requires a name\n"));
@@ -1487,6 +1552,8 @@ const char *md_shortopts = "mm:,mP,mQ,ml,mN,mn,my,mY";
 
 struct option md_longopts[] =
 {
+  {"msilicon-errata", required_argument, NULL, OPTION_SILICON_ERRATA},
+  {"msilicon-errata-warn", required_argument, NULL, OPTION_SILICON_ERRATA_WARN},
   {"mmcu", required_argument, NULL, OPTION_MMCU},
   {"mcpu", required_argument, NULL, OPTION_MCPU},
   {"mP", no_argument, NULL, OPTION_POLYMORPHS},
@@ -1510,6 +1577,10 @@ md_show_usage (FILE * stream)
 	     "  -mmcu=<msp430-name>     - select microcontroller type\n"
              "  -mcpu={430|430x|430xv2} - select microcontroller architecture\n"));
   fprintf (stream,
+	   _("  -msilicon-errata=<name>[,<name>...] - enable fixups for silicon errata\n"
+	     "  -msilicon-errata-warn=<name>[,<name>...] - warn when a fixup might be needed\n"
+	     "   supported errata names: cpu4, cpu8, cpu11, cpu12, cpu13, cpu19, cpu42, cpu42+\n"));
+  fprintf (stream,
 	   _("  -mQ - enable relaxation at assembly time. DANGEROUS!\n"
 	     "  -mP - enable polymorph instructions\n"));
   fprintf (stream,
@@ -1746,14 +1817,14 @@ msp430_srcoperand (struct msp430_operand_s * op,
 	    }
 	  else if (x == 4)
 	    {
-#ifdef PUSH_1X_WORKAROUND
-	      if (bin == 0x1200)
+	      if (bin == 0x1200 && ! target_is_430x ())
 		{
-		  /* Remove warning as confusing.
-		     as_warn (_("Hardware push bug workaround")); */
+		  /* CPU4: The shorter form of PUSH #4 is not supported on MSP430.  */
+		  if (silicon_errata_warn & SILICON_ERRATA_CPU4)
+		    as_warn (_("cpu4: not converting PUSH #4 to shorter form"));
+		  /* No need to check silicon_errata_fixes - this fix is always implemented.  */
 		}
 	      else
-#endif
 		{
 		  op->reg = 2;
 		  op->am = 2;
@@ -1763,14 +1834,13 @@ msp430_srcoperand (struct msp430_operand_s * op,
 	    }
 	  else if (x == 8)
 	    {
-#ifdef PUSH_1X_WORKAROUND
-	      if (bin == 0x1200)
+	      if (bin == 0x1200 && ! target_is_430x ())
 		{
-		  /* Remove warning as confusing.
-		     as_warn (_("Hardware push bug workaround")); */
+		  /* CPU4: The shorter form of PUSH #8 is not supported on MSP430.  */
+		  if (silicon_errata_warn & SILICON_ERRATA_CPU4)
+		    as_warn (_("cpu4: not converting PUSH #8 to shorter form"));
 		}
 	      else
-#endif
 		{
 		  op->reg = 2;
 		  op->am = 3;
@@ -2003,6 +2073,14 @@ msp430_srcoperand (struct msp430_operand_s * op,
 	      op->ol = 0;
 	      return 0;
 	    }
+
+	  if (op->reg == 1 && (x & 1))
+	    {
+	      if (silicon_errata_fix & SILICON_ERRATA_CPU8)
+		as_bad (_("CPU8: Stack pointer accessed with an odd offset"));
+	      else if (silicon_errata_warn & SILICON_ERRATA_CPU8)
+		as_warn (_("CPU8: Stack pointer accessed with an odd offset"));
+	    }
 	}
       else if (op->exp.X_op == O_symbol)
 	;
@@ -2353,7 +2431,11 @@ try_encode_mova (bfd_boolean imm_op,
   return 0;
 }
 
-static bfd_boolean check_for_nop = FALSE;
+#define NOP_CHECK_INTERRUPT  (1 << 0)
+#define NOP_CHECK_CPU12      (1 << 1)
+#define NOP_CHECK_CPU19      (1 << 2)
+
+static signed int check_for_nop = 0;
 
 #define is_opcode(NAME) (strcmp (opcode->name, NAME) == 0)
 
@@ -2380,7 +2462,6 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line)
   const char * error_message;
   static signed int repeat_count = 0;
   bfd_boolean fix_emitted;
-  bfd_boolean nop_check_needed = FALSE;
 
   /* Opcode is the one from opcodes table
      line contains something like
@@ -2513,20 +2594,20 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line)
       repeat_count = 0;
     }
 
-  if (check_for_nop && is_opcode ("nop"))
-    check_for_nop = FALSE;
-
-  switch (fmt)
+  if (check_for_nop)
     {
-    case 0:			/* Emulated.  */
-      switch (opcode->insn_opnumb)
+      if (! is_opcode ("nop"))
 	{
-	case 0:
-	  if (is_opcode ("eint") || is_opcode ("dint"))
+	  bfd_boolean doit = FALSE;
+
+	  do
 	    {
-	      if (check_for_nop)
+	      switch (check_for_nop & - check_for_nop)
 		{
-		  if (warn_interrupt_nops)
+		case NOP_CHECK_INTERRUPT:
+		  if (warn_interrupt_nops
+		      || silicon_errata_warn & SILICON_ERRATA_CPU42
+		      || silicon_errata_warn & SILICON_ERRATA_CPU42_PLUS)
 		    {
 		      if (gen_interrupt_nops)
 			as_warn (_("NOP inserted between two instructions that change interrupt state"));
@@ -2534,18 +2615,56 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line)
 			as_warn (_("a NOP might be needed here because of successive changes in interrupt state"));
 		    }
 
-		  if (gen_interrupt_nops)
-		    {
-		      /* Emit a NOP between interrupt enable/disable.
-			 See 1.3.4.1 of the MSP430x5xx User Guide.  */
-		      insn_length += 2;
-		      frag = frag_more (2);
-		      bfd_putl16 ((bfd_vma) 0x4303 /* NOP */, frag);
-		    }
-		}
+		  if (gen_interrupt_nops
+		      || silicon_errata_fix & SILICON_ERRATA_CPU42_PLUS)
+		    /* Emit a NOP between interrupt enable/disable.
+		       See 1.3.4.1 of the MSP430x5xx User Guide.  */
+		    doit = TRUE;
+		  break;
+
+		case NOP_CHECK_CPU12:
+		  if (silicon_errata_warn & SILICON_ERRATA_CPU12)
+		    as_warn (_("CPU12: CMP/BIT with PC destinstion ignores next instruction"));
+
+		  if (silicon_errata_fix & SILICON_ERRATA_CPU12)
+		    doit = TRUE;
+		  break;
+
+		case NOP_CHECK_CPU19:
+		  if (silicon_errata_warn & SILICON_ERRATA_CPU19)
+		    as_warn (_("CPU19: Instruction setting CPUOFF must be followed by a NOP"));
 
-	      nop_check_needed = TRUE;
+		  if (silicon_errata_fix & SILICON_ERRATA_CPU19)
+		    doit = TRUE;
+		  break;
+		  
+		default:
+		  as_bad (_("internal error: unknown nop check state"));
+		  break;
+		}
+	      check_for_nop &= ~ (check_for_nop & - check_for_nop);
+	    }
+	  while (check_for_nop);
+	  
+	  if (doit)
+	    {
+	      frag = frag_more (2);
+	      bfd_putl16 ((bfd_vma) 0x4303 /* NOP */, frag);
+	      dwarf2_emit_insn (2);
 	    }
+	}
+
+      check_for_nop = 0;
+    }
+
+  switch (fmt)
+    {
+    case 0:			/* Emulated.  */
+      switch (opcode->insn_opnumb)
+	{
+	case 0:
+	  if (is_opcode ("eint") || is_opcode ("dint"))
+	    check_for_nop |= NOP_CHECK_INTERRUPT;
 
 	  /* Set/clear bits instructions.  */
 	  if (extended_op)
@@ -2574,30 +2693,37 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line)
 
 	  bin |= (op1.reg | (op1.am << 7));
 
-	  if (is_opcode ("clr") && bin == 0x4302 /* CLR R2*/)
+	  /* If the PC is the destination...  */
+	  if (op1.am == 0 && op1.reg == 0
+	      /* ... and the opcode alters the SR.  */
+	      && !(is_opcode ("bic") || is_opcode ("bis") || is_opcode ("mov")
+		   || is_opcode ("bicx") || is_opcode ("bisx") || is_opcode ("movx")))
 	    {
-	      if (check_for_nop)
-		{
-		  if (warn_interrupt_nops)
-		    {
-		      if (gen_interrupt_nops)
-			as_warn (_("NOP inserted between two instructions that change interrupt state"));
-		      else
-			as_warn (_("a NOP might be needed here because of successive changes in interrupt state"));
-		    }
-
-		  if (gen_interrupt_nops)
-		    {
-		      /* Emit a NOP between interrupt enable/disable.
-			 See 1.3.4.1 of the MSP430x5xx User Guide.  */
-		      insn_length += 2;
-		      frag = frag_more (2);
-		      bfd_putl16 ((bfd_vma) 0x4303 /* NOP */, frag);
-		    }
-		}
-
-	      nop_check_needed = TRUE;
+	      if (silicon_errata_fix & SILICON_ERRATA_CPU11)
+		as_bad (_("CPU11: PC is destinstion of SR altering instruction"));
+	      else if (silicon_errata_warn & SILICON_ERRATA_CPU11)
+		as_warn (_("CPU11: PC is destinstion of SR altering instruction"));
 	    }
+	  
+	  /* If the status register is the destination...  */
+	  if (op1.am == 0 && op1.reg == 2
+	      /* ... and the opcode alters the SR.  */
+	      && (is_opcode ("adc") || is_opcode ("dec") || is_opcode ("decd")
+		  || is_opcode ("inc") || is_opcode ("incd") || is_opcode ("inv")
+		  || is_opcode ("sbc") || is_opcode ("sxt")
+		  || is_opcode ("adcx") || is_opcode ("decx") || is_opcode ("decdx")
+		  || is_opcode ("incx") || is_opcode ("incdx") || is_opcode ("invx")
+		  || is_opcode ("sbcx")
+		  ))
+	    {
+	      if (silicon_errata_fix & SILICON_ERRATA_CPU13)
+		as_bad (_("CPU13: SR is destinstion of SR altering instruction"));
+	      else if (silicon_errata_warn & SILICON_ERRATA_CPU13)
+		as_warn (_("CPU13: SR is destinstion of SR altering instruction"));
+	    }
+	  
+	  if (is_opcode ("clr") && bin == 0x4302 /* CLR R2*/)
+	    check_for_nop |= NOP_CHECK_INTERRUPT;
 
 	  /* Compute the entire instruction length, in bytes.  */
 	  op_length = (extended_op ? 2 : 0) + 2 + (op1.ol * 2);
@@ -2691,6 +2817,19 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line)
 	      break;
 	    }
 
+	  /* If the status register is the destination...  */
+	  if (op1.am == 0 && op1.reg == 2
+	      /* ... and the opcode alters the SR.  */
+	      && (is_opcode ("rla") || is_opcode ("rlc")
+		  || is_opcode ("rlax") || is_opcode ("rlcx")
+		  ))
+	    {
+	      if (silicon_errata_fix & SILICON_ERRATA_CPU13)
+		as_bad (_("CPU13: SR is destinstion of SR altering instruction"));
+	      else if (silicon_errata_warn & SILICON_ERRATA_CPU13)
+		as_warn (_("CPU13: SR is destinstion of SR altering instruction"));
+	    }
+	  
 	  if (extended_op)
 	    {
 	      if (!addr_op)
@@ -3297,33 +3436,56 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line)
 
       bin |= (op2.reg | (op1.reg << 8) | (op1.am << 4) | (op2.am << 7));
 
+      /* If the PC is the destination...  */
+      if (op2.am == 0 && op2.reg == 0
+	  /* ... and the opcode alters the SR.  */
+	  && !(is_opcode ("bic") || is_opcode ("bis") || is_opcode ("mov")
+	       || is_opcode ("bicx") || is_opcode ("bisx") || is_opcode ("movx")))
+	{
+	  if (silicon_errata_fix & SILICON_ERRATA_CPU11)
+	    as_bad (_("CPU11: PC is destinstion of SR altering instruction"));
+	  else if (silicon_errata_warn & SILICON_ERRATA_CPU11)
+	    as_warn (_("CPU11: PC is destinstion of SR altering instruction"));
+	}
+	  
+      /* If the status register is the destination...  */
+      if (op2.am == 0 && op2.reg == 2
+	  /* ... and the opcode alters the SR.  */
+	  && (is_opcode ("add") || is_opcode ("addc") || is_opcode ("and")
+	      || is_opcode ("dadd") || is_opcode ("sub") || is_opcode ("subc")
+	      || is_opcode ("xor")
+	      || is_opcode ("addx") || is_opcode ("addcx") || is_opcode ("andx")
+	      || is_opcode ("daddx") || is_opcode ("subx") || is_opcode ("subcx")
+	      || is_opcode ("xorx")
+	      ))
+	{
+	  if (silicon_errata_fix & SILICON_ERRATA_CPU13)
+	    as_bad (_("CPU13: SR is destinstion of SR altering instruction"));
+	  else if (silicon_errata_warn & SILICON_ERRATA_CPU13)
+	    as_warn (_("CPU13: SR is destinstion of SR altering instruction"));
+	}
+	  
       if (   (is_opcode ("bic") && bin == 0xc232)
 	  || (is_opcode ("bis") && bin == 0xd232)
 	  || (is_opcode ("mov") && op2.mode == OP_REG && op2.reg == 2))
 	{
-	  if (check_for_nop)
-	    {
-	      if (warn_interrupt_nops)
-		{
-		  if (gen_interrupt_nops)
-		    as_warn (_("NOP inserted between two instructions that change interrupt state"));
-		  else
-		    as_warn (_("a NOP might be needed here because of successive changes in interrupt state"));
-		}
-
-	      if (gen_interrupt_nops)
-		{
-		  /* Emit a NOP between interrupt enable/disable.
-		     See 1.3.4.1 of the MSP430x5xx User Guide.  */
-		  insn_length += 2;
-		  frag = frag_more (2);
-		  bfd_putl16 ((bfd_vma) 0x4303 /* NOP */, frag);
-		}
-	    }
-
-	  nop_check_needed = TRUE;
+	  /* Avoid false checks when a constant value is being put into the SR.  */
+	  if (op1.mode == OP_EXP
+	      && op1.exp.X_op == O_constant
+	      && (op1.exp.X_add_number & 0x8) != 0x8)
+	    ;
+	  else
+	    check_for_nop |= NOP_CHECK_INTERRUPT;
 	}
 
+      if (((is_opcode ("bis") && bin == 0xd032)
+	   || (is_opcode ("mov") && bin == 0x4032)
+	   || (is_opcode ("xor") && bin == 0xe032))
+	  && op1.mode == OP_EXP
+	  && op1.exp.X_op == O_constant
+	  && (op1.exp.X_add_number & 0x10) == 0x10)
+	check_for_nop |= NOP_CHECK_CPU19;
+
       /* Compute the entire length of the instruction in bytes.  */
       op_length = (extended_op ? 2 : 0)	/* The extension word.  */
 	+ 2 			/* The opcode */
@@ -3433,6 +3595,12 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line)
 	}
 
       dwarf2_emit_insn (insn_length);
+
+      /* If the PC is the destination...  */
+      if (op2.am == 0 && op2.reg == 0
+	  /* ... but the opcode does not alter the destination.  */
+	  && (is_opcode ("cmp") || is_opcode ("bit") || is_opcode ("cmpx")))
+	check_for_nop |= NOP_CHECK_CPU12;
       break;
 
     case 2:			/* Single-operand mostly instr.  */
@@ -3464,6 +3632,17 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line)
 	  break;
 	}
 
+      /* If the status register is the destination...  */
+      if (op1.am == 0 && op1.reg == 2
+	  /* ... and the opcode alters the SR.  */
+	  && (is_opcode ("rra") || is_opcode ("rrc") || is_opcode ("sxt")))
+	{
+	  if (silicon_errata_fix & SILICON_ERRATA_CPU13)
+	    as_bad (_("CPU13: SR is destinstion of SR altering instruction"));
+	  else if (silicon_errata_warn & SILICON_ERRATA_CPU13)
+	    as_warn (_("CPU13: SR is destinstion of SR altering instruction"));
+	}
+	  
       insn_length = (extended_op ? 2 : 0) + 2 + (op1.ol * 2);
       frag = frag_more (insn_length);
       where = frag - frag_now->fr_literal;
@@ -3726,7 +3905,6 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line)
     }
 
   input_line_pointer = line;
-  check_for_nop = nop_check_needed;
   return 0;
 }
 
@@ -4461,8 +4639,8 @@ msp430_fix_adjustable (struct fix *fixp ATTRIBUTE_UNUSED)
 void
 msp430_md_end (void)
 {
-  if (check_for_nop == TRUE && warn_interrupt_nops)
-    as_warn ("assembly finished with the last instruction changing interrupt state - a NOP might be needed");
+  if (check_for_nop)
+    as_warn ("assembly finished without a possibly needed NOP instruction");
 
   bfd_elf_add_proc_attr_int (stdoutput, OFBA_MSPABI_Tag_ISA,
 			     target_is_430x () ? 2 : 1);
diff --git a/gas/doc/c-msp430.texi b/gas/doc/c-msp430.texi
index 2a372db..5b72c76 100644
--- a/gas/doc/c-msp430.texi
+++ b/gas/doc/c-msp430.texi
@@ -36,6 +36,40 @@ also enables NOP generation unless the @option{-mN} is also specified.
 selects the cpu architecture.  If the architecture is 430Xv2 then this
 also enables NOP generation unless the @option{-mN} is also specified.
 
+@item -msilicon-errata=@var{name}[,@var{name}@dots{}]
+Implements a fixup for named silicon errata.  Multiple silicon errata
+can be specified by multiple uses of the @option{-msilicon-errata}
+option and/or by including the errata names, separated by commas, on
+an individual @option{-msilicon-errata} option.  Errata names
+currently recognised by the assembler are:
+
+@table @code
+@item cpu4
+@code{PUSH #4} and @option{PUSH #8} need longer encodings on the
+MSP430.  This option is enabled by default, and cannot be disabled.
+@item cpu8
+Do not set the @code{SP} to an odd value.
+@item cpu11
+Do not update the @code{SR} and the @code{PC} in the same instruction.
+@item cpu12
+Do not use the @code{PC} in a @code{CMP} or @code{BIT} instruction.
+@item cpu13
+Do not use an arithmetic instruction to modify the @code{SR}.
+@item cpu19
+Insert @code{NOP} after @code{CPUOFF}.
+@item cpu42
+Warn where a @code{NOP} ought to be present after enabling interrupts.
+@item cpu42+
+Add @code{NOP} after enabling interrupts.
+@end table
+
+@item -msilicon-errata-warn=@var{name}[,@var{name}@dots{}]
+Like the @option{-msilicon-errata} option except that instead of
+fixing the specified errata, a warning message is issued instead.
+This option can be used alongside @option{-msilicon-errata} to
+generate messages whenever a problem is fixed, or on its own in order
+to inspect code for potential problems.
+
 @item -mP
 enables polymorph instructions handler.
 
diff --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog
index 07ec4c8..89d282f 100644
--- a/gas/testsuite/ChangeLog
+++ b/gas/testsuite/ChangeLog
@@ -1,3 +1,14 @@
+2015-10-22  Nick Clifton  <nickc@redhat.com>
+
+	* gas/msp430/errata_fixes.s: New test source file.
+	* gas/msp430/errata_fixes.d: New test control file.
+	* gas/msp430/errata_warns.s: New test source file.
+	* gas/msp430/errata_warns.d: New test control file.
+	* gas/msp430/errata_warns.l: New test message file.
+	* gas/msp430/msp430.exp: Run the new tests.
+	* gas/msp430/bad.l: Update expected warning messages
+	* gas/msp430/msp430.exp: Run the new tests.
+
 2015-10-22  H.J. Lu  <hongjiu.lu@intel.com>
 
 	* gas/i386/i386.exp: Run x86-64-gotpcrel.
diff --git a/gas/testsuite/gas/msp430/bad.l b/gas/testsuite/gas/msp430/bad.l
index 8de1338..6cc3e3a 100644
--- a/gas/testsuite/gas/msp430/bad.l
+++ b/gas/testsuite/gas/msp430/bad.l
@@ -7,8 +7,9 @@
 [^:]*:11: Error: instruction bis.a does not exist
 [^:]*:19: Warning: a NOP might be needed here because of successive changes in interrupt state
 [^:]*:20: Warning: a NOP might be needed here because of successive changes in interrupt state
+[^:]*:23: Warning: a NOP might be needed here because of successive changes in interrupt state
 [^:]*:25: Warning: a NOP might be needed here because of successive changes in interrupt state
 [^:]*:26: Warning: a NOP might be needed here because of successive changes in interrupt state
 [^:]*:27: Warning: a NOP might be needed here because of successive changes in interrupt state
 [^:]*:28: Warning: a NOP might be needed here because of successive changes in interrupt state
-[^:]*: Warning: assembly finished with the last instruction changing interrupt state - a NOP might be needed
+[^:]*: Warning: assembly finished without a possibly needed NOP instruction
diff --git a/gas/testsuite/gas/msp430/errata_fixes.d b/gas/testsuite/gas/msp430/errata_fixes.d
new file mode 100644
index 0000000..c116405
--- /dev/null
+++ b/gas/testsuite/gas/msp430/errata_fixes.d
@@ -0,0 +1,23 @@
+#name: Fixes for Silicon Errata
+#source: errata_fixes.s
+#as: -msilicon-errata=cpu4,cpu12,cpu19
+#objdump: -d --prefix-addresses --show-raw-insn
+
+.*: +file format .*msp.*
+
+Disassembly of section .text:
+0+0000 <[^>]*> 30 12 04 00[ 	]+push	#4		;
+0+0004 <[^>]*> 30 12 08 00[ 	]+push	#8		;
+0+0008 <[^>]*> 10 c3[ 	]+bic	#1,	r0	;r3 As==01$
+0+000a <[^>]*> 10 d3[ 	]+bis	#1,	r0	;r3 As==01$
+0+000c <[^>]*> 10 43[ 	]+br	#1		;r3 As==01$
+0+000e <[^>]*> 10 92 c8 00[ 	]+cmp	&0x00c8,r0	;0x00c8
+0+0012 <[^>]*> 03 43[ 	]+nop			
+0+0014 <[^>]*> 00 b1[ 	]+bit	r1,	r0	;
+0+0016 <[^>]*> 03 43[ 	]+nop			
+0+0018 <[^>]*> 32 d0 10 00[ 	]+bis	#16,	r2	;#0x0010
+0+001c <[^>]*> 03 43[ 	]+nop			
+0+001e <[^>]*> 32 40 10 00[ 	]+mov	#16,	r2	;#0x0010
+0+0022 <[^>]*> 03 43[ 	]+nop			
+0+0024 <[^>]*> 32 e0 10 00[ 	]+xor	#16,	r2	;#0x0010
+0+0028 <[^>]*> 03 43[ 	]+nop			
diff --git a/gas/testsuite/gas/msp430/errata_fixes.s b/gas/testsuite/gas/msp430/errata_fixes.s
new file mode 100644
index 0000000..dd6d14d
--- /dev/null
+++ b/gas/testsuite/gas/msp430/errata_fixes.s
@@ -0,0 +1,24 @@
+	.text
+errata:
+	.cpu	msp430
+	# CPU4: PUSH #4/#8 has to be encoded using the long form
+	push	#4
+	push	#8
+
+	# CPU11: The SR flags can be left in a bogus state after writing to the PC
+	# Instructions that do not set the SR flags are unaffected.
+	bic	 #1, pc
+	bis	 #1, pc
+	mov	 #1, pc
+	
+	#CPU12: A CMP or BIT instruction with the PC as the second operand may
+	# not execute the instruction after it - so a NOP must be inserted.
+	cmp   	 &200, PC
+	bit	 r1, pc
+
+	#CPU19: Instructions that sets CPUOFF must be followed by a NOP
+	bis	#0x10, r2
+	mov	#0x10, r2
+	xor	#0x10, r2
+	nop
+	
\ No newline at end of file
diff --git a/gas/testsuite/gas/msp430/errata_warns.d b/gas/testsuite/gas/msp430/errata_warns.d
new file mode 100644
index 0000000..eef8c2e
--- /dev/null
+++ b/gas/testsuite/gas/msp430/errata_warns.d
@@ -0,0 +1,4 @@
+#name: Warning Messages for Silicon Errata
+#source: errata_warns.s
+#as: -msilicon-errata-warn=cpu4,cpu8,cpu11,cpu12,cpu13,cpu19
+#error-output: errata_warns.l
diff --git a/gas/testsuite/gas/msp430/errata_warns.l b/gas/testsuite/gas/msp430/errata_warns.l
new file mode 100644
index 0000000..52df6b9
--- /dev/null
+++ b/gas/testsuite/gas/msp430/errata_warns.l
@@ -0,0 +1,44 @@
+[^:]*: Assembler messages:
+[^:]*:5: Warning: cpu4: not converting PUSH #4 to shorter form
+[^:]*:6: Warning: cpu4: not converting PUSH #8 to shorter form
+[^:]*:11: Warning: CPU8: Stack pointer accessed with an odd offset
+[^:]*:12: Warning: CPU8: Stack pointer accessed with an odd offset
+[^:]*:13: Warning: CPU8: Stack pointer accessed with an odd offset
+[^:]*:14: Warning: CPU8: Stack pointer accessed with an odd offset
+[^:]*:15: Warning: CPU8: Stack pointer accessed with an odd offset
+[^:]*:18: Warning: CPU11: PC is destinstion of SR altering instruction
+[^:]*:19: Warning: CPU11: PC is destinstion of SR altering instruction
+[^:]*:20: Warning: CPU11: PC is destinstion of SR altering instruction
+[^:]*:21: Warning: CPU12: CMP/BIT with PC destinstion ignores next instruction
+[^:]*:21: Warning: CPU11: PC is destinstion of SR altering instruction
+[^:]*:22: Warning: CPU11: PC is destinstion of SR altering instruction
+[^:]*:23: Warning: CPU11: PC is destinstion of SR altering instruction
+[^:]*:24: Warning: CPU11: PC is destinstion of SR altering instruction
+[^:]*:25: Warning: CPU11: PC is destinstion of SR altering instruction
+[^:]*:26: Warning: CPU11: PC is destinstion of SR altering instruction
+[^:]*:30: Warning: CPU11: PC is destinstion of SR altering instruction
+[^:]*:31: Warning: CPU12: CMP/BIT with PC destinstion ignores next instruction
+[^:]*:31: Warning: CPU11: PC is destinstion of SR altering instruction
+[^:]*:34: Warning: CPU12: CMP/BIT with PC destinstion ignores next instruction
+[^:]*:34: Warning: CPU13: SR is destinstion of SR altering instruction
+[^:]*:35: Warning: CPU13: SR is destinstion of SR altering instruction
+[^:]*:36: Warning: CPU13: SR is destinstion of SR altering instruction
+[^:]*:37: Warning: CPU13: SR is destinstion of SR altering instruction
+[^:]*:38: Warning: CPU13: SR is destinstion of SR altering instruction
+[^:]*:39: Warning: CPU13: SR is destinstion of SR altering instruction
+[^:]*:40: Warning: CPU13: SR is destinstion of SR altering instruction
+[^:]*:41: Warning: CPU13: SR is destinstion of SR altering instruction
+[^:]*:42: Warning: CPU13: SR is destinstion of SR altering instruction
+[^:]*:43: Warning: CPU13: SR is destinstion of SR altering instruction
+[^:]*:44: Warning: CPU13: SR is destinstion of SR altering instruction
+[^:]*:45: Warning: CPU13: SR is destinstion of SR altering instruction
+[^:]*:46: Warning: CPU13: SR is destinstion of SR altering instruction
+[^:]*:47: Warning: CPU13: SR is destinstion of SR altering instruction
+[^:]*:48: Warning: CPU13: SR is destinstion of SR altering instruction
+[^:]*:49: Warning: CPU13: SR is destinstion of SR altering instruction
+[^:]*:50: Warning: CPU13: SR is destinstion of SR altering instruction
+[^:]*:51: Warning: CPU13: SR is destinstion of SR altering instruction
+[^:]*:52: Warning: CPU13: SR is destinstion of SR altering instruction
+[^:]*:56: Warning: CPU19: Instruction setting CPUOFF must be followed by a NOP
+[^:]*:57: Warning: CPU19: Instruction setting CPUOFF must be followed by a NOP
+[^:]*:57: Warning: CPU13: SR is destinstion of SR altering instruction
diff --git a/gas/testsuite/gas/msp430/errata_warns.s b/gas/testsuite/gas/msp430/errata_warns.s
new file mode 100644
index 0000000..c67d9c7
--- /dev/null
+++ b/gas/testsuite/gas/msp430/errata_warns.s
@@ -0,0 +1,59 @@
+	.text
+errata:
+	.cpu	msp430
+	# CPU4: PUSH #4/#8 has to be encoded using the long form
+	push	#4
+	push	#8
+
+	# CPU8: Do not use odd offsets with the stack pointer
+	.set fred,3
+	.set bert,1
+	mov.w	#4, 7(sp)
+	mov	3(r1), 5(r0)
+	mov.b	@r10+,fred-bert+1(sp)
+	add.w	#1,1(sp)
+	add.w	#7,-1(sp)
+
+	# CPU11: The SR flags can be left in a bogus state after writing to the PC
+	add.w	 #3, pc
+	and	 #1, pc
+	bit	 #1, pc
+	dadd	 #1, pc
+	inc	 pc
+	incd	 pc
+	sub	 #1, pc
+	subc	 #1, pc
+	xor	 #1, pc
+
+	#CPU12: A CMP or BIT instruction with the PC as the second operand may
+	# not execute the instruction after it.
+	cmp   	 &200, PC
+	bit	 r1, pc
+
+	#CPU13: Arithmetic operations with SR as the destination do not work.
+	add	#3, sr
+	adc	sr
+	addc	#3, sr
+	and	#3, sr
+	dadd	#3, sr
+	dec	sr
+	decd	sr
+	inc	sr
+	incd	sr
+	inv	sr
+	rla	sr
+	rlc	sr
+	rra	sr
+	rrc	sr
+	sbc	sr
+	sub	#3, sr
+	subc	#3, sr
+	sxt	sr
+	xor	#3, sr
+
+	#CPU19: Instructions that sets CPUOFF must be followed by a NOP
+	bis	#0x10, r2
+	mov	#0x10, r2
+	xor	#0x10, r2
+	nop
+	
\ No newline at end of file
diff --git a/gas/testsuite/gas/msp430/msp430.exp b/gas/testsuite/gas/msp430/msp430.exp
index 78aa764..7742f55 100644
--- a/gas/testsuite/gas/msp430/msp430.exp
+++ b/gas/testsuite/gas/msp430/msp430.exp
@@ -22,4 +22,6 @@ if [expr [istarget "msp430-*-*"]]  then {
     run_dump_test "opcode"
     run_dump_test "msp430x"
     run_dump_test "bad"
+    run_dump_test "errata_warns"
+    run_dump_test "errata_fixes"
 }



More information about the Binutils-cvs mailing list