前回
ファミコンエミュレータを写経してみるお話2【PPU】 - 196Log
やること
前回はPPUの機能を実装しましたが、まだ動作確認ができていないので、CPUと合わせてテストROMが動くようにしようと思います。まずはこちらのsample1.nesを起動させてみます。hello word!と表示されるものです。他のromはおそらく動きません。

参考にするもの
- コード周りはこちらのコードを観させてもらおうと思います。また
Rustの書き方の勉強としても頼りにさせてもらいます。
github.com
ファミコンエミュレータの創り方 - Speaker Deck
- こちらに有志の皆さんが
NESの情報をまとめて下さっているので、利用させてもらいます。特に、コードを写経しているだけでは意味がないので、まずこちらを見て自分で実装を考えます。
- こちらの本も参考にさせてもらいます。1つ目のリンクの方の実装と見比べる事で、実装にマストな部分を見出すために使いました。また、こちらの方の実装順番も参考にしてます。
読み始める前に
- ファミコンの仕様についてはネット上にたくさん情報が上がっているので、ここでは詳しい事は書かないです。(自分も分からない)用語の説明もほとんどしていません。 しかし、実装手順の再現性があるサイトは個人的に少ないなと感じたので、自分の試行錯誤をここにまとめて、うまく踏み台にしてもらえたらなと考えています。言語は
Rustを使っており参考サイトもRustが中心のものが多いです。 - また、解説力も乏しいので、適宜実装が完了したと思われる
commitにジャンプできるGithubのリンクをそれぞれに置いておくので、そこからコミット履歴などを参照していただいてもらう形にします。申し訳ないです。
修正
sample1.nesを呼び出すために修正した箇所があります。まだ修正してない場合は参照してください。
【Fix】Hello world bug fix by 196Ikuchil · Pull Request #7 · 196Ikuchil/nes_emulator · GitHub
ひとまず呼び出そうとしてみる
現状頑張って機能を使おうとした場合、何が足りないのか把握します。下のリンクは軽い修正も含めて今までのものを実装したものになります。
rendererという生成したスプライトを描画する機能- カセットを読み込む機能(
ROM,parse,Cassette) - 上を操る
js側の実装全般
カセットのデータ
Busも通さなければいけないので、最初にカセットの読み込みを実装するのが良さそうです。下のリンクではカセットデータをRomへ流し込み、エミュレータのContext内で扱えるように実装しなおしています。コミット履歴から、カセットのパーサーやRomの実装についても確認可能です。
描画担当
次はrendererを実装します。これは描画を担当する部分です。PPUで生成したデータを取り扱ってくれるようにします。
環境を整える
Rustの成果物をjsから呼び出して、ブラウザ上で動作させるようにします。npmによって入れるものはローカルで成果物を走らせてブラウザで表示するために使用します。main.rsには、js側から呼び出すrunメソッドを実装します。Makefileを作りmakeでビルド等を走らせます。.cargo/configに、ビルドに必要な設定を記述しておきましょう。
ビルドの際に必要になるものは以下なので、PCにインストールしておいてください。
- `nodejs` - `cmake` - `emscripten`(emcc) - `rustup`
externsにはjs側が公開しているメソッドをrust側から呼び出すためのことを記述しています。起動実行にはemscriptenが用意したメソッドを、描画にはcanvas_renderというメソッドを呼び出せるようにしています。
最終的にプルリクにまとめているので、こちらを見た方が早いかもしれません。
sample1.nesは起動しますが、他はまだ起動しないでしょう。
デバッグに関して
起動しない場合、まずCPUの実装を疑うべきですが、初回はbackgroundの値を出力してみるべきと思います。それにより描画部分かそれ以前かに分けられるので、以前であればtileあたりのデータを覗いてみましょう。
そこにもデータが上手く反映されていなければ、CPUの実装ミスを疑います。特に今回のROMは短いので、バイナリエディタと合わせて、実装されるopecodeを追っていくことで、CPUの実装ミスに気がつけると思います。
<br>
それがダメであればPPUの実装をみますが、この辺りは単独では大変なので、僕は参考コードと自分の実装、同じ位置にprintln!`をおき、値をくらべながら違う値が扱われている箇所を探しました。実装がほぼ同じであれば、意外と有効な技なので、試してみてください。
次回
次回はデバッグを行うためにnestest.nesを起動させ(るためにデバッグを行います。
次
ファミコンエミュレータを写経してみるお話4【nestest.nesの起動】 - 196Log