[GAS,MSP430] Improve NOP warnings/insertion behaviour around interrupt state changes

Message ID 20181125132704.49071042@jozef-Aspire-VN7-793G
State New
Headers show
Series
  • [GAS,MSP430] Improve NOP warnings/insertion behaviour around interrupt state changes
Related show

Commit Message

Jozef Lawrynowicz Nov. 25, 2018, 1:30 p.m.
The attached patch for the assembler improves the handling of NOPs around
interrupt state changes for MSP430.

Currently the assembler will insert a NOP after an interrupt state change for
both 430 and 430x ISA. Unless the interrupt state change instruction is
explicitly "EINT", then a generic message about how a NOP might be needed after
an interrupt state change is emitted.

The new behaviour tightens the constraints for warning about NOPs for the 430
ISA, so NOPs are only inserted/warned about when needed:
- 430 and 430x ISA require a NOP after DINT.
- Only the 430x ISA requires NOP before EINT
- Only the 430x ISA requires NOP after every EINT. CPU42 errata.

There are also some new messages to better describe where NOPs are being
inserted/are thought to be required.

Another change is some logic to interpret the value being written
to the SR when the constant generator is used as the source, to understand if
interrupts will be enabled or disabled as a result of the instruction.

Also added many new tests.

If the patch is acceptable, I would appreciate if someone would apply it for
me, as I don't have write access.

Comments

Nick Clifton Nov. 27, 2018, 12:30 p.m. | #1
Hi Jozef,

> If the patch is acceptable, I would appreciate if someone would apply it for

> me, as I don't have write access.


Approved and applied.

Note - there was one bug in the patch:

> diff --git a/gas/config/tc-msp430.c b/gas/config/tc-msp430.c

[...]
> @@ -2654,37 +2733,76 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line)

[...]
>  

> -		  if (gen_interrupt_nops)

> -		    /* Emit a NOP between interrupt enable/disable.

> -		       See 1.3.4.1 of the MSP430x5xx User Guide.  */

> -		    doit = TRUE;

> -		  break;

> -

>  		case NOP_CHECK_CPU12:


This deleted the "break" statement at the end of NOP_CHECK_INTERRUPT case.
I assumed that your intent was not to fall through into the NOP_CHECK_CPU12
case, so I restored the break statement.

Cheers
  Nick
Jozef Lawrynowicz Nov. 27, 2018, 3:58 p.m. | #2
On Tue, 27 Nov 2018 12:30:44 +0000
Nick Clifton <nickc@redhat.com> wrote:

> Approved and applied.


Hi Nick, 
Thanks for the review.

> > diff --git a/gas/config/tc-msp430.c b/gas/config/tc-msp430.c  

> [...]

> > @@ -2654,37 +2733,76 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line)  

> [...]

> >  

> > -		  if (gen_interrupt_nops)

> > -		    /* Emit a NOP between interrupt enable/disable.

> > -		       See 1.3.4.1 of the MSP430x5xx User Guide.  */

> > -		    doit = TRUE;

> > -		  break;

> > -

> >  		case NOP_CHECK_CPU12:  

> 

> This deleted the "break" statement at the end of NOP_CHECK_INTERRUPT case.

> I assumed that your intent was not to fall through into the NOP_CHECK_CPU12

> case, so I restored the break statement.

> 


Ah yes, that was a mistake, thanks for fixing it.

Jozef

Patch

From d54b73aed8e68995f1701474753c20153201b289 Mon Sep 17 00:00:00 2001
From: Jozef Lawrynowicz <jozef.l@mittosystems.com>
Date: Sun, 25 Nov 2018 11:27:25 +0000
Subject: [PATCH] [GAS][MSP430] Improve NOP warnings/insertion behaviour around
 interrupt state changes

2018-11-25  Jozef Lawrynowicz  <jozef.l@mittosystems.com>

	gas/ChangeLog:

	* config/tc-msp430.c (is_dint): New.
	(is_eint): New.
	(gen_nop): New.
	(warn_eint_nop): New.
	(warn_unsure_interrupt): New.
	(msp430_operands): Determine the effect MOV #N,SR insns have on
	interrupt state.
	Only emit NOP warnings for 430 ISA in certain situations.
	(msp430_md_end): Only warn about an EINT at the end of the file
	if NOP warnings are enabled.
	* testsuite/gas/msp430/bad.l: Adjust expected output for new warnings.
	* testsuite/gas/msp430/msp430.exp: Run new tests.
	* testsuite/gas/msp430/nop-dint-430.d: New.
	* testsuite/gas/msp430/nop-dint-430.l: New.
	* testsuite/gas/msp430/nop-dint-430x-ignore.d: New.
	* testsuite/gas/msp430/nop-dint-430x-silent.d: New.
	* testsuite/gas/msp430/nop-dint-430x.d: New.
	* testsuite/gas/msp430/nop-dint-430x.l: New.
	* testsuite/gas/msp430/nop-dint.s: New.
	* testsuite/gas/msp430/nop-eint-430.d: New.
	* testsuite/gas/msp430/nop-eint-430.l: New.
	* testsuite/gas/msp430/nop-eint-430x-ignore.d: New.
	* testsuite/gas/msp430/nop-eint-430x-silent.d: New.
	* testsuite/gas/msp430/nop-eint-430x.d: New.
	* testsuite/gas/msp430/nop-eint-430x.l: New.
	* testsuite/gas/msp430/nop-eint.s: New.
	* testsuite/gas/msp430/nop-int-430.d: New.
	* testsuite/gas/msp430/nop-int-430.l: New.
	* testsuite/gas/msp430/nop-int-430x-silent.d: New.
	* testsuite/gas/msp430/nop-int-430x.d: New.
	* testsuite/gas/msp430/nop-int-430x.l: New.
	* testsuite/gas/msp430/nop-int.s: New.
