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

ファミコンエミュレータを写経してみるお話6【ROMの吸い出し、Mapper】

//

前回

ファミコンエミュレータを写経してみるお話5【keypad, sound】 - 196Log


やること

前回、キーパッドと音の実装を行ったので、ゲームを動かしつつ、バグを修正していきます。タイトルは写経となっていますが、この辺りから少し毛色が変わってきますので、動くか心配です。

参考にするもの

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

github.com

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

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

hp.vector.co.jp

pgate1.at-ninja.jp

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

booth.pm

読み始める前に

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

ROMの吸い出し

有名なマリオのゲームをROMから吸い出しました。

吸い出す機会はこちらで購入しました。

https://www.amazon.co.jp/gp/product/B073PT9QB5/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1

吸い出しアプリケーションは製造元のサイトからダウンロードできます。Win, Mac共に対応していましたが、なんとなく怖かったので私は仮想Windows上で作業しました。特に問題はないかと思います。吸い出し自体もほぼ自動で情報を読み取って作業してくれました。 ちなみに、カセットにはマッパーと呼ばれるいくつかの種類に分けられるそうですが、本エミュレータは現状Mapper0(ベーシックなやつ)にしか対応してないです。
もちろん吸い出したromを配る分けにはいかないので、このあたりは各自で用意お願いします、、、

バグの修正

ここからは、ゲームが正常に動くように修正を繰り返しました。


最終的に修正が完了したプルリクが以下になります。修正ごとにコミットをなるべく分けているので、順に見て頂けると理解できるかと思います。

github.com

主な修正内容

ざっくりと修正したことを書きます。

  • Spriteの実装ミス
    • Spriteの横幅を考慮せずに生成を行っていたため、配列にアクセス時パニックを起こしてホワイトアウトしていた。
  • Keypadの実装ミス
    • jsからの入力に使用する領域を、適切に確保しておらず入力が上手く伝わらなかった。
  • スイープの方向フラグ
    • フラグの書き込み時の判定がタイポでおかしくなっていた。
  • 三角波の実装ミス
    • 周波数が毎回初期化でセットされていたため、音が途切れ途切れだった。
    • 音が流れっぱなしになってしまうので、ボリュームが0になるタイミングを適切になるようにした。
    • その他、音量などのリファクタを含む。

以上より、マリオが動くようになりました。

DMC等の対応ができていませんが、ひとまず動くところまで来れました。

Mapper3に対応したい

最終目標はMapper4への対応なのですが、参考リポジトリさんはMapper3の実装がされているので、先にこちらを練習がてら実装しようと思います。(実装量的にもかなり少ない。)
とりあえず、現状のコードをリファクタします。mapperとして機能を分けています。

github.com

次に本命のmapper3を実装しました。

github.com


その際に気がついた、バグについてはこちらで修正しております。

github.com


無事Mapper3ドラクエ1が動きました。が、どうやらBGMにIRQ割り込みを利用しているそうで、現状だと音が出ません。(APUに未実装)そのため、ROMを多少書き換える事で対応しました。


Mapper4

続いて、Mapper4に対応していきます。mmc3とも呼ばれているそうです。 cpuから見えるアドレスは既に固定されており、カセットのPRG ROMへは0x8000-0xFFFFでのみアクセスできます。つまり、カセットにどれだけソフトのプログラムを積んだところで、先の0x8000分のアドレス空間にしかアクセスできないため、全てのデータを読み出すことはできません。

これを解消するのがmapper(カセット側に搭載されている)で、mapper4ではバンクを切り替えることで、0x8000-0xFFFFのアクセスを柔軟に0x80000分ぐらいのPRGROMに振り分けています。
CHR RAMに対しても似たようにbank分けしている模様。

MMC3 - Nesdev wiki


実行は以下のプルリクになります。IRQの割り込みの実装がまだだったため、はじめに実装しています。また、mapper4ではcpuレジスタ等にアクセスが必要であったため、周辺の実装にも細かな変更が加わっています。

github.com

私は手元でff3の画面の動作を確認できました。


積み残し

  • ff3にて音が鳴らない(dmcが未実装なのでその可能性あり。もしくは再生停止周りのバグ)
  • Save Ramのデータが保持されない

の2点です。Save Ram0x6000からアクセスできるRamで、セーブに対応しているカセットはボタン電池にて、データが消えないように電気が流れているようです。次回はこのあたりを直していきたいと思います。

ファミコンエミュレータを写経してみるお話7【DMC, SRAM(バッテリーバックアップRAM)】 - 196Log