NES Elite — Code source documenté d’Elite pour NES
(github.com/markmoxon)- Code source de Elite pour NES, par Ian Bell et David Braben, documenté ligne par ligne, avec des explications pour la plupart des lignes, et reconstruit manuellement à partir du désassemblage du binaire original du jeu
- Permet de compiler, depuis le source sur des ordinateurs modernes, un jeu entièrement fonctionnel et de générer une image ROM iNES chargeable sur une vraie NES ou dans un émulateur
- Les variantes prises en charge sont la variante PAL d’Imagineer et la variante NTSC du site personnel d’Ian Bell ; la compilation par défaut utilise la variante PAL
- Pour explorer le source, on peut le consulter sous une forme lisible sur elite.bbcelite.com ou ouvrir le source annoté dans un IDE ; le contenu du site web et des fichiers source est identique
- Les prérequis de compilation sont BeebAsm, Python et
makesur Mac/Linux ; la compilation Python n’a été testée qu’avec Python 3.x, et Windows inclutmake.exe- Sous Windows, la compilation se fait avec
make.bat, et sous Mac/Linux avecmake; la sortie par défaut estelite-pal.NESdans le dossier5-compiled-rom-images variant=ntscpermet de générerelite-ntsc.NES
- Sous Windows, la compilation se fait avec
- Les options de compilation contrôlent notamment le choix de la variante, l’utilisation d’un commander de test proche du maximum, l’omission de la correspondance avec le binaire original et la désactivation de la vérification crc32
- Exemple représentatif :
make variant=ntsc commander=max match=no verify=no crc32.pycompare côte à côte les checksums et tailles de fichier du fichier généré et du fichier de référence extrait des sources originales
- Exemple représentatif :
- Les variantes PAL et NTSC diffèrent notamment par le nombre de cycles du gestionnaire NMI, l’en-tête Imagineer/Nintendo de l’écran de démarrage, le temps d’attente de l’auto-play de la démo de combat, l’algorithme de checksum des emplacements de sauvegarde, le numéro de version interne, le message de copyright caché, le texte défilant et des constantes de coordonnée y
- La variante NTSC ne fonctionne pas sur du matériel NTSC réel ; il s’agit d’une émulation NTSC dont le timing NMI a été modifié pour correspondre au mode NTSC de certains émulateurs
- Aucun fichier de licence n’est fourni ; le droit d’auteur par défaut s’applique, ce qui n’autorise que la lecture et le fork, tandis que la reproduction, la distribution et la création d’œuvres dérivées ne sont pas autorisées
1 commentaires
Avis de Hacker News
Il y a longtemps, quand je travaillais chez Frontier, David Braben m’a raconté une anecdote intéressante à propos de NES Elite. Dans mon souvenir, au départ, le jeu utilisait le timer matériel de la NES pour suivre le temps réel, afin que la physique avance de façon constante même si le framerate variait.
Lors des contrôles de pré-lancement de Nintendo, certaines premières NES auraient été jugées incompatibles parce que ce timer ne fonctionnait pas correctement ; on m’a dit que Bell/Braben avaient alors fait en sorte que chaque fonction conserve sa propre estimation du nombre de cycles d’horloge utilisés pendant la frame, puis que ces valeurs soient additionnées en fin de frame pour estimer le temps écoulé.
Mais en regardant le code source sur GitHub, il semble que je me sois mal souvenu, ou que je n’aie pas bien compris ce que Braben disait. Dans
elite-source-bank-7.asm, un commentaire indique : « met à jour le timer NMI utilisable à la place du timer matériel que la NES ne prend pas en charge », et il semble qu’ils aient implémenté une sorte d’horloge temps réel en comptant les interruptions non masquables.Les premières puces CPU de la NES contenaient les vestiges bogués et désactivés d’un timer à intervalle programmable : https://www.nesdev.org/wiki/RP2A03_Programmable_Interval_Tim...
Il a été complètement supprimé dans les révisions ultérieures, et il est possible qu’il ait été activé uniquement dans des environnements comme les kits de développement. Si un jeu dépendait d’une fonctionnalité qui ne marchait pas sur les machines grand public, il était logique qu’il soit refusé aux tests de Nintendo.
Même si les consoles commercialisées avaient eu un timer à intervalle programmable, il n’aurait vraiment été utile que pour des mesures sous-frame, comme des effets raster précis. Pour mesurer le temps réel, le comptage des NMI est beaucoup plus pertinent. Une NMI se produit au début de chaque frame vidéo, à une fréquence très stable de 60,0988 Hz, et même si le moteur du jeu ralentit et que le framerate varie, le traitement côté CPU ne peut pas affecter le timing du signal vidéo.
À noter que le matériel audio peut aussi générer des interruptions de timer, et que beaucoup de puces d’extension disposent de compteurs de scanlines pour synchroniser le rendu. Les façons de mesurer le temps ne manquent pas sur NES.
Lorsqu’ils essayaient de faire approuver un jeu par Nintendo, on leur aurait dit qu’il ne fonctionnait pas sur une version particulière de la NES américaine, ou qu’il provoquait une surchauffe du système. Le calendrier de sortie était serré, donc il avait dû prendre l’avion jusqu’au siège de Nintendo pour résoudre le problème ; dans mon souvenir, cette version particulière avait été distribuée à moins de 100 exemplaires.
J’ai retrouvé plus tard des notes pour un livre non publié, et en réalité c’était un peu différent. Les tests des jeux ne se limitaient pas au gameplay : il fallait les tester sur toutes les variantes de consoles NES capables de les exécuter. Andrew Davie, de Beam Software, se souvenait s’être rendu en personne dans les bureaux de Nintendo à Washington parce que “The Three Stooges” posait problème sur une NES utilisée pour les tests.
Il disait qu’il y avait « environ 23 variantes de machines » à valider, avec différentes combinaisons de fabricants de puces, et qu’en raison du manque de documentation officielle, il avait fait en sorte que les données de sprites soient écrites directement toutes les 2 secondes au lieu de les écrire en RAM comme officiellement recommandé, ce qui faisait trop chauffer la NES et provoquait du clignotement de sprites dans tout le jeu. Après correction, le jeu a été approuvé pour sortie ; on lui aurait dit que la combinaison de NES en question n’existait qu’à environ 5 exemplaires dans tous les États-Unis, et qu’elle avait été retirée de la batterie de tests de Nintendo.
J’ai récemment commencé la suite, Elite: Dangerous. Elle n’est pas sans défauts, mais c’est une expérience assez incroyable.
Voir des éléments de jeu hérités de la version de 1984 m’a étrangement ému. Les vaisseaux, et surtout les stations Coriolis, que l’on voyait à l’époque en graphismes vectoriels sur un écran à mappage mémoire de 16 Ko dernier cri, transformés en rendu 3D complet en 4K/60 fps : c’était plus touchant que je ne m’y attendais.
Découvrir enfin l’intérieur détaillé d’une Coriolis, avec panneaux publicitaires, plantes et équipement d’amarrage, m’a honnêtement presque mis les larmes aux yeux. Malgré ses difficultés actuelles, ce jeu est un héritage précieux, et j’espère qu’il continuera d’exister sous une forme ou une autre.
S’amarrer manuellement à une station en écoutant Blue Danube a toujours été une expérience apaisante.
Je me demande pourquoi les simulateurs et jeux spatiaux finissent toujours avec autant de problèmes. Elite Dangerous donne l’impression de ne plus aller nulle part, Star Citizen ressemble à une bêta éternelle, et KSP2 a aussi été décevant.
Mes réflexions écrites il y a 9 ans : https://hypertexthero.com/elite-dangerous-education/
L’extension Odyssey est aussi amusante, et j’aimerais qu’un jour ils ajoutent des sorties extravéhiculaires dans l’espace et des missions en apesanteur.
Il existe aussi Elite - The New Kind, une version en C presque fidèle à l’original : https://github.com/fesh0r/newkind
Créée par Christian Pinder : https://www.christianpinder.com/games/
La page d’accueil Elite d’Ian Bell vaut aussi le détour, avec plusieurs versions originales : http://www.ianbellelite.com/
Le cœur de la version NES de 1991, soit environ 30 % de la ROM de 128K, est essentiellement la version BBC Master de 1986, elle-même une évolution de la version BBC Micro originale de 1984. Les versions Commodore 64 et Apple II appartiennent à la même lignée, et le développement s’est aussi fait sur BBC Micro
La majeure partie du code des banques 0, 1 et 2 vient directement de la version BBC originale, avec quelques morceaux supplémentaires dans la banque 7. De nouvelles routines graphiques, sonores et de contrôleur ont été greffées devant, mais le cœur qui bat reste la version Beeb
Ian Bell, l’auteur d’Elite, a dit que la version NES était sa version 8 bits d’Elite préférée
Globalement, il aurait préféré le portage 32 bits sur Archimedes
L’interview complète se trouve ici : http://www.elitehomepage.org/archive/b5081501.htm
J’interprète cela comme voulant dire que sa version préférée est la version cassette BBC Micro, et que sa conversion préférée est la version NES. Mais je suis peut-être un fanboy de la BBC et j’interprète ça de manière optimiste
J’aime bien le fait qu’il y ait ce genre de shim de changement de banque au début de chaque banque
SEI/INC $C006/JMP BEGINL’explication détaille que c’est fait pour économiser de l’espace, mais à mes yeux la seule raison pour laquelle le
JMPest nécessaire tient au pipeline d’instructions, et il me semble qu’un simpleNOPpourrait suffire à le viderDonc mon optimisation de 2 octets serait :
SEI/INC $FFFD ; utilise à la place le C0 dans le vecteur d’instruction/NOPJMPest nécessaire tient au pipeline d’instructions » est juste, mais cela a aussi du sens pour un humain. L’exécution commence dans la banque 7, donc on saute vers la banque 7À côté de ça, sur Game Boy, le point d’entrée se trouve dans ROM0, la banque fixe, donc au moins avec les MBC courants ce problème ne se pose pas dès le départ
Comme point de comparaison, il y a le code source d’Oolite, un clone open source d’Elite écrit en Objective-C : https://github.com/OoliteProject/oolite
https://oolite.space
https://news.ycombinator.com/item?id=7894145
J’y ai joué sur C64 quand j’avais 8 ans. Trente ans plus tard, je ne comprends toujours pas ce code
Rien que la banque 0 compte 18 305 lignes d’assembleur ; je n’arrive même pas à imaginer comment on pouvait garder tout ça en tête
Même avec des outils de tout premier ordre, suivre le code devait demander une organisation et une discipline énormes. J’ai étudié des assembleurs du début des années 80 pour Hitachi 6303[0]/Motorola 6800[1], et ce que les gens ont accompli avec de telles contraintes d’outillage est impressionnant.
Par exemple, les deux assembleurs ci-dessous limitaient les labels à 6 caractères seulement, et n’avaient pas non plus de labels locaux réservés à l’intérieur d’une sous-routine. Dans mon travail, j’avais limité les labels à 40 caractères pour qu’ils restent descriptifs, et c’était déjà le cas.
Cela dit, la relative simplicité de ces architectures est vraiment rafraîchissante par rapport au travail embarqué sur les systèmes modernes. Pouvoir garder à peu près tout l’état du système en tête est clairement un avantage.
0: http://www.bitsavers.org/components/hitachi/_dataBooks/U24_H...
1: http://www.bitsavers.org/components/motorola/6800/exorciser/...
Globalement, la programmation en assembleur n’est pas si différente des langages de haut niveau. On organise le code en fonctions, en blocs, etc. Écrire un immense mur de code avec des sauts entremêlés, c’est s’attirer de sérieux problèmes
Dommage que ce ne soit pas du logiciel libre. Si j’avais été le créateur d’Elite, j’aurais publié tous les portages du jeu sous licence libre.
Quoi qu’il en soit, aujourd’hui on peut jouer à Oolite sur un netbook bon marché et, grâce à l’immense liste d’extensions, y prendre autant, voire plus de plaisir
Côté Braben, il semble qu’il ne voulait pas affaiblir ses droits d’auteur, puisqu’il travaillait sur Elite 4/Elite: Dangerous
Tout code source devrait être documenté à ce niveau