emulation - roms - émulation positive




Comment fonctionnent les émulateurs et comment sont-ils écrits? (11)

Les émulateurs sont très difficiles à créer car il existe de nombreux hacks (comme dans les effets inhabituels), des problèmes de synchronisation, etc. que vous devez simuler.

Pour un exemple de ceci, voir http://queue.acm.org/detail.cfm?id=1755886 .

Cela vous montrera également pourquoi vous avez besoin d'un processeur multi-GHz pour émuler un processeur à 1 MHz.

Comment fonctionnent les émulateurs? Quand je vois des émulateurs NES / SNES ou C64, ça m'étonne.

Avez-vous besoin d'émuler le processeur de ces machines en interprétant ses instructions de montage particulières? Qu'y a-t-il d'autre? Comment sont-ils typiquement conçus?

Pouvez-vous donner des conseils à quelqu'un qui aimerait écrire un émulateur (en particulier un système de jeu)?


Ayant créé mon propre émulateur du micro-ordinateur BBC des années 80 (tapez VBeeb dans Google), il y a un certain nombre de choses à savoir.

  • Vous n'imitez pas la vraie chose en tant que telle, ce serait une réplique. Au lieu de cela, vous imitez l' état . Un bon exemple est une calculatrice, la chose réelle a des boutons, écran, cas, etc Mais pour émuler une calculatrice, il suffit d'émuler si les boutons sont en haut ou en bas, quels segments de LCD sont allumés, etc Fondamentalement, un ensemble de chiffres représentant toutes les combinaisons possibles de choses qui peuvent changer dans une calculatrice.
  • Vous avez seulement besoin que l'interface de l'émulateur apparaisse et se comporte comme la vraie chose. Plus cela est convaincant, plus l'émulation est proche. Ce qui se passe dans les coulisses peut être tout ce que vous aimez. Mais, pour faciliter l'écriture d'un émulateur, il existe une correspondance mentale entre le système réel, c'est-à-dire les puces, les affichages, les claviers, les cartes de circuits imprimés et le code informatique abstrait.
  • Pour émuler un système informatique, il est plus facile de le décomposer en plus petits morceaux et de les émuler individuellement. Puis enchaîner le lot ensemble pour le produit fini. Tout comme un ensemble de boîtes noires avec des entrées et des sorties, qui se prête magnifiquement à la programmation orientée objet. Vous pouvez subdiviser ces morceaux pour faciliter la vie.

Pratiquement parlant, vous cherchez généralement à écrire pour la rapidité et la fidélité de l'émulation. En effet, le logiciel sur le système cible fonctionnera (peut-être) plus lentement que le matériel d'origine sur le système source. Cela peut limiter le choix du langage de programmation, des compilateurs, du système cible, etc.
En plus de cela, vous devez circonscrire ce que vous êtes prêt à émuler, par exemple il n'est pas nécessaire d'émuler l'état de tension des transistors dans un microprocesseur, mais il est probablement nécessaire d'émuler l'état du registre du microprocesseur.
En général, plus le niveau de détail de l'émulation est petit, plus la fidélité au système d'origine sera grande.
Enfin, les informations sur les systèmes plus anciens peuvent être incomplètes ou inexistantes. Il est donc essentiel de s'emparer de l'équipement d'origine, ou du moins de mettre à part un autre bon émulateur que quelqu'un d'autre a écrit!


Consultez également Emulators.com Darek Mihocka pour obtenir de précieux conseils sur l'optimisation des niveaux d'instruction pour les JIT, et de nombreuses autres astuces pour créer des émulateurs efficaces.


Des conseils pour émuler un vrai système ou votre propre truc? Je peux dire que les émulateurs fonctionnent en émulant le matériel ENTIER. Peut-être pas sur le circuit (comme déplacer des bits comme le ferait le HW. Déplacer l'octet est le résultat final donc la copie de l'octet est bien). Les émulateurs sont très difficiles à créer car il existe de nombreux hacks (comme dans les effets inhabituels), des problèmes de synchronisation, etc. que vous devez simuler. Si une pièce (en entrée) est erronée, tout le système peut le faire vers le bas ou, au mieux, avoir un bug / pépin.


J'ai écrit un article sur l'émulation du système Chip-8 en JavaScript .

C'est un bon point de départ car le système n'est pas très compliqué, mais vous apprenez toujours comment fonctionnent les opcodes, la pile, les registres, etc.

Je vais bientôt écrire un guide plus long pour la NES.


Je n'ai jamais rien fait d'aussi sophistiqué que d'émuler une console de jeu, mais j'ai suivi un cours où l'on devait écrire un émulateur pour la machine décrite dans Andrew Tanenbaums Structured Computer Organisation . C'était amusant et m'a donné beaucoup de moments aha. Vous voudrez peut-être choisir ce livre avant de plonger dans l'écriture d'un vrai émulateur.


