* 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.
+2018-11-27 Jozef Lawrynowicz <jozef.l@mittosystems.com>
+
+ * 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.
+
2018-11-23 Andre Vieira <andre.simoesdiasvieira@arm.com>
* testsuite/gas/arm/bl-local-v4t.d: Remove
#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. */
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
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:
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:
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:
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;
}
{
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)
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;
/* ... 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)
}
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));
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))
&& 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. */
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;
}
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);
[^:]*: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
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"
}
--- /dev/null
+#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[ ]+
--- /dev/null
+[^:]*: 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
--- /dev/null
+#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.*
+#...
--- /dev/null
+#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[ ]+
--- /dev/null
+#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[ ]+
--- /dev/null
+[^:]*: 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
--- /dev/null
+ .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
--- /dev/null
+#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[ ]+
--- /dev/null
+[^:]*: Assembler messages:
+[^:]*:36: Warning: NOP inserted here, after an interrupt disable instruction
+[^:]*:39: Warning: NOP inserted here, after an interrupt disable instruction
--- /dev/null
+#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.*
+#...
--- /dev/null
+#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[ ]+
--- /dev/null
+#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[ ]+
--- /dev/null
+[^:]*: 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
--- /dev/null
+ .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
--- /dev/null
+#name: Interrupt NOP Warnings (MSP430 CPU)
+#source: nop-int.s
+#as: -my -mcpu=430
+#warning_output: nop-int-430.l
--- /dev/null
+[^:]*: 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
--- /dev/null
+#name: Silence Interrupt NOP Warnings (MSP430X CPU)
+#source: nop-int.s
+#as: -mY -mcpu=430x
+#objdump: -d --prefix-addresses --show-raw-insn
+#pass
--- /dev/null
+#name: Interrupt NOP Warnings (MSP430X CPU)
+#source: nop-int.s
+#as: -my -mcpu=430x
+#warning_output: nop-int-430x.l
--- /dev/null
+[^:]*: 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
--- /dev/null
+ .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