Comment fonctionnent les émulateurs? Quand je vois des émulateurs NES / SNES ou C64, cela m'étonne.
Devez-vous é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 généralement conçus?
Pouvez-vous donner des conseils à quelqu'un qui souhaite écrire un émulateur (en particulier un système de jeu)?
Réponses:
L'émulation est un domaine à multiples facettes. Voici les idées de base et les composants fonctionnels. Je vais le diviser en morceaux, puis 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, veuillez poser 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 individuelle du système, puis connectez les pièces comme le font les fils dans le matériel.
Émulation de processeur:
Il existe trois façons de gérer l'émulation du processeur:
Avec tous ces chemins, vous avez le même objectif global: exécuter un morceau de code pour modifier l'état du processeur et interagir avec le «matériel». L'état du processeur est une conglomération des registres du processeur, des gestionnaires d'interruption, etc. pour une cible de processeur donnée. Pour le 6502, vous auriez un certain nombre d'entiers 8 bits représentant des registres:
A
,X
,Y
,P
etS
; vous auriez également unPC
registre 16 bits .Avec l'interprétation, vous commencez au
IP
(pointeur d'instruction - également appeléPC
, compteur de programme) et lisez l'instruction dans la mémoire. Votre code analyse cette instruction et utilise ces informations pour modifier l'état du processeur comme spécifié par votre processeur. Le problème central de l'interprétation est qu'elle est très lente; 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 un peu comme l'interprétation, mais au lieu d'exécuter simplement des opcodes, vous créez une liste d'opérations. Une fois que vous avez atteint une instruction de branche, vous compilez cette liste d'opérations sur le code machine de 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é, vous n'avez qu'à exécuter le code à partir du cache. (BTW, la plupart des gens ne font pas réellement une liste d'instructions mais les compilent à la machine à la volée - cela le rend plus difficile à optimiser, mais cela sort du cadre de cette réponse, sauf si suffisamment de personnes sont intéressées)
Avec la recompilation statique, vous faites la même chose qu'en recompilation dynamique, mais vous suivez les branches. Vous finissez par construire un morceau de code qui représente tout le code du programme, qui peut ensuite être exécuté sans autre interférence. Ce serait un excellent mécanisme s'il n'y avait pas les problèmes suivants:
Celles-ci se combinent pour rendre la recompilation statique complètement irréalisable dans 99% des cas. Pour plus d'informations, Michael Steil a fait de grandes recherches sur la recompilation statique - le meilleur que j'ai vu.
L'autre côté de l'émulation de processeur est la manière dont vous interagissez avec le matériel. Cela a vraiment deux côtés:
Calendrier du processeur:
Certaines plates-formes - en particulier les consoles plus anciennes comme NES, SNES, etc. - nécessitent que votre émulateur ait un timing strict pour être complètement compatible. Avec le NES, vous avez le PPU (unité de traitement des pixels) qui nécessite que le CPU place 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 / beaucoup / plus complexes.
Interruption de la manipulation:
Les interruptions sont le principal mécanisme que la CPU communique avec le matériel. Généralement, vos composants matériels indiqueront au CPU les interruptions dont il se soucie. C'est assez simple - lorsque votre code lève une interruption donnée, vous regardez la table du gestionnaire d'interruption et appelez le rappel approprié.
Émulation matérielle:
L'émulation d'un périphérique matériel donné a deux côtés:
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 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 le périphérique surveille pour les modifications à effectuer pour la signalisation) 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'irais plus en détail, mais il y a un million de façons de procéder. Si vous avez des questions spécifiques ici, n'hésitez pas à me les poser et j'ajouterai les informations.
Ressources:
Je pense que j'ai donné une assez bonne introduction ici, mais il y a une tonne de domaines supplémentaires. Je suis plus qu'heureux de répondre à toutes vos questions; J'ai été très vague dans la plupart de cela simplement en raison de l'immense complexité.
Liens Wikipédia obligatoires:
Ressources d'émulation générales:
Projets d'émulation à référencer:
Références de recompilation du processeur:
Addenda:
Cela fait bien plus d'un an que cette réponse a été soumise et avec toute l'attention qu'elle suscite, j'ai pensé qu'il était temps de mettre à jour certaines choses.
La chose la plus excitante dans l'émulation en ce moment est peut-être libcpu , démarré par Michael Steil susmentionné. Il s'agit d'une bibliothèque destinée à prendre en charge un grand nombre de cœurs de processeur, qui utilisent LLVM pour la recompilation (statique et dynamique!). Son potentiel est énorme et je pense que cela fera de grandes choses pour l'émulation.
emu-docs a également été porté à mon attention, qui abrite un grand référentiel de documentation système, qui est très utile à des fins d'émulation. Je n'y ai pas passé beaucoup de temps, mais on dirait qu'ils ont beaucoup de bonnes ressources.
Je suis content que ce post ait été utile, et j'espère que je pourrai me défouler et terminer mon livre sur le sujet d'ici la fin de l'année / au début de l'année prochaine.
la source
Un gars du nom de 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 ici .
Si vous ne voulez pas vous inscrire avec scribd , vous pouvez google pour le titre PDF, "Etude des techniques de programmation d'émulation" . Il existe plusieurs sources différentes pour le PDF.
la source
L'émulation peut sembler intimidante mais est en fait bien plus facile que la simulation.
Tout processeur a généralement une spécification bien écrite qui décrit les états, les interactions, etc.
Si vous ne vous souciez pas du tout des performances, vous pouvez facilement émuler la plupart des processeurs plus anciens en utilisant des programmes orientés objet très élégants. Par exemple, un processeur X86 aurait besoin de quelque chose pour maintenir l'état des registres (facile), de quelque chose pour maintenir l'état de la mémoire (facile) et de quelque chose qui prendrait chaque commande entrante et l'appliquerait à l'état actuel de la machine. Si vous vouliez vraiment de la précision, vous émuleriez également des traductions de mémoire, la mise en cache, etc., mais c'est faisable.
En fait, de nombreux fabricants de micropuces et de processeurs testent des programmes contre un émulateur de la puce, puis contre la puce elle-même, ce qui les aide à savoir s'il y a des problèmes dans les spécifications de la puce ou dans la mise en œuvre réelle de la puce dans le matériel. Par exemple, il est possible d'écrire une spécification de puce qui entraînerait des blocages, et lorsqu'une échéance se produit dans le matériel, il est important de voir si elle pourrait être reproduite dans la spécification car cela indique un problème plus important que quelque chose dans la mise en œuvre de la puce.
Bien sûr, les émulateurs pour les jeux vidéo se soucient généralement des performances afin de ne pas utiliser d'implémentations naïves, et 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 assez facile sur les systèmes modernes. En fait, il est encore plus étonnant que vous puissiez simplement télécharger un ensemble de tous les jeux SNES ou tout jeu Atari 2600, étant donné que lorsque ces systèmes étaient populaires, l'accès gratuit à chaque cartouche aurait été un rêve devenu réalité.
la source
Je sais que cette question est un peu ancienne, mais je voudrais ajouter quelque chose à la discussion. La plupart des réponses se concentrent ici sur les émulateurs interprétant les instructions machine des systèmes qu'ils émulent.
Cependant, il existe une exception très connue à cela appelée "UltraHLE" ( article WIKIpedia ). UltraHLE, l'un des émulateurs les plus célèbres jamais créés, émulait des jeux commerciaux Nintendo 64 (avec des performances décentes sur les ordinateurs personnels) à une époque où il était largement considéré comme impossible de le faire. En fait, Nintendo produisait encore de nouveaux titres pour la Nintendo 64 lorsque UltraHLE a été créé!
Pour la première fois, j'ai vu des articles sur les émulateurs dans des magazines imprimés où auparavant, je ne les avais vus que discutés sur le Web.
Le concept d'UltraHLE était de rendre possible l'impossible en émulant des appels de bibliothèque C au lieu d'appels de niveau machine.
la source
Quelque chose à regarder est la tentative d'Imran Nazar d'écrire un émulateur Gameboy en JavaScript.
la source
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.
En pratique, vous cherchez généralement à écrire pour la vitesse et la fidélité de l'émulation. Cela est dû au fait que le logiciel sur le système cible fonctionnera (peut) 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 outre, 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 c'est probablement nécessaire pour émuler l'état de l'ensemble de registres du microprocesseur.
De manière générale, plus le niveau de détail de l'émulation est petit, plus vous obtiendrez de fidélité au système d'origine.
Enfin, les informations sur les anciens systèmes peuvent être incomplètes ou inexistantes. Il est donc essentiel de se procurer l'équipement d'origine, ou du moins de mettre à part un autre bon émulateur que quelqu'un d'autre a écrit!
la source
Oui, vous devez interpréter le désordre du code machine binaire entier "à la main". Non seulement cela, la plupart du temps, vous devez également simuler du 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. Une approche plus rapide est la recompilation - la conversion du code machine source en code machine cible. Ceci est plus compliqué, car la plupart des instructions ne seront pas mappées un à un. Au lieu de cela, vous devrez effectuer des contournements élaborés qui impliquent du code supplémentaire. Mais au final, c'est beaucoup plus rapide. La plupart des émulateurs modernes le font.
la source
... --- ...
- ces trois codes Morse représentent les trois lettres S, O, S." Parce que...
c'est un code représentant la lettre "S". Non?Lorsque vous développez un émulateur, vous interprétez l'assemblage de processeur sur lequel le système travaille (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.
la source
Pour un exemple de cela, 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.
la source
Consultez également Emulators.com de Darek Mihocka pour d'excellents conseils sur l'optimisation de niveau d'instruction pour les JIT, et de nombreux autres goodies sur la construction d'émulateurs efficaces.
la source
Je n'ai jamais rien fait d'extraordinaire pour émuler une console de jeu, mais j'ai suivi un cours où la tâche consistait à écrire un émulateur pour la machine décrite dans Andrew Tanenbaums Structured Computer Organization . C'était amusant et 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.
la source
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 dans le circuit (comme le ferait le déplacement de bits comme le ferait le matériel. Le déplacement de l'octet est le résultat final, donc la copie de l'octet est très 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 (entrée) est erronée, tout le système peut être en panne ou au mieux avoir un bug / problème.
la source
L' émulateur de périphérique source partagé contient du code source à construire vers un émulateur PocketPC / Smartphone (nécessite Visual Studio, s'exécute sur Windows). J'ai travaillé sur V1 et V2 de la version binaire.
Il résout de nombreux problèmes d'émulation: - traduction d'adresse efficace du virtuel invité au physique invité en virtuel hôte - Compilation JIT du code invité - simulation de périphériques tels que les adaptateurs réseau, l'écran tactile et l'audio - Intégration d'interface utilisateur, pour le clavier et la souris hôte - sauvegarde / restauration de l'état, pour simulation de reprise à partir du mode basse consommation
la source
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, nous pouvons voir les catégories d'émulateurs suivantes.
Interprétation: bochs est un exemple d'interprète, c'est un émulateur PC x86, il prend chaque instruction du système invité la traduit dans un autre ensemble d'instructions (de l'hôte ISA) pour produire l'effet souhaité.Oui c'est très lent, ça ne marche pas 'cache rien donc chaque instruction passe par le même cycle.
Emalateur dynamique: Qemu est un émulateur dynamique. La traduction à la volée des instructions invitées 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 afin que l'émulation soit plus rapide. Aussi, comme mentionné par Cody, il divise le code en blocs (1 flux d'exécution unique).
Émulateur statique: Pour autant que je sache, aucun émulateur statique ne peut être utile pour la virtualisation.
la source
Comment commencer l'émulation.
1.Obtenez des livres basés sur une programmation de bas niveau, vous en aurez besoin pour le système d'exploitation "simulé" du Nintendo ... game boy ...
2.Obtenez des livres sur l'émulation en particulier, et peut-être sur le développement du système d'exploitation. (vous ne ferez pas un os, mais le plus proche de lui.
3. regardez certains émulateurs open source, en particulier ceux du système pour lequel vous souhaitez créer un émulateur.
4. copiez des extraits du code plus complexe dans votre IDE / compilateur. Cela vous évitera d'écrire du code long. C'est ce que je fais pour le développement du système d'exploitation, utilisez un district de Linux
la source
J'ai écrit un article sur l'émulation du Chip-8 en JavaScript .
C'est un excellent endroit pour commencer car le système n'est pas très compliqué, mais vous apprenez toujours comment les opcodes, la pile, les registres, etc.
J'écrirai bientôt un guide plus long pour la NES.
la source