みずぴー日記

人間の再起動ボタンはハワイのビーチにある

ファミコン エミュレータ

f:id:mzp:20160904225208p:plain

エミュレータを作ってみたいなぁという漠然とした思いがずっとあったので、ファミコンエミュレータを書いている。スクリーンショットにあるような表示はできる。

ファミコンにした理由

エミュレータは作りたいが、よく知らない機械のエミュレータを作ってもつまらないので、多少は親しんだファミコンにした。

一番印象深いゲーム機はスーパーファミコンだが、スーパーがついてないほうが簡単かな、と思ってファミコンにした。

買ったもの

カートリッジからROMイメージを吸い出すために、吸い出し機をAmazonで購入した。

ゲーム自体は大須レトロゲームを取り扱ってる店に行って買った。1200円くらいした。

f:id:mzp:20160904230002p:plain

進捗の様子

Hello world

f:id:mzp:20160904230234p:plain

NES研究所にあるサンプル。

最初はこれを動かすのを目標にしていた。作ろうと思ってから、これを動かすまで2週間ほどかかっている。

ギコ猫

f:id:mzp:20160904230540p:plain

ギコ猫でもわかるファミコンプログラミングにあるサンプルを一個づつ動かしていった。ギコ猫なつかしい。

スーパーマリオブラザーズ

一番最初にスーパーマリオブラザーズを動かしたときの様子。 空の色がおかしい。 f:id:mzp:20160904230658p:plain

だいたいの背景色が正しくなったが、一部おかしい。

f:id:mzp:20160904230732p:plain

空の表示はできるようになった。

f:id:mzp:20160904230834p:plain

Sprite 0の当り判定(ヒットフラグ)を実装したら、タイトルがでるようになった。

f:id:mzp:20160904230859p:plain

VRAMの読み込みがおかしかったので修正した。

f:id:mzp:20160904231000p:plain

スプライトの表示をちゃんとしたらマリオっぽいのが表示された。 が体がバラバラになっている。

f:id:mzp:20160904231053p:plain

スプライトの反転処理を実装したら、体がくっついた。

f:id:mzp:20160904231134p:plain

スプライトの背景処理をちゃんとした。

f:id:mzp:20160904231202p:plain

他の画面もそこそこ動く。

f:id:mzp:20160904232335p:plain

f:id:mzp:20160904231230p:plain

実装してないこと

実装してない部分を列挙すると以下のようになる。ゲームとして遊ぶのは無理だと思う。

  • mapper 0以外のカートリッジの対応
  • タイミング制御。普通に画面がチラつく。
  • サウンド

つらさ

うまく動作しないときの原因の特定が、本当に大変だった。

エミュレータは任意のプログラムを入力とするので、許容する入力が圧倒的に多い。さらに、その内容は機械語で書かれているので意図を理解するのが難しい。 だいたいは、以下のような手順でデバッグしていた。

  1. ディスアセンブルしたコードを読んでなんとなくの動きを把握する。
  2. そして、その通りに動いてるかどうかをメモリを監視しながら確認する。
  3. 変な動きをしてるところがあったら命令のログもとって重点的に動きを追っていく。

Rubyで書かれたNESエミュレータであるoptcarrotと動きを比較してみることも多かった。

現状

さぼっていた部分がだんだんと致命的になってきてウワーとなっている。

  • 上から順に1ラインづつ画面を更新していく、
  • CPUとPPUのタイミング動機

がっつり直さないといけないけど、どうしようかな…。

レポジトリ

https://github.com/mzp/famicom/

そろそろGo言語を勉強するか、という気分だったのでGo言語で書いている。深い意図はない。

参考にしたページ

その他

f:id:mzp:20160904231928p:plain

f:id:mzp:20160904231448j:plain

f:id:mzp:20160904231506j:plain