Übungsblatt 1: Funktion der PC-Register und einfache PC-Assemblerbefehle
Im heutigen Labor werden wir uns etwas näher mit den
Allzweckregistern und dem Flag-Register des PC beschäftigen und
uns mit einigen grundlegenden Assemblerbefehlen vertraut machen.
Zu diesem Zweck werden wir die Assemblerentwicklungsumgebung Jasmin einsetzen. Jasmin wurde in
Java geschrieben und ist sowohl unter Windows, als auch auf dem Mac
lauffähig.
Jasmin erlaubt das interaktive Editieren, Ausführen und Visualisieren von
Assemblerbefehlen und -programmen, ohne dass ein expliziter Übersetzungsvorgang
("assembly") in Maschinensprache erforderlich ist.
Step/ Schritttaste Resettaste
Abb.1: Buttons
Starten Sie zunächst Jasmin und legen Sie ein neues Dokument an. Auf der
linken Seite blendet Jasmin die gegenwärtigen Registerinhalte ein. Hier finden
sie die 32-Bit-Allzweckregister EAX bis EDX, die auch als arithmetische
Register bezeichnet werden, und das Flag-Register ("flags") in Form seiner
wichtigsten Kontrollbits (Abb. 2).
Abb.2: Flag-Register
Tippen Sie den Befehl mov ax,100 in Zeile 0 ein und führen Sie
diesen als Einzelbefehl durch Drücken der Schritttaste (s. Abb. 1) aus. Der grüne Balken
springt dabei eine Zeile weiter und markiert
so die als nächstes auszuführende Befehlszeile. Durch wiederholtes Drücken der
Schritttaste kann ein Programm Befehl für Befehl durchlaufen werden.
Abb.3: Jasmin Oberfläche
Das Resultat jedes Programmbefehls können Sie an Hand der Registerwerte
studieren.
Wie Sie in Abbildung 3 sehen, interpretiert Jasmin die 100 als Dezimalzahl. Diese wird
durch den MOV-Befehl in das Akkumulatorregister AX geschrieben. Da der
Zahlenwert in ein Byte passt, landet dieser im unteren Byte AL des Registers
AX. Um die genaue Belegung der Registerbytes einsehen zu können, müssen Sie auf
den Button ... links neben dem Register klicken, damit die Registeransicht
expandiert wird.
Wenn Sie nun auf hex und bin klicken, können Sie den Hexadezimal- und
Binärwert der Dezimalzahl 100 sehen. Mit +-dec und dec schalten Sie zwischen
der vorzeichenbehafteten und vorzeichenlosen dezimalen
Zahlendarstellung um.
Durch Drücken der Resettaste (s. Abb. 1) ist es
möglich, wieder an den Anfang eines Programms zu springen. Dabei werden alle
Register auf 0 zurückgesetzt.
Ändern Sie den Befehl in Zeile 0 ab zu mov
ax,-100. Drücken Sie danach die Resettaste und führen Sie
den Befehl erneut aus. Expandieren Sie dann die Registeransicht
und schalten Sie zwischen bin, +-dec
und dec um, um die Unterschiede zwischen den
verschiedenen Darstellungen zu sehen.
Aufgabe 2: Allzweckregister
Neben Dezimalzahlen können Sie durch ein nachgestelltes h, z. B. 100h,
oder durch ein vorangestelltes 0x, z. B. 0x100, auch Hexadezimalzahlen,
durch ein nachgestelltes b Dualzahlen und schließlich durch ein
nachgestelltes o Oktalzahlen eingeben.
Probieren Sie dies an Hand der Zahl
100 aus. Je nach gewählten Zahlensystem erscheint die 100 dann als solche,
wenn Sie nach der Eingabe den jeweiligen Reiter des Zahlensystems
wählen.
Zusätzlich zu Kleinbuchstaben sind bei Jasmin auch Großbuchstaben bei
der Zahlensystemmarkierung erlaubt. Bei Hexadezimalzahlen funktionieren die
nachgestellten Buchstaben allerdings nur bei Zahlen, die keine Buchstaben
enthalten. Es geht also z. B. 0xFFFF, aber nicht FFFFh.
Versuchen Sie den Wert 100000 in das Register AX zu schreiben. Was
passiert nun?
Wie können Sie den Wert 100000 in das Akkumulatorregister schreiben?
Als nächstes werden wir einen einfachen Zähler programmieren. Kopieren
Sie den folgenden Code in Jasmin, aktivieren Sie die Binäransicht "bin" und
führen Sie das Programm aus. Der Befehl inc inkrementiert den
Inhalt des angegebenen Registers, d. h. erhöht den Registerwert um 1. Mit
jedem inc wird hier also der Wert des Akkumulatorregisters um
1 erhöht. Jedes zweite Inkrementieren führt dabei zu einem Übertrag in die
nächsthöhere Stelle, d. h. nach links, da das Dualsystem nur die beiden
Ziffern 0 und 1 kennt.
Aktivieren Sie danach die Dezimalansicht "dec" und führen Sie das
Programm erneut aus. Hier entsteht beim Programmdurchlauf nur ein einzelner
Übertrag in die nächsthöhere Stelle, da das Dezimalsystem 9 Ziffern kennt.
Probieren Sie nun den Assemblerbefehl zur Multiplikation aus.
Unabhängig vom gewählten Zahlensystem funktioniert der Stellenübertrag
immer gleich. Wird z. B. 11 mit 100 multipliziert, so ist das Resultat eine
Verschiebung um zwei Stellen nach links zu 1100, egal ob im Dezimalsystem
oder in irgendeinem anderen Zahlensystem. Kopieren und starten Sie den
folgenden Code, um dies zu überprüfen:
mov ax,11
mov bx,100
mul bx
mov ax,11h
mov bx,100h
mul bx
mov ax,11b
mov bx,100b
mul bx
Wenn Sie den zum jeweiligen Zahlensystem gehörenden Reiter wählen, werden
Sie sehen, dass das Ergebnis immer das gleiche ist.
Zu welcher Klasse von Befehlen gehören inc und
mul?
Laden Sie nun den Dezimalwert 1000 in das AX-Register und
multiplizieren Sie diesen danach mit dem Dezimalwert 35. Das Ergebnis 35000
sollte im AX-Register angezeigt werden. Multiplizieren Sie dieses Ergebnis
danach mit dem Dezimalwert 3. Stellen Sie einen Unterschied hinsichtlich
der Darstellung des Ergebnisses fest? Falls ja: welchen?
Schalten Sie die Hexadezimalansicht der Registerwerte ein und starten Sie
zum Vergleich den Taschenrechner des Windowssystems (Start > Alle
Programme > Zubehör > Rechner) und schalten Sie die Ansicht für
Programmierer ein (Ansicht > Programmierer). Geben Sie 105000 ein und
schalten Sie auch hier mit Hex die hexadezimale Darstellung ein.
Vergleichen Sie das Ergebnis mit den Inhalten der Allzweckregister.
Wiederholen Sie die Multiplikationen mit den 32-Bit-Registern. Was
passiert nun und warum?
Als nächstes wenden wir uns der Division zu. Teilen Sie 1000 im
AX-Register durch 35 im BX-Register. Wie wird die Lösung dargestellt und
warum ist dies so?
Teilen Sie danach 1000 im AX-Register durch 35 im BL-Register. Wie
wird die Lösung dargestellt und warum ist dies so?
Teilen Sie schließlich 1000 im AX-Register durch 35 im BH-Register.
Gibt es hier einen Unterschied zur Lösung der vorherigen Aufgabe?
Aufgabe 3: Flag-Register
Das wichtigste Instrument zur Kontrolle des Ablaufs arithmetischer
Operationen ist das Flag-Register, da mit seiner Hilfe, z. B. bei
arithmetischen Operationen, Zahlenbereichsüberläufe und auch -wechsel
festgestellt werden können. Dies werden wir nun an Hand einiger Beispiele
ausprobieren.
Die Bits bzw. Flags des Flag-Registers sind in die beiden Gruppen der
Control Flags ("Steuerzeichen") und Status Flags ("Zustandszeichen")
aufgeteilt. Mit Hilfe der Steuerzeichen kann der Rechner in bestimmte
Betriebsmodi überführt werden. Zu den Steuerzeichen gehört beispielsweise das
Interrupt-Flag, welches bei Aktivierung die schrittweise Ausführung eines
Programms erlaubt. Steuerzeichen werden explizit aktiviert oder deaktiviert und
behalten bis zur nächsten Änderung ihren Wert.
Zustandszeichen hingegen ändern sich laufend als Folge der gerade
durchgeführten Operation. Zu den wichtigsten Zustandszeichen bzw. Status Flags
gehören Carry, Overflow, Sign und Zero.
Geben Sie in Jasmin den folgenden Code ein:
mov ax,0xFFFF
add ax,1
Ausführen des mov-Befehls setzt zunächst alle Bits des
AX-Registers auf 1 (warum?). Die Flags im Flag-Register bleiben davon
unberührt. Der nachfolgende Befehl hat dann eine Reihe von Änderungen zur
Folge. Zunächst werden alle Bits von AX auf 0 gesetzt, da die Summe nicht
mehr in das AX-Register passt. Es wäre ein 17. Bit erforderlich, um den
letzten Übertrag aufzunehmen. Dieses 17. Bit existiert nicht in AX. Es
existiert aber in gewisser Weise schon: in Form des Carry-Flags im
Statusregister. Der letzte Übertrag wandert also in das Carry-Bit des
Statusregisters. Deswegen ist dieses nach der zweiten Operation gesetzt.
Daneben sind allerdings noch zwei weitere Bits gesetzt: das Zero-Bit und
das Parity-Bit. Das Zero-Bit ist auf 1 gesetzt, weil der Inhalt des
AX-Registers nun gleich 0 ist. Das gesetzte Parity-Bit zeigt hingegen an,
dass der Inhalt des AX-Registers nun eine gerade Parität besitzt (wann
besaß ein Binärwort gerade Parität?).
Führen Sie noch einmal schrittweise den Code des einfachen Zählers aus
und betrachten Sie dabei die Änderungen des Parity-Bits.
Führen Sie auch den folgenden Code aus. Schalten Sie zuvor in die
expandierte Ansicht des AX-Registers (Button ...) und die bin-Darstellung.
Betrachten Sie bei der Ausführung den Registerinhalt und das Zero-Bit:
mov ax,0xFFFC
inc al
inc al
inc al
inc al
inc al
inc al
Das Zero-Bit wird offenbar auch dann auf 1 gesetzt, wenn nur ein Teil
des Registers den Wert 0 enthält, sofern die vorhergehende Operation sich
nur auf einen Teil des Registers bezog.
Welchen Wert wird das Zero-Bit nach folgender Operation besitzen:
sub ax,ax?
Bei dem Beispiel
mov ax,0xFFFF
add ax,1
sahen Sie, dass ein Übertrag entstand, der im Carry-Flag landete, da er
im AX-Register keinen Platz mehr fand. Das gesetzte Carry-Flag
signalisierte also, dass ein Übertrag aus der größten Stelle entstanden und
die Rechnung damit ungültig war. Es stellt sich nun die Frage, wie groß
Überträge ganz allgemein werden können? Tatsächlich ist es so, dass ein
Übertrag in die nächsthöhere Stelle nie mehr als 1 sein kann, unabhängig
von der Größe der addierten Zahlen und vom gewählten Zahlensystem. Es ist
also immer eine 1, die in die nächsthöhere Stelle oder eventuell in das
Carry-Bit rutscht, selbst dann, wenn maximal mögliche Zahlenwerte, wie z.
B. 999+999, addiert werden.
Probieren Sie die folgenden Codesegmente aus, um dies zu bestätigen:
Schalten Sie dazu in die zum jeweiligen Zahlensystem passende
Ansicht.
Aufgabe 4: Polynomauswertung
Programmieren Sie in Jasmin das in der Vorlesung behandelte Beispiel
zur Polynomauswertung. Wenn Sie alles richtig gemacht haben, sollte das im
AX-Register angezeigte dezimale Ergebnis 342 lauten.