15
\$\begingroup\$

The AVR SEI instruction (http://www.atmel.com/webdoc/avrassembler/avrassembler.wb_SEI.html) waits for the next instruction to finish before enabling interrupts.

If I use another instruction to set the I flag in SREG, will this also wait 1 instruction?

In other words: Is the wait a feature of the SEI instruction or the status register?

If it is a feature of the SEI instruction, then at what point does the flag actually get set, in the cycle that executes SEI or with the next instruction?

\$\endgroup\$
3
  • \$\begingroup\$ This is a great question, but it shouldn't be too difficult to test and be sure. \$\endgroup\$
    – Vorac
    Jan 5, 2016 at 12:44
  • 1
    \$\begingroup\$ @Vorac Can you give me an example of how this could be tested? That would be my accepted answer for sure. \$\endgroup\$
    – jayjay
    Jan 5, 2016 at 13:03
  • 1
    \$\begingroup\$ It may be a feature of an implementation of the AVR architecture, and where interrupts can be handled. IIRC, the AVR architecture used a 3-stage pipeline. So the next instruction may be already 'in-flight' (i.e. in pipeline stage one, or further) before the I flag change can be used to check for interrupts. I haven't looked for a long time, but I don't think the designers of the AVR architecture would have over-constrained themselves. So, testing the interrupt for an instruction in stage 1 of the pipeline, and not before the next instruction (in stage 2) gives them some flexibility. \$\endgroup\$
    – gbulmer
    Jan 6, 2016 at 0:24

4 Answers 4

10
\$\begingroup\$

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/

\$\endgroup\$
3
  • 3
    \$\begingroup\$ When the specification is ambiguous, there is a problem with "Empirical results". Simply because the specific piece of hardware you tested works in a specific way, does not mean other parts will work that way. Atmel are at liberty to change the implementation providing it doesn't change the specification. So, "Where the documentation is ambiguous, ..." it remains exactly that, after experiment and test, it is still ambiguous. \$\endgroup\$
    – gbulmer
    Jan 6, 2016 at 0:02
  • \$\begingroup\$ @gbulmer I agree 100%. He who uses undocumented features in production is bound to be sad. Still an interesting empirical question (and answer), and probably ok to depend on for a one-off personal project. \$\endgroup\$
    – bigjosh
    Jan 6, 2016 at 0:22
  • 1
    \$\begingroup\$ Yes, you did a fascinating investigation. \$\endgroup\$
    – gbulmer
    Jan 6, 2016 at 0:25
4
\$\begingroup\$

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.

\$\endgroup\$
5
  • \$\begingroup\$ So there is no aspect of delaying the operation, specific to SEI but not OUT, that allows the following instruction to complete? \$\endgroup\$
    – user16324
    Jan 5, 2016 at 13:01
  • \$\begingroup\$ In the case of your second example, when is a pending interrupt handled? Is there a cycle delay like in the first? \$\endgroup\$
    – jayjay
    Jan 5, 2016 at 13:11
  • \$\begingroup\$ @jayjay see my update. \$\endgroup\$ Jan 5, 2016 at 14:22
  • 1
    \$\begingroup\$ Note that SBI cannot be used to set the I bit in SREGso any code that does this likely was not actually tested in real life because it will not even assemble. SBI can only operate on the lower 32 registers and SREG is at slot 63. \$\endgroup\$
    – bigjosh
    Jan 5, 2016 at 20:20
  • \$\begingroup\$ @bigjosh the SBI example was one I thought of later - out was the one I was using originally. I thought I'd come across an AVR (might be an ATTiny) that has the SREG in the lower 32 registers, but I may be imagining it. \$\endgroup\$ Jan 5, 2016 at 21:32
1
\$\begingroup\$

IMHO does writing to SREG still delay 1 instruction can be tested like this (pseudocode):

ISR() { PORTA = 0; while(1); }
main() 
{
    cli();
    DDRA = 0xff;
    configure_isr_for_level_interrupt_that_will_trigger_immediately();
    SREG = 0xff;
    cli();
    PORTA = 0xff;
    while(1);
}

Unfortunately I lack the time to do it :(

\$\endgroup\$
0
\$\begingroup\$

That is not what it says. The documentations says

The instruction following SEI will be executed before any pending interrupts.

not that it waits for the next instruction. I read this as the flag is set immediately but even though enabled, no interrupts will be handled until the next instruction has been executed.

\$\endgroup\$
2
  • \$\begingroup\$ This is all true, but my question is: Is this behavior specific to SEI? \$\endgroup\$
    – jayjay
    Jan 5, 2016 at 13:06
  • \$\begingroup\$ @jayjay I suspect this is due to the instruction pipeline length \$\endgroup\$
    – crasic
    Jan 5, 2016 at 20:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.