AVR SEI instruction

Empirical results!

While the other answers are thoughtful and well reasoned, they are all incomplete or just conjecture. Where the documentation is ambiguous, we must experiment and we must test every case.

This question deserves a conclusive answer, so let's pull out an AVR and start setting some bits!

Procedure

To test, I made a little Arduino (ATMEGA328P) program that would...

  1. setup an ISR that would never return (while (1))
  2. assigned the ISR to a source I could trigger in software (INT0 going low)
  3. disabled interrupts
  4. enabled and triggered the interrupt so it would be pending

I used a test bed that would turn on an LED in the single instruction after interrupts were enabled. By trying different ways of enabling interrupts in the test bed and checking the LED, I could tell if the instruction after the enabling instruction was executed or not.

If the LED did not come on, then I know that the ISR executed (and locked) immediately after interrupts were enabled.

If the LED did come on, then I know that the next instruction was allowed to execute before the ISR was called.

Results

SEI instruction (base case)

Code:

sei

Result: LED on. Following instruction executed.

OUT instruction

Code:

in  r16,0x3f   // Get SREG
ori r16,128    // Set I bit 
out 0x3f,r16   // Save back to SREG

Result:

LED on. Following instruction executed.

ST instruction

Code:

   clr r29        // Clear Y high byte
   ldi r28,0x5f   // Set Y low byte to point to SREG
   ld r16, Y      // Get SREG
   ori r16,128    // Set I bit 
   st Y,r16       // Put SREG

Result:

LED on. Following instruction executed.

Conclusion!

Q: Is the wait a feature of the SEI instruction or the status register?

A: It appears that changing the I bit in SREG is from a 0 to a 1 will allow the following instruction to execute next even if there is a pending interrupt, regardless of what instruction is used to set the bit.

Notes

This actually turned into a very interesting question with lots of complications. If you are interested int he details, check out...

http://wp.josh.com/2016/01/05/different-ways-to-set-i-bit-in-avr-sreg-besides-sei/


It is my understanding from the documentation that performing the sei instruction is no different from directly writing a 1 to the I bit of the SREG. The advantage of the instruction is you don't need to first load a value of 1<<I into a working register in order to change the SREG, thus it saves time.

To elaborate, using sei:

sei ; One cycle

Setting the bit using sbi (would only work if SREG was in the lower 32 bytes of the register map, but it seems that on most if not all it isn't.)

sbi SREG,7 ; Two cycles

Writing to I bit directly in SREG:

in  r24,SREG ;
ori r24,0x80 ;
out SREG,r24 ; Three cycles

The I bit should be set in SREG as soon as the sei instruction (or sbi or out) completes. However, any pending interrupts will not be handled until after the next instruction completes - the bit will be set, but it takes an extra cycle for the interrupts to become enabled. Because an interrupt cannot be handled mid instruction, and some instructions take more than one cycle to execute, they specify the time it takes to become enabled as one instruction. This should be the case for all versions of the code - i.e. each of the above will cause the delay of an instruction.


After a bit of searching, I found this thread on the Arduino forum in which several different tests were performed to verify the behaviour. It seems to agree with what I said above.

Furthermore, according to that thread, if the I flag is already set, then there is no delayed response of an interrupt caused by sei which implies that the delayed response is caused not by the instruction itself, but rather in the internal hardware controlled by the I flag - so any operation which changes the flag in SREG, be it sei or out or sts will have exactly the same behaviour.