エミュレーターはどのように機能し、どのように記述されますか?[閉まっている]


968

エミュレーターはどのように機能しますか?NES / SNESまたはC64エミュレーターを見ると、びっくりします。

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

特定のアセンブリ命令を解釈することにより、それらのマシンのプロセッサをエミュレートする必要がありますか?他に何が入りますか?それらは通常どのように設計されていますか?

エミュレータ(特にゲームシステム)の作成に興味がある人に何かアドバイスはありますか?


15
見つける必要がある最も重要なものは、そのシステムの「プログラママニュアル」です。これは、ハードウェアベンダーとプログラマの間の「契約」を詳しく説明し、関連のない変更の可能性がある詳細を隠しているためです。可能性はシステムの人気に依存します。
Uri

155
良いゲームの選択。
クリスティアンロモ

2
ええ


8
私はそのゲームを初めてプレイして以来、なぜハイラルが「8ボール」の岩で散らかされているのかといつも疑問に思っていました:-)
ビビアンリバー

回答:


1124

エミュレーションは多面的な領域です。基本的なアイデアと機能コンポーネントは次のとおりです。それを細かく分割し、編集して詳細を入力します。これから説明することの多くは、プロセッサの内部動作の知識を必要とします-アセンブリの知識が必要です。特定のことについて少し漠然としている場合は、質問に答えてください。そうすれば、この答えを改善し続けることができます。

基本的な考え方:

エミュレーションは、プロセッサと個々のコンポーネントの動作を処理することによって機能します。システムの各部分を構築してから、ハードウェアでのワイヤーと同じように各部分を接続します。

プロセッサエミュレーション:

プロセッサエミュレーションを処理する方法は3つあります。

  • 解釈
  • 動的再コンパイル
  • 静的再コンパイル

これらのすべてのパスで、同じ全体的な目標があります。プロセッサの状態を変更して「ハードウェア」とやり取りするコードを実行します。プロセッサの状態は、特定のプロセッサターゲットのプロセッサレジスタ、割り込みハンドラなどの集まりです。6502のために、あなたはレジスタを表す8ビット整数の数を持っていると思います:AXYP、とS。また、16ビットのPCレジスタも必要です。

解釈では、IP(命令ポインタ- PC、プログラムカウンタとも呼ばれます)から開始し、メモリから命令を読み取ります。コードはこの命令を解析し、この情報を使用して、プロセッサーによって指定されたプロセッサーの状態を変更します。解釈の中心的な問題は、非常に遅いということです。特定の命令を処理するたびに、それをデコードして必要な操作を実行する必要があります。

動的再コンパイルでは、解釈と同様にコードを反復処理しますが、オペコードを実行するだけでなく、操作のリストを作成します。分岐命令に到達したら、この操作のリストをホストプラットフォームのマシンコードにコンパイルし、このコンパイルされたコードをキャッシュして実行します。その後、特定の命令グループを再度ヒットした場合、キャッシュからコードを実行するだけで済みます。(ところで、ほとんどの人は実際に命令のリストを作成するのではなく、それらをその場で機械語コードにコンパイルします-これは最適化をより困難にしますが、十分な人々が興味がない限り、これはこの回答の範囲外です)

静的再コンパイルでは、動的再コンパイルと同じですが、ブランチに従います。プログラム内のすべてのコードを表すコードのチャンクを構築することになり、その後、干渉を受けることなく実行できます。これは、次の問題がない場合に最適なメカニズムです。

  • プログラムに含まれていないコード(たとえば、圧縮、暗号化、実行時に生成/変更など)は再コンパイルされないため、実行されません
  • 特定のバイナリですべてのコードを見つけることは、停止問題と同等であることが証明されています

これらの組み合わせにより、99%のケースで静的再コンパイルが完全に実行不可能になります。詳細については、Michael Steilが静的再コンパイルについていくつかの優れた研究を行っています。

プロセッサエミュレーションの反対側は、ハードウェアとやり取りする方法です。これには本当に2つの側面があります。

  • プロセッサのタイミング
  • 割り込み処理

プロセッサのタイミング:

特定のプラットフォーム(特にNES、SNESなどの古いコンソール)では、完全に互換性を保つためにエミュレーターに厳密なタイミングが必要です。NESを使用すると、CPUが正確なタイミングでピクセルをメモリに配置する必要があるPPU(ピクセル処理ユニット)があります。解釈を使用すると、サイクルを簡単にカウントし、適切なタイミングをエミュレートできます。動的/静的再コンパイルでは、物事は/ lot /より複雑になります。

