In Kapitel AVR-Assembler - Teil 1 wurden bereits einfache Additionsbefehle vorgestellt. In diesem Kapitel geht es
unter anderem um die arithmetischen Instruktionen: ADD (Addition), SUB (Subtraktion), NEG (Negation), CP (Vergleich),
INC (Increment oder erhöhe um 1), DEC (Dekrement oder erniedrige um 1) und COM (1-er Komplement).
In dieser Übung wird gezeigt, wie man zwei 8-Bit Zahlen addiert. Dazu wird ein ATmega8 auf dem STK200 Board verwendet. Als optische Hilfe wird die
Bargraf-Anzeige genutzt und das Ergebnis in binärer Form dargestellt.
Wer nicht (mehr) vertraut ist mit dem binären Zahlsystem, sollte sich das vorher
noch einmal anschauen. Insbesondere, wie zwei Dualzahlen addiert, subtrahiert und multipliziert werden.
Bevor es an die Programmierarbeit geht, wird erst einmal das Datenblatt des ATtiny8 befragt. Gib eine Antwort auf die folgenden
beiden Fragen:
- Welche arithmetischen Rechenbefehle stellt der Controller
laut Datenblatt zur Verfügung? Schaue hierzu im Instruction Set Summary nach.
- Welche Grundrechenoperation wird nicht bereit gestellt?
Antworten:
Es sind über 10 OP-Codes im Datenblatt unter der Rubrik "arithmetic and logic instructions" zu finden.
Ein Befehl für die Division ist nicht angegeben.
Die in diesem Kapitel benutzten neuen Assembler-Instruktionen zeigen die nachfolgenden Tabellen 1a und 1b.
Tabelle 1a - Nur die rot markierten Flags werden von einer Instruktion bei Aufruf verändert.
Tabelle 1b - Nur die rot markierten Flags werden von einer Instruktion bei Aufruf verändert.
- Z-Flag
Wird immer gesetzt bei einem Null-Ergebnis bei einer arithmetischen oder logischen Operation.
- C-Flag
Das Übertrags-Flag. Es wird immer gesetzt bei einem Übertrag bei einer arithmetischen oder logischen Operation.
- N-Flag
Das N-Flag zeigt ein negatives Ergebnis (Bit 7 ist 1) bei einer arithmetischen oder logischen Operation an.
- H-Flag
Das Halbübertrags-Flag zeigt bei einigen arithmetischen Operationen einen Halbübertrag (Übertrag von Bit3 im lower nibble zu Bit4 im upper nibble) an.
- V-Flag
Dieses Überlauf-Flag unterstützt die 2-er Komplement Arithmetik.
- S-Flag
Das S-Flag ist immer das Ergebnis aus der logischen Verknüpfung von S XOR V (XOR -> exklusives ODER).
Übung 1 - Addition |
Material |
- 1x STK200 mit Steckernetzteil und ISP2
- Datenblatt des ATmega8
|
Aufgabe |
- Lege ein neues Projekt rechnen1 an
- Gib das Assemblerprogramm addition.asm in den Editor ein und speichere es ab.
- Brenne das Programm in den Controller und starte es anschließend.
- Überprüfe, ob auf der Bargraf-Anzeige LED1 und LED2 leuchten. Abb. 1 zeigt das Ergebnis.
|
Schaltungsaufbau
Hat man kein STK200 Board zur Verfügung, lässt sich die Schaltung mit acht LEDs separat auf einem Steckbrett
aufbauen.
Abbildung 1
Separater Schaltungsaufbau mit 10 Segment Bargraf-Anzeige. Nicht gezeigt werden die peripheren Beschaltungen (Spannungs-versorgung, Abblockkondensatoren etc.) des Controllers.
Das Programm addition.asm
Abb. 2
In dem Programm addition.asm wird im Initialisierungsblock der PORTB auf Ausgang geschaltet.
Im Hauptprogramm werden die beiden Zahlen 2 und 5 in die Speicher R19 und R20 geladen und anschließend addiert und die Summe in R20 abgelegt.
Nach Bildung des 1-er Komplements wird der Inhalt von R20 an PORTB (LEDs) ausgegeben.
Wie arbeitet das Programm addition.asm?
- Die drei Direktiven (.nolist, .include, .list)
zu Anfang des Programms kennen wir bereits.
- Der Hauptteil beginnt mit LDI (Load Immediate). Er lädt eine 8-Bit Konstante mit dem Wert 2 direkt in das Register R19 und eine zweite Konstante mit dem Wert 5 in das
Register R20.
- ADD (Add without Carry) addiert die Inhalte der beiden Register R19 und R20 und legt das Ergebnis in R20
ab.
- Die Ausgabe des Ergebnisses erfolgt über eine Bargraf-Anzeige. Die LEDs leuchten genau dann, wenn sie auf 0 gezogen werden. Deshalb muss aus der Binärzahl 6 (Summe
aus 2 und 4) 0b00000110 durch Komplementbildung (0 wird zu 1 und umgekehrt) 0b11111001 erzeugt werden. Das macht COM z2.
- Die Ausgabe erfolgt über die Bargraf-Anzeige, die mit PORTB verbunden ist. Von PORTB müssen alle Portpins auf Ausgang geschaltet werden. Dazu wird zspchr
(R18) mit 1 gefüllt -> 0xFF und anschließend über OUT in das DDRB-Register geladen.
Über das in AVR-Studio integrierte Hilfe-Menü (Help - Assembler Help) lassen sich zu allen hier benutzten Operanden-Codes umfangreiche Hilfetexte mit Programmbeispielen
aufrufen. Eine weitere Besprechung der Wirkungsweise dieser Operanden entfällt deshalb.
- Mit 8-Bit lassen sich nur vorzeichenlose Zahlen von 0 bis 255 (0b1111_1111) darstellen.
Was ist zu tun, um zwei 16-Bit Zahlen addieren zu können? Das wird in nachfolgender Übung untersucht.
- Mit 16-Bit lassen sich vorzeichenlose Zahlen zwischen 0 und 65.535,
- mit 32-Bit zwischen 0 und 4.294.967.294 darstellen.
Übung 2 - Addition von 16-Bit Zahlen - Instruktionen: ADC, SER
Die Addition zweier 16-Bit Zahlen verläuft im Prinzip wie die von zwei 8-Bit Zahlen. Es werden zuerst die lower Bytes und anschließend die higher Bytes mit Carry
addiert. Fertig.
Das Addieren mit Carry wird über ADC, das Addieren ohne Carry mit ADD aufgerufen. Ein Ablaufplan oder Pseudocode könnte so aussehen:
- Addiere zahl1L und zahl2L (SummeLowByte)
- Addiere mit Carry zahl1H und zahl2H plus Carry-Bit
(SummeHighByte).
- Gib auf der Bargraf-Anzeige das SummeHighByte aus.
Übung 2 - Addition zweier 16-Bit Zahlen |
Material |
- 1x STK200 mit Steckernetzteil und ISP2
- Datenblatt des ATmega8
|
Aufgabe |
- Lege ein neues Projekt addition2 an
- Gib das Assemblerprogramm addition2.asm in den Editor ein und speichere es ab.
- Brenne das Programm in den Controller und starte es anschließend.
- Notiere, welche LEDs der Bargraf-Anzeige leuchten (1) und
welche nicht (0).
|
Schaltungsaufbau
wie in Übung 1, Abb. 1.
Das Programm addition2.asm
Abb. 3 - addition2.asm mit den Instruktionen ADD, ADC, COM, SER
Wie arbeitet das Programm addition2.asm?
- Die drei Direktiven (.nolist, .include, .list)
zu Anfang des Programms kennen wir bereits. Auch nicht neu ist die Direktive .equ. Über sie wird
einer Variablen ein fester Wert zugewiesen.
- Der Initialisierungsteil beginnt mit LDI (Load Immediate). Es werden vier 8-Bit Zahlen (der Controller verarbeitet nur 8-Bit Zahlen!!!), je zwei Lowbytes und Highbytes der beiden 16-Bit Zahlen in vier verschiedene Register
geladen.
- ADD (Add without Carry) addiert die Inhalte der beiden Lowbyte-Register R16 und R17 und legt das Ergebnis in R16
ab.
- ADC (Add with Carry) addiert die Inhalte der beiden Highbyte-Register R18 und R19 und legt das Ergebnis, unter
Berücksichtigung des Carry, in R18 ab.
- Die Ausgabe des Ergebnisses erfolgt über eine Bargraf-Anzeige. Die LEDs leuchten genau dann, wenn sie auf 0 gezogen werden (low
active). Deshalb muss von der Binärzahl in R18 das Komplement gebildet werden. Das ist die Aufgabe von COM R16.
- Die Ausgabe erfolgt über die Bargraf-Anzeige, die mit PORTB verbunden ist. Von PORTB müssen alle Portpins auf Ausgang geschaltet werden. Dazu wird R20 mit Einsen gefüllt -> SER (Set all bits in Register) und anschließend über OUT in das DDRB-Register gesetzt. Über das Programm werden die 8 höchstwertigen Bits angezeigt.
- Für die Ausgabe der 8 niedrigwertigen Bits muss das Programm in zwei Zeilen geändert werden: com r16 und out portb, r16 muss es dann
heißen.
Hat man das Prinzip verstanden, ist die Addition von beliebig großen Zahlen mit Assembler möglich und einfach durchzuführen. Im
vorliegenden Beispielprogramm der Übung 2 werden die beiden Zahlen
- 0xC2F3 oder dezimal 49907 und
- 0x04BA oder dezimal 1210
miteinander addiert. Die Summe ist: 51117 oder 0b1100_0111_1010_1101. Die rot markierten acht Bit
stehen für das Highbyte, die blauen acht Bit für das Lowbyte. Dreht man das STK200-Board um 90° nach rechts, so dass die Bargraf-Anzeige horizontal liegt, kann man die entsprechende
Bitkonfiguration unmittelbar ablesen (siehe Abb. 4).
Abb. 4 - High- und Low-Byte der Summe zweier 16-Bit Zahlen.
Übung 3 - Subtraktion mit Unterlauf - Instruktionen SUB, NEG
Die Subtraktion zweier Zahlen kann
- ein positives Ergebnis oder
- ein negatives Ergebnis (Unterlauf)
liefern. Das hängt davon ab, ob der Minuend größer oder kleiner als der Subtrahend ist. Wie wirkt sich ein Unterlauf in der Zahldarstellung aus? Das untersucht die
folgende Übung 3.
Etwas Theorie zur Subtraktionsmethode
Die Subtraktion wird in dieser Übung zurückgeführt auf eine
- Addition mit Zweierkomplementbildung.
Dazu werden alle Stellen des Subtrahenden -B negiert (Einerkomplement; Assemblerinstruktion: COM) und zu dem sich neu ergebenden Wert eine 1 addiert.
Dadurch entsteht das Zweierkomplement /B + 1 des Subtrahenden (Assemblerinstruktion: NEG). Dieses entspricht der Zahl -B:
Um mit vorzeichenbehafteten (signed) Zahlen arbeiten zu können, benötigt man ein Vorzeichenbit. Per definitionem ist dies das
- MSB (most significant
bit)
das am weitestens links stehende höchstwertige Bit; für die reine vorzeichenbehaftete Zahldarstellung stehen bei verfügbaren 8-Bit dann
noch 7-Bit zur Verfügung. Der vorzeichenbehaftete Zahlenbereich erstreckt sich von
- -128, ..., 0, ..., +127 oder allgemein
- -2n-1, ..., 0, ..., +2n-1-1 mit n aus N, Anzahl der verfügbaren Bits
Ein Beispiel
Die Zahlen 0x03 (dezimal: 3) und 0x0D (dezimal: 13) sollen subtrahiert werden. Die Subtraktion wird
durch eine Addition mit Zweierkomplementbildung ausgeführt.
- Minuend: 0x03 oder 0000 0011 bleibt unverändert
- Subtrahend: 0x0D oder 0000 1101
- Zweierkomplement: aus 0000 1101 wird 1111 0011
- Addition: 0000 0011 + 1111 0011 = 1111 0110
- Bit 7 enthält eine 1, sie signalisiert ein negatives Ergebnis. Bleiben sieben Bitstellen für die Differenz: 11
10110 (siehe Abb. 5; dies entspricht der Zahl -10).
- Ergebnis von 0x03 - 0x0D = 11 10110 oder -10
Abb. 5
Die linke Spalte zeigt die positiven, die rechte die negativen Binärzahlen in der Zweierkomplent-Arithmetik. Das höchstwertige Bit (hier im Bild: Bit 4) signalisiert eine negative
Zahl.
In Übung 3 werden wir die Zweierkomplementarithmetik praktisch anwenden.
Die Erläuterungen zum Programmablauf finden sich in den Kommentarzeilen des Programms.
Übung 3 - Subtraktion zweier 8-Bit Zahlen mit Unterlauf |
Material |
- 1x STK200 mit Steckernetzteil und ISP2
- Datenblatt des ATmega8
|
Aufgabe |
- Lege ein neues Projekt differenz1 an
- Gib das Assemblerprogramm differenz1.asm in den Editor ein und speichere es ab.
- Brenne das Programm in den Controller und starte es anschließend.
- Notiere, welche LEDs der Bargraf-Anzeige leuchten (1) und
welche nicht (0).
|
Schaltungsaufbau
wie in Übung 1, Abb. 1.
Das Programm differenz1.asm
Abb. 6 - Subtraktion mit Unterlauf (negativer Differenz)
Ergebnisausgabe auf der LED Bargrafanzeige eines STK200
Abb. 7
Die LEDs auf dem STK200 sind werksseitig active low geschaltet. Aus diesem Grund muss auf das Ergebnis das Einerkomplement angewendet werden. Es wird dann ohne Vorzeichen binär als 4
angezeigt.
Links neben der LED-Zeile stehen die Positionsbezeichner der LEDs: 0 - 7. Darunter etwas verdeckt: ISP (in-system-programming) und ON (Betriebsanzeige).
Läßt man die Instruktion
im Programm (siehe Abb. 6) weg, dann zeigt die LED Bargrafanzeige das folgende Bild:
Abb. 7b
Bei vorzeichenbehafteter Arithmetik zeigt das STK200 bei negativer Differenz das Ergebnis "invertiert" an, wenn die Instruktion com
r17 aus Programm differenz1.asm weggelassen wird.
Was das folgende Programm der Übung 4 macht und warum, dass soll in dieser Übung geklärt werden. Dazu ist unbedingt das Instruction Set Summary notwendig.
Die Kommentarzeilen im Quelltext des Programms geben ausführliche Hinweise.
Übung 4 - Instruktion BRCS |
Material |
- 1x STK200 mit Steckernetzteil und ISP2
- Datenblatt des ATmega8
|
Aufgabe |
- Lege ein neues Projekt differenz2 an
- Gib das Assemblerprogramm differenz2.asm (siehe Abb. 8) in den Editor ein und speichere es
ab.
- Brenne das Programm in den Controller und starte es anschließend.
- Notiere, welche LEDs der Bargraf-Anzeige leuchten und welche
nicht.
- Ändere anschließend das Programm ab, indem du die Werte von Minuend und Subtrahend vertauschst. Brenne das
Programm in den Controller und starte es erneut.
- Notiere, welche LEDs der Bargraf-Anzeige leuchten und welche nicht.
- Erkläre mit eigenen Worten, wie das Programm arbeitet. Gib für jede Programmzeile eine Beschreibung, was die
Instruktion bewirkt und ggf. warum der Befehl notwendig ist.
- Warum wurde der Befehl BRCS gewählt? Gib eine Erklärung. Liesse sich auch ein andere
Verzweigungsbefehl aus dem Instruction Set Summary auswählen? Begründe ggf. warum.
|
Das Programm differenz2.asm
Abb. 8 - Differenz2.asm Programm
Wie arbeitet das Programm differenz2.asm ?
Schauen wir uns dazu für jede aufgerufene Instruktion die Registerinhalte und Flags im AVR Simulator an.
1. Durchlauf - Minuend (0x09) kleiner als Subtrahend (0x0D) -> negatives Ergebnis
Abb. 9a - Nach den ersten vier Instruktionen stehen in R16 (Subtrahend) -> 13, R17 (Minuend) -> 9 und in R20 ->
255. PORTB ist Ausgang. Im SREG sind keine Flags gesetzt. Der folgende Befehl ist SUB R17,R16.
Abb. 9b - Der fünfte Befehl führt die Subtraktion aus. Vier Flags im SREG (HSNC) sind gesetzt, da das Ergebnis negativ ist (Unterlauf). Der
Inhalt von R17 zeigt die Differenz. Das Programm verzweigt nach diff_negativ, da Flag C gesetzt ist; der nächste Befehl ist NEG R17.
Abb. 9c - Die siebte Instruktion gibt das Ergebnis von R17 an den Ausgang PORTB, an dem die LEDs angeschlossen sind. Es leuchtet die LED an der Bitposition 2: 0000 0100.
Dezimal entspricht das einer 4.
Da das Ergebnis negativ ist (Flag C ist gesetzt) und weil auf einem STK200 alle LE.Ds activ low geschaltet sind, leuchten auf einem STK200 alle LEDs, deren
Pin auf LOW liegt. Dies gilt bis auf PORTB.2 (liegt auf 1) für alle anderen PORTB.x.
Für den zweiten Durchlauf werden die Zuweisungswerte für Minuendn und Subtrahend vertauscht
- .EQU minuend = 0x0D
- .EQU subtrahend = 0x09
Das Programm muss im Simulator neu assembliert und geladen werden, bevor man die Simulation starten kann. Die Ergebnisse zeigen die folgenden Screenshots.
2. Durchlauf - Minuend (0x0D) größer als Subtrahend (0x09) -> positives Ergebnis
Abb. 10a - Nach den ersten vier Instruktionen stehen in R16 (Subtrahend) -> 9, R17 (Minuend) -> 13 und in R20
-> 255. PORTB ist Ausgang. Im SREG sind keine Flags gesetzt. Der folgende Befehl ist SUB R17,R16.
Abb. 10b - Der fünfte Befehl führt die Subtraktion aus. Im SREG ist kein Flag gesetzt (positives Ergebnis). Der Inhalt von R17 zeigt die Differenz. Das
Programm verzweigt nicht, da kein Flag gesetzt ist; der nächste Befehl ist LDI R20,0xFF. .
Abb. 10c - Die siebte Instruktion setzt alle Ausgangsleitungen PORTB.x auf 1 (EXOR-Verknüpfung), die eine 0 in R17 stehen haben. Das Ergebnis wird zurückgeschrieben in R17. Es leuchten auf
einem STK200 nur die LEDs, die auf LOW liegen; das ist in diesem Fall bei PORTB.2 der Fall. Es wird die Zahl 4 angezeigt.