Assembler-Kurs Teil 5 Das Thema, das wir diesmal behandeln, wird Sie sicherlich nicht in Verzückung geraten lassen, aber es ist leider notwendig: Das Rechnen in ASSEMBLER. Wie Sie sicher schon ahnen, wird die Sache etwas komplizierter als in BASIC. Mit einer Zeile, wie C = A + B ist es in ASSEMBLER leider nicht getan. Um diesen Kursteil nicht unnötig zu komplizieren, werden wir uns heute nur mit der Addition und Subtraktion von ganz- zahligen Werten (genannt: Integers) be- schäftigen. Dabei kommt man allerdings um die Kenntnis der Flaggen des Status- registers (bekannt aus Kursteil 3) nicht herum. Bevor wir munter addieren und subtra- hieren, sollten Sie vielleicht doch erstmal einen Blick auf die dualen Zahlendarstellungen des C64 werfen. Das Verlassen des erlaubten Zahlenbereiches kann einige unschöne Nebeneffekte haben. Unser Computer kennt die ganzzahlige Werte von - 128 bis +127 bei 8-Bit- Zahlen und von -32768 bis +32767 bei 16-Bit-Zahlen. Positive Dualzahlen sind für uns ja kein Problem, aber wie stellt man den negative Zahlen dar? Das soll an dem Beispiel der Zahl -18 erklärt werden: Die Zahl +18 wird bekanntlich als 00010010 kodiert. Um die negative Zahl zu erhalten, muß man das Komplement der Zahl bilden (d.h. die Zahl wird inver- tiert: aus jeder 0 wird eine 1 und umge- kehrt) und +1 dazuaddieren. Das Komple- ment von +18 ist 11101101. Nun muß noch +1 dazuaddiert werden und man kommt zu 11101110, was der Zahl -18 entspricht. Das äußerste rechte Bit (Bit 7) nennt man das Vorzeichenbit, wobei 0 eine positive und 1 eine negative Zahl kenn- zeichnet. Diese Darstellungsform, bei der die negativen Zahlen umgewandelt werden, die positiven aber wie gewohnt aussehen, nennt man ZWEIERKOMPLEMENT.
ADC (ADd with Carry) --------------------
Wenn zwei Zahlen addiert werden, dann muß die eine im Akkumulator stehen, die zweite kann unmittelbar oder als Inhalt einer Speicherstelle gegeben sein. Das Ergebnis der Rechenoperation steht wieder im Akkumulator. Dies gilt auch für die Subtraktion. Das Ergebnis sollte aus dem Akkumulator schnell in eine Speicherstelle geschrieben werden, da es sonst beim weiteren Programmablauf verlorengehen könnte. Unser neuer Befehl ADC addiert aber nicht nur zwei Zahlen, sondern auch noch den Wert des Carry-Bits (was uns bei 8-Bit-Additionen gar nicht recht sein kann). Daher sollte vor dem ADC zuerst der Befehl CLC stehen, mit dem das Carry-Bit gelöscht wird. Nun erhalten wir auf jeden Fall des richtige Ergebnis. Dualzahlen werden fast wie Dezimalzahlen addiert:
0 + 0 = 0 0 + 1 = 1 1 + 0 = 1 1 + 1 = 0 und zusätzlich enthält hier das Carry-Bit den Übertrag 1, der bei der nächsten Stelle nicht berücksichtigt wird.
Ein kleines Beispiel:
CLC LDA #$5D 01011101 (Dez. 93) ADC #$0E + 00001110 (Dez. 14) STA $1500 ---------- 01101011 (Dez. 107)
Das Ergebnis #$6B (=107) steht jetzt im Akkumulator und in der Speicherstelle $1500. Ein weiteres Rechenbeispiel:
115 01110011 + 14 + 00001110 ----- --------- 129 10000001
Hier ist offensichtlich etwas schiefge- gangen. Das Ergebnis hätte +129 lauten sollen;herausgekommen ist aber 10000001, was der Zahl -127 im Zweierkomplement entspricht.Das diese Rechnung nicht korrekt ist, liegt am Verlassen des erlaubten Zahlenbereiches. Der Computer gibt uns hier zwar keine Fehlermeldung aus, er warnt uns jedoch vor dem Ergebnis, indem er die V-Flagge setzt. Diese Overfolw-Flagge wird immer dann gesetzt, wenn ein unbeabsichtigter Übertrag in das Vorzeichenbit stattfand. Die gesetzte N-Flagge (Vorzeichenflagge) sagt uns, daß das Ergebnis eine negative Zahl ist. Die V-Flagge wird eigentlich automatisch gesetzt oder gelöscht. Dennoch gibt es den Befehl CLV, mitdem man die V-Flagge auch selbst wieder löschen kann, und somit das Warnsignal unterdrückt. Bisher wurde nur die Addition von 1-Byte- (8-Bit) Zahlen geschildert. Die Addition von 2-Byte- (16-Bit) Zahlen wird noch etwas komplizierter, da der Akkumulator nur 8 Bits aufnehmen kann. Des Rätsels Lösung: Man addiert zunächst nur die niederwertigen Bytes der 16-Bit- Zahlen. Sollte dort ein Übertrag über das 8. Bit hinaus vorliegen, so gelangt dieser ins Carry-Bit. Nun werden die beiden höherwertigen Bytes addiert, und der Inhalt des Carry-Bits hinzugezählt. Das Abspeichern der beiden Bytes muß ebenfalls getrennt erfolgen. Erwähnt sei noch, daß bei 16-Bit-Zahlen das Bit 15 das Vorzeichen enthält. Beispiel für eine 16-Bit-Addition: $1000/$1001 enthalten die erste Zahl $1100/$1101 enthalten die zweite Zahl $1200/$1201 sollen das Ergebnis enthalten Das Programm dafür sieht folgendermaßen aus:
CLC LDA $1000 ADC $1100 ; Addition des niederwerigen STA $1200 Bytes LDA $1001 ADC $1101 ; Addition des höherwertigen STA $1201 Bytes ohne CLC
SBC (SuBtract with Carry) -------------------------
Dieser Befehl, wer hätte es gedacht, subtrahiert zwei Zahlen voneinander. Das Dumme ist nur: Unser Prozessor kann überhaupt nicht subtrahieren, er kann nur addieren! Um dennoch Zahlen von- einander abziehen zu können, wendet er einen Trick an. Eine der beiden Zahlen wird einfach zu einer negativen Zahl gemacht und dann werden beide Zahlen addiert. Diese Uwandlung nimmt uns der Befehl SBC jedoch schon ab. Es wird zu dem ersten Operanden nicht nur das Zweierkomplement der zweiten Zahl, sondern auch noch das Komplement des Carry-Bits addiert. D.h. wenn das Carry- Bit das Ergebnis bei der Subtraktion nicht verfälschen soll, muß es zuvor ge- setzt sein. Dazu dient der Befehl SEC (SEt Carry), der vor jedem SBC stehen sollte. Ein Beispiel:
SEC LDA #$7D SBC #$0A STA $1500
Per Hand sieht die Rechnung so aus:
Dezimal Binär 125 01111101 - 10 + 11110110 ------- ----------- 115 (1) 01110011
Das Ergebnis $73 (115) steht im Akku und in der Speicherstelle $1500. Wie Sie sehen, erhalten wir das richtige Ergebnis. Das Vorzeichen der Zahl ist positiv, da die N-Flagge nicht gesetzt ist. Das gesetzte "9.Bit" steht im Carry und wird bei der 8-Bit-Subtraktion nicht benötigt. Auch bei der Subtraktion signalisiert die V-Flagge ein ubeab- sichtigtes Verlassen des Zahlenbereichs. Der SBC-Befehl hat also große Ähnlich- keit mit dem ADC, und so ist es nicht verwunderlich, daß eine 16-Bit-Subtrak- tion einer 16-Bit-Addition auch sehr verwandt ist. Beispiel für eine 16-Bit-Subtraktion: $1000/$1001 enthalten die erste Zahl $1100/$1101 enthalten die zweite Zahl $1200/$1201 sollen das Ergebnis enthalten Das Programm sieht folgendermaßen aus:
SEC LDA $1000 SBC $1100 ; Subtraktion der STA $1200 niederwertigen Bytes LDA $1001 SBC $1101 ; Subtraktion der höher- STA $1201 wertigen Bytes ohne SEC
Abschließend möchte ich noch zeigen, daß es dem Programmierer selbst überlassen bleibt, ob er die Zahlen wirklich als vorzeichenbehaftet ansieht, wie es eigentlich vorgesehen ist, oder ob er die Zahlen als vorzeichenlos betrachtet. Dazu ein Beispiel:
Dezimal Binär -6 11111010 + 2 + 00000010 ---- ---------- -4 11111100
Das Ergebnis ist bei vorzeichenbehaftet- en Zahlen richtig, da -6 ($FA) und -4 ($FC) im Zweierkomplement gegeben sind. Nun vergessen Sie mal das Zweierkomple- ment und betrachten Sie die Zahlen als vorzeichenlos. Dann hätten wir $FA + $02 = $FC (also dezimal 250 + 2 = 252) gerechnet. Auch dieses Ergebnis ist korrekt. Dieses Beispiel zeigt, daß es am Programmierer liegt, welches der beiden Ergebnisse er beabsichtigt.
BCD-Darstellung (Binary Coded Decimals) ---------------------------------------
Da die Befehle ADC und SBC sowohl im Binär-, als auch im Dezimalmodus arbeiten, muß es wohl Befehle geben, die zwischen den beiden Modi umschalten. Wenn es nicht vom Programm geändert wurde, ist automatisch der Binärmodus angeschaltet. CLD: schaltet den Binärmodus an SED: schlaten auf Dezimalmodus um Bei deisen "binär-kodierten" Dezimal- zahlen gibt es nur die Ziffern 0 bis 9. Es wird also jede Dezimalstelle für sich getrennt kodiert. Um diese 10 Ziffern kodieren zu können, benötigt man 4 Bits, mit denen bis zu 16 Kombination- en möglich wären. Sechs der Kombi- nationsmöglichkeiten bleiben daher unge- nutzt. Die Dezimalzahl 0 wird als 0000, die 9 als 1001 kodiert. Die BCD-Dar- stellung der Zahl 128 lautet z.B.:
0001 0010 1000 binär 1 2 8 dezimal
Da jede Ziffer 4 Bits in Anspruch nimmt, fasst man je zwei BCD-Ziffern in einem Byte zusammen. Die Zahl 128 liegt folgendermaßen imnm SPeicher: 00000001 00101000. Die BCD-Zahlen seien hier jedoch nur am Rande erwähnt, da Sie nur sehr selten verwendet werden. Rechnen werden wir nicht mit diesen Zahlen. Das richtige Verständnis für die diesmal erlernten Befehle werden Sie erst durch eigenes Ausprobieren erhalten. Also nichts wie hingesetzt und losprogram- miert. Auch diesmal gibt es selbstver- ständlich wieder ein Begleitprogramm zu dem Kurs auf Diskette. Es nennt sich "ASSEMBLER-KURS 5" und enthält neben einer Joystickabfrage in ASSEMBLER auch noch einige nützliche Anwendungen der neuen Befehle.
Zusammenfassung der Befehle: ---------------------------
ADC (ADd with Carry) --------------------
Zwei Zahlen werden zusammen mit dem Inhalt des Carry-Bits addiert. Das Ergebnis steht wieder im Akkumulator. Dieser Befehl gilt sowohl für die binäre, als auch für die dezimale (BDC) Addition. Der ADC-Befehl kann die Flaggen N, V, Z und C beeinflussen.
SBC (SuBtract with Carry) -------------------------
Zwei Zahlen werden subtrahiert, indem das Zweierkomplement der zweiten Zahl zu der ersten dazuaddiert wird. Das Ergebis der Operation steht im Akkumulator. Auch SBC kann sowohl im Binär-, als auch im Dezimalmodus arbeiten.
CLC (CLear Carry) -----------------
Löscht die Übertragungsflagge. Dieser Befehl sollte immer vor einem ADC benutzt werden.
SEC (SEt Carry) ---------------
Setzt die Übertragsflagge. SEC sollte vor jedem SBC stehen.
CLD (CLear Decimal mode) ------------------------
Löscht die Dezimalflagge und schaltet somit den Binärmodus ein.
SED (SEt Decimal mode) ----------------------
Setzt die Dezimalflagge auf 1. Dadurch werden alle Rechenoperationen im Dezimalmodus ausgeführt.
CLV (CLear oVerflow flag) -------------------------
Löscht die Überlaufflagge.
(Ralf Trabhardt/wk)