割り込み処理:

割り込みは、CPUがハードウェアと通信する主要なメカニズムです。一般に、ハードウェアコンポーネントは、CPUにどの割り込みを処理するかを指示します。これは非常に簡単です。コードが特定の割り込みをスローするとき、割り込みハンドラテーブルを見て、適切なコールバックを呼び出します。

ハードウェアエミュレーション:

特定のハードウェアデバイスをエミュレートするには、2つの側面があります。

  • デバイスの機能をエミュレートする
  • 実際のデバイスインターフェイスのエミュレート

ハードドライブの場合を考えてみましょう。機能は、バッキングストレージ、読み取り/書き込み/フォーマットルーチンなどを作成することによってエミュレートされます。この部分は、通常、非常に簡単です。

デバイスの実際のインターフェースはもう少し複雑です。これは通常、メモリマップレジスタ(たとえば、デバイスがシグナリングを行うために変更を監視するメモリの一部)と割り込みの組み合わせです。ハードドライブの場合は、読み取りコマンド、書き込みなどを配置し、このデータを読み取るメモリマップ領域がある場合があります。

もう少し詳しく説明しますが、それには100万通りの方法があります。ここで具体的な質問がある場合は、遠慮なく質問してください。情報を追加します。

リソース:

私はイントロここにかなり良いを与えてくれたと思いますが、そこにあるトンの追加領域のは。質問があれば喜んでお手伝いします。非常に複雑なため、私はこれのほとんどを非常に曖昧にしてきました。

必須のウィキペディアのリンク:

一般的なエミュレーションリソース:

  • Zophar- ここで私はエミュレーションを始めました。最初にエミュレータをダウンロードし、最終的にはドキュメントの膨大なアーカイブを略奪します。これは、おそらく最高のリソースです。
  • NGEmu-多くの直接的なリソースはありませんが、彼らのフォーラムは無敵です。
  • RomHacking.net-ドキュメントセクションには、一般的なコンソールのマシンアーキテクチャに関するリソースが含まれています

参照するエミュレータプロジェクト:

  • IronBabel-これは、Nemerleで書かれた.NETのエミュレーションプラットフォームであり、コードをオンザフライでC#に再コンパイルします。免責事項:これは私のプロジェクトなので、恥知らずなプラグインを許してください。
  • BSnes-完璧なサイクル精度を目標とした素晴らしいSNESエミュレーター。
  • MAME - アーケードエミュレータ。素晴らしい参照。
  • 6502asm.com- これは、クールな小さなフォーラムを持つJavaScript 6502エミュレーターです。
  • dynarec'd 6502asm-これは私が1〜2日かけて行った小さなハックです。私は6502asm.comから既存のエミュレーターを取り、コードを動的にJavaScriptに再コンパイルして速度を大幅に向上させるように変更しました。

プロセッサの再コンパイルの参照:

  • Michael Steil(上記参照)が行った静的再コンパイルの研究は、この論文で最高潮に達し、ソースなどをここで見つけることができます。

補遺:

この回答が提出されてから1年以上が経過しており、注目を集めているところで、いくつかの更新を行う時期が来たと思いました。

おそらく、現在エミュレーションで最もエキサイティングなのは、前述のMichael Steilによって開始されたlibcpuです。これは、再コンパイル(静的および動的!)にLLVMを使用する多数のCPUコアをサポートすることを目的としたライブラリです。それは大きな可能性を秘めているし、エミュレーションにとって素晴らしいことになると思う。

emu-docsにも注目が集まりました。これには、エミュレーションの目的で非常に役立つシステムドキュメントの優れたリポジトリが格納されています。私はそこであまり時間を費やしていませんが、すばらしいリソースがたくさんあるようです。

この投稿が役に立ったことを嬉しく思います。お尻から降りて、年末/来年初めまでにこの本について私の本を仕上げることができればと思っています。


37
これはすでに壮大な答えになるための準備をしています。最後に、リソースを教えてもらえれば幸いです。私はおそらくSNESまたはNESシステムをエミュレートし、それを私の学期のプロジェクトにしようと考えています。
mmcdole 2009年

8
もちろん。リソースのすばらしいリストを作成します。具体的なご要望がございましたら、全力でご対応させていただきます。
Cody Brocious

3
@thenonhacker、私のリソースセクションで参照されているIronBabelプロジェクトは私のものです。(恥知らずなプラグにはマークが付けられています;))
Cody Brocious

