(The most) Basic Programming

Allgemein

Nachdem wir uns bisher die wunderbare Altair SIMH-Simulation als historische Entwicklungsumgebung für BASIC-Programme angesehen haben, versteht sich heute das Wort Basic im Titel nicht als Akronym, sondern im eigentlichen Wortsinn: grundlegend.

Wenn man heute oder auch vor 30 Jahren einen Home-Computer gekauft hat, war das für Gewöhnlich ein Apparat, der mit einem Bildschirm, einer Tastatur und einer Maus daher kam. Selbst mein erster eigener Computer – der legendäre Commodore VC 20, Hatte die Tastatur fest eingebaut im Gehäuse dabei, als Monitor diente der Zweitfernseher und statt Maus wurde ein Joystick als analoges Eingabegerät angeschlossen. Die 5k Hauptspeicher erschienen mir allerdings sehr schnell als zu wenig. Damals (1982) war mir überhaupt nicht bewusst, dass dieses Gerät einen ungeheuren Luxus bedeutete, im Vergleich zum ersten Home-Computer, nur sieben Jahre zuvor. Der 1975 auf den Markt gekommene Altair 8800 kam nämlich ohne Bildschirm, Tastatur und Maus – und auch nur mit 256 Byte RAM – beim glücklichen Käufer an und wurde auch zum Anfang so betrieben. Wie das funktionieren konnte, möchte ich heute einmal demonstrieren.

Durch Zufall bin ich auf eine digitale Kopie des original „Altair 8800 Operator’s Manual“ gestoßen und so können wir die gleichen Schritte zum ersten Programm heute mit dem virtuellen Altair nachvollziehen. Um zu verstehen, wie man sich mit dem Altair verständigen konnte, wenn man nichts als den nackten Computer besaß, werfen wir einen Blick auf das Fronpanel des Rechners – für heutige Verhältnisse ein vollkommen ungewohnter Anblick.

Altair 8800 Frontpanel – Urheber: Cromemco (2016) – Lizenz: Creative Commons

Da gibt es eine Menge LEDs und eine Reihe mit Kippschaltern und ein paar Taster. Nicht mal eine 7-Segmentanzeige oder was immer man in Abwesenheit eines Bildschirms sonst erwartet hätte. dabei gehören die weißen und roten Kippschalter jeweils zu den darüber angeordneten LEDs. Nicht zufällig sind die diese Elemente horizontal in zwei Gruppen zu jeweils acht angeordnet und wenn man jetzt die Schalterstellung oben als binär „1“ und unten als binär „0“ interpretiert, wird schnell klar, dass man so 2 Byte = 16 Bit auf diesem Weg eingeben und sich dazu korrespondierend 16 Bit als Binärzahl über die LEDs darstellen lassen kann. Wie das geht sehen wir gleich, zuvor noch ein Blick auf die Bedienelemente, die wir zusätzlich benötigen, nämlich die hellblauen Taster von Stop/Run bis Protect/Unprotect.

Nun wollen wir uns das Programmierbeispiel ansehen, dass im Altair Bedienerhandbuch als Einstieg in die Programmierung vorgeschlagen wird:

Altair 8800 Operator’s Manual Seite 15 (MITS Inc. 1975)

Also: Zweck des Programmes ist es zwei Zahlen zu addieren, die sich irgendwo im Hauptspeicher befinden, und das Ergebnis dann ebenfalls wieder im Hauptspeicher abzulegen. Das ist eine Aufgabe, für die man gerne mal einen Computer verwendet. Das sehr übersichtliche Flussdiagramm veranschaulicht das auch für den Einsteiger ganz schön.

Nun ist die nächste Frage: Programmieren – ja gerne – aber mit welcher Programmiersprache denn? Darauf gab es mit Auslieferung des Altairs nur eine Antwort: Natürlich in Maschinensprache. Eine Alternative gab es zunächst nicht, bis dann Bill Gates das erste Basic für den Altair programmiert hat.

Wenn wir uns über Maschinensprache unterhalten ist zuerst einmal zu klären, für welchen Prozessor denn bitteschön? Der Altair wurde zunächst mit dem Intel 8080 ausgeliefert- der Queen Victoria einer Prozessordynastie, die heute als I3, I5, I7 und so weiter die Desktop-PC regiert. Erst später war ein Upgrade auf den sehr erfolgreichen Zilog Z80 möglich.