L' émulateur de périphérique Shared Source contient du code source pouvant être assemblé vers un émulateur PocketPC / Smartphone (nécessite Visual Studio, s'exécute sous Windows). J'ai travaillé sur V1 et V2 de la version binaire.

Il aborde de nombreux problèmes d'émulation: - traduction d'adresse efficace de invité virtuel à invité physique à hôte virtuel - compilation JIT de code invité - simulation de périphériques tels que cartes réseau, écran tactile et audio - interface utilisateur, pour clavier et souris hôte - save / rétablissement de l'état, pour la simulation de la reprise du mode basse consommation


L'émulation est un domaine à plusieurs facettes. Voici les idées de base et les composants fonctionnels. Je vais le découper en morceaux et ensuite remplir les détails via des modifications. Beaucoup de choses que je vais décrire nécessiteront une connaissance du fonctionnement interne des processeurs - la connaissance de l'assemblage est nécessaire. Si je suis un peu trop vague sur certaines choses, posez des questions afin que je puisse continuer à améliorer cette réponse.

Idée basique:

L'émulation fonctionne en gérant le comportement du processeur et des composants individuels. Vous construisez chaque pièce du système, puis reliez les pièces comme les fils dans le matériel.

Émulation du processeur:

Il y a trois façons de gérer l'émulation du processeur:

  • Interprétation
  • Recompilation dynamique
  • Recompilation statique

Avec tous ces chemins, vous avez le même objectif général: exécuter un morceau de code pour modifier l'état du processeur et interagir avec le 'matériel'. L'état du processeur est un conglomérat des registres du processeur, des gestionnaires d'interruption, etc. pour une cible de processeur donnée. Pour le 6502, vous auriez un nombre d'entiers de 8 bits représentant les registres: A , X , Y , P et S ; vous auriez aussi un registre PC 16 bits.

Avec l'interprétation, vous démarrez à l' IP (pointeur d'instruction - également appelé PC , compteur de programme) et lisez l'instruction de la mémoire. Votre code analyse cette instruction et utilise cette information pour modifier l'état du processeur tel que spécifié par votre processeur. Le problème principal de l'interprétation est que c'est très lent. chaque fois que vous manipulez une instruction donnée, vous devez la décoder et effectuer l'opération requise.

Avec la recompilation dynamique, vous itérez sur le code un peu comme l'interprétation, mais au lieu de simplement exécuter des opcodes, vous créez une liste d'opérations. Une fois que vous avez atteint une instruction de branchement, vous compilez cette liste d'opérations en code machine pour votre plate-forme hôte, puis vous mettez en cache ce code compilé et l'exécutez. Ensuite, lorsque vous cliquez à nouveau sur un groupe d'instructions donné, vous n'avez qu'à exécuter le code à partir du cache. (BTW, la plupart des gens ne font pas vraiment une liste d'instructions mais les compilent au code machine à la volée - ceci rend plus difficile à optimiser, mais c'est hors de portée de cette réponse, à moins que suffisamment de gens soient intéressés)

Avec la recompilation statique, vous faites la même chose que dans la recompilation dynamique, mais vous suivez les branches. Vous finissez par construire un morceau de code qui représente tout le code dans le programme, qui peut ensuite être exécuté sans autre interférence. Ce serait un bon mécanisme s'il n'y avait pas les problèmes suivants:

  • Le code qui n'est pas dans le programme pour commencer (par exemple compressé, crypté, généré / modifié au moment de l'exécution, etc.) ne sera pas recompilé, donc il ne fonctionnera pas
  • Il a été prouvé que trouver tout le code dans un binaire donné est équivalent au problème d'Halting

Ceux-ci se combinent pour rendre la recompilation statique complètement impossible dans 99% des cas. Pour plus d'informations, Michael Steil a fait de bonnes recherches sur la recompilation statique - le meilleur que j'ai vu.

L'autre côté de l'émulation du processeur est la façon dont vous interagissez avec le matériel. Cela a vraiment deux côtés:

  • Minutage du processeur
  • Manipulation d'interruption

Moment du processeur:

Certaines plates-formes - en particulier les anciennes consoles comme le NES, SNES, etc - exigent que votre émulateur ait un timing strict pour être complètement compatible. Avec le NES, vous avez le PPU (pixel processing unit) qui nécessite que le CPU mette des pixels dans sa mémoire à des moments précis. Si vous utilisez l'interprétation, vous pouvez facilement compter les cycles et émuler le bon timing; avec la recompilation dynamique / statique, les choses sont un / lot / plus complexe.

Manipulation d'interruption:

Les interruptions sont le mécanisme principal que la CPU communique avec le matériel. Généralement, vos composants matériels indiqueront au CPU les interruptions qui l'intéressent. C'est assez simple - quand votre code lance une interruption donnée, vous regardez la table du gestionnaire d'interruption et appelez le rappel approprié.

Émulation matérielle

Il y a deux côtés pour émuler un périphérique matériel donné:

  • Émuler la fonctionnalité de l'appareil
  • Emulation des interfaces de périphérique réelles