1
「特定のバイナリのすべてのコードを見つけることは、停止問題と同等であることが証明されています」-参考にしてください。それとも、「任意のバイナリですべてのコードを見つけることがホールティング問題と同等であることが証明されている」でしょうか?また、
シュタイル

4
あなたは本を書いていると言っています。最新情報を教えていただけますか?私は、一つは、それを読むことに興味があるでしょう。
アレックス2012

126

ビクターモヤデルバリオという男がこのトピックについての論文を書きました。152ページにたくさんの良い情報があります。こちらからPDFをダウンロードできます。

scribdに登録したくない場合は、PDFタイトル「Study the Techniques of the Emulation Programming 」でグーグルできます。PDFのソースはいくつかあります。


43

エミュレーションは困難に思えるかもしれませんが、実際にはシミュレーションよりもかなり簡単です。

通常、どのプロセッサにも、状態、相互作用などを記述する適切に記述された仕様があります。

パフォーマンスにまったく関心がない場合は、非常にエレガントなオブジェクト指向プログラムを使用して、ほとんどの古いプロセッサーを簡単にエミュレートできます。たとえば、X86プロセッサには、レジスタの状態を維持する(簡単)、メモリの状態を維持する(簡単)、および各着信コマンドを取得してそれをマシンの現在の状態に適用するものが必要です。本当に正確さが必要な場合は、メモリの変換、キャッシングなどもエミュレートしますが、それは可能です。

実際、多くのマイクロチップおよびCPUメーカーは、チップのエミュレーターに対して、次にチップ自体に対してプログラムをテストします。これにより、チップの仕様またはハードウェアでのチップの実際の実装に問題があるかどうかを確認できます。たとえば、デッドロックが発生するチップ仕様を作成することは可能です。ハードウェアで期限が発生した場合、仕様に再現できるかどうかを確認することが重要です。それは、チップ実装の問題よりも大きな問題を示しているためです。

もちろん、ビデオゲームのエミュレーターは通常、パフォーマンスに関心があるため、単純な実装を使用せず、描画やサウンドを使用するなど、ホストシステムのOSとインターフェイスするコードも含まれています。

古いビデオゲーム(NES / SNESなど)の非常に遅いパフォーマンスを考慮すると、エミュレーションは最新のシステムでは非常に簡単です。実際、これらのシステムが人気であったときにすべてのカートリッジに無料でアクセスできることは夢の実現であったことを考えると、これまでにすべてのSNESゲームまたはこれまでの任意のAtari 2600ゲームのセットをダウンロードできることはさらに驚くべきことです。


1
エミュレーションとシミュレーションの違いは何ですか?
Wei Hu

2
@Wei:一般的に言えば、エミュレータはエミュレートするシステムのように「外部」で動作するはずですが、同様の方法で実装する必要があると言うことは何もありません。シミュレーターは、シミュレートされたシステムを模倣する方法で実装され、結果としてそのように動作します。
ウリ

エミュレータが「エミュレート」する間、「シミュレータ」が似ていると思います
mP。


29

この質問は少し古いですが、ディスカッションに何か付け加えたいと思います。ここでの答えのほとんどは、エミュレータがエミュレートするシステムの機械語命令を解釈することを中心にしています。

ただし、これには「UltraHLE」と呼ばれる非常によく知られた例外があります(WIKIpediaの記事)。これまでに作成された最も有名なエミュレーターの1つであるUltraHLEは、市販のニンテンドー64ゲームを(家庭用コンピューターではまともなパフォーマンスで)エミュレートすることが不可能であると広く考えられていたときにエミュレートしました。実際のところ、UltraHLEが作成されたとき、ニンテンドーはまだニンテンドー64の新しいタイトルを作成していました!

印刷雑誌でエミュレーターに関する記事を初めて見たのは、以前はウェブで議論されているエミュレーターを見ただけでした。

UltraHLEの概念は、マシンレベルの呼び出しの代わりにCライブラリの呼び出しをエミュレートすることで不可能を可能にすることでした。


22

注目に値するのは、JavaScriptでゲームボーイエミュレータを作成しようとしたイムランナザールの試みです。


1
Gameboyゲームの生のオペコード命令を取得するにはどうすればよいですか?
Pacerier 2013

「灰色の市場」で販売可能なデバイスがいくつかあります。あなたは先進国のどの主要な店でもそれらを見つけることはありません。これらのデバイスは、ゲームカートリッジから通常「ROM」と呼ばれるファイルに命令をコピーすることができます。Googleの「Gameboy Roms」ですが、安全でないリンクや攻撃サイトに注意してください。
ビビアン川