Der Befehlssatz des 8080 ist für heutige Verhältnisse recht überschaubar aber gleichzeitig typisch für das Verständnis von Microprozessoren für Personal-Computer bis heute. Ohne sich jetzt didaktisch mit all zu viel Details aufzuhalten, werden im Handbuch die passenden Befehle des 8080 neben das Flussdiagramm geschrieben.

Altair 8800 Operator’s Manual Seite 16 (MITS Inc. 1975)

Tatsächlich folgt dann aber auf den nächsten Seiten eine detaillierte Beschreibung der Architektur des Altairs und des 8080 bevor es dann auf Seite 33 endlich ans Programmieren geht:

Altair 8800 Operator’s Manual Seite 33 (MITS Inc. 1975)

Um das zu verstehen, braucht man eine gewisse Vorstellung davon, wie ein Prozessor aufgebaut ist und arbeitet. praktisch alle Digitalcomputer der letzten 80 Jahre wurden nach der sogenannten Von-Neumann-Architektur realisiert. Das heißt, der Prozessor holt sein Programm – die Folge der Anweisungen die er verarbeiten soll – genauso wie die Daten, die er verarbeiten soll aus dem Hauptspeicher (RAM) und speichert die Ergebnisse der Operationen ebenfalls dort. Die eigentliche Verarbeitung erfolgt (sehr verkürzt und nicht ganz richtig beschrieben) in sogenannten Registern des Prozessors, deren Größe (Speichervermögen) in Bit eine wichtige Kenngröße darstellt. Beim den frühen Intel-Prozessoren 8080, 8088 und 8086 wie auch dem Z80 waren das 8 Bit, beim Intel 80286 dann 16 Bit, seit dem Intel 80386 32 Bit und heute üblicherweise 64 Bit (x64).

Typischerweise ist eines dieser Register, genannt Akkumulator, die Zentrale Anlaufstelle für alle Berechnungen. Das ist auch beim 8080 so. Daraus ergibt sich der oben beschriebene Programmablauf, jetzt etwas ausführlicher kommentiert:

  1. LDA [Adresse-1] = Akkumulator mit dem Inhalt der Speicherstelle an der Adresse 1 füllen
  2. MOV [Ziel-Register] = Akkumulator-Inhalt in ein anderes Register kopieren
  3. LDA [Adresse-2] = Akkumulator mit dem Inhalt der Speicherstelle an der Adresse 2 füllen
  4. ADD [Register] = Akkumulator-Inhalt und Inhalt des angegebenen Registers addieren. Ergebnis im Akkumulator.
  5. STA [Adresse-3] = Ergebnis (Inhalt des Akkumulators) in den Speicher an Adresse 3 schreiben
  6. JMP [Adresse-4] = Das Programm springt an die Adresse-4 und arbeitet dort weiter

Das Konzept war im Original, bei 6. das Programm nicht zu beenden, sondern durch einen unbedingten Sprung zurück an den Anfang in eine Endlosschleife zu schicken. Das möchte ich hier nicht tun sondern verwende statt dessen:

6. HLT = Der Prozessor hält an und legt sich schlafen. Das fühlt sich für mich mehr wie ein normales Programmende an, als die immer gleiche Berechnung in einer Endlosschleife durchzuführen.

Die oben aufgeführten Befehlsmnemonics sind schon eine Ebene höher eingeordnet als die eigentliche Maschinensprache, die das Einzige ist, was der Prozessor in Wirklichkeit versteht – aber was ist das nun, was der Prozessor versteht? Maschinensprache ist nichts anderes als eine Folge von Bits im Speicher des Rechners. Die eigentliche Abarbeitung eines Programmes folgt einem sehr einfachen Schema. Jeder Prozessor verfügt über einen sogenannten Program-Counter, ein Register, in dem jeweils die Hauptspeicheradresse des nächsten abzuarbeitenden Befehls steht. Dieser Befehl wird aus dem Speicher gelesen, dekodiert – also geschaut ob das ein bekannter Befehl ist, welche Parameter erwartet werden und was zu tun ist. Nachdem dieser Befehl wird abgearbeitet wurde wird der Programmzähler auf den nächsten Befehl gesetzt und das ganze beginnt von vorne.

