AVR SEI指令


13

AVR SEI指令(http://www.atmel.com/webdoc/avrassembler/avrassembler.wb_SEI.html)在允许中断之前等待下一条指令完成。

如果我使用另一条指令在SREG中设置I标志,这还会等待1条指令吗?

换句话说:等待是SEI指令或状态寄存器的功能吗?

如果它是SEI指令的功能,那么在执行SEI的周期中或与下一条指令一起在哪一点实际设置该标志?


这是一个很好的问题,但是测试和确定它应该不会太困难。
Vorac

1
@Vorac您能举个例子说明如何测试吗?那肯定是我接受的答案。
jayjay 2016年

1
它可能是AVR架构实现的一个功能,可以在其中处理中断。IIRC,AVR体系结构使用了3级流水线。因此,下一条指令可能已经在执行中(即,在流水线的第一个阶段或更远的阶段),然后才能使用I标志更改来检查中断。我已经好久没看了,但是我不认为AVR架构的设计者会过度约束自己。因此,在流水线的阶段1中而不是在下一条指令之前(阶段2)对一条指令的中断进行测试可以为它们提供一定的灵活性。
gbulmer

Answers:


8

实验结果!

尽管其他答案都是经过深思熟虑和合理推理的,但它们都是不完整的或仅是推测。在文档不明确的地方,我们必须进行试验,并且必须测试每种情况。

这个问题值得一个肯定的答案,所以让我们拉出AVR并开始设置一些位!

程序

为了测试,我制作了一个小的Arduino(ATMEGA328P)程序,该程序可以...

  1. 设置一个永不返回的ISR(while (1)
  2. 将ISR分配给可以在软件中触发的源(变INT0低)
  3. 禁用的中断
  4. 使能并触发了中断,因此它将挂起

我使用了一个测试台,在启用中断后,该测试台会在一条指令中打开LED。通过尝试在测试台中启用中断的不同方式并检查LED,我可以判断启用指令之后的指令是否已执行。

如果LED指示灯不亮,那么我知道在允许中断后立即执行(并锁定)了ISR。

如果LED确实点亮,那么我知道在调用ISR之前允许执行下一条指令。

结果

SEI 指令(基本情况)

码:

sei

结果:LED亮。执行以下指令。

OUT 指令

码:

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

结果:

带领。执行以下指令。

ST 指令

码:

   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

结果:

带领。执行以下指令。

结论!

问:等待是SEI指令或状态寄存器的功能吗?

答:看来,即使有挂起的中断,无论使用什么指令来设置该位,将I位中的位SREG从a 更改0为a 1都将允许下一条指令继续执行。

笔记

这实际上变成了一个非常有趣的问题,并带有许多复杂性。如果您对详细信息感兴趣,请查看...

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


2
当规范不明确时,“经验结果”就会出现问题。仅仅因为您测试的特定硬件以特定的方式工作,并不意味着其他部分也会以这种方式工作。Atmel可以自由更改实现,前提是它不会更改规范。因此,“文档存在歧义的地方……”,经过实验和测试,它仍然模棱两可。
gbulmer

@gbulmer我同意100%。在生产中使用未记录功能的人注定会很难过。仍然是一个有趣的经验问题(和答案),可能可以依靠一个一次性的个人项目。
bigjosh

是的,您进行了一次有趣的调查。
gbulmer

4

我从文档中了解到,执行sei指令与直接将1写入SREG的I位没有什么不同。该指令的优点是您无需先将一个值加载1<<I到工作寄存器中即可更改SREG,从而节省了时间。

要详细说明,请使用sei

sei ; One cycle

使用设置该位sbi(仅当SREG位于寄存器映射的低32字节时才起作用,但似乎在大多数情况下(如果不是全部的话)不是。)

sbi SREG,7 ; Two cycles

直接在SREG中写信给我:

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

指令(或)完成后,I应在SREG中将该位置1 。但是,直到下一条指令完成后,任何待处理的中断都不会被处理-该位将被置1,但是要使中断使能需要花费额外的时间。由于无法在指令中间处理中断,并且某些指令需要执行一个以上的周期,因此它们指定将其作为一条指令启用所花费的时间。对于所有版本的代码都应该是这种情况-即上述每个都会导致指令的延迟。seisbiout


经过一番搜索,我在Arduino论坛上找到了线程,在线程中进行了几种不同的测试以验证行为。这似乎与我上面所说的一致。

此外,根据该线程,如果I已经设置了该标志,则不存在引起中断的延迟响应,sei这意味着该延迟响应不是由指令本身引起的,而是由I标志控制的内部硬件引起的-因此,任何更改SREG中标志的操作,无论是sei还是outsts都会具有完全相同的行为。


因此,没有延迟操作的方面(特定于SEI而不是OUT)可以完成以下指令吗?
Brian Drummond

对于第二个示例,何时处理未决中断?是否像第一个一样有周期延迟?
jayjay

@jayjay看到我的更新。
汤姆·卡彭特

1
请注意,SBI由于不能使用它来设置该I位,SREG因此任何可能执行此操作的代码实际上都不会在实际中进行测试,因为它甚至都不会汇编。SBI只能在低32个寄存器上运行,并且SREG在插槽63上
。– bigjosh

@bigjosh SBI示例是我后来想到的一个示例- out是我最初使用的示例。我以为我会遇到一个AVR(可能是ATTiny),它的低32位寄存器中有SREG,但是我可能在想它。
汤姆·卡彭特

1

恕我直言,确实向SREG写入仍然延迟1条指令可以这样测试(伪代码):

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);
}

不幸的是,我没有时间去做:(


0

那不是它的意思。文件说

SEI之后的指令将在任何未决中断之前执行。

不是说它等待下一条指令。我读到这是因为该标志立即被设置,但是即使启用了该标志,在执行下一条指令之前也不会处理任何中断。


都是如此,但是我的问题是:这种行为特定于SEI吗?
jayjay

@jayjay我怀疑这是由于指令流水线长度所致
crasic'1
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.