---
 gas/config/tc-msp430.c                          | 297 +++++++++++++++++++-----
 gas/testsuite/gas/msp430/bad.l                  |  21 +-
 gas/testsuite/gas/msp430/msp430.exp             |  11 +
 gas/testsuite/gas/msp430/nop-dint-430.d         |  32 +++
 gas/testsuite/gas/msp430/nop-dint-430.l         |   9 +
 gas/testsuite/gas/msp430/nop-dint-430x-ignore.d |   8 +
 gas/testsuite/gas/msp430/nop-dint-430x-silent.d |  31 +++
 gas/testsuite/gas/msp430/nop-dint-430x.d        |  32 +++
 gas/testsuite/gas/msp430/nop-dint-430x.l        |   9 +
 gas/testsuite/gas/msp430/nop-dint.s             |  37 +++
 gas/testsuite/gas/msp430/nop-eint-430.d         |  31 +++
 gas/testsuite/gas/msp430/nop-eint-430.l         |   3 +
 gas/testsuite/gas/msp430/nop-eint-430x-ignore.d |   8 +
 gas/testsuite/gas/msp430/nop-eint-430x-silent.d |  47 ++++
 gas/testsuite/gas/msp430/nop-eint-430x.d        |  48 ++++
 gas/testsuite/gas/msp430/nop-eint-430x.l        |  20 ++
 gas/testsuite/gas/msp430/nop-eint.s             |  44 ++++
 gas/testsuite/gas/msp430/nop-int-430.d          |   4 +
 gas/testsuite/gas/msp430/nop-int-430.l          |   3 +
 gas/testsuite/gas/msp430/nop-int-430x-silent.d  |   5 +
 gas/testsuite/gas/msp430/nop-int-430x.d         |   4 +
 gas/testsuite/gas/msp430/nop-int-430x.l         |  10 +
 gas/testsuite/gas/msp430/nop-int.s              |  74 ++++++
 23 files changed, 716 insertions(+), 72 deletions(-)
 create mode 100644 gas/testsuite/gas/msp430/nop-dint-430.d
 create mode 100644 gas/testsuite/gas/msp430/nop-dint-430.l
 create mode 100644 gas/testsuite/gas/msp430/nop-dint-430x-ignore.d
 create mode 100644 gas/testsuite/gas/msp430/nop-dint-430x-silent.d
 create mode 100644 gas/testsuite/gas/msp430/nop-dint-430x.d
 create mode 100644 gas/testsuite/gas/msp430/nop-dint-430x.l
 create mode 100644 gas/testsuite/gas/msp430/nop-dint.s
 create mode 100644 gas/testsuite/gas/msp430/nop-eint-430.d
 create mode 100644 gas/testsuite/gas/msp430/nop-eint-430.l
 create mode 100644 gas/testsuite/gas/msp430/nop-eint-430x-ignore.d
 create mode 100644 gas/testsuite/gas/msp430/nop-eint-430x-silent.d
 create mode 100644 gas/testsuite/gas/msp430/nop-eint-430x.d
 create mode 100644 gas/testsuite/gas/msp430/nop-eint-430x.l
 create mode 100644 gas/testsuite/gas/msp430/nop-eint.s
 create mode 100644 gas/testsuite/gas/msp430/nop-int-430.d
 create mode 100644 gas/testsuite/gas/msp430/nop-int-430.l
 create mode 100644 gas/testsuite/gas/msp430/nop-int-430x-silent.d
 create mode 100644 gas/testsuite/gas/msp430/nop-int-430x.d
 create mode 100644 gas/testsuite/gas/msp430/nop-int-430x.l
 create mode 100644 gas/testsuite/gas/msp430/nop-int.s

diff --git a/gas/config/tc-msp430.c b/gas/config/tc-msp430.c
index bebae6e..fc1ba99 100644
--- a/gas/config/tc-msp430.c
+++ b/gas/config/tc-msp430.c
@@ -2495,6 +2495,79 @@  static signed int check_for_nop = 0;
 
 #define is_opcode(NAME) (strcmp (opcode->name, NAME) == 0)
 
+/* is_{e,d}int only check the explicit enabling/disabling of interrupts.
+   For MOV insns, more sophisticated processing is needed to determine if they
+   result in enabling/disabling interrupts.  */
+#define is_dint(OPCODE, BIN) ((strcmp (OPCODE, "dint") == 0) \
+				   || ((strcmp (OPCODE, "bic") == 0) \
+				       && BIN == 0xc232) \
+				   || ((strcmp (OPCODE, "clr") == 0) \
+				       && BIN == 0x4302))
+
+#define is_eint(OPCODE, BIN) ((strcmp (OPCODE, "eint") == 0) \
+				   || ((strcmp (OPCODE, "bis") == 0) \
+				       && BIN == 0xd232))
+
+const char * const INSERT_NOP_BEFORE_EINT = "NOP inserted here, before an interrupt enable instruction";
+const char * const INSERT_NOP_AFTER_DINT = "NOP inserted here, after an interrupt disable instruction";
+const char * const INSERT_NOP_AFTER_EINT = "NOP inserted here, after an interrupt enable instruction";
+const char * const INSERT_NOP_BEFORE_UNKNOWN = "NOP inserted here, before this interrupt state change";
+const char * const INSERT_NOP_AFTER_UNKNOWN ="NOP inserted here, after the instruction that changed interrupt state";
+const char * const INSERT_NOP_AT_EOF = "NOP inserted after the interrupt state change at the end of the file";
+
+const char * const WARN_NOP_BEFORE_EINT = "a NOP might be needed here, before an interrupt enable instruction";
+const char * const WARN_NOP_AFTER_DINT = "a NOP might be needed here, after an interrupt disable instruction";
+const char * const WARN_NOP_AFTER_EINT = "a NOP might be needed here, after an interrupt enable instruction";
+const char * const WARN_NOP_BEFORE_UNKNOWN = "a NOP might be needed here, before this interrupt state change";
+const char * const WARN_NOP_AFTER_UNKNOWN = "a NOP might also be needed here, after the instruction that changed interrupt state";
+const char * const WARN_NOP_AT_EOF = "a NOP might be needed after the interrupt state change at the end of the file";
+
+static void
+gen_nop (void)
+{
+  char *frag;
+  frag = frag_more (2);
+  bfd_putl16 ((bfd_vma) 0x4303 /* NOP */, frag);
+  dwarf2_emit_insn (2);
+}
+
+/* Insert/inform about adding a NOP if this insn enables interrupts.  */
+static void
+warn_eint_nop (bfd_boolean prev_insn_is_nop, bfd_boolean prev_insn_is_dint)
+{
+  if (prev_insn_is_nop
+      /* Prevent double warning for DINT immediately before EINT.  */
+      || prev_insn_is_dint
+      /* 430 ISA does not require a NOP before EINT.  */
+      || (! target_is_430x ()))
+    return;
+  if (gen_interrupt_nops)
+    {
+      gen_nop ();
+      if (warn_interrupt_nops)
+	as_warn (_(INSERT_NOP_BEFORE_EINT));
+    }
+  else if (warn_interrupt_nops)
+    as_warn (_(WARN_NOP_BEFORE_EINT));
+}
+
+/* Use when unsure what effect the insn will have on the interrupt status,
+   to insert/warn about adding a NOP before the current insn.  */
+static void
+warn_unsure_interrupt (void)
+{
+  /* Since this could enable or disable interrupts, need to add/warn about
+     adding a NOP before and after this insn.  */
+  if (gen_interrupt_nops)
+    {
+      gen_nop ();
+      if (warn_interrupt_nops)
+	as_warn (_(INSERT_NOP_BEFORE_UNKNOWN));
+    }
+  else if (warn_interrupt_nops)
+    as_warn (_(WARN_NOP_BEFORE_UNKNOWN));
+}
+
 /* Parse instruction operands.
    Return binary opcode.  */
 
@@ -2519,6 +2592,12 @@  msp430_operands (struct msp430_opcode_s * opcode, char * line)
   const char * error_message;
   static signed int repeat_count = 0;
   static bfd_boolean prev_insn_is_nop = FALSE;
