Domanda

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 in genere progettati?

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

È stato utile?

Soluzione

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 di 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 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, avresti un numero di numeri interi a 8 bit che rappresentano i registri: A , X , Y , P e S ; avresti anche un registro PC a 16 bit.

Con l'interpretazione, inizi dal IP (puntatore alle istruzioni - chiamato anche PC , contatore dei programmi) e leggi 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 esegue l'iterazione del codice in modo molto simile all'interpretazione, ma invece di eseguire solo i 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 è incluso nel programma (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 arresto

Questi si combinano per rendere completamente impossibile la ricompilazione statica nel 99% dei casi. Per ulteriori informazioni, Michael Steil ha fatto delle ricerche fantastiche 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:

  • Tempi del processore
  • Interrompi gestione

Tempi 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 dinamico / iricompilazione tatic, le cose sono molto / molto / più complesse.

Gestione interruzioni:

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 l'archivio di backup, le routine di lettura / scrittura / formattazione, ecc. Questa parte è generalmente molto semplice.

L'interfaccia attuale del dispositivo è un po 'più complessa. Questa è generalmente una combinazione di registri mappati in memoria (ad esempio parti di memoria che il dispositivo osserva per apportare modifiche per segnalare) e interrompe. Per un disco rigido, potresti avere un'area mappata in memoria in cui inserisci comandi di lettura, scritture, ecc., Quindi rileggi 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 dato un'introduzione abbastanza buona qui, ma ci sono un tonnellata 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 Wikipedia obbligatori:

Risorse generali di emulazione:

  • Zophar - È qui che ho iniziato con l'emulazione, scaricando prima gli emulatori e infine saccheggiando il loro immenso 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 dei documenti contiene risorse relative all'architettura delle macchine per console popolari

Progetti di emulatori a cui fare 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 . Grande 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 sulla ricompilazione del processore:

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

Addendum:

È passato molto più di un anno da quando questa risposta è stata inviata e

Altri suggerimenti

Un ragazzo di nome Victor Moya del Barrio ha scritto la sua tesi su questo argomento. Molte buone informazioni su 152 pagine. Puoi scaricare il PDF qui .

Se non vuoi registrarti con scribd , puoi cercare su Google il titolo PDF, " Studio delle tecniche per la programmazione dell'emulazione " . Esistono un paio di fonti diverse per il PDF.

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

Ogni processore in genere ha 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'effettiva implementazione 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à.

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 chiamato "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.

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

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

  • Non stai emulando la cosa reale in quanto tale, sarebbe una replica. Invece, stai emulando 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 che rappresentano 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, in genere stai 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 devi circoscrivere ciò che sei pronto a emulare, ad esempio non è necessario emulare lo stato di tensione dei transistor in un microprocessore, ma probabilmente è necessario 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!

Sì, devi interpretare l'intero messaggio di codice binario della macchina "manualmente". 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.

Quando sviluppi un emulatore stai 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 usano un processore Z80, non sto sbagliando) O per C64.

  

Gli emulatori sono molto difficili da creare poiché ci sono molti hack (come inusuali   effetti), 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 & # 8217; una CPU multi-GHz per emulare una CPU da 1MHz.

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.

Emulatore dispositivo di origine condiviso contiene buildable codice sorgente a 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 all'host virtuale - Compilazione JIT del codice ospite - simulazione di dispositivi periferici come adattatori di rete, touchscreen e audio - Integrazione dell'interfaccia utente, per tastiera e mouse host - salvataggio / ripristino dello stato, per la simulazione del ripristino dalla modalità a basso consumo

Per aggiungere la risposta fornita da @Cody Brocious
Nel contesto della virtualizzazione in cui si sta emulando un nuovo sistema (CPU, I / O ecc.) Su 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 memorizza nella cache nulla, quindi ogni istruzione passa attraverso lo stesso ciclo.

Emalatore dinamico: Qemu è un emulatore dinamico. Fa anche la traduzione al volo delle istruzioni degli ospiti memorizza anche 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 possa essere utile nella virtualizzazione.

Come vorrei iniziare l'emulazione.

1.Prendi i libri basati sulla programmazione di basso livello, ne avrai bisogno per il "pretend " sistema operativo del Nintendo ... game boy ...

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

3. guarda alcuni emulatori open source, in particolare quelli del sistema per cui vuoi creare un emulatore.

4.copia 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

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.

Presto scriverò una guida più lunga per il NES.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top