Projektvorstellung: Entwicklung eines C64 Emulators in Java

  • Hallo zusammen,


    bereits seit längerer Zeit spiele ich mit der Idee, einen C64 Emulator zu entwickeln. Nein, keine Hardwarelösung, das überlasse ich den Profis, sondern eine Softwareimplementierung.


    Ja, ich weiß, dass es bereits genug davon gibt. Mir geht es auch gar nicht darum, da irgendwie in Konkurrenz zu treten, sondern für mich persönlich dies als Lernprojekt anzugehen, um einerseits tiefer den C64 kennen zu lernen, andererseits auch um endlich mal zu sehen, wie es ist, ein System auf einem völlig anderen zu implementieren.


    In diesem Thread möchte ich Euch das Projekt sowie den Fortschritt vorstellen. Vielleicht interessiert es den einen oder anderen?


    Da ich dies zum ersten Mal mache, ist es natürlich nicht als eine genaue Anleitung zu sehen, wie man so etwas macht, sondern vielmehr wird der Emulator sukzessive wachsen zusammen mit meinem Lernfortschritt. Daher ist dieser Thread eher als Brainstorming, Vorstellung der Lösungen und der Weg zum (hoffentlich) am Ende funktionierenden Emulator zu sehen.


    Ich wäre Euch auch sehr dankbar für Eure Ideen und Hilfestellung zwischendurch! Wenn Euch irgendwelche Pitfalls oder blöde Ideen von mir auffallen, bitte auch gleich melden!




    Rahmendaten:


    Implementierung ist in Java. Wieso? Weil ich Java eben mag. Mittlerweile kann es Java durchaus performancemässig mit C++ aufnehmen, zumindest bei einigen Fragestellungen, daher probiere ich es zuerst damit. Rein gefühlsmässig sollte die Performance einer aktuellen JVM auf einer modernen Hadware völlig ausreichend sein. Falls es sich zu langsam erweist, wird eben doch auf C++ portiert. Reines Java SE, da ich keinen Grund für Spring & Co sehe. Buildsystem ist Maven. Meine Entwicklungsumgebung: Eclipse.


    Der Code selbst ist frei verfügbar und liegt in GitLab: https://gitlab.com/DigitalMach…italmachines-c64-emulator


    Hier selbst werde ich eher nicht den Code posten, das würde den Thread ja sprengen, sondern vielmehr grundsätzliche Ideen, Überlegungen und Code Snipperts nur da, wo es von Bedeutung ist.


    Wer das Projekt mitverfolgen möchte, sollte idealerweise über zumindest rudimentäre Kenntnisse der OOP-Programmierung in Java haben. Wenn etwas unklar ist, gern fragen, aber die Prinzipien und die Grundkenntnisse sollte man schon haben.


    Wichtiger Punkt: es geht nicht darum, technisch den C64 exakt nachzubilden, sondern nur logisch, so dass sich C64-basierte Programme ausführen lassen, sowohl in BASIC wie auch in Maschinencode. Das bedeutet, im Vergleich zu der reinen Elektroniksicht wird es Änderungen geben, Vereinfachungen, etc. Entscheidend ist die Logik, nicht die Elektronik!


    Ich halte mich zwar schon an das Agile-Paradigma, aber ohne definierte Zeitfenster. Als Freizeitprojekt wird es mir sicherlich schwer fallen, da die üblichen 4-Wochen Zeiträume einzuhalten. Und Planungsmeeting mit mir selbst sind ja auch irgendwie witzlos. Die Implementierung möchte ich jedoch nach Sprints aufteilen, um selbst Überblick zu behalten und mich nicht in Seitenstränge zu verzetteln.


    An Euch alle, die interessiert sind, mir über die Schulter zu schauen, habe ich eine Bitte: bitte benutzt diese Thread ausschließlich zur Diskussion von Punkten, die für die Entwicklung des Emulators relevant sind. Seitendiskussionen bitte ins separate Threads auslagen, damit dieser hier nicht verwässert wird. Danke!



    Sprint 1

    Im nächsten Beitrag möchte ich starten der Zielsetzung:

    Implementierung der grundsätzlichen Architektur, aber noch ohne Taktgeber.

    Da ich allerdings die nächsten Tage erst einmal im Urlaub bin, werde ich mir etwas Fachliteratur mitnehmen und in freien Minuten etwas reinlesen.

  • Architekturvorstellung:


    Anbei erst einmal ein grobes UML-Diagramm, wie ich mir die grundsätzliche Architektur vorstelle.


    Die einzelnen Chips wie die CPU, VIC, SID und die beiden CIAs werden als eigene Klassen implementiert, die sich von einer abstrakten Basisklasse ICChip ableiten.


    Wie wohl sofort erkennbar, habe ich nicht zwei separate Busse für Daten und Adressen vorgesehen, sondern alles zu einem zusammengefasst sowie PLA eingespart. Die Idee ist hier, alles in den Datenbus zu intergrieren, welches als eine Schnittstelle zwischen den Memories und den einzelnen Chips agiert. Ob das am Ende auch so klappt, werden wir sehen. Die Kommunikation via den Datenbus soll über Messages erfolgen, die aus Adresse, Daten sowie einem Flag Lesen/Schreiben bestehen und vom Datenbus zum richtigen Objekt geschicht werden.


    Ebenso von einer Basisklasse abgeleitet sind die beiden CIAs. Auf dem Diagram habe ich hier die Verbindung zum Datenbus vergessen.


    Die RAM-Bereiche sind auch eigene Klassen, die sich von entweder ROM (nur read()) oder RAM (read(), write()) als abstrakte Basis ableiten. Im Diagram ist nur ZeichenROM als Implementierung da, aber die Idee ist, für jeden Memoryblock eine eigene Klasse zu definieren, die in einem Array den relevanten Speicherinhalt hält. Der Datenbus hält die Pointer darauf mit den zugehörigen Memorybereichen und weiß, wohin er die Anfrage der CPU etc. zu schicken hat



    Kommunikation nach Außen (Ausgabe GUI, Ausgabe TON, Ports, Tastatur etc) möchte ich über definierte nachrichtenbasierte APIs machen: die Komponenten setzen Nachrichten mit ihren Ausgaben ab und die Peripherienimplementierungen holen diese ab. Also beispielsweise klare Trennung zwischen der errechneten grafischen Darstellung des VICs und dem tatsächlichen grafischen Rendern durch die Implementierung der GUI. Die Idee dahinter ist, dass sich damit Komponenten wie GUI oder Diskettenlaufwerk nach Belieben austauschen gegen anderen sowie auch für andere Projekte recyceln lassen, da sie nur die entsprechende API berücksichtigen müssen.



    Die einzelnen Befehle der CPU möchte ich als eigene Klassen implementieren, die von der CPU über eine Map mit opCodes als Key aufgerufen werden. Damit könnte man hier auf endlose If-Baums verzichten und es ist eben wesentlich eleganter. Darüber hinaus ist die Lösung schön erweiterbar durch weitere Befehle oder andere Implementierung der Befehle, sollte es notwendig sein.


    Die Bildschirmausgabe wird ein separates Päckchen sein, vermutlich entweder in JavaFX oder doch in gutem, altem Swing.


    Über Außeninterfaces wie Diskettenlaufwerk mache ich mir noch keine Gedanken, kommt später im Sprint x+y...



    Sodele, dann los ans Aufsetzen des Projektes und die Implementierung...