Retro Gaming: Wie man einen Emulator programmiert
Warum nicht mal selbst einen Emulator programmieren? Das ist lehrreich und macht Spaß - wenn er funktioniert. Wie es geht, zeigen wir am Gameboy.

Hat die Welt nicht eigentlich schon genug Emulatoren? Für jede Plattform gibt es einen, man muss ihn nur herunterladen - im schlimmsten Fall steht davor noch die Entscheidung, welcher es genau sein soll. Oder man lädt sich gleich Retropie herunter und kann direkt Dutzende Retro-Computer und -Konsolen nutzen.
- Retro Gaming: Wie man einen Emulator programmiert
- Einen Prozessor mit Software nachbauen
- Der Speicher
- Die Grafikeinheit
- Das Soundmodul
- Die Spielemodule
- Zusammenfassung
Wer gern tüftelt und sich für Hardware interessiert, wird sicher ein weitergehendes Interesse an dem Projekt Emulator entwickeln. Eine gute Umsetzung ist nämlich gar nicht so einfach, dafür umso lehrreicher. Man gewinnt nicht nur spannende Einblicke in den Aufbau der jeweiligen Hardware, ein Emulator ist auch eine hervorragende Programmierübung. Begnügt man sich mit der Emulation einer 8- oder 16-Bit-Konsole, ist nicht einmal Assembler-Code erforderlich.
Teile des Codes in Assembler zu implementieren, bietet zwar enormes Optimierungspotenzial, ein halbwegs aktueller Computer führt aber selbst nicht-optimierten Java-Code schnell genug aus. Für erste Versuche ist das ein großer Vorteil, da selbst ohne Optimierung und große Hirnakrobatik ein voll funktionsfähiger Emulator entsteht.
Wo fange ich an?
Am Anfang steht natürlich die Frage: Was möchte ich emulieren? Für mich stand die Antwort fest - den klassischen Gameboy. Er hat drei Vorteile: Er ist gut dokumentiert, die Hardware ist übersichtlich und einfach - und er ist die Konsole meiner Kindheit. Das Gameboy-CPU-Manual lag seit Jahren auf meiner Festplatte, im Internet Archive findet sich sogar das Programmierhandbuch von Nintendo.
Die nächste Frage: Welche Programmiersprache nutze ich? Grundsätzlich funktioniert jede Sprache, so lange sie nicht zur Laufzeit interpretiert wird. Ich habe für meine Implementierung Java genutzt, denn eigentlich wollte ich den Emulator ursprünglich auf Android-Geräten laufen lassen. Daraus wurde nie etwas, aus diesem Grund kommen aber in diesem Artikel Begriffe aus der Java-Welt vor. Generell fand ich einen objektorientierten Ansatz hilfreich. Verwendet man Templates und Interfaces, erspart man sich viele manuelle Prüfungen - das kann helfen, Fehler zu vermeiden.
Und das möchte man, denn einen Emulator zu debuggen ist kein Vergnügen, da das erwartete Verhalten nur teilweise bekannt ist. Was die emulierte Software tut, ist in der Regel unbekannt, weshalb man bei Fehlern schnell im Trüben fischt. Daher lege ich allen, die sich an einem Emulator versuchen wollen, sehr ans Herz, alle entwickelten Komponenten zu testen. Ich habe tagelang einen Fehler gesucht, der durch die fehlerhafte Implementierung eines Prozessorbefehls entstanden war.
Was macht eigentlich ein Emulator?
Damit der Emulator originalgetreu funktioniert, ist eine exakte Nachbildung des Prozessors und der Peripherie als Software erforderlich. Die Software tut am Ende das, was auch der originale Prozessor macht: Sie liest und verarbeitet Befehle, zusätzlich werden Komponenten benötigt, die Grafik und Sound erzeugen.
Beim Gameboy steckt all das in einem Chip, das Mainboard ist recht übersichtlich. Darauf finden sich neben dem Chip 16 KByte RAM, von denen jeweils 8 KByte als Arbeits- und Grafikspeicher dienen. Der Prozessor ist ein Derivat des beliebten Z80, allerdings wurde der Befehlssatz stark beschnitten. So fehlen fast alle Befehle für 16-Bit-Arithmetik, dafür kamen einige eigene hinzu. Neben Operationen für binär codierte Dezimalzahlen (BCD) finden sich Befehle zur Manipulation einzelner Bits.
Die meisten Befehle sind ein Byte lang, die Abarbeitung erfolgt in vier Stufen. Dabei handelt es sich um die klassische Zerlegung der Ausführung in
- Befehl aus dem Speicher holen (Instruction Fetch, IF)
- Befehl decodieren (Instruction Decode, ID)
- Befehl ausführen (Execute)
- Ergebnis schreiben (Write Back, WB)
Da der Prozessor kein Pipelining implementiert, benötigt jeder Befehl vier (oder ein ganzzahliges Vielfaches) Prozessortakte zur Ausführung. Befehle, die länger als vier Takte zur Ausführung benötigen, durchlaufen die einzelnen Schritte mehrfach. Dabei passiert gegebenenfalls in einzelnen Phasen nichts, sie können allerdings nicht ausgelassen werden. Damit arbeitet der Prozessor Befehle mit einer Frequenz von 1,05 MHz ab.
Oder nutzen Sie das Golem-pur-Angebot
und lesen Golem.de
- ohne Werbung
- mit ausgeschaltetem Javascript
- mit RSS-Volltext-Feed
Einen Prozessor mit Software nachbauen |
+1 Bin schon auf den Folgeartikel zur Umsetzung der parallel stattfindenden HW-Abläufe...
Sheep It Up ist für mich ein Musterbeispiel eines Homebrewspiels für den GB. Simpel...
Ich finde es daher umso erstaunlicher, wie die Leute Cores für den Mister erstellen. Ich...
Zuerst noch einmal vielen Dank für den Artikel. Bei aller Abkürzung hätte ich mir aber...