Comment fonctionnent les émulateurs et comment sont-ils écrits? [fermé]

StackOverflow https://stackoverflow.com/questions/448673

  •  19-08-2019
  •  | 
  •  

Question

Comment fonctionnent les émulateurs? Quand je vois des émulateurs NES / SNES ou C64, cela me stupéfie.

http://www.tommowalker.co.uk/snemzelda.png

Devez-vous émuler le processeur de ces machines en interprétant ses instructions de montage particulières? Quoi d'autre va dedans? Comment sont-ils généralement conçus?

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

Était-ce utile?

La solution

L’émulation est une zone à multiples facettes. Voici les idées de base et les composants fonctionnels. Je vais le casser en morceaux, puis compléter les détails via des modifications. Beaucoup des choses que je vais décrire vont nécessiter 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 de base:

L’émulation fonctionne en gérant le comportement du processeur et des composants individuels. Vous construisez chaque composant du système, puis connectez les composants comme le font les câbles dans le matériel.

Emulation du processeur:

Il existe trois façons de gérer l'émulation de processeur:

  • Interprétation
  • Recompilation dynamique
  • Recompilation statique

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

Avec interprétation, vous commencez par IP (pointeur d'instruction - également appelé PC , compteur de programme) et lisez l'instruction à partir 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 essentiel de l’interprétation est qu’il 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 parcourez le code comme une interprétation, mais au lieu de simplement exécuter des opcodes, vous créez une liste d'opérations. Une fois que vous atteignez une instruction de branche, 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 frappez à nouveau un groupe d'instructions donné, il vous suffit d'exécuter le code à partir du cache. (Au fait, la plupart des gens ne font pas réellement une liste d'instructions mais les compilent en code machine à la volée - cela rend plus difficile l'optimisation, mais c'est hors du champ de cette réponse, sauf si suffisamment de personnes sont intéressées)

Avec la recompilation statique, vous procédez comme pour la recompilation dynamique, mais vous suivez les branches. Vous créez un bloc de code qui représente tout le code du programme, qui peut ensuite être exécuté sans autre interférence. Ce serait un très bon mécanisme si ce n’était les problèmes suivants:

  • Le code qui n'est pas dans le programme pour commencer (par exemple, compressé, chiffré, généré / modifié à l'exécution, etc.) ne sera pas recompilé, donc il ne s'exécutera pas
  • Il a été prouvé que la recherche de tout le code dans un binaire donné équivaut au Problème stoppant .

Celles-ci se combinent pour rendre impossible la recompilation statique dans 99% des cas. Pour plus d’informations, Michael Steil a effectué d’excellentes recherches sur la recompilation statique - la meilleure que j’ai jamais vue.

L’autre côté de l’émulation du processeur est la manière dont vous interagissez avec le matériel. Cela a vraiment deux côtés:

  • Synchronisation du processeur
  • Traitement des interruptions

Synchronisation du processeur:

Certaines plates-formes - notamment les anciennes consoles telles que la NES, la SNES, etc. - exigent que votre émulateur ait un minutage strict pour être totalement compatible. Avec le NES, vous avez le PPU (unité de traitement de pixels) qui exige 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 dynamique / srecompilation tatic, les choses sont / beaucoup / plus complexes.

Traitement des interruptions:

Les interruptions sont le mécanisme principal par lequel la CPU communique avec le matériel. Généralement, vos composants matériels informeront le processeur des interruptions dont il se soucie. C’est assez simple: lorsque votre code génère une interruption donnée, vous consultez la table des gestionnaires d’interruptions et appelez le rappel approprié.

Émulation matérielle:

L'émulation d'un périphérique matériel donné présente deux aspects:

  • Emulation de la fonctionnalité du périphérique
  • 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 / formatage, etc. Cette partie est généralement très simple.

