AVR SEI-Anweisung

Die AVR-SEI-Anweisung ( http://www.atmel.com/webdoc/avrassembler/avrassembler.wb_SEI.html ) wartet auf die Beendigung der nächsten Anweisung, bevor Interrupts aktiviert werden.

Wenn ich eine andere Anweisung verwende, um das I-Flag in SREG zu setzen, wird diese auch 1 Anweisung warten?

Mit anderen Worten: Ist das Warten ein Merkmal des SEI-Befehls oder des Statusregisters?

Wenn es sich um eine Funktion des SEI-Befehls handelt, an welchem ​​Punkt wird das Flag dann tatsächlich gesetzt, in dem Zyklus, der SEI ausführt, oder mit dem nächsten Befehl?

Dies ist eine großartige Frage, aber es sollte nicht zu schwierig sein, sie zu testen und sicher zu sein.
@Vorac Können Sie mir ein Beispiel geben, wie dies getestet werden könnte? Das wäre mit Sicherheit meine akzeptierte Antwort.
Es kann ein Merkmal einer Implementierung der AVR-Architektur sein und wo Interrupts gehandhabt werden können. IIRC, die AVR-Architektur, verwendete eine dreistufige Pipeline. So kann die nächste Anweisung bereits "im Flug" sein (dh in der Pipeline-Stufe eins oder weiter), bevor die I-Flag-Änderung verwendet werden kann, um auf Interrupts zu prüfen. Ich habe nicht lange gesucht, aber ich glaube nicht, dass die Designer der AVR-Architektur sich zu sehr eingeschränkt hätten. Das Testen des Interrupts auf eine Anweisung in Stufe 1 der Pipeline und nicht vor der nächsten Anweisung (in Stufe 2) gibt ihnen also eine gewisse Flexibilität.

Antworten (4)

Empirische Ergebnisse!

Während die anderen Antworten nachdenklich und gut begründet sind, sind sie alle unvollständig oder nur Vermutungen. Wo die Dokumentation mehrdeutig ist, müssen wir experimentieren und jeden Fall testen.

Diese Frage verdient eine abschließende Antwort, also ziehen wir einen AVR heraus und fangen an, ein paar Bits einzustellen!

Verfahren

Zum Testen habe ich ein kleines Arduino-Programm (ATMEGA328P) erstellt, das ...

  1. Richten Sie eine ISR ein, die niemals zurückkehren würde ( while (1))
  2. ISR einer Quelle zugewiesen, die ich in der Software auslösen könnte ( INT0niedrig)
  3. deaktivierte Interrupts
  4. aktiviert und den Interrupt ausgelöst, so dass er anhängig wäre

Ich habe ein Prüfbett verwendet, das eine LED in der einzelnen Anweisung einschaltet, nachdem Interrupts aktiviert wurden. Indem ich verschiedene Möglichkeiten ausprobierte, Interrupts im Testbett zu aktivieren und die LED zu überprüfen, konnte ich feststellen, ob die Anweisung nach der Aktivierungsanweisung ausgeführt wurde oder nicht.

Wenn die LED nicht aufleuchtete, dann weiß ich, dass die ISR sofort ausgeführt (und gesperrt) wurde, nachdem Interrupts aktiviert wurden.

Wenn die LED aufleuchtete, dann weiß ich, dass die nächste Anweisung ausgeführt werden durfte, bevor die ISR aufgerufen wurde.

Ergebnisse

SEIAnleitung (Basisfall)

Code:

sei

Ergebnis: LED an. Folgende Anweisung ausgeführt.

OUTAnweisung

Code:

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

Ergebnis:

LED an. Folgende Anweisung ausgeführt.

STAnweisung

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

Ergebnis:

LED an. Folgende Anweisung ausgeführt.

Fazit!

F: Ist das Warten eine Funktion des SEI-Befehls oder des Statusregisters?

A: Es scheint, dass das Ändern des IBits in SREGis von a 0zu a 1die folgende Anweisung als nächstes ausführen lässt, selbst wenn ein anstehender Interrupt vorliegt, unabhängig davon, welche Anweisung zum Setzen des Bits verwendet wird.

Anmerkungen

Dies wurde tatsächlich zu einer sehr interessanten Frage mit vielen Komplikationen. Wenn Sie an den Details interessiert sind, schauen Sie sich...

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

Wenn die Spezifikation mehrdeutig ist, gibt es ein Problem mit "Empirische Ergebnisse". Nur weil die von Ihnen getestete spezifische Hardware auf eine bestimmte Weise funktioniert, bedeutet das nicht, dass andere Teile auf diese Weise funktionieren. Es steht Atmel frei, die Implementierung zu ändern, sofern dadurch die Spezifikation nicht geändert wird. Also, "Wo die Dokumentation mehrdeutig ist, ..." es bleibt genau das, nach Experiment und Test, es ist immer noch mehrdeutig.
@gbulmer Dem stimme ich zu 100% zu. Wer undokumentierte Features in der Produktion einsetzt, muss traurig sein. Immer noch eine interessante empirische Frage (und Antwort) und wahrscheinlich in Ordnung, um sich auf ein einmaliges persönliches Projekt zu verlassen.
Ja, Sie haben eine faszinierende Untersuchung durchgeführt.

Aus der Dokumentation geht hervor, dass sich das Ausführen der seiAnweisung nicht vom direkten Schreiben einer 1 in das I-Bit des SREG unterscheidet. Der Vorteil der Anweisung besteht darin, dass Sie nicht zuerst einen Wert 1<<Iin ein Arbeitsregister laden müssen, um das SREG zu ändern, wodurch Zeit gespart wird.

Um dies zu erläutern, verwenden Sie sei:

sei ; One cycle

Das Setzen des Bits mit sbi(würde nur funktionieren, wenn sich SREG in den unteren 32 Bytes der Registerzuordnung befände, aber es scheint, dass dies bei den meisten, wenn nicht allen, nicht der Fall ist.)

sbi SREG,7 ; Two cycles

Schreiben an I bit direkt in SREG:

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

Das IBit sollte in SREG gesetzt werden, sobald die seiAnweisung (oder sbioder out) abgeschlossen ist. Alle anstehenden Interrupts werden jedoch nicht behandelt, bis der nächste Befehl abgeschlossen ist – das Bit wird gesetzt, aber es dauert einen zusätzlichen Zyklus, bis die Interrupts aktiviert werden. Da ein Interrupt nicht mitten im Befehl behandelt werden kann und einige Befehle mehr als einen Zyklus zur Ausführung benötigen, geben sie die Zeit an, die benötigt wird, um als ein Befehl aktiviert zu werden. Dies sollte für alle Versionen des Codes der Fall sein – dh jede der obigen wird die Verzögerung einer Anweisung verursachen.


Nach einigem Suchen fand ich diesen Thread im Arduino-Forum, in dem verschiedene Tests durchgeführt wurden, um das Verhalten zu überprüfen. Es scheint mit dem übereinzustimmen, was ich oben gesagt habe.

Darüber hinaus gibt es laut diesem Thread, wenn das IFlag bereits gesetzt ist, keine verzögerte Antwort eines Interrupts, der durch verursacht wird, seiwas impliziert, dass die verzögerte Antwort nicht durch die Anweisung selbst verursacht wird, sondern in der internen Hardware, die durch das IFlag gesteuert wird - also jede Operation, die das Flag in SREG ändert, sei es oder sei, wird genau das gleiche Verhalten haben.outsts

Es gibt also keinen Aspekt der Verzögerung der Operation, der spezifisch für SEI, aber nicht für OUT ist, der es ermöglicht, die folgende Anweisung abzuschließen?
Wann wird im Fall Ihres zweiten Beispiels ein anstehender Interrupt behandelt? Gibt es eine Zyklusverzögerung wie im ersten?
@jayjay siehe mein Update.
Beachten Sie, dass das Bit SBInicht gesetzt werden kann, sodass Code, der dies tut, wahrscheinlich nicht wirklich im wirklichen Leben getestet wurde, da er nicht einmal assembliert wird. kann nur mit den unteren 32 Registern arbeiten und SREG befindet sich auf Steckplatz 63. ISREGSBI
@bigjosh das SBI-Beispiel war eines, an das ich später dachte - outwar das, das ich ursprünglich verwendet habe. Ich dachte, ich würde auf einen AVR stoßen (möglicherweise ein ATTiny), der das SREG in den unteren 32 Registern hat, aber ich bilde es mir vielleicht ein.

IMHO verzögert das Schreiben in SREG immer noch 1 Anweisung, die wie folgt getestet werden kann (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);
}

Leider fehlt mir die Zeit dafür :(

Das ist nicht, was es sagt. Die Dokumentationen sagen

Die auf SEI folgende Anweisung wird vor irgendwelchen anhängigen Interrupts ausgeführt.

nicht, dass es auf die nächste Anweisung wartet. Ich lese dies, da das Flag sofort gesetzt wird, aber obwohl es aktiviert ist, werden keine Interrupts behandelt, bis die nächste Anweisung ausgeführt wurde.

Das ist alles wahr, aber meine Frage ist: Ist dieses Verhalten spezifisch für SEI?
@jayjay Ich vermute, dass dies auf die Länge der Befehlspipeline zurückzuführen ist