Come funzionano gli emulatori e come vengono scritti? [chiuso]


968

Come funzionano gli emulatori? Quando vedo gli emulatori NES / SNES o C64, mi stupisce.

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

Devi emulare il processore di quelle macchine interpretando le sue particolari istruzioni di assemblaggio? Cos'altro ci va dentro? Come sono tipicamente progettati?

Puoi dare qualche consiglio a qualcuno interessato a scrivere un emulatore (in particolare un sistema di gioco)?


15
La cosa più importante che devi trovare è il "manuale del programmatore" per quel sistema, dal momento che dettaglia il "contratto" tra il fornitore HW e i programmatori e nasconde dettagli che non sono rilevanti e potrebbero cambiare. Le tue possibilità dipendono dalla popolarità del sistema.
Uri,

155
Buona scelta di gioco.
Cristián Romo,


16
Per chiunque si chieda Emulazione vs Simulazione
Lazer,

8
Sin dalla prima volta che ho giocato a quel gioco, mi sono sempre chiesto perché Hyrule è disseminata di massi "8-Ball" :-)
Vivian River

Risposte:


1124

L'emulazione è un'area multiforme. Ecco le idee di base e i componenti funzionali. Lo spezzerò in pezzi e poi riempirò i dettagli tramite le modifiche. Molte delle cose che descriverò richiederanno la conoscenza del funzionamento interno dei processori: è necessaria la conoscenza dell'assemblaggio. Se sono un po 'troppo vago su certe cose, ti preghiamo di porre domande in modo da poter continuare a migliorare questa risposta.

Idea base:

L'emulazione funziona gestendo il comportamento del processore e dei singoli componenti. Costruisci ogni singolo pezzo del sistema e quindi connetti i pezzi proprio come fanno i fili nell'hardware.

Emulazione del processore:

Esistono tre modi per gestire l'emulazione del processore:

  • Interpretazione
  • Ricompilazione dinamica
  • Ricompilazione statica

Con tutti questi percorsi, hai lo stesso obiettivo generale: eseguire un pezzo di codice per modificare lo stato del processore e interagire con "hardware". Lo stato del processore è un conglomerato di registri del processore, gestori di interrupt, ecc. Per un determinato target del processore. Per il 6502, si avrebbe un numero di interi a 8 bit che rappresentano i registri: A, X, Y, P, e S; avresti anche un PCregistro a 16 bit .

Con l'interpretazione, si inizia dal IP(puntatore dell'istruzione - chiamato anche PC, contatore del programma) e si leggono le istruzioni dalla memoria. Il codice analizza queste istruzioni e utilizza queste informazioni per modificare lo stato del processore come specificato dal processore. Il problema principale con l'interpretazione è che è molto lento; ogni volta che gestisci una determinata istruzione, devi decodificarla ed eseguire l'operazione richiesta.

Con la ricompilazione dinamica, si scorre il codice in modo molto simile all'interpretazione, ma invece di eseguire solo codici operativi, si crea un elenco di operazioni. Una volta raggiunta un'istruzione di succursale, compili questo elenco di operazioni in codice macchina per la tua piattaforma host, quindi memorizzi nella cache questo codice compilato ed eseguilo. Quindi, quando premi di nuovo un determinato gruppo di istruzioni, devi solo eseguire il codice dalla cache. (A proposito, la maggior parte delle persone in realtà non crea un elenco di istruzioni ma le compila al codice macchina al volo - questo rende più difficile l'ottimizzazione, ma non rientra nell'ambito di questa risposta, a meno che non siano interessate abbastanza persone)

Con la ricompilazione statica, fai la stessa cosa della ricompilazione dinamica, ma segui i rami. Alla fine si crea un blocco di codice che rappresenta tutto il codice nel programma, che può quindi essere eseguito senza ulteriori interferenze. Questo sarebbe un ottimo meccanismo se non fosse per i seguenti problemi:

  • Il codice che non è nel programma per cominciare (ad esempio, compresso, crittografato, generato / modificato in fase di esecuzione, ecc.) Non verrà ricompilato, quindi non verrà eseguito
  • È stato dimostrato che trovare tutto il codice in un dato binario equivale al problema di Halting