Solange kein Sprungbefehl auftaucht bedeutet das, der Programmzähler wird um so viele Bytes hochgezählt, wie der gerade abgearbeitet Befehl und seine Parameter lang sind. Bei einem 8080 sind das 1, 2 oder 3 Bytes. Das liegt daran, dass der 8080 ein 8 Bit-Prozessor mit einem 16 Bit Datenbus ist. In diesem Fall ist ein Befehl immer ein Byte lang und er hat keinen weiteren Parameter, oder einen 8-Bit Wert, der direkt nach dem Befehl steht oder eine 16-Bit-Adresse, also zwei Byte nach dem Befehl, die eine Speicherstelle bestimmen, aus der Daten gelesen werden. Im Internet finden sich viele gute Beschreibungen des Befehlssatzes (z. B. hier dunfield.classiccmp.org/r/8080.txt), so dass ich an dieser Stelle auf mehr Details verzichten möchte um dann auch bald mal zu programmieren.

Altair 8800 Operator’s Manual Seite 34 (MITS Inc. 1975)
Altair 8800 Operator’s Manual Seite 35 oben (MITS Inc. 1975)

Ab hier wird dann das Operator’s Manual sehr spezifisch. Jedem Befehlsmnemonic wird das eigentlich Bitmuster in Maschinensprache zugeordnet und gleichzeitig kommentiert. Umgangssprachlich ist der Programmfluss wie folgt:

  • (0) Hole dir einen 8-Bit-Wert von der angegebenen Speicherstelle, in diesem Fall Byte 128 des Hauptspeichers, in den Akkumulator (Register A)
  • (1) Merke dir diesen Wert im Register B
  • (2) Hole dir den zweiten Summanden als 8-Bit-Wert von Speicherstelle 129 in den Akkumulator
  • (3) Addiere den Inhalt von Register B zum Inhalt des Akkumulators. Das Ergebnis steht im Akkumulator. Das ist ein Beispiel für einen Befehl mit Länge eins (ohne folgende Parameter), weil der Befehlscode (10 000 000 binär = 128 dezimal) genau das besagt: Addiere A und B. Einen entsprechenden Befehl gibt es für alle Register, z. B. ADD C (A := A + C) mit dem Befehlscode 10 000 001 2 = 12910
  • (4) Speichere das Ergebnis aus dem Akkumulator an die Speicherstelle 130
  • (5) Im Original würde das Programm durch den unbedingten Sprungbefehl (JMP [Adresse]) in eine Endlosschleife geschickt. Stattdessen verwenden wir hier dem Halte-Befehl HLT des 8080 (011101102 = 11810), der keine weiteren Parameter braucht

Wie bekommen wir nun das Programm in den Computer? Beim Altair als einem echten Stück Hardware werden dafür die bereits erwähnten Schalter verwendet.

Altair 8800 Operator’s Manual Seite 36 unten (MITS Inc. 1975)

Wir beginnen mit einem Druck auf den Reset-Knopf, der den Programmzähle (PC) auf null setzt. Mit den acht weißen Kippschaltern rechts stellen wir Byte für Byte die numerischen Werte für die Prozessorbefehle und die Speicheradressen ein und speichern sie dann jeweils durch drücken des Deposit-Knopfes. Dabei springt der Programmzähler jeweils eine Speicheradresse weiter.

Nun haben wir aber keinen Altair als Hardware zur Verfügung und müssen mal schauen, wie unser SIMH-Altair damit umgeht. Also, erst mal SIMH starten, unter Windows – je nach Architektur – altairz80_x86-64.exe oder altairz80.exe:

Es meldet sich dir freundliche Programmzeile des Simulators und warte darauf, dass wir die virtuellen Tasten drücken.

Wie im Handbuch beschrieben, machen wir als erstes einen Reset:

Der RESET-Befehl in SIMH ohne weitere Paramater setzt alle Komponenten des virtuellen Computers zurück. Das können wir gleich insoweit überprüfen, als wir uns den Inhalt des Programmzählers anzeigen lassen können. Das macht der Befehl EXAMINE, der allerdings viele Parameter zulässt. Wir beschränken uns für den Moment auf die Anzeige des Programmzählers (PC) und sehen, dass der korrekt auf null steht.

Laut Handbuch sollen wir nun den numerischen Wert für die erste Speicherstelle mittels der Schalter einstellen und dann die DEPOSIT-Taste drücken. Das geht mit SIMH natürlich etwas eleganter mit dem sehr flexiblen DEPOSIT-Kommando, das aber dummerweise keine Binärzahlen versteht. Freundlicherweise nennt uns das Altair-Manual aber die dazugehörigen Octal-Werte, die dann auch wieder unser SIMH versteht.

