Emulation ist ein facettenreiches Gebiet. Hier sind die grundlegenden Ideen und Funktionskomponenten. Ich werde es in Stücke brechen und dann die Details durch Bearbeitungen ausfüllen. Viele der Dinge, die ich beschreiben werde, erfordern Kenntnisse über das Innenleben von Prozessoren - Assembler-Kenntnisse sind erforderlich. Wenn ich bei bestimmten Dingen etwas zu vage bin, stellen Sie bitte Fragen, damit ich diese Antwort weiter verbessern kann.
Die Grundidee:
Bei der Emulation wird das Verhalten des Prozessors und der einzelnen Komponenten nachgebildet. Sie bauen jedes einzelne Teil des Systems und verbinden die Teile dann ähnlich wie Drähte in der Hardware.
Prozessor-Emulation:
Es gibt drei Möglichkeiten, mit der Prozessoremulation umzugehen:
- Auslegung
- Dynamische Neukompilierung
- Statische Neukompilierung
Bei all diesen Pfaden verfolgen Sie das gleiche Ziel: Sie führen ein Stück Code aus, um den Prozessorstatus zu ändern und mit der "Hardware" zu interagieren. Der Prozessorstatus ist ein Konglomerat aus Prozessorregistern, Interrupt-Handlern usw. für ein bestimmtes Prozessorziel. Für den 6502 gibt es eine Reihe von 8-Bit-Ganzzahlen, die Register darstellen: A
, X
, Y
, P
y S
; Sie hätten auch eine 16-Bit PC
registrieren.
Beim Dolmetschen beginnt man bei der IP
(Befehlszeiger -- auch genannt PC
, Programmzähler) und lesen den Befehl aus dem Speicher. Ihr Code analysiert diese Anweisung und verwendet diese Informationen, um den Zustand des Prozessors entsprechend den Vorgaben Ihres Prozessors zu ändern. Das Hauptproblem bei der Interpretation ist, dass sie sehr langsam; jedes Mal, wenn Sie eine bestimmte Anweisung bearbeiten, müssen Sie sie dekodieren und die erforderliche Operation durchführen.
Bei der dynamischen Rekompilierung durchlaufen Sie den Code ähnlich wie bei der Interpretation, aber anstatt nur Opcodes auszuführen, erstellen Sie eine Liste von Operationen. Sobald Sie zu einer Verzweigungsanweisung gelangen, kompilieren Sie diese Liste von Operationen zu Maschinencode für Ihre Host-Plattform, dann speichern Sie diesen kompilierten Code zwischen und führen ihn aus. Wenn Sie dann erneut auf eine bestimmte Befehlsgruppe stoßen, müssen Sie nur noch den Code aus dem Cache ausführen. (Übrigens erstellen die meisten Leute keine Liste von Anweisungen, sondern kompilieren sie spontan zu Maschinencode - das erschwert die Optimierung, aber das würde den Rahmen dieser Antwort sprengen, es sei denn, genügend Leute sind daran interessiert.)
Bei der statischen Neukompilierung tun Sie dasselbe wie bei der dynamischen Neukompilierung, aber Sie folgen den Verzweigungen. Am Ende wird ein Stück Code erstellt, das den gesamten Code des Programms repräsentiert und das dann ohne weitere Eingriffe ausgeführt werden kann. Dies wäre ein großartiger Mechanismus, wenn es nicht die folgenden Probleme gäbe:
- Code, der nicht von Anfang an im Programm enthalten ist (z. B. komprimiert, verschlüsselt, zur Laufzeit generiert/geändert usw.), wird nicht neu kompiliert und kann daher nicht ausgeführt werden.
- Es ist erwiesen, dass das Auffinden des gesamten Codes in einer gegebenen Binärdatei gleichbedeutend ist mit der Halteproblem
Diese Kombination macht die statische Neukompilierung in 99 % der Fälle völlig undurchführbar. Für weitere Informationen hat Michael Steil einige großartige Untersuchungen zur statischen Rekompilierung durchgeführt - die besten, die ich gesehen habe.
Die andere Seite der Prozessoremulation ist die Art und Weise, wie Sie mit der Hardware interagieren. Dies hat wirklich zwei Seiten:
- Prozessor-Timing
- Behandlung von Unterbrechungen
Prozessor-Taktung:
Bestimmte Plattformen - vor allem ältere Konsolen wie das NES, SNES usw. - verlangen von Ihrem Emulator ein strenges Timing, um vollständig kompatibel zu sein. Beim NES gibt es die PPU (Pixel Processing Unit), die dafür sorgt, dass die CPU die Pixel zu bestimmten Zeitpunkten in den Speicher lädt. Wenn Sie die Interpretation verwenden, können Sie leicht Zyklen zählen und das richtige Timing emulieren; mit dynamischer/statischer Rekompilierung sind die Dinge viel komplexer.
Behandlung von Unterbrechungen:
Interrupts sind der wichtigste Mechanismus, mit dem die CPU mit der Hardware kommuniziert. Im Allgemeinen teilen Ihre Hardwarekomponenten der CPU mit, welche Interrupts für sie von Bedeutung sind. Das ist ziemlich einfach - wenn Ihr Code einen bestimmten Interrupt auslöst, schauen Sie in die Interrupt-Handler-Tabelle und rufen den richtigen Callback auf.
Hardware-Emulation:
Es gibt zwei Seiten der Emulation eines bestimmten Hardwaregeräts:
- Emulation der Funktionalität des Geräts
- Emulation der tatsächlichen Geräteschnittstellen
Nehmen wir den Fall einer Festplatte. Die Funktionalität wird durch die Erstellung des Sicherungsspeichers, Lese-/Schreib-/Formatierungsroutinen usw. emuliert. Dieser Teil ist im Allgemeinen sehr einfach.
Die eigentliche Schnittstelle des Geräts ist etwas komplexer. In der Regel handelt es sich um eine Kombination aus speicherabgebildeten Registern (z. B. Teile des Speichers, die das Gerät auf Änderungen zur Signalisierung überwacht) und Interrupts. Bei einem Festplattenlaufwerk können Sie einen speicherzugeordneten Bereich haben, in dem Sie Lese- und Schreibbefehle usw. platzieren und diese Daten dann zurücklesen.
Ich würde mehr ins Detail gehen, aber es gibt eine Million Möglichkeiten, die Sie damit gehen können. Wenn Sie irgendwelche spezifischen Fragen haben, fragen Sie mich, und ich werde die Informationen hinzufügen.
Ressourcen:
Ich denke, ich habe hier eine ziemlich gute Einführung gegeben, aber es gibt eine t von zusätzlichen Bereichen. Ich bin gerne bereit, Ihnen bei Fragen zu helfen; ich habe mich aufgrund der immensen Komplexität in den meisten Punkten sehr vage ausgedrückt.
Obligatorische Wikipedia-Links:
Allgemeine Emulationsressourcen:
- Zophar -- Hier habe ich meine ersten Erfahrungen mit Emulationen gemacht, indem ich zunächst Emulatoren heruntergeladen und schließlich deren riesige Dokumentationsarchive geplündert habe. Das ist die absolut beste Ressource, die man haben kann.
- NGEmu -- Nicht viele direkte Ressourcen, aber ihre Foren sind unschlagbar.
- RomHacking.net -- Der Abschnitt "Dokumente" enthält Ressourcen zur Maschinenarchitektur für gängige Konsolen
Emulator-Projekte zum Nachschlagen:
- EisenBabel -- Dies ist eine Emulationsplattform für .NET, die in Nemerle geschrieben ist und Code im Handumdrehen nach C# rekompiliert. Haftungsausschluss: Dies ist mein Projekt, also verzeihen Sie die schamlose Werbung.
- BSnes -- Ein großartiger SNES-Emulator mit dem Ziel der zyklusgenauen Genauigkeit.
- MAME -- Die Arcade-Emulator. Tolle Referenz.
- 6502asm.com -- Dies ist ein JavaScript 6502-Emulator mit einem coolen kleinen Forum.
- dynarec'd 6502asm -- Dies ist ein kleiner Hack, den ich innerhalb von ein oder zwei Tagen gemacht habe. Ich nahm den bestehenden Emulator von 6502asm.com und änderte ihn so, dass er den Code dynamisch in JavaScript neu kompiliert, um die Geschwindigkeit massiv zu erhöhen.
Referenzen für die Neukompilierung des Prozessors:
- Die von Michael Steil durchgeführten Forschungen zur statischen Rekompilierung (siehe oben) gipfelten in dieses Papier und Sie können Quellen und dergleichen finden aquí .
Nachtrag:
Es ist weit über ein Jahr her, dass diese Antwort eingereicht wurde, und bei all der Aufmerksamkeit, die sie erhalten hat, dachte ich mir, dass es an der Zeit ist, einige Dinge zu aktualisieren.
Die vielleicht aufregendste Sache auf dem Gebiet der Emulation ist im Moment libcpu die von dem bereits erwähnten Michael Steil ins Leben gerufen wurde. Es ist eine Bibliothek, die eine große Anzahl von CPU-Kernen unterstützen soll, die LLVM für die Neukompilierung (statisch und dynamisch!) verwenden. Es hat ein riesiges Potenzial, und ich denke, es wird große Dinge für die Emulation tun.
emu-docs wurde ich auch auf eine große Sammlung von Systemdokumentation aufmerksam gemacht, die für Emulationszwecke sehr nützlich ist. Ich habe noch nicht viel Zeit dort verbracht, aber es sieht so aus, als hätten sie eine Menge großartiger Ressourcen.
Ich freue mich, dass dieser Beitrag hilfreich war, und ich hoffe, dass ich meinen Arsch hochbekomme und mein Buch zu diesem Thema bis Ende des Jahres/Anfang nächsten Jahres fertigstellen kann.
15 Stimmen
Das Wichtigste, was Sie finden müssen, ist das "Programmiererhandbuch" für dieses System, da es den "Vertrag" zwischen dem HW-Anbieter und den Programmierern beschreibt und Details verbirgt, die nicht relevant sind und sich ändern könnten. Ihre Chancen hängen von der Popularität des Systems ab.
155 Stimmen
Gute Wahl des Spiels.
2 Stimmen
Ja, ich glaube schon: de.wikipedia.org/wiki/Die_Legende_von_Zelda:_Eine_Verbindung_zur_Vergangenheit
16 Stimmen
Für alle, die sich fragen Emulation vs. Simulation
8 Stimmen
Seitdem ich das Spiel zum ersten Mal gespielt habe, habe ich mich immer gefragt, warum Hyrule mit "8-Ball"-Brocken übersät ist :-)