Questi si combinano per rendere completamente impossibile la ricompilazione statica nel 99% dei casi. Per ulteriori informazioni, Michael Steil ha fatto delle ottime ricerche sulla ricompilazione statica, la migliore che abbia mai visto.

L'altro lato dell'emulazione del processore è il modo in cui interagisci con l'hardware. Questo ha davvero due lati:

  • Tempistica del processore
  • Interrompere la gestione

Tempistica del processore:

Alcune piattaforme, in particolare le console più vecchie come NES, SNES, ecc., Richiedono che il tuo emulatore abbia un tempismo rigoroso per essere completamente compatibile. Con il NES hai la PPU (unità di elaborazione dei pixel) che richiede che la CPU metta i pixel nella sua memoria in momenti precisi. Se usi l'interpretazione, puoi facilmente contare i cicli ed emulare i tempi corretti; con la ricompilazione dinamica / statica, le cose sono molto / molto / più complesse.

Interrompere la gestione:

Gli interrupt sono il meccanismo principale che la CPU comunica con l'hardware. In generale, i componenti hardware diranno alla CPU ciò che interrompe. Questo è piuttosto semplice: quando il tuo codice genera un determinato interrupt, dai un'occhiata alla tabella del gestore di interrupt e chiami il callback corretto.

Emulazione hardware:

Esistono due lati per emulare un determinato dispositivo hardware:

  • Emulazione della funzionalità del dispositivo
  • Emulazione delle attuali interfacce del dispositivo

Prendi il caso di un disco rigido. La funzionalità viene emulata creando la memoria di supporto, le routine di lettura / scrittura / formattazione, ecc. Questa parte è generalmente molto semplice.

L'interfaccia effettiva del dispositivo è un po 'più complessa. In genere si tratta di una combinazione di registri mappati in memoria (ad esempio parti di memoria che il dispositivo rileva per apportare modifiche) e interrompe. Per un disco rigido, è possibile disporre di un'area mappata in memoria in cui si inseriscono comandi di lettura, scritture, ecc., Quindi si rileggono questi dati.

Andrei più nel dettaglio, ma ci sono un milione di modi in cui puoi seguirlo. Se hai domande specifiche qui, sentiti libero di chiedere e io aggiungerò le informazioni.

risorse:

Penso di aver fatto un'introduzione abbastanza buona qui, ma ci sono un sacco di aree aggiuntive. Sono più che felice di aiutarti con qualsiasi domanda; Sono stato molto vago in gran parte di questo semplicemente a causa dell'immensa complessità.

Link obbligatori a Wikipedia:

Risorse generali di emulazione:

  • Zophar - È qui che ho iniziato con l'emulazione, scaricando prima gli emulatori e infine saccheggiando i loro immensi archivi di documentazione. Questa è la miglior risorsa in assoluto che tu possa avere.
  • NGEmu - Non molte risorse dirette, ma i loro forum sono imbattibili.
  • RomHacking.net - La sezione documenti contiene risorse relative all'architettura della macchina per console popolari

Progetti di emulatore per riferimento:

  • IronBabel - Questa è una piattaforma di emulazione per .NET, scritta in Nemerle e ricompila il codice in C # al volo. Disclaimer: questo è il mio progetto, quindi scusate la spina spudorata.
  • BSnes - Un fantastico emulatore SNES con l'obiettivo di un'accuratezza perfetta per il ciclo.
  • MAME - L' emulatore arcade. Ottimo riferimento
  • 6502asm.com - Questo è un emulatore JavaScript 6502 con un piccolo forum interessante.
  • dynarec'd 6502asm - Questo è un piccolo trucco che ho fatto in un giorno o due. Ho preso l'emulatore esistente da 6502asm.com e l'ho modificato per ricompilare dinamicamente il codice in JavaScript per aumenti di velocità massicci.

