Sinclair ZX81 Emulator für den Calliope mini

Motivation

Im Jahr 1981,brachte die Firma Sinclair den Homecomputer ZX81 auf den Markt. Der Computer wurde mit einem Fernseher verbunden und Programme konnten mithilfe eines Kassettenrecorders gespeichert und geladen werden. Die Leistungsfähigkeit des Computer war nicht mit der heutiger Computer vergleichbar. Dennoch war der Computer für viele der Einstieg in die Programmierung und hat Biografien nachhaltig beeinflusst.

zx81
©cc-by-sa 3.0 commons.wikimedia.org

Für den im ZX81 verbauten Prozessor Z80 hat der Entwickler Lin Ke-Fong einen Emulator geschrieben. Ferner steht eine freie Version des im ZX81 verwendeten BASIC-Interpereters zur Verfügung (vgl. http://sz81.sourceforge.net). Damit sind die Voraussetzungen gegeben, den Emulator prinzipiell auf jeden anderen Computer zu übertragen, sofern dieser ausreichend leistungsfähig ist.

Der calliope mini ist ein Lerncomputer für Kinder. Dieser wird normalerweise mittels einer bildlichen Programmiersprache programmiert. Es ist aber genauso möglich Programme jeder beliebiger Programmiersprache dafür zu erzeugen, sofern für die Programmiersprache ein Compiler vorliegt.

calliope mini
©cc-by-sa https://calliope.cc

Die zu klärende Fragestellung war nun, ob es möglich ist, einen Emulator für den ZX81 auf dem Calliope betreiben zu können.

Grundsätzliches

Die Emulation erfolgt prinzipiell so: Es wird ein Array gebildet, dass das RAM des ZX81 simuliert. Die Größe dieses Arrays entspricht der Größe des RAMs. Im ZX81 gab es neben dem RAM noch ein ROM in dem der BASIC-Interpreter gespeichert war. Der Inhalt dieses ROMs wird ebenfalls in ein Array geschrieben. Eine Aufgabe des Emulators ist es, diese beiden Arrays bereitzustellen und die Speicheradressen des ZX81 auf die richtigen Indizes der Arrays umzurechnen. Eine weitere Aufgabe ist die Emulation des Z80 Prozessors. Hierfür dient die o.g. Implementierung. Es wird in einer Schleife dieser Softwareprozessor aufgerufen und es werden mehrere Zyklen des Prozessors dabei durchgeführt. Dazu muss man wissen, dass jeder Prozessor im Grunde nach dem Prinzip arbeitet, einen Befehl aus dem Speicher zu lesen, diesen auszuführen und anschließend das Ergebnis in eine spezielle Speicherzelle des Prozessors zu schreiben. Darüber hinaus gibt es Befehle, mittels derer Inhalte in diesen speziellen Speicherzellen in das RAM oder eine andere Adresse des Computers zu schreiben. Die Emulation muss nun sicherstellen, dass die gelesenen und geschriebenen Speicherbereiche richtig auf die o.g. Arrays abgebildet werden. Ist das gewährleistet wird ein Befehl nach dem nächsten von dem Softwareprozessor abgearbeitet.

Ausgabe

Ursprünglich erfolgte die Ausgabe des ZX81 auf einem Fernseher. Dazu wurde das anzuzeigende Bild aus dem Speicher gelesen und in Fernsehsignale umgewandelt. An den Calliope lässt sich nun nicht so einfach ein Fernseher anschließen, daher erfolgt die Ausgabe auf andere Weise: Der ZX81 hat das Videobild im RAM abgelegt. Der Bildschirm des ZX81 erlaubte im Textmodus die Darstellung von 24 Zeilen mit 32 Zeichen. Jedes Zeichen einer Zeile benötigte 1 Byte im Speicher. Damit belegt ein komplett gefüllter Bildschirm 768 Byte des Speichers. Man beachte, dass der ZX81 ohne Speichererweiterung gerade mal 1024 Byte RAM besessen hatte! Somit bliebe in diesem Fall nicht viel Platz für ein Programm. Damit nicht immer 768 Byte für das Videobild geopfert wurden, hat man ein Zeilenendezeichen definiert. Damit verbrauchten leere Zeilen nur noch ein Byte statt 24 Byte im Speicher. Ein leerer Bildschirm konnte so in 24 Byte dargestellt werden.

Durch diese Optimierung des Bildschirmspeichers ändert sich andauernd die Position des Videobildes im RAM. An welcher Stelle im Speicher das Videobild beginnt, wurde daher an eine spezielle Stelle im RAM geschrieben. Für die Erzeugung des Fernsehbildes wurde hierüber die Startadresse des Videospeichers ermittelt und die 24 Zeile ausgelesen.

Der Emulator ermittelt das Videobild auf ähnliche Weise. Es wird zwar kein Fernsehbild erzeugt, dennoch wird der Videospeicher ausgelesen und die darin enthaltenen Informationen werden in ASCII-Zeichen übersetzt und an die serielle Schnittstelle weitergeleitet. So ist es einfach möglich, ein Terminalprogramm an den Calliope anzuschließen und den Bildschirminhalt darzustellen.

calliope_zx81 zx81_sinus

Eingabe

Die Eingabe erfolgt wie die Ausgabe über die serielle Schnittstelle. Allerdings lassen sich die gelesenen Zeichen nicht 1:1 an den ZX81-Programm übergeben. Die über die serielle Schnittstelle erfassten Zeichen sind ASCII-Zeichen. Diesen internationalen Standard hat der ZX81 nicht gekannt. Alle Zeichen haben einen eigenen Code. in diesen muss ein eingelesenes Zeichen übersetzt werden. Das gelesenes Zeichen wird in eine spezielle Variable geschrieben. Der Inhalt dieser Variable wird immer dann an den Z80-Prozessoremulator übergeben, wenn dieser eine spezielle Adresse abfragt. Dabei kommt es in der Emulation zu gewissen Verzögerungen bei der Eingabe: Die Tastatur des ZX81 war mehr oder weniger direkt mit dem Z80-Prozessor verbunden. Jeder Taster einer Tastatur besitzt ein Prellverhalten, d.h. nach dem Tastendruck schwingen die Kontakte noch etwas nach. Hierdurch wird ein Signal erzeugt, dass wie ein mehrfaches Drücken des Tasters wirkt. Dieses Verhalten wird durch s.g. entprellen unterdrückt. Es gibt unterschiedliche Wege, dieses zu realisieren. Im ZX81 wurde es dadurch gelöst, dass ein erneuter Tastendruck erst nach Ablauf einer gewissen Zeit zugelassen wurde. Da unklar ist wieviele Prozessorzyklen sinnvoll zu emulieren sind bevor eine Taste erneut eingelesen wird, musste experimentell ein sinnvolles Verhältnis zwischen dem Lesen eines Zeichens aus der seriellen Schnittstelle und dem Durchführen von Z80-Prozessorzyklen gefunden werden. Durch diesen Umstand sind der Eingabegeschwindikeit Grenzen gesetzt, die nichts mit der Geschwindigkeit des Calliopes selbst zu tun haben.

Laden von Programmen

Das Speichern und Laden von Programmen mittels Kassettenrecorder ist nicht mit dem Calliope umsetzbar. Statt dessen besitzt der Emulator eine Möglichkeit, den Speicherinhalt des ZX81 auf dem Bildschirm auszugeben. Dieser lässt sich dann als Array in das Programm des Emulators einbauen und von dort aus über den ursprüngliche LOAD-Befehl laden.

Hierdurch ist die Möglichkeit geschaffen, ursprüngliche Programme auf dem Calliope laufen zu lassen und auch eigene Programme zu speichern. Allerdings ist das RAM des Calliope durch die Emulation bereits so umfassend gefüllt, dass sich nur 1K-Programme des ZX81 ablaufen lassen.

Fazit

Im Ergebnis war es möglich, auf dem Calliope einen Sinclair ZX81 zu emulieren und so die Leistungsfähigkeit des Lerncomputers ins Verhältnis zu damaligen Homecomputern zu stellen. Neben diesem und dem nostalgischen Anreiz bietet dieses Projekt darüber hinaus einen Einblick in die Funktionsweise von Computern, die noch heute ihre Gültigkeit besitzen.

Quellcode

Der Quellcode des Projektes befindet sich in diesem Repository: https://github.com/theopenbit/calliope-zx81. In dem Repository ist auch die Benutzung des Emulators beschrieben.