C++ / OpenSiv3D でゲームボーイエミュレータを作り始めてから 3 か月経ちました。私がはじめに目指していた、市販のゲームをいくつか動かしてみたいという目標を超えて、思っていたよりもたくさんの機能を実装することができました。
前回の続き
前回の記事では CPU、PPU の実装と、DMA によるスプライトデータの転送が可能になったところまででした。
その後は、Tobu tobu girl や BennVenn’s Shop のダンパーで市販カートリッジを吸い出して動かしたりしていました。
ROM アドレスへの書き込みは、MBC へのバンク切り替えなどのコマンドとして扱う必要がありますが、うっかりメモリを書き換えてしまっていて、ゲームが進まなかったりしてました。よくあるハマりポイントみたいです。
それから、Snorpung 氏のデモ Is That a Demo in Your Pocket? や Oh! がうまく動かなくて、デバッグをしていました。期待される割り込みタイミングや LDH 実行タイミングがかなりシビアであることが原因で、とても苦戦しましたが、Emulicious というエミュレータでログを取り、実行結果を比較していくことでなんとか解決することができました。このエミュレータのデバッガでは、スキャンラインの何ドット目にいるかを表示することができるので、それを指標にすると細かい部分のデバッグがやりやすかったです。
デバッグモニタ
デバッグ用の情報表示について、これまではブレーク時にコンソールへレジスタの値やメモリの状態をダンプするだけでしたが、常に画面上にこれらを表示するようにしてみました。
便利さよりも、こういうのがあるとかっこいいというのが主な理由ですが……思ったより便利です。現在はさらに色々追加されて、こんな感じになってます。
サウンド (APU)
とりあえず普通に聞こえるレベルに実装できたと思いますが、かなり苦戦しました。
ドキュメントとしては Audio – Pan Docs のほか、実装の詳細については Game Boy Sound Emulation | NightShade’s Blog にまとまっており、主にこれらを参考に実装していきました。
……ただ、開発初期の頃の自分は、メモリへの書き込みがトリガーとなってハードウェアの動作が変化する、という基本的な動きがわかっていなかったため、これを理解するまでチャンネルをうまくノートオンできずにいました。
星のカービィのサウンドテスト(タイトル画面で下+B+Select)や、夢を見る島の効果音(スイープの確認など)が不自然に聞こえないかを確認しながら、修正を繰り返しました。
そこそこ聞けるレベルに至った後は放置しており、未だに Blargg のテスト ROM (dmg_sound) はパスできてません。
ゲームボーイカラー (CGB mode)
モノクロのゲームがだいたい動くようになってきて、ゲームボーイカラー (CGB) にも対応させたいと思い始めました。カラー専用の機能については、CGB Registers – Pan Docs や Palettes – Pan Docs にまとまっていました。
- カートリッジヘッダ (
$0143
) を確認 - ブート直後のレジスタの値が DMG mode とは異なる
- $FF68-6B へのアクセスは CGB 専用のパレットデータの読み書きなので、これに対応する色データをアプリ内部に保持しておく
- VRAM, WRAM バンク切り替え
- HDMA(転送タイミングは無視、とりあえず一瞬で転送されるようにする)
- PPU のカラー対応
まずは上記を実装しました。倍速モードは最初は無視してました。PPU の実装は、acid のカラー版で動作確認をしました。
スーパーゲームボーイ (SGB mode)
スーパーゲームボーイ (SGB) モード専用のカラーリングがあるカートリッジがあり、これは CGB モードでは表示できません。例えば私が好きなカービィ2など。これに対応させてみたいと思って実装を始めました。
基本的な仕組みについて。$FF00 (P1 / JOYP) レジスタへ特定の値が書き込まれると、SGB への通信として扱われます。1回の書き込みで 0 or 1 の 1bit 転送でき、そうして送信されたデータは 16 バイトでひとまとまりのパケットとして受信されます。このパケットは SGB に対するコマンドであり、例えばパレットの色を設定したり、画面上の特定の領域のパレットを変更したりといった様々な機能があります(詳細は SGB Functions – Pan Docs にまとまっています)。
現時点では、ゲーム画面のみカラー対応をすることができています。実機では、この周りにボーダー画像が表示されるのですが、今後の宿題にしたいと思います。
GUI
これはエミュレーションにはあまり関係ないところですが、公開しているアプリですし、操作性にも多少目を向けた方がよいと思ったので、キーボードだけでなくマウスでも大体の操作ができるようにしてみました。
右クリックでメニューが表示されます。かなり使いやすくなったので、作ってよかったです。
今後について
なんとなく、自分にも作れるのでは?……から急に始まったエミュレータ制作ですが、課題を解決するごとに達成感があり、想像以上に楽しいものでした。
まだ実装していない機能に少しづつ手を付けていきたいですが、別のハードウェアのエミュレーションもしてみたいと少し思い始めています。次やるとすれば、モチベーション維持のためにも思い入れがあるハードが良いと思うので、ファミコンか GBA になりますが、なんにせよエミュレータ制作はまだまだ続けていきたいと思っています。