+  static bfd_boolean prev_insn_is_dint = FALSE;
+  static bfd_boolean prev_insn_is_eint = FALSE;
+  /* We might decide before the end of the function that the current insn is
+     equivalent to DINT/EINT.  */
+  bfd_boolean this_insn_is_dint = FALSE;
+  bfd_boolean this_insn_is_eint = FALSE;
   bfd_boolean fix_emitted;
 
   /* Opcode is the one from opcodes table
@@ -2654,37 +2733,76 @@  msp430_operands (struct msp430_opcode_s * opcode, char * line)
       repeat_count = 0;
     }
 
+  /* The previous instruction set this flag if it wants to check if this insn
+     is a NOP.  */
   if (check_for_nop)
     {
       if (! is_opcode ("nop"))
 	{
-	  bfd_boolean doit = FALSE;
-
 	  do
 	    {
 	      switch (check_for_nop & - check_for_nop)
 		{
 		case NOP_CHECK_INTERRUPT:
-		  if (warn_interrupt_nops)
+		  /* NOP_CHECK_INTERRUPT rules:
+		     1.  430 and 430x ISA require a NOP after DINT.
+		     2.  Only the 430x ISA requires NOP before EINT (this has
+			been dealt with in the previous call to this function).
+		     3.  Only the 430x ISA requires NOP after every EINT.
+			CPU42 errata.  */
+		  if (gen_interrupt_nops || warn_interrupt_nops)
 		    {
-		      if (gen_interrupt_nops)
-			as_warn (_("NOP inserted between two instructions that change interrupt state"));
+		      if (prev_insn_is_dint)
+			{
+			  if (gen_interrupt_nops)
+			    {
+			      gen_nop ();
+			      if (warn_interrupt_nops)
+				as_warn (_(INSERT_NOP_AFTER_DINT));
+			    }
+			  else
+			    as_warn (_(WARN_NOP_AFTER_DINT));
+			}
+		      else if (prev_insn_is_eint)
+			{
+			  if (gen_interrupt_nops)
+			    {
+			      gen_nop ();
+			      if (warn_interrupt_nops)
+				as_warn (_(INSERT_NOP_AFTER_EINT));
+			    }
+			  else
+			    as_warn (_(WARN_NOP_AFTER_EINT));
+			}
+		      /* If we get here it's because the last instruction was
+			 determined to either disable or enable interrupts, but
+			 we're not sure which.
+			 We have no information yet about what effect the
+			 current instruction has on interrupts, that has to be
+			 sorted out later.
+			 The last insn may have required a NOP after it, so we
+			 deal with that now.  */
 		      else
-			as_warn (_("a NOP might be needed here because of successive changes in interrupt state"));
+			{
+			  if (gen_interrupt_nops)
+			    {
+			      gen_nop ();
+			      if (warn_interrupt_nops)
+				as_warn (_(INSERT_NOP_AFTER_UNKNOWN));
+			    }
+			  else
+			    /* warn_unsure_interrupt was called on the previous
+			       insn.  */
+			    as_warn (_(WARN_NOP_AFTER_UNKNOWN));
+			}
 		    }
 
-		  if (gen_interrupt_nops)
-		    /* 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 destination ignores next instruction"));
 
 		  if (silicon_errata_fix & SILICON_ERRATA_CPU12)
-		    doit = TRUE;
+		    gen_nop ();
 		  break;
 
 		case NOP_CHECK_CPU19:
@@ -2692,7 +2810,7 @@  msp430_operands (struct msp430_opcode_s * opcode, char * line)
 		    as_warn (_("CPU19: Instruction setting CPUOFF must be followed by a NOP"));
 
 		  if (silicon_errata_fix & SILICON_ERRATA_CPU19)
-		    doit = TRUE;
+		    gen_nop ();
 		  break;
 		  
 		default:
@@ -2702,15 +2820,7 @@  msp430_operands (struct msp430_opcode_s * opcode, char * line)
 	      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;
     }
 
@@ -2721,24 +2831,7 @@  msp430_operands (struct msp430_opcode_s * opcode, char * line)
 	{
 	case 0:
 	  if (is_opcode ("eint"))
-	    {
-	      if (! prev_insn_is_nop)
-		{
-		  if (gen_interrupt_nops)
-		    {
-		      frag = frag_more (2);
-		      bfd_putl16 ((bfd_vma) 0x4303 /* NOP */, frag);
-		      dwarf2_emit_insn (2);
-
-		      if (warn_interrupt_nops)
-			as_warn (_("inserting a NOP before EINT"));
-		    }
-		  else if (warn_interrupt_nops)
-		    as_warn (_("a NOP might be needed before the EINT"));
-		}
-	    }
-	  else if (is_opcode ("dint"))
-	    check_for_nop |= NOP_CHECK_INTERRUPT;
+	    warn_eint_nop (prev_insn_is_nop, prev_insn_is_dint);
 
 	  /* Set/clear bits instructions.  */
 	  if (extended_op)
