エミュレーターはどのように機能しますか?NES / SNESまたはC64エミュレーターを見ると、びっくりします。
特定のアセンブリ命令を解釈することにより、それらのマシンのプロセッサをエミュレートする必要がありますか?他に何が入りますか?それらは通常どのように設計されていますか?
エミュレータ(特にゲームシステム)の作成に興味がある人に何かアドバイスはありますか?
エミュレーターはどのように機能しますか?NES / SNESまたはC64エミュレーターを見ると、びっくりします。
特定のアセンブリ命令を解釈することにより、それらのマシンのプロセッサをエミュレートする必要がありますか?他に何が入りますか?それらは通常どのように設計されていますか?
エミュレータ(特にゲームシステム)の作成に興味がある人に何かアドバイスはありますか?
回答:
エミュレーションは多面的な領域です。基本的なアイデアと機能コンポーネントは次のとおりです。それを細かく分割し、編集して詳細を入力します。これから説明することの多くは、プロセッサの内部動作の知識を必要とします-アセンブリの知識が必要です。特定のことについて少し漠然としている場合は、質問に答えてください。そうすれば、この答えを改善し続けることができます。
エミュレーションは、プロセッサと個々のコンポーネントの動作を処理することによって機能します。システムの各部分を構築してから、ハードウェアでのワイヤーと同じように各部分を接続します。
プロセッサエミュレーションを処理する方法は3つあります。
これらのすべてのパスで、同じ全体的な目標があります。プロセッサの状態を変更して「ハードウェア」とやり取りするコードを実行します。プロセッサの状態は、特定のプロセッサターゲットのプロセッサレジスタ、割り込みハンドラなどの集まりです。6502のために、あなたはレジスタを表す8ビット整数の数を持っていると思います:A
、X
、Y
、P
、とS
。また、16ビットのPC
レジスタも必要です。
解釈では、IP
(命令ポインタ- PC
、プログラムカウンタとも呼ばれます)から開始し、メモリから命令を読み取ります。コードはこの命令を解析し、この情報を使用して、プロセッサーによって指定されたプロセッサーの状態を変更します。解釈の中心的な問題は、非常に遅いということです。特定の命令を処理するたびに、それをデコードして必要な操作を実行する必要があります。
動的再コンパイルでは、解釈と同様にコードを反復処理しますが、オペコードを実行するだけでなく、操作のリストを作成します。分岐命令に到達したら、この操作のリストをホストプラットフォームのマシンコードにコンパイルし、このコンパイルされたコードをキャッシュして実行します。その後、特定の命令グループを再度ヒットした場合、キャッシュからコードを実行するだけで済みます。(ところで、ほとんどの人は実際に命令のリストを作成するのではなく、それらをその場で機械語コードにコンパイルします-これは最適化をより困難にしますが、十分な人々が興味がない限り、これはこの回答の範囲外です)
静的再コンパイルでは、動的再コンパイルと同じですが、ブランチに従います。プログラム内のすべてのコードを表すコードのチャンクを構築することになり、その後、干渉を受けることなく実行できます。これは、次の問題がない場合に最適なメカニズムです。
これらの組み合わせにより、99%のケースで静的再コンパイルが完全に実行不可能になります。詳細については、Michael Steilが静的再コンパイルについていくつかの優れた研究を行っています。
プロセッサエミュレーションの反対側は、ハードウェアとやり取りする方法です。これには本当に2つの側面があります。
特定のプラットフォーム(特にNES、SNESなどの古いコンソール)では、完全に互換性を保つためにエミュレーターに厳密なタイミングが必要です。NESを使用すると、CPUが正確なタイミングでピクセルをメモリに配置する必要があるPPU(ピクセル処理ユニット)があります。解釈を使用すると、サイクルを簡単にカウントし、適切なタイミングをエミュレートできます。動的/静的再コンパイルでは、物事は/ lot /より複雑になります。
割り込みは、CPUがハードウェアと通信する主要なメカニズムです。一般に、ハードウェアコンポーネントは、CPUにどの割り込みを処理するかを指示します。これは非常に簡単です。コードが特定の割り込みをスローするとき、割り込みハンドラテーブルを見て、適切なコールバックを呼び出します。
特定のハードウェアデバイスをエミュレートするには、2つの側面があります。
ハードドライブの場合を考えてみましょう。機能は、バッキングストレージ、読み取り/書き込み/フォーマットルーチンなどを作成することによってエミュレートされます。この部分は、通常、非常に簡単です。
デバイスの実際のインターフェースはもう少し複雑です。これは通常、メモリマップレジスタ(たとえば、デバイスがシグナリングを行うために変更を監視するメモリの一部)と割り込みの組み合わせです。ハードドライブの場合は、読み取りコマンド、書き込みなどを配置し、このデータを読み取るメモリマップ領域がある場合があります。
もう少し詳しく説明しますが、それには100万通りの方法があります。ここで具体的な質問がある場合は、遠慮なく質問してください。情報を追加します。
私はイントロここにかなり良いを与えてくれたと思いますが、そこにあるトンの追加領域のは。質問があれば喜んでお手伝いします。非常に複雑なため、私はこれのほとんどを非常に曖昧にしてきました。
この回答が提出されてから1年以上が経過しており、注目を集めているところで、いくつかの更新を行う時期が来たと思いました。
おそらく、現在エミュレーションで最もエキサイティングなのは、前述のMichael Steilによって開始されたlibcpuです。これは、再コンパイル(静的および動的!)にLLVMを使用する多数のCPUコアをサポートすることを目的としたライブラリです。それは大きな可能性を秘めているし、エミュレーションにとって素晴らしいことになると思う。
emu-docsにも注目が集まりました。これには、エミュレーションの目的で非常に役立つシステムドキュメントの優れたリポジトリが格納されています。私はそこであまり時間を費やしていませんが、すばらしいリソースがたくさんあるようです。
この投稿が役に立ったことを嬉しく思います。お尻から降りて、年末/来年初めまでにこの本について私の本を仕上げることができればと思っています。
エミュレーションは困難に思えるかもしれませんが、実際にはシミュレーションよりもかなり簡単です。
通常、どのプロセッサにも、状態、相互作用などを記述する適切に記述された仕様があります。
パフォーマンスにまったく関心がない場合は、非常にエレガントなオブジェクト指向プログラムを使用して、ほとんどの古いプロセッサーを簡単にエミュレートできます。たとえば、X86プロセッサには、レジスタの状態を維持する(簡単)、メモリの状態を維持する(簡単)、および各着信コマンドを取得してそれをマシンの現在の状態に適用するものが必要です。本当に正確さが必要な場合は、メモリの変換、キャッシングなどもエミュレートしますが、それは可能です。
実際、多くのマイクロチップおよびCPUメーカーは、チップのエミュレーターに対して、次にチップ自体に対してプログラムをテストします。これにより、チップの仕様またはハードウェアでのチップの実際の実装に問題があるかどうかを確認できます。たとえば、デッドロックが発生するチップ仕様を作成することは可能です。ハードウェアで期限が発生した場合、仕様に再現できるかどうかを確認することが重要です。それは、チップ実装の問題よりも大きな問題を示しているためです。
もちろん、ビデオゲームのエミュレーターは通常、パフォーマンスに関心があるため、単純な実装を使用せず、描画やサウンドを使用するなど、ホストシステムのOSとインターフェイスするコードも含まれています。
古いビデオゲーム(NES / SNESなど)の非常に遅いパフォーマンスを考慮すると、エミュレーションは最新のシステムでは非常に簡単です。実際、これらのシステムが人気であったときにすべてのカートリッジに無料でアクセスできることは夢の実現であったことを考えると、これまでにすべてのSNESゲームまたはこれまでの任意のAtari 2600ゲームのセットをダウンロードできることはさらに驚くべきことです。
この質問は少し古いですが、ディスカッションに何か付け加えたいと思います。ここでの答えのほとんどは、エミュレータがエミュレートするシステムの機械語命令を解釈することを中心にしています。
ただし、これには「UltraHLE」と呼ばれる非常によく知られた例外があります(WIKIpediaの記事)。これまでに作成された最も有名なエミュレーターの1つであるUltraHLEは、市販のニンテンドー64ゲームを(家庭用コンピューターではまともなパフォーマンスで)エミュレートすることが不可能であると広く考えられていたときにエミュレートしました。実際のところ、UltraHLEが作成されたとき、ニンテンドーはまだニンテンドー64の新しいタイトルを作成していました!
印刷雑誌でエミュレーターに関する記事を初めて見たのは、以前はウェブで議論されているエミュレーターを見ただけでした。
UltraHLEの概念は、マシンレベルの呼び出しの代わりにCライブラリの呼び出しをエミュレートすることで不可能を可能にすることでした。
注目に値するのは、JavaScriptでゲームボーイエミュレータを作成しようとしたイムランナザールの試みです。
80年代のBBCマイクロコンピューター(VBeebをGoogleに入力)の自分のエミュレーターを作成したので、知っておくべきことがたくさんあります。
実際には、エミュレーションのスピードと忠実性を重視して書いているのが一般的です。これは、ターゲットシステムのソフトウェアが、ソースシステムの元のハードウェアよりも動作が遅い(可能性がある)ためです。これは、プログラミング言語、コンパイラ、ターゲットシステムなどの選択を制約する可能性があります。
さらに、エミュレートする準備を整える必要があります。たとえば、マイクロプロセッサのトランジスタの電圧状態をエミュレートする必要はありませんが、おそらく必要です。マイクロプロセッサのレジスタセットの状態をエミュレートします。
一般的に言えば、エミュレーションの詳細レベルが小さいほど、元のシステムに忠実になります。
最後に、古いシステムの情報は不完全または存在しない可能性があります。したがって、元の機器を手に入れることは不可欠です。または、少なくとも他の誰かが書いた優れたエミュレータを賞賛する必要があります。
はい、バイナリマシンのコード全体を「手動」で解釈する必要があります。それだけでなく、ほとんどの場合、ターゲットマシン上に同等のものがないエキゾチックなハードウェアもシミュレートする必要があります。
簡単な方法は、指示を1つずつ解釈することです。それはうまくいきますが、遅いです。より高速なアプローチは再コンパイルです-ソースマシンコードをターゲットマシンコードに変換します。ほとんどの命令は1対1でマッピングされないため、これはさらに複雑です。代わりに、追加のコードを含む複雑な回避策を講じる必要があります。しかし、最終的にははるかに高速です。最近のほとんどのエミュレーターがこれを行います。
... --- ...
-これらの3つのモールス符号は、3つの文字S、O、Sを表します。」ため...
であるコードの文字「S」を表します。番号?
エミュレータを開発するときは、システムが動作しているプロセッサアセンブリ(Z80、8080、PS CPUなど)を解釈しています。
また、システムにあるすべての周辺機器(ビデオ出力、コントローラー)をエミュレートする必要があります。
古き良きゲームボーイ(Z80プロセッサーを使用しているので、間違えていません)やC64のような単純なシステム用のエミュレーターの作成を開始する必要があります。
シミュレートする必要のあるハック(異常な効果など)、タイミングの問題などが多数あるため、エミュレータの作成は非常に困難です。
この例については、http://queue.acm.org/detail.cfm?id=1755886を参照してください。
これは、1 MHzのCPUをエミュレートするためにマルチGHz CPUが「必要」である理由も示しています。
また、Darek MihockaのEmulators.comをチェックして、JITの命令レベルの最適化に関する優れたアドバイスや、効率的なエミュレーターの構築に関するその他の多くの利点を確認してください。
私はゲームコンソールをエミュレートするほど豪華なことをしたことがありませんが、Andrew Tanenbaums Structured Computer Organizationで説明されているマシンのエミュレーターを作成するというコースを一度受けました 。それは面白かったし、私にたくさんの瞬間を与えてくれた。実際のエミュレータを作成する前に、その本を手に入れたいと思うかもしれません。
実際のシステムまたはあなた自身のものをエミュレートすることについてのアドバイス?エミュレータはハードウェア全体をエミュレートすることで機能すると言えます。たぶん、回路にダウンしないでください(HWのようにビットを移動するのと同じです。バイトの移動が最終結果なので、バイトのコピーは問題ありません)。シミュレートする必要のある多くのハック(異常な効果など)、タイミングの問題などがあるため、エミュレータの作成は非常に困難です。1つの(入力)部分が間違っている場合、システム全体がダウンするか、せいぜいバグ/グリッチが発生する可能性があります。
シェアードソースデバイスエミュレータは、ポケットPC /スマートフォンエミュレータにビルド可能なソースコードが含まれています(Windows上のVisual Studio、実行が必要です)。バイナリリリースのV1とV2に取り組みました。
多くのエミュレーション問題に取り組みます:-ゲスト仮想からゲスト物理からホスト仮想への効率的なアドレス変換-ゲストコードのJITコンパイル-ネットワークアダプター、タッチスクリーン、オーディオなどの周辺デバイスのシミュレーション-ホストキーボードとマウスのUI統合-保存/低電力モードからの再開のシミュレーションのための状態の復元
@Cody Brociousが提供する回答を追加
するには新しいシステム(CPU、I / Oなど)を仮想マシンにエミュレートする仮想化のコンテキストでは、次のカテゴリのエミュレータを確認できます。
解釈:bochsはインタプリタの例であり、x86 PCエミュレータです。ゲストシステムからの各命令を受け取り、それを(ホストISAの)別の命令セットに変換して、意図した効果を生成します。はい、非常に遅いです。何もキャッシュしないので、すべての命令が同じサイクルを通過します。
動的エマレーター:Qemuは動的エミュレーターです。ゲスト命令のオンザフライ変換も結果をキャッシュします。最良の部分は、ホストシステムでできるだけ多くの命令を直接実行して、エミュレーションを高速化することです。また、Codyで言及されているように、コードをブロックに分割します(1つの実行フロー)。
静的エミュレーター:私が知る限り、仮想化に役立つ静的エミュレーターはありません。
エミュレーションを開始する方法。
1.低レベルのプログラミングに基づいた本を入手します。ニンテンドーの「ふり」オペレーティングシステムに必要です...ゲームボーイ...
2.具体的にはエミュレーションに関する書籍を入手してください。(OSを作成するのではなく、それに最も近いものを作成します。
3.いくつかのオープンソースエミュレーター、特にエミュレーターを作成したいシステムのエミュレーターを見てください。
4.より複雑なコードのスニペットをIDE /コンパイラにコピーします。これにより、長いコードを書く手間が省けます。これは私がOS開発のためにやっていることです、Linuxの地区を使用して
私は、Chip-8システムをJavaScriptでエミュレートすることについての記事を書きました。
システムはそれほど複雑ではないので、始めるのに最適な場所ですが、オペコード、スタック、レジスターなどがどのように機能するかをまだ学びます。
NESについては、もう少し長いガイドを書く予定です。