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" ldi r16,127 ; Lade r16 mit 127 cpi r16,127 ; Vergleiche r16 mit 127 breq LED_on ; Wenn Werte gleich, springe
LED_off: rjmp Start LED_on: ldi r16,0b00000001
out
PORTD,r16 |
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