Riferimenti di ricompilazione del processore:

  • La ricerca sulla ricompilazione statica condotta da Michael Steil (citata sopra) è culminata in questo documento e puoi trovare la fonte e simili qui .

Addendum:

È passato molto più di un anno da quando è stata inviata questa risposta e con tutta l'attenzione che sta ricevendo, ho pensato che fosse tempo di aggiornare alcune cose.

Forse la cosa più eccitante dell'emulazione in questo momento è libcpu , iniziata dal già citato Michael Steil. È una libreria destinata a supportare un gran numero di core della CPU, che usano LLVM per la ricompilazione (statica e dinamica!). Ha un enorme potenziale e penso che farà grandi cose per l'emulazione.

emu-docs è stato anche portato alla mia attenzione, che ospita un grande archivio di documentazione di sistema, che è molto utile ai fini dell'emulazione. Non ho trascorso molto tempo lì, ma sembra che abbiano molte grandi risorse.

Sono contento che questo post sia stato utile e spero di potermi staccare dal culo e finire il mio libro sull'argomento entro la fine dell'anno / all'inizio del prossimo anno.


37
Questa si sta già preparando per essere una risposta epica. Se riesci a indicarmi qualsiasi risorsa, alla fine sarebbe apprezzata. Sto forse guardando il sistema SNES o NES per emulare e renderlo il mio progetto del semestre.
mmcdole,

8
Certamente. Ho intenzione di mettere insieme un bel elenco di risorse. Se avete richieste specifiche, farò del mio meglio per soddisfarle.
Cody Brocious,

3
@thenonhacker, Il progetto IronBabel a cui fa riferimento la mia sezione risorse è mia. (La spina spudorata è contrassegnata;))
Cody Brocious,