L’interface réelle du périphérique 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 surveillées par le dispositif pour détecter les modifications à effectuer) et des interruptions. Pour un disque dur, vous pouvez avoir une zone mappée en mémoire où vous placez des commandes de lecture, des écritures, etc., puis relisez ces données.

J'entrerais dans les détails, mais il y a un million de façons d'y aller. Si vous avez des questions spécifiques ici, n'hésitez pas à demander et je vais ajouter l'info.

Ressources:

Je pense avoir donné une assez bonne introduction, mais il y a tonnes de domaines supplémentaires. Je suis plus qu'heureux d'aider avec toutes les questions; J'ai été très vague dans la plupart des cas, simplement en raison de l'immense complexité.

Liens obligatoires dans Wikipedia:

Ressources d'émulation générales:

  • Zophar - C’est là que j’ai commencé avec l’émulation, le premier téléchargement d’émulateurs, puis le pillage de leur immense archives de documentation. C’est la meilleure ressource que vous puissiez avoir.
  • NGEmu : peu de ressources directes, mais leurs forums sont imbattables.
  • RomHacking.net - La section des documents contient des ressources sur l'architecture des machines pour consoles populaires

Projets d'émulateur à référencer:

  • IronBabel - Il s'agit d'une plate-forme d'émulation pour .NET, écrite en Nemerle et recompilant le code en C #. à la volée. Disclaimer: Ceci est mon projet, alors pardonnez-moi la fiche sans vergogne.
  • BSnes - Un émulateur SNES génial ayant pour objectif une précision de cycle parfaite.
  • MAME - L'émulateur d'arcade . Grande 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 repris l'émulateur existant sur 6502asm.com et je l'ai modifié pour recompiler dynamiquement le code en JavaScript afin d'augmenter considérablement la vitesse.

Références de recompilation du processeur:

  • Les recherches sur la recompilation statique effectuées par Michael Steil (voir référence ci-dessus) ont abouti à cet article et vous pouvez trouver la source et les ici .

Addendum:

Cela fait bien plus d'un an que cette réponse a été soumise et

Autres conseils

Un homme du nom de Victor Moya del Barrio a rédigé sa thèse sur ce sujet. Beaucoup de bonnes informations sur 152 pages. Vous pouvez télécharger le fichier PDF ici .

Si vous ne souhaitez pas vous enregistrer auprès de scribd , vous pouvez rechercher le titre PDF, " Étude des techniques de programmation d'émulation " <. Il existe différentes sources pour le PDF.

L’émulation peut sembler décourageante, mais elle est en réalité plus simple que la simulation.

Tout processeur a généralement une spécification bien écrite décrivant les états, les interactions, etc.

Si les performances ne vous intéressent pas du tout, vous pouvez facilement émuler la plupart des processeurs les plus anciens à l’aide de programmes très élégants orientés objet. Par exemple, un processeur X86 aurait besoin de quelque chose pour maintenir l'état des registres (easy), de maintenir l'état de mémoire (easy), et de quelque chose qui prendrait chaque commande entrante et l'appliquerait à l'état actuel de la machine. Si vous voulez vraiment de la précision, vous pouvez également émuler les traductions en mémoire, la mise en cache, etc., mais c'est faisable.

En fait, de nombreux fabricants de microprocesseurs et de processeurs testent les programmes sur un émulateur de la puce, puis sur la puce elle-même, ce qui les aide à détecter les problèmes de spécifications ou de mise en oeuvre de la puce. dans le matériel. Par exemple, il est possible d'écrire une spécification de puce qui entraînerait des blocages. Lorsqu'une échéance survient dans le matériel, il est important de voir si elle peut être reproduite dans la spécification car cela indique un problème plus grave que l'implémentation de la puce.

Bien sûr, les émulateurs pour les jeux vidéo se soucient généralement des performances, ils n'utilisent donc pas d'implémentations naïves. Ils incluent également du code qui s'interface avec le système d'exploitation du système hôte, par exemple pour utiliser le dessin et le son.

