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]

Commit: MSP430: Add support for silicon errata


Hi Guys,

  I am checking in the patch below to add support for fixing various
  MSP430 CPU silicon errata in the assembler.  Two new options are
  implemented:

      -msilicon-errata=<name>[,<name>...]
    
    Implements a fixup for named silicon errata.  Multiple silicon
    errata can be specified by multiple uses of the -msilicon-errata
    option and/or by including the errata names, separated by commas,
    on an individual -msilicon-errata option.  The option acts silently
    except when handling errata cpu42.  Errata names currently
    recognised by the assembler are:

    cpu4
      PUSH #4 and PUSH #8 need longer encodings on the MSP430.
      This option is enabled by default, and cannot be disabled.
    cpu8
      Do not set the stack pointer to an odd value.
    cpu11
      Do not update the status register and the PC in the same
      instruction.
    cpu12
      Do not use the PC in a CMP or BIT instruction.
    cpu13
      Do not use an arithmetic instruction to modify the status
      register.
    cpu19
      Insert NOP after CPUOFF.
    cpu42
      Warn where a NOP ought to be present after enabling interrupts.
    cpu42+
      Add NOP after enabling interrupts.


      -msilicon-errata-warn=<name>[,<name>...]
    
    Like the -msilicon-errata option except that instead of fixing the
    specified errata, a warning message is issued instead.  This option
    can be used alongside -msilicon-errata to generate messages whenever
    a problem is fixed, or on its own in order to inspect code for
    potential problems.

Cheers
  Nick

gas/ChangeLog
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.

gas/testsuite/ChangeLog
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.

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/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/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"
 }
--- /dev/null	2015-10-22 08:06:26.143786336 +0100
+++ gas/testsuite/gas/msp430/errata_fixes.s	2015-10-22 15:54:43.671894188 +0100
@@ -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
--- /dev/null	2015-10-22 08:06:26.143786336 +0100
+++ gas/testsuite/gas/msp430/errata_fixes.d	2015-10-22 15:54:43.671894188 +0100
@@ -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			
--- /dev/null	2015-10-22 08:06:26.143786336 +0100
+++ gas/testsuite/gas/msp430/errata_warns.s	2015-10-22 15:54:43.673894198 +0100
@@ -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
--- /dev/null	2015-10-22 08:06:26.143786336 +0100
+++ gas/testsuite/gas/msp430/errata_warns.l	2015-10-22 15:54:43.672894193 +0100
@@ -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
--- /dev/null	2015-10-22 08:06:26.143786336 +0100
+++ gas/testsuite/gas/msp430/errata_warns.d	2015-10-22 15:54:43.672894193 +0100
@@ -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

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