1
"È stato dimostrato che trovare tutto il codice in un dato binario equivale al problema di Halting" - Per favore, riferimento? O dovrebbe essere "È stato dimostrato che trovare tutto il codice in un dato binario equivale al problema di Halting"? Inoltre non posso accedere al documento di Steil :-(
squelart

4
Dici che stai scrivendo un libro; puoi per favore darci un aggiornamento su questo? Io, per esempio, sarei interessato a leggerlo.
alex,


43

L'emulazione può sembrare scoraggiante ma in realtà è molto più semplice della simulazione.

Qualsiasi processore ha in genere una specifica ben scritta che descrive stati, interazioni, ecc.

Se non ti interessavi affatto delle prestazioni, allora potevi emulare facilmente i processori più vecchi usando programmi orientati agli oggetti molto eleganti. Ad esempio, un processore X86 avrebbe bisogno di qualcosa per mantenere lo stato dei registri (facile), qualcosa per mantenere lo stato della memoria (facile) e qualcosa che prenderebbe ogni comando in arrivo e lo applicherebbe allo stato corrente della macchina. Se desideri davvero la precisione, dovresti anche emulare traduzioni di memoria, memorizzazione nella cache, ecc., Ma è fattibile.

In effetti, molti produttori di microchip e CPU testano i programmi contro un emulatore del chip e quindi contro il chip stesso, il che li aiuta a scoprire se ci sono problemi nelle specifiche del chip o nell'attuazione effettiva del chip nell'hardware. Ad esempio, è possibile scrivere una specifica del chip che comporterebbe deadlock e quando si verifica una scadenza nell'hardware è importante vedere se potrebbe essere riprodotto nelle specifiche poiché ciò indica un problema maggiore rispetto a qualcosa nell'implementazione del chip.

Naturalmente, gli emulatori per i videogiochi di solito si preoccupano delle prestazioni, quindi non usano implementazioni ingenue e includono anche il codice che si interfaccia con il sistema operativo del sistema host, ad esempio per utilizzare disegno e suono.

Considerando le prestazioni molto lente dei vecchi videogiochi (NES / SNES, ecc.), L'emulazione è abbastanza semplice sui sistemi moderni. In effetti, è ancora più sorprendente che tu possa semplicemente scaricare una serie di tutti i giochi SNES di sempre o di qualsiasi gioco Atari 2600 di sempre, considerando che quando questi sistemi erano popolari avere libero accesso a ogni cartuccia sarebbe stato un sogno diventato realtà.


1
Quali sono le differenze tra emulazione e simulazione?
Wei Hu,

2
@Wei: in generale, si suppone che un emulatore si comporti "esternamente" come il sistema che emula, ma non c'è nulla da dire che deve essere implementato in modo simile. Un simulatore è implementato in un modo che imita il sistema simulato e, di conseguenza, si comporta in modo simile.
Uri,

Quando vedi "Simulatore" pensa che sia simile mentre un emulatore "emula"
mP.


29

So che questa domanda è un po 'vecchia, ma vorrei aggiungere qualcosa alla discussione. La maggior parte delle risposte qui è incentrata sugli emulatori che interpretano le istruzioni della macchina dei sistemi che emulano.

Tuttavia, esiste un'eccezione molto nota a questo chiamata "UltraHLE" ( articolo WIKIpedia ). UltraHLE, uno degli emulatori più famosi mai creati, emulava giochi per Nintendo 64 commerciali (con prestazioni decenti sui computer di casa) in un momento in cui era ampiamente considerato impossibile farlo. È un dato di fatto, Nintendo stava ancora producendo nuovi titoli per Nintendo 64 quando è stato creato UltraHLE!

Per la prima volta, ho visto articoli sugli emulatori nelle riviste di stampa in cui prima li avevo visti solo discussi sul web.

Il concetto di UltraHLE era di rendere possibile l'impossibile emulando chiamate in libreria C anziché chiamate a livello di macchina.


22

Qualcosa che vale la pena dare un'occhiata è il tentativo di Imran Nazar di scrivere un emulatore di Gameboy in JavaScript.


1
Come possiamo ottenere le istruzioni di codice operativo non elaborate per il gioco Gameboy?
Pacerier,

Esistono numerosi dispositivi disponibili per la vendita sul "mercato grigio". Non li troverai in nessuno dei principali negozi del mondo sviluppato. Questi dispositivi sono in grado di copiare le istruzioni dalla cartuccia del gioco ai file che di solito vengono chiamati "ROM". Google "Gameboy Roms", ma fai attenzione ai collegamenti non sicuri e ai siti di attacco!
Fiume Vivian,

18

Avendo creato il mio emulatore del microcomputer BBC degli anni '80 (digita VBeeb in Google), ci sono un certo numero di cose da sapere.

  • Non stai emulando la cosa reale in quanto tale, sarebbe una replica. Invece, stai emulando lo stato . Un buon esempio è una calcolatrice, la cosa reale ha pulsanti, schermo, custodia ecc. Ma per emulare una calcolatrice devi solo emulare se i pulsanti sono su o giù, quali segmenti di LCD sono accesi, ecc. Fondamentalmente, un insieme di numeri rappresenta tutte le possibili combinazioni di cose che possono cambiare in una calcolatrice.
  • Hai solo bisogno che l'interfaccia dell'emulatore appaia e si comporti come la cosa reale. Più questo è convincente, più l'emulazione è vicina. Ciò che accade dietro le quinte può essere qualsiasi cosa ti piaccia. Ma, per facilitare la scrittura di un emulatore, esiste una mappatura mentale che avviene tra il sistema reale, ad esempio chip, display, tastiere, circuiti stampati e il codice astratto del computer.
  • Per emulare un sistema informatico, è più semplice suddividerlo in blocchi più piccoli ed emularli singolarmente. Quindi mettere insieme l'intero lotto per il prodotto finito. Proprio come una serie di scatole nere con ingressi e uscite, che si presta magnificamente alla programmazione orientata agli oggetti. È possibile suddividere ulteriormente questi blocchi per semplificare la vita.

In pratica, stai generalmente cercando di scrivere per la velocità e la fedeltà dell'emulazione. Questo perché il software sul sistema di destinazione funzionerà (potrebbe) più lentamente dell'hardware originale sul sistema di origine. Ciò può limitare la scelta del linguaggio di programmazione, dei compilatori, del sistema di destinazione, ecc.
Inoltre, è necessario circoscrivere ciò che si è pronti a emulare, ad esempio non è necessario emulare lo stato di tensione dei transistor in un microprocessore, ma è probabilmente necessario per emulare lo stato del set di registri del microprocessore.
In generale, minore è il livello di dettaglio dell'emulazione, maggiore sarà la fedeltà al sistema originale.
Infine, le informazioni per i sistemi più vecchi possono essere incomplete o inesistenti. Quindi procurarsi l'equipaggiamento originale è essenziale, o almeno valorizzare un altro buon emulatore che qualcun altro ha scritto!


17

Sì, devi interpretare l'intero pasticcio del codice della macchina binaria "a mano". Non solo, la maggior parte delle volte devi anche simulare hardware esotico che non ha un equivalente sul computer di destinazione.

L'approccio semplice è quello di interpretare le istruzioni una per una. Funziona bene, ma è lento. Un approccio più rapido è la ricompilazione: la traduzione del codice macchina sorgente nel codice macchina di destinazione. Questo è più complicato, poiché la maggior parte delle istruzioni non eseguirà il mapping uno a uno. Dovrai invece fare elaborate soluzioni alternative che prevedono codice aggiuntivo. Ma alla fine è molto più veloce. La maggior parte degli emulatori moderni lo fa.


1
La cosa peggiore è di gran lunga la documentazione mancante. È quando scopri che il core Z80 modificato in GameBoy Color ha operazioni flag non documentate che il gioco che stai testando inizia davvero a perdere fiducia.
Callum Rogers,

1
Pet peeve: è un codice macchina (singolare), non codici macchina (plurale); così come è il codice Morse e non i codici Morse .
Lawrence Dol,

1
@Vilx: In realtà no - il termine "codice macchina", riferito alle istruzioni impostate per una CPU è stato utilizzato sin dall'inizio del software e non è plurale. Si riferisce al " set di istruzioni ", una forma singolare, non alla forma plurale "istruzioni". Come il codice del programma, il codice Morse, ecc. L'uso della forma plurale si è insinuato da un uso improprio, in genere da parte di coloro che parlano inglese come seconda lingua.
Lawrence Dol,

1
@Software Monkey - Ma non posso usare la parola "codice" per riferirmi a un singolo elemento del set? Ad esempio: " ... --- ...- questi tre codici Morse rappresentano le tre lettere S, O, S." Perché ...è un codice che rappresenta la lettera "S". No?
Vilx-

1
No, il codice è un sostantivo non numerabile, non ha forma plurale come acqua o sabbia ..
Ivan

15

Quando si sviluppa un emulatore, si sta interpretando l'assemblaggio del processore su cui sta lavorando il sistema (Z80, 8080, CPU PS, ecc.).

È inoltre necessario emulare tutte le periferiche presenti nel sistema (uscita video, controller).

Dovresti iniziare a scrivere emulatori per i sistemi simpe come il buon vecchio Game Boy (che usa un processore Z80, non sto sbagliando) O per C64.


9
C64 un sistema "semplice"? Mentre il 6510 è relativamente semplice (dopo aver coperto i codici operativi non elencati), i chip audio (SID) e video (VIC) sono tutt'altro che semplici. Per raggiungere un livello decente di compatibilità, dovresti emularli - bug hardware e tutto il resto.
Moobaa,

10

L'emulatore è molto difficile da creare poiché ci sono molti hack (come in effetti insoliti), problemi di temporizzazione, ecc. Che devi simulare.

Per un esempio di ciò, vedi http://queue.acm.org/detail.cfm?id=1755886 .

Questo ti mostrerà anche perché 'hai bisogno' di una CPU multi-GHz per emulare una CPU da 1MHz.


9

Dai un'occhiata anche agli emulatori.com di Darek Mihocka per ottimi consigli sull'ottimizzazione a livello di istruzione per le squadre investigative comuni e molti altri vantaggi sulla creazione di emulatori efficienti.


7

Non ho mai fatto nulla di così fantasioso da emulare una console di gioco, ma una volta ho fatto un corso in cui il compito era quello di scrivere un emulatore per la macchina descritta in Andrew Tanenbaums Structured Computer Organization . È stato divertente e mi ha regalato molti momenti aha. Potresti prendere quel libro prima di immergerti nella scrittura di un vero emulatore.


4

Consigli sull'emulazione di un sistema reale o delle tue cose? Posso dire che gli emulatori funzionano emulando l'INTERO hardware. Forse non giù al circuito (come farebbe spostare i bit in giro come l'HW. Spostare il byte è il risultato finale, quindi copiare il byte va bene). L'emulatore è molto difficile da creare poiché ci sono molti hack (come in effetti insoliti), problemi di temporizzazione, ecc. Che devi simulare. Se un pezzo (input) è sbagliato, l'intero sistema può fare down o, nella migliore delle ipotesi, avere un bug / glitch.


4

L' emulatore di dispositivo di origine condiviso contiene codice sorgente costruibile su un emulatore PocketPC / Smartphone (richiede Visual Studio, funziona su Windows). Ho lavorato su V1 e V2 della versione binaria.

Affronta molti problemi di emulazione: - efficiente traduzione degli indirizzi da ospite virtuale a ospite fisico per ospitare virtuale - compilazione JIT di codice ospite - simulazione di dispositivi periferici come adattatori di rete, touchscreen e audio - integrazione UI, per tastiera e mouse host - salva / ripristino dello stato, per la simulazione del ripristino dalla modalità a basso consumo


1

Per aggiungere la risposta fornita da @Cody Brocious
Nel contesto della virtualizzazione in cui si sta emulando un nuovo sistema (CPU, I / O ecc.) In una macchina virtuale, è possibile visualizzare le seguenti categorie di emulatori.

Interpretazione: bochs è un esempio di interprete, è un emulatore per PC x86, prende ogni istruzione dal sistema guest e la traduce in un'altra serie di istruzioni (dell'ISA host) per produrre l'effetto desiderato.Sì è molto lento, non lo fa memorizza nella cache qualsiasi cosa così ogni istruzione passa attraverso lo stesso ciclo.

Emalatore dinamico: Qemu è un emulatore dinamico. Fa anche la traduzione al volo delle istruzioni guest memorizza nella cache i risultati. La parte migliore è che esegue quante più istruzioni possibili direttamente sul sistema host in modo che l'emulazione sia più veloce. Inoltre, come menzionato da Cody, divide il codice in blocchi (1 singolo flusso di esecuzione).

Emulatore statico: per quanto ne so non esiste un emulatore statico che può essere utile nella virtualizzazione.


1

Come vorrei iniziare l'emulazione.

1.Ricevi libri basati sulla programmazione di basso livello, ne avrai bisogno per il sistema operativo "fingi" di Nintendo ... game boy ...

2. Ottieni libri sull'emulazione in particolare e forse sullo sviluppo del sistema operativo. (non farai un SO, ma il più vicino ad esso.

3. guardare alcuni emulatori open source, in particolare quelli del sistema per cui si desidera creare un emulatore.

4.Copia i frammenti del codice più complesso nel tuo IDE / compilatore. Questo ti salverà scrivendo un codice lungo. Questo è quello che faccio per lo sviluppo del sistema operativo, uso un distretto di Linux


1

Ho scritto un articolo sull'emulazione del sistema Chip-8 in JavaScript .

È un ottimo punto di partenza poiché il sistema non è molto complicato, ma si impara comunque come funzionano gli opcode, lo stack, i registri, ecc.

Scriverò presto una guida più lunga per il NES.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.