Altair 8800 Operator’s Manual Seite 35 unten und 36 oben (MITS Inc. 1975)

Damit funktioniert DEPOSIT auch wieder für uns, indem wir den Schalter -o (Buchstabe o) mit angeben. Also zum Beispiel in der Form DEPOSIT -o 000 072. Das bedeutet, speichere den Wert 0728 an der Speicherstelle 0008. So finden wir aber auch gleich den Pferdefuß des DEPOSIT-Kommandos: Er erwartet immer eine Speicheradresse. Das würde aber bedeuten, dass wir – anders als beim Original – die Adressen selber hochzählen müssten. Hier hilft uns der Befehl IDEPOSIT, der als Parameter einen Speicherbereich erwartet. Das unser Programm an den Stellen 0-13 im Speicher liegen soll, starten wird IDEPOSIT genau so:

Der Prompt „0:“ signalisiert, dass wir den Wert für die Speicherstelle null eingeben und mit Return bestätigen sollen. Dann springt die Eingabe automatisch eine Speicherstelle weiter.

So können wir jetzt ziemlich schnell das ganze Programm eingeben:

Dabei habe ich den Sprungbefehl durch HLT (1668) ersetzt. Am Ende des angegebenen Bereichs springt SIMH wieder auf den Prompt zurück. Anders als beim echten Altair haben wir hier eine sehr schöne Möglichkeit unsere Eingabe zu kontrollieren. Neben IDEPOSIT gibt es auch für EXAMINE die Option sich den Inhalt von Speicherbereichen anzeigen zu lassen. Und da wir eine Programm eingetippt haben können wir den Schalter -m verwenden um uns statt der numerischen Werte die Mnemonics ausgeben zu lassen. Et voilá:

Jetzt müssen wir uns nur noch überlegen, was unser Programm den berechnen soll. Aber Achtung: Da wir hier nur mit 8-Bit-Werten arbeiten sollten die Eingabewerte nicht zu groß sein. Also fangen wir mal ganz klein an, mit der Addition von 13 und 19. Dafür schreiben wir die Summanden an die Speicherstellen 8016und 8116 – entsprechend 12810 – 12910:

Und jetzt drücken wir (virtuell) die RUN-Taste des Altair, die in SIMH durch den GO-Befehl ersetzt wird:

Da der Programmzähler nach dem RESET zum Anfang immer noch auf Adresse 0 zeigt, beginnt der Prozessor hier mit der Berechnung und arbeitet so lange, bis er auf einen HALT-Befehl stößt. Damit geht die Kontrolle an SIMH zurück:

Um uns zu überzeugen, dass unser Programm korrekt gearbeitet hat, schauen wir uns das Ergebnis mit dem EXAMINE-Kommando an (mit dezimaler Ausgabe – so rechnet es sich im Kopf doch leichter):

Und … es hat funktioniert! Darum jetzt mal mit größeren Zahlen:

Immer noch richtig! Darum gleich noch mehr (und – ja – man kann viele SIMH-Befehle auch abkürzen, was ich auch oft tue. Für EXAMINE ist das wenig überraschend der Buchstabe E, für DEPOSIT D):

Das Programm erneut gestartet (GO 0 bedeutet, den PC erst auf 0 zu setzen und dann loszulaufen) und dann schnell nachgeschaut. Das Ergebnis ist dann doch etwas überraschend: 255+1=0

So richtig überraschen ist das dann doch nicht. Da der Prozessor im Akkumulator nur 8-Bit-Werte verarbeiten kann, also Zahlen von 0-25510, fängt er einfach wieder von vorne an, wenn es zu einem Überlauf – also einem Rechenergebnis von mehr 25510 kommt. Im Akkumulator stehen damit nur noch die niedrigwertigsten (am weitesten rechts stehenden 8-Bit des Ergebnisses. Wie wir damit umgehen können, wollen wir uns ein anderes Mal anschauen.

Zu guter Letzt wollen wir einen Vorteil des SIMH gegenüber dem minimalistischen Original-Altair ausnutzen. Wir können nämlich sehr einfach unser Programm speichern indem wir den relevanten Teil des Speicherinhalts in eine Binärdatei „dumpen“:

Damit möchte ich für heute schließen und wir machen ein anderes Mal hier weiter.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.