Compte tenu des performances très lentes des anciens jeux vidéo (NES / SNES, etc.), l’émulation est relativement simple sur les systèmes modernes. En fait, il est encore plus étonnant de pouvoir télécharger un jeu de tous les jeux SNES ou Atari 2600, étant donné que lorsque ces systèmes étaient populaires, le libre accès à chaque cartouche aurait été un rêve devenu réalité.

Je sais que cette question est un peu ancienne, mais j'aimerais ajouter quelque chose à la discussion. La plupart des réponses proposées ici concernent des émulateurs interprétant les instructions machine des systèmes qu’ils émulent.

Cependant, il existe une exception très connue à celle appelée "UltraHLE". ( article de WIKIpedia ). UltraHLE, l'un des émulateurs les plus célèbres jamais créés, a imité les jeux commerciaux Nintendo 64 (avec des performances décentes sur les ordinateurs à la maison) à un moment où il était largement considéré impossible de le faire. En fait, lorsque UltraHLE a été créé, Nintendo produisait encore de nouveaux titres pour la Nintendo 64!

Pour la première fois, j'ai vu des articles sur les émulateurs dans des magazines imprimés alors que je ne les avais jamais vus que discutés sur le Web.

Le concept d'UltraHLE était de rendre l'impossible possible en émulant les appels de bibliothèque C au lieu d'appels au niveau de l'ordinateur.

Il est intéressant de regarder Imran Nazar dans sa tentative d'écrire un Gameboy émulateur en JavaScript.

Après avoir créé mon propre émulateur du micro-ordinateur BBC des années 80 (type VBeeb dans Google), vous devez connaître un certain nombre de choses.

  • Vous n'imitez pas la réalité en tant que telle, ce serait une réplique. Au lieu de cela, vous émulez État . Un bon exemple est une calculatrice, la vraie chose a des boutons, écran, cas, etc. Mais pour émuler une calculatrice, il vous suffit d'émuler si les boutons sont en haut ou en bas, quels segments de l'écran LCD sont allumés, etc. En gros, un ensemble de nombres représentant toutes les combinaisons possibles de choses pouvant changer dans une calculatrice.
  • Il suffit que l'interface de l'émulateur apparaisse et se comporte comme si de rien n'était. Plus c'est convaincant, plus l'émulation est proche. Ce qui se passe dans les coulisses peut être ce que vous voulez. Cependant, pour faciliter l'écriture d'un émulateur, un mappage mental se produit entre le système réel, c'est-à-dire les puces, les écrans, 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 diviser en morceaux plus petits et d’émuler ces morceaux individuellement. Ensuite, enchaînez le tout pour le produit fini. Un peu comme un ensemble de boîtes noires avec des entrées et des sorties, qui se prête bien à la programmation orientée objet. Vous pouvez encore subdiviser ces morceaux pour vous rendre la vie plus facile.

Concrètement, 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 s'exécutera (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.

De plus, vous devez limiter 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 jeu de registres du microprocesseur.
En règle générale, plus le niveau de détail de l'émulation est faible, plus vous resterez fidèle au système d'origine.
Enfin, les informations pour les systèmes plus anciens peuvent être incomplètes ou inexistantes. Il est donc essentiel de mettre la main sur l’équipement d’origine ou au moins de distinguer un autre bon émulateur écrit par quelqu'un d'autre!

Oui, vous devez interpréter le désordre de code machine binaire "à la main". De plus, 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 par une. Cela fonctionne bien, mais c'est lent. La recompilation est une approche plus rapide: convertir le code machine source en code machine cible. C’est plus compliqué, car la plupart des instructions ne mapperont pas un à un. Au lieu de cela, vous devrez créer des solutions de rechange qui impliquent du code supplémentaire. Mais au final c'est beaucoup plus rapide. La plupart des émulateurs modernes le font.

Lorsque vous développez un émulateur, vous interprétez l'assemblage de processeurs 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, je ne me trompe pas) OU pour C64.

  

