Assembler-Beispiel 2 |
Ausgabe "Hello World" 10 mal auf den Bildschirm
So sollte es auf dem Bildschirm aussehen:
Das ist natürlich ganz einfach (denkt man), da muss man 10 Ausgaben organisieren.
Das ist fast richtig, aber was macht man, wenn das 100 mal oder 1000 mal
passieren soll? Ersteres nehmen wir nun in Angriff. |
So etwa sähe die Lösung in einer höheren Programmiersprache aus. Man vereinbart eine Zählvariable, in diesem Fall i, macht eine Ausgabe, bzw. die Aktion die wiederholt werden soll, ehöht die Zählvariable um 1 und fragt dann ab, ob der Wert der Endwert, in diesem Fall 10, ist. Hat sie noch nicht den Endwert, geht es wieder zurück zur Ausgabe, ist der Endwert erreicht, wird auch die Schleife beendet.
So weit, so gut! |
Einen Zwischenschritt kann man sparen, man zählt gleich rückwärts. Dazu wird i=10
gesetzt und in jedem Durchlauf um 1 reduziert. Dazu benutzt man den SUB-Befehl, der
setzt immer das Z-Flag. Der nächste Befehl muss dann ohne andere Zwischenaktionen die
Auswertung des Flags sein. Der Befehl heißt: JZ (Jump wenn Z gesetzt) oder JNZ (Jump Not Zero - Z=0). Der Befehl vereinbart außerdem eine Marke, also z.B. JPZ m1, es wird, wenn die Bedingung zutrifft (das Flag ist nicht gesetzt), ein Sprung zur angegebenen Marke ausgeführt, anderenfalls wird der nächste Befehl ausgeführt, es gibt so unterschiedliche Stellen zu weiteren Abarbeitung des Programms. |
Nun zum Assembler-Programm: Es soll gleich die LST-Datei zur Beschreibung genutzt werden. Eine Änderung ist gleich am Anfang sichtbar, es wird nun das SMALL-Speichermodell verwendet (ein Code- und ein Datensegment). Mit .DATA wird das Datensegment eröffnet und als nächstes folgt sofort unsere bekannte Zeichenkette. Mit .CODE wird das Datensegment geschlossen und das Codesegment eröffnet. Die erste beiden Befehle ordnen nun die vom System vergebene Adresse des Datensegments dem Register DS zu. Nun kann das Programm beginnen. Dazu wird als erstes ein Wert auf 10 gesetzt. Gegenüber unserem kleinen Prozessor "ERNA" haben wir nun den Vorteil auf weitere interne Register des Prozessors zugreifen zu können, wir brauchen den Speicher nicht. Und man muss weiter überlegen, wieviel Bit man braucht. Da 8 Bit einen Wert bis zu 255 aufnehmen können, brauchen wir nur ein halbes Register, wir nehmen BL, den unteren Teil vom B-Register, also MOV BL,10. Man könnte auch MOV BL,0Ah schreiben, dez 10 hex geschrieben. Nach dem PAP kommt die Ausgabe, aber zuvor soll es hierher zurückgehen. Man kann eine Marke direkt auf den ersten Befehl der Ausgabe setzen, aber es geht auch, dass ein sinnloser Befehl (einer der nichts macht) für die Marke genutzt wird, NOP heißt er (NO oPeration). Als Marke schreiben wir davor "m1:". Dann folgt wieder die bekannte Ausgabe, dann der SUB-Befehl und sofort danach die Abfrage des Zero-Flags. Ist es nicht gesetzt, geht es zur Marke m1, anderenfalls zum nächsten Befehl und damit in bekannter Weise zum Ende des Programms. |
Na ja, so wollten wir es aber nicht!
Wenn man einmal die "!" zählt, kann man auch 10 zählen, die Schleife hat wohl schon funktioniert, aber die Darstellung entspricht nicht unseren Vorstellungen - was tun? Wir brauchen einen Zeilenumbruch in der Ausgabe. |
Die Schreibmaschine ist noch immer das Vorbild. Es kann zwar noch kaum Einer
mit dem Ding arbeiten, aber diese Steuerung bezieht sich darauf!
Es gibt einen Hebel, der, wenn man ihn vorsichtig betätigt, den Wagen wieder
zurückfährt, man schreibt wieder vom linken Rand. Drückt man kräftiger weiter, dreht
auch noch die Walze ein wenig weiter, wir kommen nun auch noch in eine neue Zeile.
Es werden zwei Funktionen ausgeführt:
Betriebssystem | Zeichensatz | Abkürzung | Code Hex | Code Dezimal | Escape-Sequenz |
Unix, Linux, Mac OS X, AmigaOS, BSD, weitere | ASCII | LF | 0A | 10 | \n |
Windows, DOS, OS/2, CP/M, TOS (Atari) | ASCII | CR LF | 0D 0A | 13 10 | \r\n |
Mac OS bis Version 9, Apple II | ASCII | CR | 0D | 13 | \r |
AIX OS & OS/390 | EBCDIC | NEL | 15 | 21 |
Bei der Schreibmaschine gibt es einen extra Hebel für den Zeilenumbruch, in Assembler
aber leider keinen extra Befehl!
Dafür hat man die ASCII-Zeichen unter 20h reserviert. Wenn entsprechende Zeichen
(in diesem Fall 0Ah oder 0Dh) auf dem Ausgabegerät ausgegeben werden, muss das Gerät
diese als Steuerzeichen erkennen und eine entsprechende Reaktion am Gerät auslösen.
Dabei ist durchaus nicht garantiert, dass auch jedes Gerät das gleiche macht, also
diese ASCII-Zeichen nur gezielt einsetzen!
Wenn man also einen Vorschub haben will, muss das mit im Ausgabetext vorhanden sein.
Wer schon in einer höheren Programmiersprache gearbeitet hat, kennt das, z.B. verwendet
PASCAL writeln oder C printf(" \n", ); , da braucht man modifizierte Befehle,
bzw. C schreibt das auch in die Zeichenkette.
Nun zu unserem Assembler-Programm
Man muss irgendwie in die Zeichenkette vor dem "$" ein "0Ah" kriegen:
text DB "hello world!$"
Das kann man, indem ein einzelnes Zeichen mit Komma eingefügt wird:
text DB "hello world!",0Ah,"$"
Wieder übersetzen und ansehen:
Es soll nicht verschwiegen werden, dass der 8086 auch einen einfachen Schleifenbefehl
hat: loop Marke. Von der Marke bis zu diesem Befehl wird alles was dazwischen
steht pausenlos wiederholt, man braucht also auch eine Zählgröße, damit das nicht
unendlich wird. Vor der Marke muss auf CX (16Bit) die Anzahl der Durchläufe vereinbart
werden:
Man spart intern den SUB-Befehl, man braucht aber ein 8Bit-Register mehr. |
Im Beispiel 3 wollen wir noch weitere Schleifen in das Programm einbringen.
zurück zur Start-Seite (Beispiele) / weiter Beispiel 3 | ||
zurück zur Start-Seite |