セキュリティ系の勉強、その他開発メモとか雑談. GithubはUnity触っていた頃ものがメイン Twitterフォローもよろしくです

ファミコンエミュレータを写経してみるお話2【PPU】

//

前回

thinline196.hatenablog.com

やること

前回は初歩として、CPUの実装を行い、参考サイトを元に一通りの必要と思われる命令を網羅的に実装しました。まだファミコンをエミュレートする際に必要な実装がかけているかもしれませんが、その場合は後々修正していこうと思っています。

LogiClover vol.1を読んでいると、CPUの次にPPUを実装しています。これは、ファミコンの描画を司る部分だそうで、CPUにより間接的に制御されているとのこと。今回は制御をする機構はなるべく後回しに、PPUスタンドアロンなトコから実装していけたらなと思ってます。

参考にするもの

  • コード周りはこちらのコードを観させてもらおうと思います。またRustの書き方の勉強としても頼りにさせてもらいます。 github.com

ファミコンエミュレータの創り方 - Speaker Deck

  • こちらに有志の皆さんがNESの情報をまとめて下さっているので、利用させてもらいます。特に、コードを写経しているだけでは意味がないので、まずこちらを見て自分で実装を考えます。

hp.vector.co.jp

pgate1.at-ninja.jp

  • こちらの本も参考にさせてもらいます。1つ目のリンクの方の実装と見比べる事で、実装にマストな部分を見出すために使いました。また、こちらの方の実装順番も参考にしてます。

booth.pm

読み始める前に

  • ファミコンの仕様についてはネット上にたくさん情報が上がっているので、ここでは詳しい事は書かないです。(自分も分からない)用語の説明もほとんどしていません。 しかし、実装手順の再現性があるサイトは個人的に少ないなと感じたので、自分の試行錯誤をここにまとめて、うまく踏み台にしてもらえたらなと考えています。言語はRustを使っており参考サイトもRustが中心のものが多いです。
  • また、解説力も乏しいので、適宜実装が完了したと思われるcommitにジャンプできるGithubのリンクをそれぞれに置いておくので、そこからコミット履歴などを参照していただいてもらう形にします。申し訳ないです。

レジスタ

前回のCPU同様、レジスタ周りから作り始めるのが良さそうです。ということで、コード参考のリポジトリを確認すると、どうやらRAMの実装とOAMPPU_ADDRなどを別途細かく分けて実装していること、またそれらにRAMの実装が必要なことが分かったので同時にやってしまいます。RAMの実装は、いろんな箇所で使いまわせるような実装になっていました。Registerの入出力周りのベースを実装したのがこのコミットです。

github.com

現状ここの実装が分からなかったので、修正しました。今後の動きによっては元に戻そうと思います。 https://github.com/196Ikuchil/nes_emulator/commit/5c3f2690437d9552b7af515fb047210fc8aaa309#r37678779

PPU

レジスタが動きそうなので、これを利用してPPUの動きをエミュレートしていきます。まず描画する背景、スプライトを生成できるようにしようと思います。参考書籍より、タイルが最小構成要素だと思ったのですが、参考実装ではsprite_utils.rsSpriteという構造体がおそらく最小要素になっている(タイル・スプライトの共通要素をここで定義)ので、そこから作ります。

注意点として以下があります。

  • 8*16のスプライトに対応済みとのことなのでそのまま実装する
  • Mapper3に対応済みとのことだが、現状不必要なので実装しない

PPUを呼び出せる部分まで実装しました。これをフレームごとに呼び出して画面を作っていくイメージです。リンクはPPUメイン実装時のコミットですが、パーツごとになんとなくコミットを分けているのでそちらも実装順の参考になるかもです。

github.com

runさせることで、そのフレームで必要な背景とスプライトを一通り生成するはずです。

DMA

CPUを介さずに直接RAMへデータを読み込む機構を実装します。詳しくはこのスライドに紹介されています。
ファミコンエミュレータの創り方 - Speaker Deck

これも機能のみ実装しておきます。

github.com

後々に、Bus0x4014番地に書き込みがあった場合にDMAによる転送が有効になるように仕込みますが、現状は実装されていません。

積み残し

今回は最低限PPUの機能として必要そうな部分のみの実装を行いました。テストコードをサボってしまい少ない分、しっかり動くかまだ未知数ですが、切りがいいので続きは次回に回します。次回は前回のCPUと合わせてテストROMを動かせるようにして、今回の分のデバッグも行いたいと考えています。

追記

修正が加わっているので、PPUあたりの該当コードは直しておいてください。後々修正する記事で同じリンクが登場するので今じゃなくても大丈夫です。

github.com github.com
ここではspriteに修正に入っています。

github.com
またここでは画面のスクロールに修正が入っています。

github.com