ファミコンエミュレータを写経してみるお話6【ROMの吸い出し、Mapper】
前回
ファミコンエミュレータを写経してみるお話5【keypad, sound】 - 196Log
やること
前回、キーパッドと音の実装を行ったので、ゲームを動かしつつ、バグを修正していきます。タイトルは写経となっていますが、この辺りから少し毛色が変わってきますので、動くか心配です。
参考にするもの
- コード周りはこちらのコードを観させてもらおうと思います。また
Rust
の書き方の勉強としても頼りにさせてもらいます。
ファミコンエミュレータの創り方 - Speaker Deck
- こちらに有志の皆さんが
NES
の情報をまとめて下さっているので、利用させてもらいます。特に、コードを写経しているだけでは意味がないので、まずこちらを見て自分で実装を考えます。
- こちらの本も参考にさせてもらいます。1つ目のリンクの方の実装と見比べる事で、実装にマストな部分を見出すために使いました。また、こちらの方の実装順番も参考にしてます。
読み始める前に
- ファミコンの仕様についてはネット上にたくさん情報が上がっているので、ここでは詳しい事は書かないです。(自分も分からない)用語の説明もほとんどしていません。 しかし、実装手順の再現性があるサイトは個人的に少ないなと感じたので、自分の試行錯誤をここにまとめて、うまく踏み台にしてもらえたらなと考えています。言語は
Rust
を使っており参考サイトもRust
が中心のものが多いです。 - また、解説力も乏しいので、適宜実装が完了したと思われる
commit
にジャンプできるGithub
のリンクをそれぞれに置いておくので、そこからコミット履歴などを参照していただいてもらう形にします。申し訳ないです。
ROMの吸い出し
有名なマリオのゲームをROM
から吸い出しました。
動きそうなので吸い出すよっ pic.twitter.com/gpRTAGrMxt
— いくちる (@196Ikuchil) March 17, 2020
吸い出す機会はこちらで購入しました。
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
を配る分けにはいかないので、このあたりは各自で用意お願いします、、、
バグの修正
ここからは、ゲームが正常に動くように修正を繰り返しました。
後ろにしか進めないジャンプが不調なマリオ pic.twitter.com/7gEUINO2g5
— いくちる (@196Ikuchil) March 18, 2020
最終的に修正が完了したプルリクが以下になります。修正ごとにコミットをなるべく分けているので、順に見て頂けると理解できるかと思います。
主な修正内容
ざっくりと修正したことを書きます。
Sprite
の実装ミスSprite
の横幅を考慮せずに生成を行っていたため、配列にアクセス時パニックを起こしてホワイトアウトしていた。
Keypad
の実装ミスjs
からの入力に使用する領域を、適切に確保しておらず入力が上手く伝わらなかった。
- スイープの方向フラグ
- フラグの書き込み時の判定がタイポでおかしくなっていた。
- 三角波の実装ミス
- 周波数が毎回初期化でセットされていたため、音が途切れ途切れだった。
- 音が流れっぱなしになってしまうので、ボリュームが0になるタイミングを適切になるようにした。
- その他、音量などのリファクタを含む。
以上より、マリオが動くようになりました。
スイープとDMCが不完全だけど、あらかた動いたっす pic.twitter.com/apse0U9bhb
— いくちる (@196Ikuchil) March 19, 2020
DMC
等の対応ができていませんが、ひとまず動くところまで来れました。
Mapper3に対応したい
最終目標はMapper4
への対応なのですが、参考リポジトリさんはMapper3
の実装がされているので、先にこちらを練習がてら実装しようと思います。(実装量的にもかなり少ない。)
とりあえず、現状のコードをリファクタします。mapper
として機能を分けています。
次に本命のmapper3
を実装しました。
その際に気がついた、バグについてはこちらで修正しております。
無事Mapper3
のドラクエ1が動きました。が、どうやらBGMにIRQ
割り込みを利用しているそうで、現状だと音が出ません。(APUに未実装)そのため、ROM
を多少書き換える事で対応しました。
原点にして始点 pic.twitter.com/GBKpYdv43M
— いくちる (@196Ikuchil) March 26, 2020
Mapper4
続いて、Mapper4
に対応していきます。mmc3
とも呼ばれているそうです。 cpu
から見えるアドレスは既に固定されており、カセットのPRG ROMへは0x8000-0xFFFFでのみアクセスできます。つまり、カセットにどれだけソフトのプログラムを積んだところで、先の0x8000分のアドレス空間にしかアクセスできないため、全てのデータを読み出すことはできません。
これを解消するのがmapper(カセット側に搭載されている)で、mapper4ではバンクを切り替えることで、0x8000-0xFFFFのアクセスを柔軟に0x80000分ぐらいのPRGROMに振り分けています。
CHR RAMに対しても似たようにbank分けしている模様。
実行は以下のプルリクになります。IRQ
の割り込みの実装がまだだったため、はじめに実装しています。また、mapper4
ではcpuレジスタ等にアクセスが必要であったため、周辺の実装にも細かな変更が加わっています。
私は手元でff3
の画面の動作を確認できました。
やっと動いた、、! pic.twitter.com/D8HjEMRa0K
— いくちる (@196Ikuchil) April 4, 2020
積み残し
ff3
にて音が鳴らない(dmc
が未実装なのでその可能性あり。もしくは再生停止周りのバグ)Save Ram
のデータが保持されない
の2点です。Save Ram
は0x6000
からアクセスできるRamで、セーブに対応しているカセットはボタン電池にて、データが消えないように電気が流れているようです。次回はこのあたりを直していきたいと思います。
次