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 ganzzahligen Werten ( genannt: Integers) beschäftigen. Dabei kommt man allerdings
um die Kenntnis der Flaggen des Statusregisters ( bekannt aus Kursteil 3) nicht
herum.
Bevor wir munter addieren und subtrahieren, 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 invertiert: aus jeder 0 wird eine 1 und umgekehrt) und +1 dazuaddieren. Das Komplement 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 kennzeichnet. 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 #$6 B (=107) steht jetzt im
Akkumulator und in der Speicherstelle
$1500 .
Ein weiteres Rechenbeispiel:
115 01110011 + 14 + 00001110 ----- --------- 129 10000001
Hier ist offensichtlich etwas schiefgegangen. 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 voneinander 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 gesetzt 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 ubeabsichtigtes Verlassen des Zahlenbereichs.
Der SBC-Befehl hat also große Ähnlichkeit 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 vorzeichenbehafteten Zahlen richtig, da -6($ FA) und -4($ FC) im Zweierkomplement gegeben sind.
Nun vergessen Sie mal das Zweierkomplement 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ärkodierten" Dezimalzahlen 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 Kombinationen möglich wären. Sechs der Kombinationsmöglichkeiten bleiben daher ungenutzt. 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:0000000100101000 . 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 losprogrammiert. Auch diesmal gibt es selbstverstä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)