NES Elite – Der dokumentierte Quellcode von Elite für das NES
(github.com/markmoxon)- Der Elite-Quellcode von Ian Bell und David Braben für das NES, bei dem jede Zeile dokumentiert ist und für den größtenteils Erklärungen vorliegen; manuell rekonstruiert aus dem Disassembly der originalen Spiel-Binärdatei
- Es lässt sich auf modernen Computern ein vollständig funktionsfähiges Spiel aus dem Quellcode bauen, wobei ein iNES ROM image erzeugt wird, das auf einem echten NES oder in einem Emulator geladen werden kann
- Unterstützte Varianten sind die Imagineer-PAL variant und die NTSC-Variante von Ian Bells persönlicher Website; der Standard-Build ist die PAL-Variante
- Der Quellcode kann entweder in einer menschenlesbaren Form auf elite.bbcelite.com durchsucht oder als kommentierter Quellcode in einer IDE geöffnet werden; die Inhalte der Website und der Quelldateien sind identisch
- Build-Anforderungen sind BeebAsm, Python und unter Mac/Linux
make; der Python-Build wurde nur mit 3.x getestet, und für Windows istmake.exeenthalten- Unter Windows wird mit
make.batgebaut, unter Mac/Linux mitmake; die Standardausgabe istelite-pal.NESim Ordner5-compiled-rom-images - Mit
variant=ntsckannelite-ntsc.NESerzeugt werden
- Unter Windows wird mit
- Die Build-Optionen steuern unter anderem die Variantenauswahl, die Verwendung eines Test-Commanders nahe den Maximalwerten, das Überspringen des Abgleichs mit dem Original-Binärfile und das Deaktivieren der crc32-Prüfung
- Ein typisches Beispiel ist
make variant=ntsc commander=max match=no verify=no crc32.pyvergleicht Prüfsummen und Dateigrößen der erzeugten Dateien direkt mit Referenzdateien, die aus der Originalquelle extrahiert wurden
- Ein typisches Beispiel ist
- Die PAL- und NTSC-Varianten unterscheiden sich unter anderem bei der Zykluszahl des NMI-Handlers, der Imagineer/Nintendo-Überschrift auf dem Startbildschirm, der Wartezeit für Auto-Play in der Combat-Demo, dem Prüfsummenalgorithmus für Save-Slots, der internen Versionsnummer, einer versteckten Copyright-Nachricht, dem Scroll-Text und y-Koordinaten-Konstanten
- Die NTSC-Variante läuft nicht auf echter NTSC-Hardware; sie ist eine NTSC-Emulation, bei der das NMI-Timing an den NTSC-Modus einiger Emulatoren angepasst wurde
- Es gibt keine Lizenzdatei; es gilt daher das Standard-Urheberrecht, das nur Lesen und Forken erlaubt, nicht jedoch Vervielfältigung, Verbreitung oder die Erstellung abgeleiteter Werke
1 Kommentare
Hacker-News-Kommentare
Als ich vor langer Zeit bei Frontier arbeitete, hörte ich von David Braben eine interessante Anekdote über NES Elite. Wenn ich mich richtig erinnere, nutzte es anfangs den Hardware-Timer des NES, um die tatsächliche Zeit zu verfolgen, damit die Physik auch bei unterschiedlichen Frameraten gleichmäßig weiterlief.
Bei Nintendos Vorabprüfung vor der Veröffentlichung sei die Nutzung untersagt worden, weil dieser Timer bei einigen frühen NES-Geräten nicht korrekt funktionierte. Daher hätten Bell/Braben eine eigene Schätzung gepflegt, wie viele Clock Cycles jede Funktion in diesem Frame verbraucht hatte, und diese am Ende des Frames aufsummiert, um die verstrichene Zeit zu schätzen.
Wenn ich mir nun den GitHub-Quellcode ansehe, habe ich mich offenbar falsch erinnert oder Braben nicht richtig verstanden. In
elite-source-bank-7.asmgibt es einen Kommentar: „Aktualisiert den NMI-Timer, der anstelle eines vom NES nicht unterstützten Hardware-Timers verwendet werden kann“, und es sieht so aus, als hätten sie durch Zählen der nicht maskierbaren Interrupts eine Art Echtzeituhr implementiert.Auf frühen NES-CPU-Dies gab es Reste eines fehlerhaften und deaktivierten programmierbaren Intervalltimers: https://www.nesdev.org/wiki/RP2A03_Programmable_Interval_Tim...
In späteren Revisionen wurde er vollständig entfernt; es ist möglich, dass er nur in Entwicklungskits o. Ä. aktiviert war. Wenn man sich auf eine Funktion verlassen hätte, die auf Consumer-Geräten nicht funktioniert, wäre eine Ablehnung durch Nintendos Tests selbstverständlich gewesen.
Selbst wenn ausgelieferte Konsolen einen programmierbaren Intervalltimer gehabt hätten, wäre er wohl eher für Subframe-Messungen wie präzise Rastereffekte nützlich gewesen. Für die Messung der tatsächlichen Zeit ist das Zählen von NMIs deutlich sinnvoller. Ein NMI tritt zu Beginn jedes Videoframes auf, ist mit 60,0988 Hz sehr konstant, und selbst wenn die Game-Engine langsamer wird und sich die Framerate ändert, kann die CPU-seitige Verarbeitung das Timing des Videosignals nicht beeinflussen.
Nebenbei kann auch die Audio-Hardware Timer-Interrupts erzeugen, und viele Erweiterungschips haben Scanline-Counter zur Render-Synchronisierung. Es gibt auf dem NES keinen Mangel an Möglichkeiten, Zeit zu messen.
Als sie ein Spiel von Nintendo freigeben lassen wollten, habe es auf einer bestimmten Version des amerikanischen NES entweder nicht funktioniert oder das System überhitzt. Wegen des engen Release-Zeitplans mussten sie zur Nintendo-Zentrale fliegen, um das zu lösen; wenn ich mich richtig erinnere, waren von genau dieser Version weniger als 100 Geräte im Umlauf.
Später fand ich Notizen für ein unveröffentlichtes Buch, und tatsächlich war es etwas anders. Die Spieletests beschränkten sich nicht nur auf das Gameplay; es musste auf allen NES-Konsolenvarianten getestet werden, auf denen es laufen konnte. Andrew Davie von Beam Software erinnerte sich, dass „The Three Stooges“ auf einem Test-NES in Nintendos Büro in Washington Probleme machte und er persönlich dorthin reiste.
Er sagte, es habe „ungefähr 23 Maschinenvarianten“ gegeben, darunter verschiedene Kombinationen von Chipherstellern, die ein Spiel bestehen musste. Wegen des Mangels an offizieller Dokumentation habe er Sprite-Daten nicht wie offiziell empfohlen in den RAM geschrieben, sondern alle 2 Sekunden direkt geschrieben, wodurch das NES zu heiß wurde und im ganzen Spiel Sprite-Flackern auftrat. Nach der Korrektur wurde das Spiel zur Veröffentlichung freigegeben; die problematische NES-Kombination habe es in den gesamten USA nur etwa fünfmal gegeben, und sie sei aus Nintendos Test-Lineup entfernt worden.
Ich habe vor Kurzem mit dem Nachfolger Elite: Dangerous angefangen, und trotz einiger Probleme ist es eine ziemlich erstaunliche Erfahrung.
Es war auf seltsame Weise bewegend, Spielelemente wiederzusehen, die auf die Version von 1984 zurückgehen. Die Schiffe und besonders die Coriolis-Station, die man damals als Vektorgrafik auf einem damals hochmodernen 16K-speicherabgebildeten Bildschirm sah, nun als vollständiges 3D-Rendering in 4K/60fps zu erleben, traf mich emotionaler als erwartet.
Endlich das detaillierte Innere einer Coriolis-Station mit Werbetafeln, Pflanzen und Docking-Ausrüstung zu sehen, hat mir ehrlich gesagt fast die Augen feucht werden lassen. Trotz der aktuellen Schwierigkeiten ist dieses Spiel ein wertvolles Vermächtnis, und ich hoffe, dass es in irgendeiner Form erhalten bleibt.
Ein Raumschiff manuell anzudocken, während Blue Danube lief, war immer eine entspannende Erfahrung.
Ich frage mich, warum Weltraumsimulatoren und Weltraumspiele immer so problematisch werden. Elite Dangerous wirkt, als komme es nirgendwo mehr hin, Star Citizen fühlt sich wie eine ewige Beta an, und KSP2 war ebenfalls enttäuschend.
Meine Gedanken von vor 9 Jahren: https://hypertexthero.com/elite-dangerous-education/
Die Odyssey-Erweiterung macht ebenfalls Spaß, und ich hoffe, dass eines Tages Außenbordeinsätze, Weltraumspaziergänge und Schwerelosigkeitsmissionen dazukommen.
Es gibt auch Elite - The New Kind, eine C-Version, die dem Original weitgehend treu bleibt: https://github.com/fesh0r/newkind
Erstellt von Christian Pinder: https://www.christianpinder.com/games/
Auch Ian Bells Elite-Homepage ist sehenswert; dort gibt es mehrere Originalversionen: http://www.ianbellelite.com/
Der Kern der NES-Version von 1991, also etwa 30 % des 128K-ROMs, ist im Wesentlichen die BBC-Master-Version von 1986, die ihrerseits eine Weiterentwicklung der ursprünglichen BBC-Micro-Version von 1984 ist. Die Commodore-64- und Apple-II-Versionen gehören ebenfalls zu dieser Linie, und die Entwicklung erfolgte auch auf dem BBC Micro
Der größte Teil des Codes in den Banks 0, 1 und 2 wurde direkt aus der ursprünglichen BBC-Version übernommen, und in Bank 7 steckt noch etwas mehr davon. Vorne wurden neue Grafik-, Sound- und Controller-Routinen angehängt, aber das schlagende Herz ist immer noch die Beeb-Version
Ian Bell, der Autor von Elite, sagte, die NES-Version sei seine liebste 8-Bit-Version von Elite
Insgesamt habe er den 32-Bit-Port auf den Archimedes am liebsten gemocht
Das vollständige Interview gibt es unter http://www.elitehomepage.org/archive/b5081501.htm
Ich interpretiere das so, dass seine Lieblingsversion die BBC-Micro-Kassettenversion ist und seine liebste Umsetzung die NES-Version. Allerdings bin ich BBC-Fanboy, also lege ich es vielleicht etwas hoffnungsvoll aus
Mir gefällt, dass am Anfang jeder Bank so ein Bank-Switching-Shim steht
SEI/INC $C006/JMP BEGINEs wird ausführlich erklärt, dass das Platz spart, aber für mich sieht es so aus, als wäre der einzige Grund für das
JMPdie Instruction Pipeline, und als könnte man sie auch einfach mit einemNOPflushenMeine 2-Byte-Optimierung wäre daher:
SEI/INC $FFFD ; nutzt stattdessen das C0 im Befehlsvektor/NOPJMPdie Instruction Pipeline ist“, stimmt zwar, aber es ergibt auch für Menschen Sinn. Die Ausführung beginnt in Bank 7, also springt man zu Bank 7Nebenbei: Beim Game Boy liegt der Entry Point in der festen Bank ROM0, daher gibt es dieses Problem zumindest bei den gängigen MBCs von vornherein nicht
Als Vergleich gibt es den Quellcode von Oolite, einem in Objective-C geschriebenen Open-Source-Elite-Klon: https://github.com/OoliteProject/oolite
https://oolite.space
https://news.ycombinator.com/item?id=7894145
Ich habe das mit 8 Jahren auf dem C64 gespielt. Auch 30 Jahre später verstehe ich diesen Code immer noch nicht
Allein Bank 0 hat 18.305 Zeilen Assembly – ich kann mir nicht einmal vorstellen, wie man das alles im Kopf behalten konnte.
Selbst mit Werkzeugen auf höchstem Niveau hätte es enorme Organisation und Disziplin erfordert, den Code nachzuverfolgen. Ich habe Assembler für den Hitachi 6303[0]/Motorola 6800[1] aus den frühen 80ern untersucht, und es ist erstaunlich, was Menschen unter solchen Werkzeugbeschränkungen geschafft haben.
Zum Beispiel erlaubten die beiden unten genannten Assembler Labels mit nur 6 Zeichen, und es gab auch keine lokalen Labels, die nur innerhalb einer Subroutine galten. Bei meiner Arbeit habe ich Labels der Aussagekraft wegen auf 40 Zeichen begrenzt, und selbst das war schon der Fall.
Allerdings ist die relative Einfachheit solcher Architekturen im Vergleich zur Embedded-Arbeit an modernen Systemen wirklich erfrischend. Dass man den Gesamtzustand des Systems grob im Kopf behalten kann, ist eindeutig ein Vorteil.
0: http://www.bitsavers.org/components/hitachi/_dataBooks/U24_H...
1: http://www.bitsavers.org/components/motorola/6800/exorciser/...
Insgesamt unterscheidet sich Assembly-Programmierung nicht grundlegend von Hochsprachen. Man organisiert Code in Funktionen, Blöcken usw. Eine riesige Wand aus Code mit verschlungenen Sprüngen zu schreiben, bedeutet, sich massive Probleme einzuhandeln.
Schade, dass es keine freie Software ist. Wenn ich der Schöpfer von Elite wäre, hätte ich alle Portierungen des Spiels unter einer freien Lizenz veröffentlicht.
Jedenfalls kann man heutzutage Oolite auf einem günstigen Netbook spielen und dank der riesigen Add-on-Liste genauso viel oder sogar noch mehr Spaß haben.
Brabens Seite arbeitete damals wohl an Elite 4/Elite: Dangerous und wollte das Urheberrecht nicht schwächen.
Jeder Quellcode sollte in diesem Maß dokumentiert sein