AVR SEI-Anweisung


13

Der AVR-SEI-Befehl ( http://www.atmel.com/webdoc/avrassembler/avrassembler.wb_SEI.html ) wartet auf den Abschluss des nächsten Befehls, bevor Interrupts aktiviert werden.

Wenn ich einen anderen Befehl verwende, um das I-Flag in SREG zu setzen, wartet dieser auch 1 Befehl?

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

Wenn es sich um ein Merkmal des SEI-Befehls handelt, wann wird das Flag tatsächlich gesetzt, in dem Zyklus, in dem der SEI ausgeführt wird, 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

1
@Vorac Kannst du mir ein Beispiel geben, wie das getestet werden könnte? Das wäre mit Sicherheit meine akzeptierte Antwort.
Jayjay

1
Es kann ein Merkmal einer Implementierung der AVR-Architektur sein und wo Interrupts behandelt werden können. IIRC, die AVR-Architektur, verwendete eine dreistufige Pipeline. Der nächste Befehl befindet sich möglicherweise bereits im Flug (dh in der ersten oder weiteren Phase der Pipeline), bevor die Änderung des I-Flags verwendet werden kann, um nach Interrupts zu suchen. Ich habe lange nicht gesucht, aber ich glaube nicht, dass die Designer der AVR-Architektur sich selbst überfordert hätten. Das Testen des Interrupts für einen Befehl in Stufe 1 der Pipeline und nicht vor dem nächsten Befehl (in Stufe 2) gibt ihnen eine gewisse Flexibilität.
gbulmer

Antworten:


8

Empirische Ergebnisse!

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

Diese Frage verdient eine abschließende Antwort, also lasst uns einen AVR herausziehen und ein paar Bits setzen!

Verfahren

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

  1. Richten Sie einen ISR ein, der niemals zurückkehren würde ( while (1))
  2. wies den ISR einer Quelle zu, die ich in der Software auslösen konnte ( INT0wird niedrig)
  3. deaktivierte Interrupts
  4. aktiviert und den Interrupt ausgelöst, damit er ansteht

Ich habe einen Prüfstand verwendet, der in der Einzelanweisung eine LED einschaltet, nachdem Interrupts aktiviert wurden. Durch Ausprobieren verschiedener Möglichkeiten zum Aktivieren von Interrupts im Prüfstand und Überprüfen der LED konnte ich feststellen, ob der Befehl nach dem Freigabebefehl ausgeführt wurde oder nicht.

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

Wenn die LED aufleuchtet, weiß ich, dass der nächste Befehl ausgeführt werden durfte, bevor der ISR aufgerufen wurde.

Ergebnisse

SEI Anweisung (Basisfall)

Code:

sei

Ergebnis: LED an. Folgeanweisung ausgeführt.

OUT Anweisung

Code:

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

Ergebnis:

LED leuchtet. Folgeanweisung ausgeführt.

ST Anweisung

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 leuchtet. Folgeanweisung ausgeführt.

Fazit!

F: Ist das Warten ein Merkmal des SEI-Befehls oder des Statusregisters?

A: Es sieht so aus, als würde das IBit in SREGvon a 0nach a geändert1 die nächste Ausführung des folgenden Befehls ermöglicht, selbst wenn ein Interrupt ansteht, unabhängig davon, welcher Befehl zum Setzen des Bits verwendet wird.

Anmerkungen

Dies wurde tatsächlich zu einer sehr interessanten Frage mit vielen Komplikationen. Wenn Sie sich für die Details interessieren, lesen Sie ...

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


2
Wenn die Spezifikation nicht eindeutig ist, liegt ein Problem mit "empirischen Ergebnissen" vor. Nur weil die von Ihnen getestete Hardware auf eine bestimmte Weise funktioniert, bedeutet dies nicht, dass andere Teile auf diese Weise funktionieren. Es steht Atmel frei, die Implementierung zu ändern, sofern die Spezifikation nicht geändert wird. "Wo die Dokumentation mehrdeutig ist, ..." bleibt es also genau so, dass es nach Experiment und Test immer noch mehrdeutig ist.
gbulmer

@gbulmer Ich stimme zu 100%. Wer in der Produktion undokumentierte Merkmale verwendet, ist mit Sicherheit traurig. Immer noch eine interessante empirische Frage (und Antwort), auf die man sich wahrscheinlich für ein einmaliges persönliches Projekt verlassen kann.
Bigjosh

Ja, Sie haben eine faszinierende Untersuchung durchgeführt.
gbulmer

4

Nach meinem Verständnis aus der Dokumentation unterscheidet sich das Ausführen des seiBefehls nicht vom direkten Schreiben einer 1 in das I-Bit des SREG. Der Vorteil des Befehls besteht darin, dass Sie nicht erst einen Wert von 1<<Iin ein Arbeitsregister laden müssen, um das SREG zu ändern, wodurch Zeit gespart wird.

Zum Ausarbeiten verwenden Sie sei:

sei ; One cycle

Setzen des Bits mit sbi(würde nur funktionieren, wenn sich SREG in den unteren 32 Bytes der Registerkarte befindet, aber es scheint, dass dies auf den meisten, wenn nicht allen nicht der Fall ist.)

sbi SREG,7 ; Two cycles

Schreiben an mich direkt in SREG:

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

Das IBit sollte in SREG gesetzt werden, sobald der seiBefehl (oder sbioder out) abgeschlossen ist. Anstehende Interrupts werden jedoch erst nach Abschluss des nächsten Befehls behandelt - das Bit wird gesetzt, aber es dauert einen zusätzlichen Zyklus, bis die Interrupts aktiviert werden. Da ein Interrupt während der Ausführung eines Befehls nicht verarbeitet werden kann und einige Befehle mehr als einen Zyklus benötigen, geben sie die Zeit an, die erforderlich ist, um als ein Befehl aktiviert zu werden. Dies sollte für alle Versionen des Codes der Fall sein - dh, jede der oben genannten Situationen führt zu einer Verzögerung einer Anweisung.


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.

Wenn gemäß diesem Thread das IFlag bereits gesetzt ist, gibt es keine verzögerte Antwort eines Interrupts, seiwas impliziert, dass die verzögerte Antwort nicht durch den Befehl selbst verursacht wird, sondern durch die interne Hardware, die durch das IFlag gesteuert wird. so jede Operation , die die Flagge in SREG ändert, sei es seioder outoder stshaben genau das gleiche Verhalten.


Es gibt also keinen Aspekt der Verzögerung der Operation, der für SEI spezifisch ist, aber nicht für OUT, der es ermöglicht, die folgende Anweisung zu vervollständigen.
Brian Drummond

Wann wird im Fall Ihres zweiten Beispiels ein anstehender Interrupt behandelt? Gibt es eine Zyklusverzögerung wie in der ersten?
Jayjay

@ JayJay siehe mein Update.
Tom Carpenter

1
Beachten Sie, dass SBInicht verwendet werden kann, um das IBit SREGso einzustellen, dass ein Code, der dies wahrscheinlich tut, nicht im wirklichen Leben getestet wurde, da er nicht einmal zusammengesetzt werden kann. SBIkann nur mit den unteren 32 Registern arbeiten und SREG befindet sich auf
Position

@bigjosh das SBI-Beispiel war eines, an das ich später gedacht habe - outwar dasjenige, das ich ursprünglich verwendet habe. Ich dachte, ich stoße auf einen AVR (könnte ein ATTiny sein), der die SREG in den unteren 32 Registern hat, aber ich kann es mir vorstellen.
Tom Carpenter

1

IMHO schreibt an SREG noch Verzögerung 1 Anweisung kann wie folgt getestet werden (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 :(


0

So steht es nicht. In den Dokumentationen heißt es

Die Anweisung nach SEI wird vor anstehenden Interrupts ausgeführt.

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


Das ist alles wahr, aber meine Frage ist: Ist dieses Verhalten für SEI spezifisch?
Jayjay

@ Jayjay Ich vermute, dies liegt an der Länge der Anweisungs-Pipeline
crasic
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.