Flags - Der AVR gibt Flagsignale

 

Etwas Hardware

 

Für die Versuche dieser Seite reicht der Aufbau des Lehrgangs  Erste Befehle - Mit Assembler das Laufen lernen. Wir benötigen hier im Grunde nur die Leuchtdiode als Statusanzeige.

 

 

Grundlagen

 

Eines der Tatsachen, dass ein Mikroprozessor so leistungsfähig ist, ist es, das dieser Entscheidungen fällen kann und dem entsprechend das Programm ausführt. In den Hochsprachen gibt es für solche Entscheidungen immer eine Form eines 'if'-Befehls. Aber in Assembler suchen wir diese vergebens. Da aber jede Hochsprache irgendwann auch in Assembler mündet, muss es dort ja auch so etwas geben.

 

In Assembler bedient man sich nicht direkt eines Befehls. Vielmehr wird der Zustand eines oder mehreren Bits im Prozessor angefragt und je nach Status des entsprechend Bits fortgefahren. Um diese Bits zu ändern gibt es eine Reihe von Befehlen. Auch nahezu alle mathematischen und logischen Befehle beeinflussen diese Bits.

 

Diese Bits nennt man Flags. Es gibt eine Reihe davon im so genannten Statusregister. Dieses findet man im IO-Bereich. Jedes Flag hat eine bestimmte Bedeutung und wird nur zu bestimmten Situationen gesetzt oder gelöscht. Auch beeinflusst nicht jeder Befehl alle Flags. Einige Befehle, wie z.B. Lade- und Transportbefehle (z.B. ldi), verwenden keine Flags. Andere, wie mathematische Befehle, beeinflussen nahezu alle Flags.

 

Es gibt auch ein Flag, dass wird von keinem normalen Befehl beeinflusst und steht dem Anwender zur freien Verfügung. Hierfür gibt es spezielle Befehle um dieses Flag zu bearbeiten und abzufragen.

 

 

Die Flags im Detail

 

Das SREG, also das Status-Register, beinhaltet 8 Flags. In der folgenden Tabelle sind die vorhanden Flags dargestellt:

 

Bit: 7 6 5 4 3 2 1 0
Flag: I T H S V N Z C

 

Die beiden wichtigsten Flags sind das Z (Zero) und das C-Flag (Carry). Carry wird gesetzt wenn es zu irgendeinen Überlauf kommt. Wir z.b. versuchen 200+177 zu berechnen, obwohl wir nur 1 8 Bit-Register zur Verfügung haben.

 

Zero steht auf 1 wenn die letzte Anweisung das Ergebnis 0 ergibt.

 

Die Flags N, V, S und H werden durch mathematische Operationen beeinflusst. Diese zu erklären würde hier etwas zu weit führen und werden in dem entsprechenden Kapitel erläutert.

 

Das T-Flag ist für den Anwender frei verfügbar. Mit speziellen Befehlen kann der Anwender dieses Flag beeinflussen.

 

Um zu prüfen ob irgendwelche Interrupts aktiv sind, gibt es das I-Flag.

 

 

Flags in der Praxis

 

Um auf den Eingang dieses Kurses zurück zu kommen, wollen wir ja so etwas wie eine 'if'-Abfrage in Assembler durchführen. Nun wissen wir, dass dies mit Hilfe von Flags geschieht. Jetzt müssen wir ein Befehl haben, mit dem wir 2 Werte miteinander vergleichen können und die Flags entsprechend gesetzt werden. So ein Befehl gibt es. Er lautet 'cpi'. Dieser vergleicht den Inhalt eines Registers mit einem konstanten Wert und setzt entsprechend die Flags.

 

Als nächstes müssen wir dann in Abhängigkeit der Flags im Programm springen. Hierfür bietet der AVR eine ganze Galerie von Befehlen an. Hier für uns interessant sind vor allem der 'breq' und 'brne'-Befehl. 'breq', was soviel bedeutet wie: Springe wenn gleich, wird ausgeführt wenn das Z-Flag gesetzt ist. Was hat aber nun das Z-Flag mit Gleichheit zweier Werte zu tun?

 

Soll der AVR ein Vergleich, z.B. mit dem 'cpi'-Befehl, durchführen, so wird intern eine Subtraktion durchgeführt. Sind beide Werte gleich ist das Ergebnis dieser Subtraktion 0 und somit wird das Z-Flag gesetzt. Gegenüber einer richtigen Subtraktion wird das Ergebnis aber nirgends gespeichert sondern es werden nur die Flags gesetzt, wie z.B. das Z-Flag.

 

Um das in der Praxis einmal zu testen, gibt es hier ein kleines Programm:

 

.include    "m8def.inc"

Start:
    ldi     r16,0xFF
    out     DDRD,r16

    ldi     r16,127              ; Lade r16 mit 127

    cpi     r16,127              ; Vergleiche r16 mit 127

    breq    LED_on               ; Wenn Werte gleich, springe

LED_off:
    ldi     r16,0b00000000
    out     PORTD,r16

    rjmp    Start

LED_on:

    ldi     r16,0b00000001

    out     PORTD,r16
    rjmp    Start

 

Nach dem Start, leuchtet die LED auf, womit wir gezeigt bekommen, dass der Vergleich stimmt. Tauscht man nun den 'breq'-Befehl gegen den 'brne'-Befehl aus, so bleibt die LED, nach dem Übertragen des Programmes, dunkel. Erst wenn man eines der beiden Vergleichsparameter ändert, stimmt der Status für den Sprungbefehl wieder (hier: Springe wenn nicht gleich) und die LED wird eingeschaltet.

 

Durch ändern der beiden Parameter und des Sprungbefehls, kann man alle möglichen Vergleiche selbst ausprobieren. Bei den Sprungbefehlen gibt es folgende Möglichkeiten:

 

breq: Springe wenn gleich

brne: Springe wenn ungleich

brce: Springe wenn Carry gelöscht

brcs: Springe wenn Carry gesetzt

brsh: Springe wenn gleich oder größer

brlo: Springe wenn kleiner

brmi: Springe wenn Ergebnis Minus

brpl: Springe wenn Ergebnis Plus

brge: Springe wenn größer oder gleich mit Vorzeichenbeachtung

brlt: Springe wenn kleiner mit Vorzeichenbeachtung

brhs: Springe wenn Halbübertrag erfolgt ist

brhc: Springe wenn kein Halbübertrag erfolgt ist

brts: Springe wenn T-Flag gesetzt

brtc: Springe wenn T-Flag gelöscht

brvs: Springe wenn Zweierkomplement-Übertrag erfolgt ist

brvc: Springe wenn kein Zweierkomplement-Übertrag erfolgt ist

brie: Springe wenn Interrupts aktiviert sind

brid: Springe wenn keine Interrupts aktiviert sind

 

 

Zurück zur Auswahlseite            Zur Hauptseite