18

80年代のBBCマイクロコンピューター(VBeebをGoogleに入力)の自分のエミュレーターを作成したので、知っておくべきことがたくさんあります。

  • あなたは本物そのものをエミュレートするのではなく、それはレプリカになります。代わりに、Stateをエミュレートしています。良い例は電卓です。本物にはボタン、画面、ケースなどがありますが、電卓をエミュレートするには、ボタンが上か下か、LCDのどのセグメントがオンになっているかなどをエミュレートするだけです。基本的に、一連の数値電卓で変化する可能性のあるもののすべての可能な組み合わせを表す。
  • エミュレータのインターフェースが必要なのは、本物のように表示され、動作するためだけです。これが説得力のあるものであるほど、エミュレーションは近くなります。舞台裏で何が起こっているかはあなたが好きなものにすることができます。しかし、エミュレータを簡単に作成できるように、実際のシステム、つまりチップ、ディスプレイ、キーボード、回路基板、および抽象的なコンピュータコードの間で行われるメンタルマッピングがあります。
  • コンピュータシステムをエミュレートするには、それを小さなチャンクに分割し、それらのチャンクを個別にエミュレートするのが最も簡単です。その後、完成品のロット全体をひもでつなぎます。オブジェクト指向プログラミングに美しく役立つ、入力と出力を備えたブラックボックスのセットによく似ています。これらのチャンクをさらに細かく分割して、作業を簡単にすることができます。

実際には、エミュレーションのスピードと忠実性を重視して書いているのが一般的です。これは、ターゲットシステムのソフトウェアが、ソースシステムの元のハードウェアよりも動作が遅い(可能性がある)ためです。これは、プログラミング言語、コンパイラ、ターゲットシステムなどの選択を制約する可能性があります。
さらに、エミュレートする準備を整える必要があります。たとえば、マイクロプロセッサのトランジスタの電圧状態をエミュレートする必要はありませんが、おそらく必要です。マイクロプロセッサのレジスタセットの状態をエミュレートします。
一般的に言えば、エミュレーションの詳細レベルが小さいほど、元のシステムに忠実になります。
最後に、古いシステムの情報は不完全または存在しない可能性があります。したがって、元の機器を手に入れることは不可欠です。または、少なくとも他の誰かが書いた優れたエミュレータを賞賛する必要があります。


17

はい、バイナリマシンのコード全体を「手動」で解釈する必要があります。それだけでなく、ほとんどの場合、ターゲットマシン上に同等のものがないエキゾチックなハードウェアもシミュレートする必要があります。

簡単な方法は、指示を1つずつ解釈することです。それはうまくいきますが、遅いです。より高速なアプローチは再コンパイルです-ソースマシンコードをターゲットマシンコードに変換します。ほとんどの命令は1対1でマッピングされないため、これはさらに複雑です。代わりに、追加のコードを含む複雑な回避策を講じる必要があります。しかし、最終的にははるかに高速です。最近のほとんどのエミュレーターがこれを行います。


1
最悪のことははるかにドキュメントが不足していることです。GameBoy Colorの変更されたZ80コアに、文書化されていないフラグ操作が含まれていることが判明したとき、テストしているゲームが本当に信仰を失い始めます。
Callum Rogers、

1
ペットピーブ:マシンコード(単数)であり、マシンコード(複数)ではありません。ちょうどそれのようモールス符号ではないモールスコード
Lawrence Dol、2011

1
@Vilx:実際にはありません。CPUの命令セットを指す「マシンコード」という用語は、ソフトウェアの登場以来使用されており、複数形ではありません。これは、「命令セット」という単数形であり、複数形の「命令」ではありません。プログラムコード、モールスコードなどと同じです。複数形の使用は、通常、第2言語として英語を話す人による誤用から侵入しています。
ローレンスドル2011

1
@Software Monkey-しかし、「コード」という単語を使用して、セット内の単一のアイテムを参照することはできませんか?例:「... --- ...-これらの3つのモールス符号は、3つの文字S、O、Sを表します。」ため...であるコードの文字「S」を表します。番号?
Vilx- 2011

1
いいえ、コードは非可算名詞である、それは水や砂のようには複数形を持っていない...
イワン

15

エミュレータを開発するときは、システムが動作しているプロセッサアセンブリ(Z80、8080、PS CPUなど)を解釈しています。

また、システムにあるすべての周辺機器(ビデオ出力、コントローラー)をエミュレートする必要があります。