@@ -2796,9 +2889,6 @@  msp430_operands (struct msp430_opcode_s * opcode, char * line)
 		as_warn (_("CPU13: SR is destination 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);
 	  insn_length += op_length;
@@ -2896,6 +2986,8 @@  msp430_operands (struct msp430_opcode_s * opcode, char * line)
 	      /* ... and the opcode alters the SR.  */
 	      && (is_opcode ("rla") || is_opcode ("rlc")
 		  || is_opcode ("rlax") || is_opcode ("rlcx")
+		  || is_opcode ("sxt") || is_opcode ("sxtx")
+		  || is_opcode ("swpb")
 		  ))
 	    {
 	      if (silicon_errata_fix & SILICON_ERRATA_CPU13)
@@ -3447,6 +3539,12 @@  msp430_operands (struct msp430_opcode_s * opcode, char * line)
 	}
       break;
 
+      /* FIXME: Emit warning when dest reg SR(R2) is addressed with .B or .A.
+	 From f5 ref man 6.3.3:
+	   The 16-bit Status Register (SR, also called R2), used as a source or
+	   destination register, can only be used in register mode addressed
+	   with word instructions.  */
+
     case 1:			/* Format 1, double operand.  */
       line = extract_operand (line, l1, sizeof (l1));
       line = extract_operand (line, l2, sizeof (l2));
@@ -3501,20 +3599,9 @@  msp430_operands (struct msp430_opcode_s * opcode, char * line)
 	  else if (silicon_errata_warn & SILICON_ERRATA_CPU13)
 	    as_warn (_("CPU13: SR is destination 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))
-	{
-	  /* 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;
-	}
 
+      /* Chain these checks for SR manipulations so we can warn if they are not
+	 caught.  */
       if (((is_opcode ("bis") && bin == 0xd032)
 	   || (is_opcode ("mov") && bin == 0x4032)
 	   || (is_opcode ("xor") && bin == 0xe032))
@@ -3522,6 +3609,60 @@  msp430_operands (struct msp430_opcode_s * opcode, char * line)
 	  && op1.exp.X_op == O_constant
 	  && (op1.exp.X_add_number & 0x10) == 0x10)
 	check_for_nop |= NOP_CHECK_CPU19;
+      else if ((is_opcode ("mov") && op2.mode == OP_REG && op2.reg == 2))
+	{
+	  /* Any MOV with the SR as the destination either enables or disables
+	     interrupts.  */
+	  if (op1.mode == OP_EXP
+	      && op1.exp.X_op == O_constant)
+	    {
+	      if ((op1.exp.X_add_number & 0x8) == 0x8)
+		{
+		  /* The GIE bit is being set.  */
+		  warn_eint_nop (prev_insn_is_nop, prev_insn_is_dint);
+		  this_insn_is_eint = TRUE;
+		}
+	      else
+		/* The GIE bit is being cleared.  */
+		this_insn_is_dint = TRUE;
+	    }
+	  /* If an immediate value which is covered by the constant generator
+	     is the src, then op1 will have been changed to either R2 or R3 by
+	     this point.
+	     The only constants covered by CG1 and CG2, which have bit 3 set
+	     and therefore would enable interrupts when writing to the SR, are
+	     R2 with addresing mode 0b11 and R3 with 0b11.
+	     The addressing mode is in bits 5:4 of the binary opcode.  */
+	  else if (op1.mode == OP_REG
+		   && (op1.reg == 2 || op1.reg == 3)
+		   && (bin & 0x30) == 0x30)
+	    {
+	      warn_eint_nop (prev_insn_is_nop, prev_insn_is_dint);
+	      this_insn_is_eint = TRUE;
+	    }
+	  /* Any other use of the constant generator with destination R2, will
+	     disable interrupts.  */
+	  else if (op1.mode == OP_REG
+		   && (op1.reg == 2 || op1.reg == 3))
+	    this_insn_is_dint = TRUE;
+	  else
+	    {
+	      /* FIXME: Couldn't work out whether the insn is enabling or
+		 disabling interrupts, so for safety need to treat it as both
+		 a DINT and EINT.  */
+	      warn_unsure_interrupt ();
+	      check_for_nop |= NOP_CHECK_INTERRUPT;
+	    }
+	}
+      else if (is_eint (opcode->name, bin))
+	warn_eint_nop (prev_insn_is_nop, prev_insn_is_dint);
+      else if ((bin & 0x32) == 0x32)
+	{
+	  /* Double-operand insn with the As==0b11 and Rdst==0x2 will result in
+	   * an interrupt state change if a write happens.  */
+	  /* FIXME: How strict to be here? */
+	  ;
+	}
 
       /* Compute the entire length of the instruction in bytes.  */
       op_length = (extended_op ? 2 : 0)	/* The extension word.  */
@@ -3959,11 +4100,34 @@  msp430_operands (struct msp430_opcode_s * opcode, char * line)
       as_bad (_("Illegal instruction or not implemented opcode."));
     }
 
-  if (is_opcode ("nop"))
-    prev_insn_is_nop = TRUE;
-  else
-    prev_insn_is_nop = FALSE;
-	    
+    if (is_opcode ("nop"))
+      {
+	prev_insn_is_nop = TRUE;
+	prev_insn_is_dint = FALSE;
+	prev_insn_is_eint = FALSE;
+      }
+    else if (this_insn_is_dint || is_dint (opcode->name, bin))
+      {
+	prev_insn_is_dint = TRUE;
+	prev_insn_is_eint = FALSE;
+	prev_insn_is_nop = FALSE;
+	check_for_nop |= NOP_CHECK_INTERRUPT;
+      }
+    /* NOP is not needed after EINT for 430 ISA.  */
+    else if (target_is_430x () && (this_insn_is_eint || is_eint (opcode->name, bin)))
+      {
+	prev_insn_is_eint = TRUE;
+	prev_insn_is_nop = FALSE;
+	prev_insn_is_dint = FALSE;
+	check_for_nop |= NOP_CHECK_INTERRUPT;
+      }
+    else
+      {
+	prev_insn_is_nop = FALSE;
+	prev_insn_is_dint = FALSE;
+	prev_insn_is_eint = FALSE;
+      }
+
   input_line_pointer = line;
   return 0;
 }
@@ -4699,7 +4863,16 @@  void
 msp430_md_end (void)
 {
   if (check_for_nop)
-    as_warn ("assembly finished without a possibly needed NOP instruction");
+    {
+      if (gen_interrupt_nops)
+	{
+	  gen_nop ();
+	  if (warn_interrupt_nops)
+	    as_warn (INSERT_NOP_AT_EOF);
+	}
+      else if (warn_interrupt_nops)
+	as_warn (_(WARN_NOP_AT_EOF));
+    }
 
   bfd_elf_add_proc_attr_int (stdoutput, OFBA_MSPABI_Tag_ISA,
 			     target_is_430x () ? 2 : 1);
diff --git a/gas/testsuite/gas/msp430/bad.l b/gas/testsuite/gas/msp430/bad.l
index f466513..7b68583 100644
--- a/gas/testsuite/gas/msp430/bad.l
+++ b/gas/testsuite/gas/msp430/bad.l
@@ -4,14 +4,15 @@ 
 [^:]*:8: Error: junk found after instruction: mov.cd r1,r2
 [^:]*:9: Error: junk found after instruction: mov.cd r1,r2
 [^:]*:10: Warning: no size modifier after period, .w assumed
+[^:]*:10: Warning: a NOP might be needed here, before this interrupt state change
 [^:]*:11: Error: instruction bis.a does not exist
-[^:]*:16: Warning: a NOP might be needed here because of successive changes in interrupt state
-[^:]*:16: Warning: a NOP might be needed before the EINT
-[^:]*:25: Warning: a NOP might be needed here because of successive changes in interrupt state
-[^:]*:25: Warning: a NOP might be needed before the EINT
-[^:]*:29: Warning: a NOP might be needed here because of successive changes in interrupt state
-[^:]*:31: Warning: a NOP might be needed here because of successive changes in interrupt state
-[^:]*:32: Warning: a NOP might be needed here because of successive changes in interrupt state
-[^:]*:33: Warning: a NOP might be needed here because of successive changes in interrupt state
-[^:]*:34: Warning: a NOP might be needed here because of successive changes in interrupt state
-[^:]*: Warning: assembly finished without a possibly needed NOP instruction
+[^:]*:16: Warning: a NOP might also be needed here, after the instruction that changed interrupt state
+[^:]*:16: Warning: a NOP might be needed here, before an interrupt enable instruction
+[^:]*:25: Warning: a NOP might be needed here, after an interrupt disable instruction
+[^:]*:26: Warning: a NOP might be needed here, after an interrupt enable instruction
+[^:]*:29: Warning: a NOP might be needed here, after an interrupt disable instruction
+[^:]*:31: Warning: a NOP might be needed here, after an interrupt disable instruction
+[^:]*:32: Warning: a NOP might be needed here, after an interrupt disable instruction
+[^:]*:33: Warning: a NOP might be needed here, after an interrupt disable instruction
+[^:]*:34: Warning: a NOP might be needed here, after an interrupt enable instruction
+[^:]*: Warning: a NOP might be needed after the interrupt state change at the end of the file
diff --git a/gas/testsuite/gas/msp430/msp430.exp b/gas/testsuite/gas/msp430/msp430.exp
index 5e77b9b..1bc45be 100644
--- a/gas/testsuite/gas/msp430/msp430.exp
+++ b/gas/testsuite/gas/msp430/msp430.exp
@@ -27,4 +27,15 @@  if [expr [istarget "msp430-*-*"]]  then {
     run_dump_test "high-data-bss-sym" { { as "-mdata-region=upper" } }
     run_dump_test "high-data-bss-sym" { { as "-mdata-region=either" } }
     run_dump_test "pr22133"
+    run_dump_test "nop-int-430"
+    run_dump_test "nop-int-430x"
+    run_dump_test "nop-int-430x-silent"
+    run_dump_test "nop-eint-430"
+    run_dump_test "nop-eint-430x"
+    run_dump_test "nop-eint-430x-silent"
+    run_dump_test "nop-eint-430x-ignore"
+    run_dump_test "nop-dint-430"
+    run_dump_test "nop-dint-430x"
+    run_dump_test "nop-dint-430x-silent"
+    run_dump_test "nop-dint-430x-ignore"
 }
diff --git a/gas/testsuite/gas/msp430/nop-dint-430.d b/gas/testsuite/gas/msp430/nop-dint-430.d
new file mode 100644
index 0000000..99eb00b
--- /dev/null
+++ b/gas/testsuite/gas/msp430/nop-dint-430.d
@@ -0,0 +1,32 @@ 
+#name: DINT NOP Insertions (MSP430 CPU)
+#source: nop-dint.s
+#as: -my -mn -mcpu=430
+#warning_output: nop-dint-430.l
+#objdump: -d --prefix-addresses --show-raw-insn
+
+.*: +file format .*msp.*
+
+Disassembly of section .text:
+0x0+000 32 c2[ 	]+dint[ 	]+
+0x0+002 03 43[ 	]+nop[ 	]+
+0x0+004 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+008 32 c2[ 	]+dint[ 	]+
+0x0+00a 03 43[ 	]+nop[ 	]+
+0x0+00c 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+010 32 c2[ 	]+dint[ 	]+
+0x0+012 03 43[ 	]+nop[ 	]+
+0x0+014 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+018 02 43[ 	]+clr	r2		;
+0x0+01a 03 43[ 	]+nop[ 	]+
+0x0+01c 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+020 32 40 07 00[ 	]+mov	#7,	r2	;
+0x0+024 03 43[ 	]+nop[ 	]+
+0x0+026 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+02a 32 40 07 f0[ 	]+mov	#-4089,	r2	;#0xf007
+0x0+02e 03 43[ 	]+nop[ 	]+
+0x0+030 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+034 02 43[ 	]+clr	r2		;
+0x0+036 03 43[ 	]+nop[ 	]+
+0x0+038 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+03c 32 c2[ 	]+dint[ 	]+
+0x0+03e 03 43[ 	]+nop[ 	]+
diff --git a/gas/testsuite/gas/msp430/nop-dint-430.l b/gas/testsuite/gas/msp430/nop-dint-430.l
new file mode 100644
index 0000000..ab1adec
--- /dev/null
+++ b/gas/testsuite/gas/msp430/nop-dint-430.l
@@ -0,0 +1,9 @@ 
+[^:]*: Assembler messages:
+[^:]*:11: Warning: NOP inserted here, after an interrupt disable instruction
+[^:]*:15: Warning: NOP inserted here, after an interrupt disable instruction
+[^:]*:18: Warning: NOP inserted here, after an interrupt disable instruction
+[^:]*:21: Warning: NOP inserted here, after an interrupt disable instruction
+[^:]*:24: Warning: NOP inserted here, after an interrupt disable instruction
+[^:]*:27: Warning: NOP inserted here, after an interrupt disable instruction
+[^:]*:30: Warning: NOP inserted here, after an interrupt disable instruction
+[^:]*: Warning: NOP inserted after the interrupt state change at the end of the file
diff --git a/gas/testsuite/gas/msp430/nop-dint-430x-ignore.d b/gas/testsuite/gas/msp430/nop-dint-430x-ignore.d
new file mode 100644
index 0000000..e9265ae
--- /dev/null
+++ b/gas/testsuite/gas/msp430/nop-dint-430x-ignore.d
@@ -0,0 +1,8 @@ 
+#name: Ignore DINT NOP Insertions (MSP430X CPU)
+#source: nop-dint.s
+#as: -mY -mcpu=430x
+#objdump: -d --prefix-addresses --show-raw-insn
+#failif
+#...
+0x0.*nop.*
+#...
diff --git a/gas/testsuite/gas/msp430/nop-dint-430x-silent.d b/gas/testsuite/gas/msp430/nop-dint-430x-silent.d
new file mode 100644
index 0000000..66c1052
--- /dev/null
+++ b/gas/testsuite/gas/msp430/nop-dint-430x-silent.d
@@ -0,0 +1,31 @@ 
+#name: Silent DINT NOP Insertions (MSP430X CPU)
+#source: nop-dint.s
+#as: -mY -mn -mcpu=430x
+#objdump: -d --prefix-addresses --show-raw-insn
+
+.*: +file format .*msp.*
+
+Disassembly of section .text:
+0x0+000 32 c2[ 	]+dint[ 	]+
+0x0+002 03 43[ 	]+nop[ 	]+
+0x0+004 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+008 32 c2[ 	]+dint[ 	]+
+0x0+00a 03 43[ 	]+nop[ 	]+
+0x0+00c 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+010 32 c2[ 	]+dint[ 	]+
+0x0+012 03 43[ 	]+nop[ 	]+
+0x0+014 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+018 02 43[ 	]+clr	r2		;
+0x0+01a 03 43[ 	]+nop[ 	]+
+0x0+01c 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+020 32 40 07 00[ 	]+mov	#7,	r2	;
+0x0+024 03 43[ 	]+nop[ 	]+
+0x0+026 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+02a 32 40 07 f0[ 	]+mov	#-4089,	r2	;#0xf007
+0x0+02e 03 43[ 	]+nop[ 	]+
+0x0+030 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+034 02 43[ 	]+clr	r2		;
+0x0+036 03 43[ 	]+nop[ 	]+
+0x0+038 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+03c 32 c2[ 	]+dint[ 	]+
+0x0+03e 03 43[ 	]+nop[ 	]+
diff --git a/gas/testsuite/gas/msp430/nop-dint-430x.d b/gas/testsuite/gas/msp430/nop-dint-430x.d
new file mode 100644
index 0000000..ea74dfc
--- /dev/null
+++ b/gas/testsuite/gas/msp430/nop-dint-430x.d
@@ -0,0 +1,32 @@ 
+#name: DINT NOP Insertions (MSP430X CPU)
+#source: nop-dint.s
+#as: -my -mn -mcpu=430x
+#warning_output: nop-dint-430.l
+#objdump: -d --prefix-addresses --show-raw-insn
+
+.*: +file format .*msp.*
+
+Disassembly of section .text:
+0x0+000 32 c2[ 	]+dint[ 	]+
+0x0+002 03 43[ 	]+nop[ 	]+
+0x0+004 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+008 32 c2[ 	]+dint[ 	]+
+0x0+00a 03 43[ 	]+nop[ 	]+
+0x0+00c 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+010 32 c2[ 	]+dint[ 	]+
+0x0+012 03 43[ 	]+nop[ 	]+
+0x0+014 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+018 02 43[ 	]+clr	r2		;
+0x0+01a 03 43[ 	]+nop[ 	]+
+0x0+01c 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+020 32 40 07 00[ 	]+mov	#7,	r2	;
+0x0+024 03 43[ 	]+nop[ 	]+
+0x0+026 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+02a 32 40 07 f0[ 	]+mov	#-4089,	r2	;#0xf007
+0x0+02e 03 43[ 	]+nop[ 	]+
+0x0+030 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+034 02 43[ 	]+clr	r2		;
+0x0+036 03 43[ 	]+nop[ 	]+
+0x0+038 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+03c 32 c2[ 	]+dint[ 	]+
+0x0+03e 03 43[ 	]+nop[ 	]+
diff --git a/gas/testsuite/gas/msp430/nop-dint-430x.l b/gas/testsuite/gas/msp430/nop-dint-430x.l
new file mode 100644
index 0000000..ab1adec
--- /dev/null
+++ b/gas/testsuite/gas/msp430/nop-dint-430x.l
@@ -0,0 +1,9 @@ 
+[^:]*: Assembler messages:
+[^:]*:11: Warning: NOP inserted here, after an interrupt disable instruction
+[^:]*:15: Warning: NOP inserted here, after an interrupt disable instruction
+[^:]*:18: Warning: NOP inserted here, after an interrupt disable instruction
+[^:]*:21: Warning: NOP inserted here, after an interrupt disable instruction
+[^:]*:24: Warning: NOP inserted here, after an interrupt disable instruction
+[^:]*:27: Warning: NOP inserted here, after an interrupt disable instruction
+[^:]*:30: Warning: NOP inserted here, after an interrupt disable instruction
+[^:]*: Warning: NOP inserted after the interrupt state change at the end of the file
diff --git a/gas/testsuite/gas/msp430/nop-dint.s b/gas/testsuite/gas/msp430/nop-dint.s
new file mode 100644
index 0000000..3dc8019
--- /dev/null
+++ b/gas/testsuite/gas/msp430/nop-dint.s
@@ -0,0 +1,37 @@ 
+	.text
+
+;;; Test for NOP warnings when disabling interrupts, which are common to both
+;;; 430 and 430x ISA.
+;;; "MOV &FOO,r10" is used as an artbitrary statement which isn't a NOP, to
+;;; break up the instructions being tested.
+
+;;; Test NOP required after DINT
+	DINT
+
+	MOV &FOO,r10
+;;; Check aliases for which the GIE bit (bit 3) of the SR can be cleared
+;;; These should all cause warnings
+	BIC.W #8,R2
+	MOV &FOO,r10
+
+	BIC.W #8,SR
+	MOV &FOO,r10
+
+	MOV.W #0,R2
+	MOV &FOO,r10
+
+	MOV.W #7,R2
+	MOV &FOO,r10
+
+	MOV.W #0xf007,R2
+	MOV &FOO,r10
+
+	CLR R2
+	MOV &FOO,r10
+
+;;; The above hopefully covers the legitimate ways the SR might be cleared,
+;;; but there are other insns that can technically modify R2, but shouldn't be
+;;; used.
+
+;;; Test DINT at end of file
+	DINT
diff --git a/gas/testsuite/gas/msp430/nop-eint-430.d b/gas/testsuite/gas/msp430/nop-eint-430.d
new file mode 100644
index 0000000..37b2c6c
--- /dev/null
+++ b/gas/testsuite/gas/msp430/nop-eint-430.d
@@ -0,0 +1,31 @@ 
+#name: EINT NOP Insertions (MSP430 CPU)
+#source: nop-eint.s
+#as: -my -mn -mcpu=430
+#warning_output: nop-eint-430.l
+#objdump: -d --prefix-addresses --show-raw-insn
+
+.*: +file format .*msp.*
+
+
+Disassembly of section .text:
+0x0+0000 32 d2[ 	]+eint[ 	]+
+0x0+0002 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+0006 32 d2[ 	]+eint[ 	]+
+0x0+0008 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+000c 32 d2[ 	]+eint[ 	]+
+0x0+000e 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+0012 32 42[ 	]+mov	#8,	r2	;r2 As==11
+0x0+0014 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+0018 32 40 0f 00[ 	]+mov	#15,	r2	;#0x000f
+0x0+001c 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+0020 32 43[ 	]+mov	#-1,	r2	;r3 As==11
+0x0+0022 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+0026 32 d2[ 	]+eint[ 	]+
+0x0+0028 32 c2[ 	]+dint[ 	]+
+0x0+002a 03 43[ 	]+nop[ 	]+
+0x0+002c 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+0030 32 c2[ 	]+dint[ 	]+
+0x0+0032 03 43[ 	]+nop[ 	]+
+0x0+0034 32 d2[ 	]+eint[ 	]+
+0x0+0036 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+003a 32 d2[ 	]+eint[ 	]+
diff --git a/gas/testsuite/gas/msp430/nop-eint-430.l b/gas/testsuite/gas/msp430/nop-eint-430.l
new file mode 100644
index 0000000..a7bb342
--- /dev/null
+++ b/gas/testsuite/gas/msp430/nop-eint-430.l
@@ -0,0 +1,3 @@ 
+[^:]*: Assembler messages:
+[^:]*:36: Warning: NOP inserted here, after an interrupt disable instruction
+[^:]*:39: Warning: NOP inserted here, after an interrupt disable instruction
diff --git a/gas/testsuite/gas/msp430/nop-eint-430x-ignore.d b/gas/testsuite/gas/msp430/nop-eint-430x-ignore.d
new file mode 100644
index 0000000..54066c0
--- /dev/null
+++ b/gas/testsuite/gas/msp430/nop-eint-430x-ignore.d
@@ -0,0 +1,8 @@ 
+#name: Ignore EINT NOP Insertions (MSP430X CPU)
+#source: nop-eint.s
+#as: -mY -mcpu=430x
+#objdump: -d --prefix-addresses --show-raw-insn
+#failif
+#...
+0x0.*nop.*
+#...
diff --git a/gas/testsuite/gas/msp430/nop-eint-430x-silent.d b/gas/testsuite/gas/msp430/nop-eint-430x-silent.d
new file mode 100644
index 0000000..ee7b362
--- /dev/null
+++ b/gas/testsuite/gas/msp430/nop-eint-430x-silent.d
@@ -0,0 +1,47 @@ 
+#name: Silent EINT NOP Insertions (MSP430X CPU)
+#source: nop-eint.s
+#as: -mY -mn -mcpu=430x
+#objdump: -d --prefix-addresses --show-raw-insn
+
+.*: +file format .*msp.*
+
+
+Disassembly of section .text:
+0x0+0000 03 43[ 	]+nop[ 	]+
+0x0+0002 32 d2[ 	]+eint[ 	]+
+0x0+0004 03 43[ 	]+nop[ 	]+
+0x0+0006 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+000a 03 43[ 	]+nop[ 	]+
+0x0+000c 32 d2[ 	]+eint[ 	]+
+0x0+000e 03 43[ 	]+nop[ 	]+
+0x0+0010 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+0014 03 43[ 	]+nop[ 	]+
+0x0+0016 32 d2[ 	]+eint[ 	]+
+0x0+0018 03 43[ 	]+nop[ 	]+
+0x0+001a 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+001e 03 43[ 	]+nop[ 	]+
+0x0+0020 32 42[ 	]+mov	#8,	r2	;r2 As==11
+0x0+0022 03 43[ 	]+nop[ 	]+
+0x0+0024 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+0028 03 43[ 	]+nop[ 	]+
+0x0+002a 32 40 0f 00[ 	]+mov	#15,	r2	;#0x000f
+0x0+002e 03 43[ 	]+nop[ 	]+
+0x0+0030 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+0034 03 43[ 	]+nop[ 	]+
+0x0+0036 32 43[ 	]+mov	#-1,	r2	;r3 As==11
+0x0+0038 03 43[ 	]+nop[ 	]+
+0x0+003a 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+003e 03 43[ 	]+nop[ 	]+
+0x0+0040 32 d2[ 	]+eint[ 	]+
+0x0+0042 03 43[ 	]+nop[ 	]+
+0x0+0044 32 c2[ 	]+dint[ 	]+
+0x0+0046 03 43[ 	]+nop[ 	]+
+0x0+0048 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+004c 32 c2[ 	]+dint[ 	]+
+0x0+004e 03 43[ 	]+nop[ 	]+
+0x0+0050 32 d2[ 	]+eint[ 	]+
+0x0+0052 03 43[ 	]+nop[ 	]+
+0x0+0054 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+0058 03 43[ 	]+nop[ 	]+
+0x0+005a 32 d2[ 	]+eint[ 	]+
+0x0+005c 03 43[ 	]+nop[ 	]+
diff --git a/gas/testsuite/gas/msp430/nop-eint-430x.d b/gas/testsuite/gas/msp430/nop-eint-430x.d
new file mode 100644
index 0000000..a28459b
--- /dev/null
+++ b/gas/testsuite/gas/msp430/nop-eint-430x.d
@@ -0,0 +1,48 @@ 
+#name: EINT NOP Insertions (MSP430X CPU)
+#source: nop-eint.s
+#as: -my -mn -mcpu=430x
+#warning_output: nop-eint-430x.l
+#objdump: -d --prefix-addresses --show-raw-insn
+
+.*: +file format .*msp.*
+
+
+Disassembly of section .text:
+0x0+0000 03 43[ 	]+nop[ 	]+
+0x0+0002 32 d2[ 	]+eint[ 	]+
+0x0+0004 03 43[ 	]+nop[ 	]+
+0x0+0006 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+000a 03 43[ 	]+nop[ 	]+
+0x0+000c 32 d2[ 	]+eint[ 	]+
+0x0+000e 03 43[ 	]+nop[ 	]+
+0x0+0010 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+0014 03 43[ 	]+nop[ 	]+
+0x0+0016 32 d2[ 	]+eint[ 	]+
+0x0+0018 03 43[ 	]+nop[ 	]+
+0x0+001a 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+001e 03 43[ 	]+nop[ 	]+
+0x0+0020 32 42[ 	]+mov	#8,	r2	;r2 As==11
+0x0+0022 03 43[ 	]+nop[ 	]+
+0x0+0024 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+0028 03 43[ 	]+nop[ 	]+
+0x0+002a 32 40 0f 00[ 	]+mov	#15,	r2	;#0x000f
+0x0+002e 03 43[ 	]+nop[ 	]+
+0x0+0030 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+0034 03 43[ 	]+nop[ 	]+
+0x0+0036 32 43[ 	]+mov	#-1,	r2	;r3 As==11
+0x0+0038 03 43[ 	]+nop[ 	]+
+0x0+003a 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+003e 03 43[ 	]+nop[ 	]+
+0x0+0040 32 d2[ 	]+eint[ 	]+
+0x0+0042 03 43[ 	]+nop[ 	]+
+0x0+0044 32 c2[ 	]+dint[ 	]+
+0x0+0046 03 43[ 	]+nop[ 	]+
+0x0+0048 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+004c 32 c2[ 	]+dint[ 	]+
+0x0+004e 03 43[ 	]+nop[ 	]+
+0x0+0050 32 d2[ 	]+eint[ 	]+
+0x0+0052 03 43[ 	]+nop[ 	]+
+0x0+0054 1a 42 00 00[ 	]+mov	&0x0000,r10	;0x0000
+0x0+0058 03 43[ 	]+nop[ 	]+
+0x0+005a 32 d2[ 	]+eint[ 	]+
+0x0+005c 03 43[ 	]+nop[ 	]+
diff --git a/gas/testsuite/gas/msp430/nop-eint-430x.l b/gas/testsuite/gas/msp430/nop-eint-430x.l
new file mode 100644
index 0000000..0e97208
--- /dev/null
+++ b/gas/testsuite/gas/msp430/nop-eint-430x.l
@@ -0,0 +1,20 @@ 
+[^:]*: Assembler messages:
+[^:]*:7: Warning: NOP inserted here, before an interrupt enable instruction
+[^:]*:9: Warning: NOP inserted here, after an interrupt enable instruction
+[^:]*:12: Warning: NOP inserted here, before an interrupt enable instruction
+[^:]*:13: Warning: NOP inserted here, after an interrupt enable instruction
+[^:]*:15: Warning: NOP inserted here, before an interrupt enable instruction
+[^:]*:16: Warning: NOP inserted here, after an interrupt enable instruction
+[^:]*:18: Warning: NOP inserted here, before an interrupt enable instruction
+[^:]*:19: Warning: NOP inserted here, after an interrupt enable instruction
+[^:]*:21: Warning: NOP inserted here, before an interrupt enable instruction
+[^:]*:22: Warning: NOP inserted here, after an interrupt enable instruction
+[^:]*:24: Warning: NOP inserted here, before an interrupt enable instruction
+[^:]*:25: Warning: NOP inserted here, after an interrupt enable instruction
+[^:]*:33: Warning: NOP inserted here, before an interrupt enable instruction
+[^:]*:34: Warning: NOP inserted here, after an interrupt enable instruction
+[^:]*:36: Warning: NOP inserted here, after an interrupt disable instruction
+[^:]*:39: Warning: NOP inserted here, after an interrupt disable instruction
+[^:]*:41: Warning: NOP inserted here, after an interrupt enable instruction
+[^:]*:44: Warning: NOP inserted here, before an interrupt enable instruction
+[^:]*: Warning: NOP inserted after the interrupt state change at the end of the file
diff --git a/gas/testsuite/gas/msp430/nop-eint.s b/gas/testsuite/gas/msp430/nop-eint.s
new file mode 100644
index 0000000..07e3238
--- /dev/null
+++ b/gas/testsuite/gas/msp430/nop-eint.s
@@ -0,0 +1,44 @@ 
+	.text
+
+;;; Test for NOP warnings when enabling interrupts, which only applies to 430x
+;;; ISA.
+;;; "MOV &FOO,r10" is used as an artbitrary statement which isn't a NOP, to
+;;; break up the instructions being tested.
+  EINT
+
+  MOV &FOO,r10
+;;; Check aliases for which the GIE bit (bit 3) of the SR can be set
+;;; These should all cause warnings
+	BIS.W #8,R2
+	MOV &FOO,r10
+
+	BIS.W #8,SR
+	MOV &FOO,r10
+
+	MOV.W #8,R2
+	MOV &FOO,r10
+
+	MOV #0xf,R2
+	MOV &FOO,r10
+
+	MOV #0xffff,R2
+	MOV &FOO,r10
+
+;;; The above hopefully covers the legitimate ways the SR might be set
+;;; but there are other insns that can technically modify R2, but shouldn't be
+;;; used.
+
+;;; Verify EINT/DINT chained behaviour
+
+  EINT
+  DINT
+
+	MOV &FOO,r10
+
+  DINT
+  EINT
+
+	MOV &FOO,r10
+
+;;; Test EINT at end of file
+  EINT
diff --git a/gas/testsuite/gas/msp430/nop-int-430.d b/gas/testsuite/gas/msp430/nop-int-430.d
new file mode 100644
index 0000000..ae8ba53
--- /dev/null
+++ b/gas/testsuite/gas/msp430/nop-int-430.d
@@ -0,0 +1,4 @@ 
+#name: Interrupt NOP Warnings (MSP430 CPU)
+#source: nop-int.s
+#as: -my -mcpu=430
+#warning_output: nop-int-430.l
diff --git a/gas/testsuite/gas/msp430/nop-int-430.l b/gas/testsuite/gas/msp430/nop-int-430.l
new file mode 100644
index 0000000..6c2a04d
--- /dev/null
+++ b/gas/testsuite/gas/msp430/nop-int-430.l
@@ -0,0 +1,3 @@ 
+[^:]*: Assembler messages:
+[^:]*:60: Warning: a NOP might be needed here, after an interrupt disable instruction
+[^:]*:66: Warning: a NOP might be needed here, after an interrupt disable instruction
diff --git a/gas/testsuite/gas/msp430/nop-int-430x-silent.d b/gas/testsuite/gas/msp430/nop-int-430x-silent.d
new file mode 100644
index 0000000..5994b43
--- /dev/null
+++ b/gas/testsuite/gas/msp430/nop-int-430x-silent.d
@@ -0,0 +1,5 @@ 
+#name: Silence Interrupt NOP Warnings (MSP430X CPU)
+#source: nop-int.s
+#as: -mY -mcpu=430x
+#objdump: -d --prefix-addresses --show-raw-insn
+#pass
diff --git a/gas/testsuite/gas/msp430/nop-int-430x.d b/gas/testsuite/gas/msp430/nop-int-430x.d
new file mode 100644
index 0000000..9e93ed3
--- /dev/null
+++ b/gas/testsuite/gas/msp430/nop-int-430x.d
@@ -0,0 +1,4 @@ 
+#name: Interrupt NOP Warnings (MSP430X CPU)
+#source: nop-int.s
+#as: -my -mcpu=430x
+#warning_output: nop-int-430x.l
diff --git a/gas/testsuite/gas/msp430/nop-int-430x.l b/gas/testsuite/gas/msp430/nop-int-430x.l
new file mode 100644
index 0000000..43f7ca2
--- /dev/null
+++ b/gas/testsuite/gas/msp430/nop-int-430x.l
@@ -0,0 +1,10 @@ 
+[^:]*: Assembler messages:
+[^:]*:13: Warning: a NOP might be needed here, before an interrupt enable instruction
+[^:]*:15: Warning: a NOP might be needed here, after an interrupt enable instruction
+[^:]*:17: Warning: a NOP might be needed here, before an interrupt enable instruction
+[^:]*:19: Warning: a NOP might be needed here, after an interrupt enable instruction
+[^:]*:41: Warning: a NOP might be needed here, after an interrupt enable instruction
+[^:]*:48: Warning: a NOP might be needed here, after an interrupt enable instruction
+[^:]*:60: Warning: a NOP might be needed here, after an interrupt disable instruction
+[^:]*:66: Warning: a NOP might be needed here, after an interrupt disable instruction
+[^:]*: Warning: a NOP might be needed after the interrupt state change at the end of the file
diff --git a/gas/testsuite/gas/msp430/nop-int.s b/gas/testsuite/gas/msp430/nop-int.s
new file mode 100644
index 0000000..efc8828
--- /dev/null
+++ b/gas/testsuite/gas/msp430/nop-int.s
@@ -0,0 +1,74 @@ 
+  .text
+
+;;; Test some common instruction patterns for disabling/enabling interrupts.
+;;; "MOV &FOO,r10" is used as an artbitrary statement which isn't a NOP, to
+;;; break up the instructions being tested.
+
+fn1:
+;;; 1: Test EINT
+;; 430 ISA: NOP *not* required before *or* after EINT
+;; 430x ISA: NOP *is* required before *and* after EINT
+  MOV &FOO,r10
+
+  EINT
+
+  MOV &FOO,r10
+
+  BIS.W #8,SR		; Alias for EINT
+
+  MOV &FOO,r10
+;;; 2: Test DINT
+;; 430 ISA: NOP *is* required after DINT
+;; 430x ISA: NOP *is* required after DINT
+  MOV &FOO,r10
+
+  DINT
+  NOP
+
+  MOV &FOO,r10
+
+  BIC.W #8,SR		; Alias for DINT
+  NOP
+
+  MOV &FOO,r10
+;;; 3: Test EINT immediately before DINT
+;; 430 ISA: NOP *not* required.
+;; 430x ISA: NOP *is* required between EINT and DINT
+  MOV &FOO,r10
+
+  NOP
+  EINT
+  DINT
+  NOP
+
+  MOV &FOO,r10
+
+  NOP
+  BIS.W #8,SR		; Alias for EINT
+  BIC.W #8,SR		; Alias for DINT
+  NOP
+
+  MOV &FOO,r10
+;;; 4: Test DINT immediately before EINT
+;; 430 ISA: NOP *is* required after DINT.
+;; 430x ISA: NOP *is* required after DINT and before EINT. Ensure only one
+;; warning is emitted.
+  MOV &FOO,r10
+
+  NOP
+  DINT
+  EINT
+  NOP
+
+  MOV &FOO,r10
+
+  BIC.W #8,SR		; Alias for DINT
+  BIS.W #8,SR		; Alias for EINT
+  NOP
+
+  MOV &FOO,r10
+
+;;; 5: Test EINT last insn in file
+
+  NOP
+  EINT
-- 
2.7.4