Prenons le cas d'un disque dur. La fonctionnalité est émulée en créant le stockage de sauvegarde, les routines de lecture / écriture / format, etc. Cette partie est généralement très simple.

L'interface réelle de l'appareil est un peu plus complexe. Il s'agit généralement d'une combinaison de registres mappés en mémoire (par exemple, des parties de la mémoire que l'appareil surveille pour les changements de signalisation) et des interruptions. Pour un disque dur, vous pouvez avoir une zone mappée en mémoire dans laquelle vous placez des commandes de lecture, des écritures, etc., puis relisez ces données.

J'y reviendrai plus en détail, mais il y a un million de façons de le faire. Si vous avez des questions spécifiques ici, n'hésitez pas à demander et je vais ajouter les informations.

Ressources:

Je pense que j'ai donné une bonne introduction ici, mais il y a une tonne de zones supplémentaires. Je suis plus qu'heureux d'aider avec des questions; J'ai été très vague dans la plupart de ceci simplement en raison de l'immense complexité.

Liens obligatoires de Wikipédia:

Ressources générales d'émulation:

  • Zophar - C'est là que j'ai commencé à émuler, en téléchargeant d'abord des émulateurs et en finissant par piller leurs immenses archives de documentation. C'est la meilleure ressource absolue que vous pouvez éventuellement avoir.
  • NGEmu - Pas beaucoup de ressources directes, mais leurs forums sont imbattables.
  • RomHacking.net - La section des documents contient des ressources concernant l'architecture de la machine pour les consoles populaires

Projets d'émulateur pour référence:

  • IronBabel - Il s'agit d'une plate-forme d'émulation pour .NET, écrite en Nemerle et recompile le code en C # à la volée. Disclaimer: Ceci est mon projet, alors pardonnez la prise éhontée.
  • BSnes - Un émulateur SNES génial avec l'objectif d'une précision parfaite.
  • MAME - L' émulateur d'arcade. Bonne référence.
  • 6502asm.com - Il s'agit d'un émulateur JavaScript 6502 avec un petit forum sympa.
  • dynarec'd 6502asm - C'est un petit bidouillage que j'ai fait pendant un jour ou deux. J'ai pris l'émulateur existant de 6502asm.com et l'ai changé pour recompiler dynamiquement le code en JavaScript pour des augmentations de vitesse massives.

Références de recompilation du processeur:

  • La recherche sur la recompilation statique effectuée par Michael Steil (référencé ci-dessus) a abouti dans cet article et vous pouvez trouver des sources et autres here .

Addenda:

Cela fait bien plus d'un an que cette réponse a été soumise et avec toute l'attention qu'elle a reçue, je me suis dit qu'il était temps de mettre à jour certaines choses.

Peut-être la chose la plus excitante dans l'émulation en ce moment est libcpu , commencé par le Michael Steil mentionné ci-dessus. C'est une librairie destinée à supporter un grand nombre de cœurs de CPU, qui utilisent LLVM pour la recompilation (statique et dynamique!). Il a un énorme potentiel, et je pense que ça va faire de grandes choses pour l'émulation.

emu-docs a également été porté à mon attention, qui contient un excellent référentiel de documentation système, très utile à des fins d'émulation. Je n'ai pas passé beaucoup de temps là-bas, mais on dirait qu'ils ont beaucoup de bonnes ressources.

Je suis content que ce message ait été utile, et j'espère pouvoir me débarrasser de mon cul et terminer mon livre sur le sujet d'ici la fin de l'année / début de l'année prochaine.


Lorsque vous développez un émulateur, vous interprétez l'ensemble processeur sur lequel le système fonctionne (Z80, 8080, CPU PS, etc.).

Vous devez également émuler tous les périphériques du système (sortie vidéo, contrôleur).

Vous devriez commencer à écrire des émulateurs pour les systèmes simpe comme le bon vieux Game Boy (qui utilise un processeur Z80, ne me trompe pas) OU pour C64.


Oui, vous devez interpréter tout le désordre du code machine binaire "à la main". Non seulement cela, la plupart du temps, vous devez également simuler un matériel exotique qui n'a pas d'équivalent sur la machine cible.

L'approche simple consiste à interpréter les instructions une à une. Cela fonctionne bien, mais c'est lent. Une approche plus rapide est la recompilation: la traduction du code machine source en code machine cible. Ceci est plus compliqué, car la plupart des instructions ne seront pas mappées en tête-à-tête. Au lieu de cela, vous devrez faire des contournements complexes qui impliquent du code supplémentaire. Mais à la fin, c'est beaucoup plus rapide. La plupart des émulateurs modernes le font.


Un gars nommé Victor Moya del Barrio a écrit sa thèse sur ce sujet. Beaucoup de bonnes informations sur 152 pages. Vous pouvez télécharger le PDF here .

Si vous ne voulez pas vous inscrire avec scribd , vous pouvez google pour le titre PDF, "Étude des techniques pour la programmation d'émulation" . Il y a plusieurs sources différentes pour le PDF.