Les émulateurs sont très difficiles à créer car il y a beaucoup de hacks (comme dans les cas inhabituels).   effets de synchronisation, etc. que vous devez simuler.

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

Cela vous montrera également pourquoi vous avez besoin de & # 8217; un processeur multi-GHz pour émuler un 1 MHz.

Consultez également les Emulators.com de Darek Mihocka pour des conseils judicieux sur l'optimisation des instructions pour les JIT, ainsi que de nombreux autres avantages. sur la construction d’émulateurs efficaces.

Je n’ai jamais rien fait d’aspirant pour émuler une console de jeu, mais j’ai suivi un cours une fois dans le but d’écrire un émulateur pour la machine décrite dans Andrew Tanenbaums Organisation de l'ordinateur structuré . C'était amusant et cela m'a donné beaucoup de moments aha. Vous voudrez peut-être prendre ce livre avant de plonger dans l'écriture d'un véritable émulateur.

Des conseils sur l’émulation d’un système réel ou de votre propre chef? Je peux dire que les émulateurs fonctionnent en émulant tout le matériel. Peut-être pas dans le circuit (déplacer des bits comme le ferait le HW; déplacer l’octet est le résultat final, donc copier l’octet convient). Les émulateurs sont très difficiles à créer car il faut simuler de nombreux hacks (comme dans les effets inhabituels), des problèmes de timing, etc. Si un élément (entrée) est incorrect, tout le système peut le faire ou au mieux avoir un bug / problème.

L’ émulateur de périphérique source partagé peut être construit. code source d'un émulateur PocketPC / Smartphone (nécessite Visual Studio, fonctionne sous Windows). J'ai travaillé sur les versions V1 et V2 de la version binaire.

Il aborde de nombreux problèmes d’émulation: - traduction d’adresses efficace d’invité virtuel à invité physique en hôte virtuel - Compilation JIT du code invité - simulation de périphériques tels que cartes réseau, écrans tactiles et audio - Intégration de l'interface utilisateur, pour clavier et souris hôtes - sauvegarde / restauration de l'état, pour la simulation de la reprise du mode basse consommation

Pour ajouter la réponse fournie par @Cody Brocious
Dans le contexte de la virtualisation où vous émulez un nouveau système (CPU, E / S, etc.) sur une machine virtuelle, vous pouvez voir les catégories suivantes d’émulateurs.

Interprétation: bochs est un exemple d’interprète. Il s’agit d’un émulateur de PC x86. Chaque instruction du système invité doit être traduite dans un autre jeu d’instructions (de l’ISA hôte) pour produire l’effet souhaité. Oui, elle est très lente. , il ne cache rien, donc chaque instruction suit le même cycle.

Emalator dynamique: Qemu est un émulateur dynamique. La traduction à la volée de l'instruction d'invité met également en cache les résultats. La meilleure partie est d'exécuter autant d'instructions que possible directement sur le système hôte, de sorte que l'émulation est plus rapide. Comme Cody l’a également mentionné, il divise le code en blocs (1 seul flux d’exécution).

Émulateur statique: Pour autant que je sache, aucun émulateur statique ne peut être utile dans la virtualisation.

Comment commencer l'émulation?

1.Obtenez des livres basés sur la programmation de bas niveau, vous en aurez besoin pour le "prétendre" système d'exploitation de la Nintendo ... Game Boy ...

2.Obtenez des livres sur l'émulation spécifiquement, et peut-être le développement OS. (vous ne ferez pas un os, mais le plus proche.

3.recherchez des émulateurs open source, en particulier ceux du système pour lequel vous souhaitez créer un émulateur.

4.copiez des fragments du code plus complexe dans votre IDE / compliler. Cela vous évitera d'écrire un long code. C’est ce que je fais pour le développement os, utilise un district de linux

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.

J'écrirai bientôt un guide plus long pour la NDA.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top