古き良きゲームボーイ(Z80プロセッサーを使用しているので、間違えていません)やC64のような単純なシステム用のエミュレーターの作成を開始する必要があります。


9
C64は「シンプルな」システムですか?6510は比較的単純ですが(リストにないオペコードをカバーした後)、サウンド(SID)およびビデオ(VIC)チップは単純ではありませ。適切なレベルの互換性を実現するには、ハードウェアのバグなど、それらをエミュレートする必要があります。
moobaa 2009年

10

シミュレートする必要のあるハック(異常な効果など)、タイミングの問題などが多数あるため、エミュレータの作成は非常に困難です。

この例については、http://queue.acm.org/detail.cfm?id=1755886を参照してください。

これは、1 MHzのCPUをエミュレートするためにマルチGHz CPUが「必要」である理由も示しています。


9

また、Darek MihockaのEmulators.comをチェックして、JITの命令レベルの最適化に関する優れたアドバイスや、効率的なエミュレーターの構築に関するその他の多くの利点を確認してください。


7

私はゲームコンソールをエミュレートするほど豪華なことをしたことがありませんが、Andrew Tanenbaums Structured Computer Organizationで説明されているマシンのエミュレーターを作成するというコースを一度受けました 。それは面白かったし、私にたくさんの瞬間を与えてくれた。実際のエミュレータを作成する前に、その本を手に入れたいと思うかもしれません。


4

実際のシステムまたはあなた自身のものをエミュレートすることについてのアドバイス?エミュレータはハードウェア全体をエミュレートすることで機能すると言えます。たぶん、回路にダウンしないでください(HWのようにビットを移動するのと同じです。バイトの移動が最終結果なので、バイトのコピーは問題ありません)。シミュレートする必要のある多くのハック(異常な効果など)、タイミングの問題などがあるため、エミュレータの作成は非常に困難です。1つの(入力)部分が間違っている場合、システム全体がダウンするか、せいぜいバグ/グリッチが発生する可能性があります。


4

シェアードソースデバイスエミュレータは、ポケットPC /スマートフォンエミュレータにビルド可能なソースコードが含まれています(Windows上のVisual Studio、実行が必要です)。バイナリリリースのV1とV2に取り組みました。

多くのエミュレーション問題に取り組みます:-ゲスト仮想からゲスト物理からホスト仮想への効率的なアドレス変換-ゲストコードのJITコンパイル-ネットワークアダプター、タッチスクリーン、オーディオなどの周辺デバイスのシミュレーション-ホストキーボードとマウスのUI統合-保存/低電力モードからの再開のシミュレーションのための状態の復元


1

@Cody Brociousが提供する回答を追加
するには新しいシステム(CPU、I / Oなど)を仮想マシンにエミュレートする仮想化のコンテキストでは、次のカテゴリのエミュレータを確認できます。

解釈:bochsはインタプリタの例であり、x86 PCエミュレータです。ゲストシステムからの各命令を受け取り、それを(ホストISAの)別の命令セットに変換して、意図した効果を生成します。はい、非常に遅いです。何もキャッシュしないので、すべての命令が同じサイクルを通過します。

動的エマレーター:Qemuは動的エミュレーターです。ゲスト命令のオンザフライ変換も結果をキャッシュします。最良の部分は、ホストシステムでできるだけ多くの命令を直接実行して、エミュレーションを高速化することです。また、Codyで言及されているように、コードをブロックに分割します(1つの実行フロー)。

静的エミュレーター:私が知る限り、仮想化に役立つ静的エミュレーターはありません。


1

エミュレーションを開始する方法。

1.低レベルのプログラミングに基づいた本を入手します。ニンテンドーの「ふり」オペレーティングシステムに必要です...ゲームボーイ...

2.具体的にはエミュレーションに関する書籍を入手してください。(OSを作成するのではなく、それに最も近いものを作成します。

3.いくつかのオープンソースエミュレーター、特にエミュレーターを作成したいシステムのエミュレーターを見てください。

4.より複雑なコードのスニペットをIDE /コンパイラにコピーします。これにより、長いコードを書く手間が省けます。これは私がOS開発のためにやっていることです、Linuxの地区を使用して


1

私は、Chip-8システムをJavaScriptでエミュレートすることについての記事を書きました。

システムはそれほど複雑ではないので、始めるのに最適な場所ですが、オペコード、スタック、レジスターなどがどのように機能するかをまだ学びます。

NESについては、もう少し長いガイドを書く予定です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.