Mise à jour, 28 juin 2021: Ars a été attristé d’apprendre que l’auteur de cette pièce, qui a également utilisé la poignée Near dans les interactions en ligne, se serait suinté au cours du week-end. Nous republions cette pièce aujourd’hui en mémoire de leurs contributions imposantes à la communauté d’émulation de jeu classique et à Ars. Vous pouvez également lire leur pièce de 2011 sur la quête de précision dans le développement de bsnes.
Si vous ou quelqu’un que vous connaissez êtes aux prises avec des pensées suicidaires, veuillez communiquer avec la Ligne de vie nationale pour la prévention du suicide au 800-273-8255, ou contacter une ligne d’assistance internationale similaire. Nous encourageons également les lecteurs à faire un don à l’American Federation for Suicide Prevention s’ils sont ainsi émus.
En tant que codeur principal de bsnes, J’ai essayé de perfectionner l’émulation super nintendo au cours des 15 dernières années. Nous sommes maintenant à un point où cet objectif est en vue, mais là, nous sommes confrontés à un dernier défi: la synchronisation précise du cycle des processeurs vidéo SNES. Obtenir ce dernier peu de précision d’émulation nécessitera un effort communautaire que j’espère que certains d’entre vous pourront aider. Mais d’abord, permettez-moi de récapituler le chemin que nous avons parcouru.
Où nous en sommes
Aujourd’hui, l’émulation SNES est dans une très bonne place. À l’exception des périphériques inhabituels qui résistent à l’émulation (tels que un club de golf basé sur un capteur de lumièreun vélo d’exerciceou un modem d’accès à distance utilisé pour placer des paris en argent réel sur des courses de chevaux en direct au Japon), chaque titre SNES sous licence officielle est entièrement jouable, et aucun jeu n’est connu pour avoir des problèmes flagrants.
L’émulation SNES est devenue si précise que j’ai même pris à diviser mon émulateur en deux versions: higan, qui met l’accent sur la précision absolue et la documentation matérielle; et bsnes, qui se concentre sur les performances, les fonctionnalités et la facilité d’utilisation.
Certaines choses étonnantes sont sorties de l’émulation SNES récemment, notamment:
… et bien plus encore !
Alors, c’est tout, non? Bravo pour un travail bien fait, merci pour tous les poissons? puits… presque.
Aujourd’hui, nous bénéficions d’une précision au niveau du cycle pour presque tous les composants du SNES. La seule exception est les PPU (unités de traitement d’images), qui sont utilisés pour générer les images vidéo envoyées à votre écran. nous surtout savoir comment fonctionnent les PPU, mais nous devons faire des suppositions pour certaines fonctionnalités qui se traduisent par une perfection moins que totale.
Les questions restantes sont relativement petites, dans le grand ordre des choses. Si vous n’êtes pas intéressé par la poursuite de la perfection d’émulation à cent pour cent fidèle pour elle-même, je ne vais pas être en mesure de vous convaincre de la nécessité d’améliorer davantage l’émulation SNES PPU. Comme pour tout objectif dans la vie, plus nous nous rapprochons de la perfection, plus les rendements sont faibles.
Je peux vous dire pourquoi c’est important pour me: c’est l’œuvre de ma vie, et je ne veux pas avoir à dire que je suis venu cette clôture à finir sans obtenir la dernière pièce de celui-ci droit. Je vieillis et je ne serai pas là pour toujours. Je veux que cette dernière pièce soit résolue afin que je puisse me sentir confiant dans ma retraite que le SNES a été fidèlement et complètement préservé par émulation. Aucune pierre n’a été laissée en l’état, aucune zone n’a été laissée inachevée. Je veux dire que c’est fait.
Si vous êtes toujours intrigué, lisez la suite pour une plongée profonde dans le contexte du problème et des solutions que je propose.
Modélisation de la conception SNES
Commençons par jeter un coup d’œil aux composants qui composent le SNES:
Les flèches indiquent la direction dans laquelle les différents processeurs du SNES peuvent communiquer entre eux, et les lignes pointillées représentent les connexions de puce mémoire.
La chose clé à retenir dès maintenant est de noter que la sortie vidéo et audio est envoyée directement à partir du PPU et du DSP spécifiquement. Cela signifie qu’ils fonctionnent comme des « boîtes noires » où nous n’avons aucune visibilité sur ce qui se passe à l’intérieur. Ce sera important plus tard.
exactitude
Imaginez que vous émulez l’instruction « multiply » d’un processeur, qui prend deux registres (variables), les multiplie ensemble et produit un résultat et quelques indicateurs qui représentent l’état du résultat (tels que déborder).
Nous pourrions concevoir un logiciel qui multiplie chaque valeur possible de 0 à 255 comme multiplicateur et multiplicand. Ensuite, nous pourrions sortir à la fois les résultats numériques et les résultats d’indicateur de la multiplication. Cela produirait deux tables de 65 536 entrées.
En analysant ces tables, nous avons pu déterminer exactement comment et quand les résultats du processeur ont été définis de certaines manières. Ensuite, nous pourrions modifier nos émulateurs afin que, lors de l’exécution du même test, nous produisions exactement les mêmes tables aux mêmes moments.
Maintenant, disons que le processeur avait des multiplications 16 bits x 16 bits. Tester chaque valeur possible générerait 4 milliards de résultats, ce qui commence à pousser ce qui est pratique à tester dans un laps de temps raisonnable. Si le processeur avait des multiplications 32 bits x 32 bits, il ne serait pas pratique de tester toutes les combinaisons d’entrées avant la mort thermique de l’univers (avec la technologie actuelle, au moins).
Dans de tels cas, nous devrons être plus sélectifs avec nos tests et essayer de déterminer exactement quand les indicateurs peuvent changer, quand les résultats peuvent déborder, etc. Sinon, nous aurions des tests qui ne se termineraient jamais.
La multiplication est une opération assez triviale, mais il s’agit du processus général derrière l’ingénierie inverse, et elle s’étend à des opérations plus complexes telles que le fonctionnement des transferts DMA (accès direct à la mémoire) d’effacement horizontal du SNES. Nous créons des tests qui tentent de détecter ce qui se passe sur les cas limites, puis confirmons que notre émulation se comporte de la même manière qu’un SNES réel.
Oscillateurs et cycles
Le SNES contient deux oscillateurs: une horloge à cristal qui fonctionne à ~ 21MHz, qui contrôle le processeur et les PPU; et un résonateur en céramique qui fonctionne à ~ 24MHz, qui contrôle le SMP et le DSP. Les coprocesseurs de cartouche utiliseront parfois l’oscillateur du processeur ~ 21MHz et incluent parfois leurs propres oscillateurs qui fonctionnent à différentes fréquences.
Une horloge est l’élément de synchronisation de base de tout système, et le SNES est conçu pour effectuer diverses tâches à certaines fréquences et heures.
Si vous imaginez une horloge 100Hz, c’est un appareil avec une broche numérique qui passe à la logique haute (+ 5 volts, par exemple), puis revenir à la logique basse (0 volts, ou terre) 100 fois par seconde. Ainsi, chaque seconde, la tension de la broche fluctuera 200 fois au total: 100 bords d’horloge ascendants et 100 bords d’horloge en baisse.
Un cycle d’horloge est généralement traité comme une transition complète, de sorte qu’une horloge de 100 Hz générerait 100 cycles d’horloge par seconde. Il existe certains systèmes qui nécessitent de faire la distinction entre les bords ascendants et tombants, et pour ceux-ci, nous décomposons cela plus bas en demi-cycles pour indiquer chaque phase (haute ou basse) du signal d’horloge.
L’objectif principal d’un émulateur authentique est d’effectuer des tâches exactement de la même manière et exactement aux mêmes moments que le matériel réel. Cela n’a pas beaucoup d’importance en particulier comment les tâches sont effectuées. Tout ce qui compte, c’est que l’émulateur, lorsqu’il reçoit les mêmes entrées, génère les mêmes sorties avec le même timing que le matériel réel.
timing
Parfois, les opérations se produisent au fil du temps. Prenez la multiplication du processeur SNES, par exemple. Plutôt que de s’arrêter pour attendre la fin de la multiplication, le processeur SNES calcule le résultat de la multiplication un bit à la fois en arrière-plan sur huit cycles d’opcode du processeur. Cela permet à votre code d’effectuer éventuellement d’autres opérations en attendant la multiplication.
Tout logiciel commercialisé est susceptible d’attendre ces huit cycles, parce que si vous essayez de lire le résultat avant qu’il ne soit prêt, vous obtiendrez un résultat partiellement calculé à la place. Pourtant, les émulateurs SNES antérieurs donnaient des résultats corrects immédiatement, sans attendre ces cycles supplémentaires.
Lorsque les amateurs ont commencé à créer et à tester le logiciel homebrew via des émulateurs, cet écart a commencé à causer des problèmes. Certains de ces logiciels, comme beaucoup de début Super Mario Monde Hacks ROM, seulement travaillé correctement sur ces émulateurs antérieurs, et non sur le matériel SNES réel. C’est parce qu’ils ont été conçus avec les résultats de multiplication immédiats (et inauthentiques à réels-matériel) de l’émulateur à l’esprit.
Au fur et à mesure que les émulateurs s’amélioraient, cet ancien logiciel s’est cassé et nous avons dû par la suite offrir des options de compatibilité dans our émulateurs plus récents afin de ne pas perdre ce logiciel à temps. Oui, aussi surréaliste que ce soit de dire, de nos jours, nos émulateurs doivent émuler d’autres émulateurs! Comme c’est méta!
La bonne chose à propos du délai de multiplication du processeur est qu’il est très prévisible: les huit cycles de calcul commencent immédiatement après avoir demandé une multiplication. En écrivant du code pour lire les résultats après chaque cycle, nous avons pu confirmer que le processeur SNES utilisait le cabine algorithme pour la multiplication.
Synchronisation de l’horloge
D’autres opérations ne sont pas si simples à modéliser, car elles se produisent de façon asynchrone en arrière-plan. L’actualisation de la DRAM de la CPU SNES est l’un de ces cas.
Pendant le rendu de chaque ligne de balayage, à un certain point, l’ensemble du processeur SNES se fige pendant une courte durée à mesure que le contenu de la puce RAM est actualisé. Cela est nécessaire car, comme mesure de réduction des coûts, le SNES a utilisé la RAM dynamique (plutôt que la RAM statique) pour sa mémoire cpu principale. La RAM dynamique doit être actualisée périodiquement afin de préserver son contenu au fil du temps.
L’idée clé pour déterminer le calendrier précis de ces opérations était de tirer parti des compteurs horizontaux et verticaux du PPU SNES. Ces compteurs avancent et sont réinitialisés après chaque période d’effacement horizontal et vertical. Cependant, leur précision n’est que d’un quart de la fréquence de l’oscillateur CPU de la SNES; c’est-à-dire que le compteur horizontal ne s’incrémente qu’une fois tous les quatre cycles d’horloge.
En lisant les compteurs plusieurs fois, j’ai pu déterminer avec quel quart d’un cycle d’horloge le compteur était aligné. En combinant cet aperçu avec une fonction spécialement conçue qui pourrait passer par un nombre précis et spécifié par l’utilisateur de cycles d’horloge, il est devenu possible d’aligner parfaitement le processeur SNES à n’importe quelle position exacte du cycle d’horloge que je voulais.
En itérant sur une plage de cycles d’horloge dans une boucle, je pouvais déterminer exactement quand certaines opérations (telles que l’actualisation de la DRAM, les transferts HDMA, l’interrogation d’interruption, etc.) se produiraient, et j’ai pu reproduire cela précisément sous émulation.
Le SNES Puce SMP a également ses propres minuteries, et l’ingénierie inverse similaire a également réussi contre ce processeur. Je pourrais passer un article entier à parler du seul registre SMP TEST, qui permet aux codeurs de contrôler le diviseur d’horloge du SMP et ses minuteries, entre autres choses horribles. Il suffit de dire que, même si ce n’était pas un processus facile ou rapide, nous avons finalement été victorieux.
Collecte des coprocesseurs
Il y avait toute une série de coprocesseurs SNES utilisés à l’intérieur de diverses cartouches de jeu qui devaient également être apprivoisées. À partir de processeurs dédiés à usage général comme le SuperFX et SA-1, aux processeurs de signaux numériques comme le DSP-1 et le Cx4, aux accélérateurs de décompression comme le S-DD1 et le SPC7110, aux horloges en temps réel de Sharp et Epson, et plus encore…
Cela signifie qu’un émulateur SNES doit être en mesure de gérer les caches d’instructions et de pixels du SuperFX ; l’arbitre de conflit de bus mémoire du SA-1 (qui permettait au processeur SNES et au SA-1 de partager simultanément les mêmes puces ROM et RAM); le firmware intégré des DSP-1 et Cx4; les codeurs arithmétiques basés sur la prédiction des S-DD1 et SPC7110; et les cas limites BCD (décimales codées binaire) impairs des horloges en temps réel. Lentement mais sûrement, en appliquant les techniques ci-dessus pour déterminer l’exactitude et le timing, nous avons pu émuler presque parfaitement toutes ces puces.
Il a en fait fallu un effort massif et des milliers de dollars pour décapiter et extraire le firmware de programmation des processeurs de signaux numériques utilisés dans divers jeux. Dans un cas, l’émulation du NEC uPD772x a conduit à code de higan utilisé pour sauver la voix du regretté professeur Stephen Hawking!
Dans un autre cas, nous avons dû désosser l’ensemble du jeu d’instructions de l’architecture Hitachi HG51B, car cette architecture n’a jamais été documentée publiquement. Dans un autre encore, un jeu (Hayazashi Nidan Morita Shougi 2) a fini par contenir un processeur ARM6 32 bits 21 MHz à part entière pour accélérer son moteur d’échecs japonais!
La préservation de tous les coprocesseurs SNES à elle seule a été un voyage de plusieurs années rempli de défis et de surprises.
Traitement du signal numérique
À ne pas confondre avec le coprocesseur de cartouche DSP-1, la puce S-DSP (processeur de signal numérique) de Sony est ce qui a généré le son distinctif du SNES. Cette puce combinait huit canaux vocaux avec un encodage ADPCM 4 bits pour produire un signal stéréo 16 bits.
En surface, et selon le diagramme système de plus tôt, le DSP ressemble initialement à une boîte noire: vous configurez les canaux vocaux et les paramètres de la table de mixage et vous vous asseyez pendant qu’il génère le son à envoyer à vos haut-parleurs.
Mais une caractéristique clé a permis à un développeur du nom de blargg de désosser entièrement cette puce : le tampon d’écho. Le DSP SNES a une caractéristique qui mélange les sorties des échantillons précédents ensemble pour produire un effet d’écho. Cela se produit à la toute fin du processus de génération audio (à l’exception d’un dernier indicateur de sourdine qui peut être appliqué pour faire taire toute la sortie audio.)
En écrivant du code soigneusement chronométré et en surveillant ces résultats d’écho, il est devenu possible de découvrir l’ordre exact des opérations que le DSP SNES prendrait pour générer chaque échantillon et produire un son précis et parfait.