Writing NES Emulator in Rustをやってみる

参考ページ
メインページ
このページをChapter1から進行する。
6502のリファレンス
6502の命令仕様はここを見て確認。
6502のWeb実行
命令を実行してレジスタやフラグの状況など確認するのにいい。

チャプター3
CPUの実装が始まる。
ここもメインのページを参考にしながら実装していく。
チャプター3-3で突き放されて少し面食らうけど、リファレンスページとWeb実行を参考にしながら実装する。よく分からないときはGitHubを参考に実装する。

チャプター5
メインページを参考にcartridgeを実装。
cpuの単体テストがビルドできなくなったので、命令の配列を受け取ってダミーカートリッジを作成する関数を用意して対応した。

チャプター5-1
無限ループ
nestest.nesを実行してみると無限ループに。。
デバッガでprogram_counterを見ると0xc004
から開始していた。
nestest.logを確認すると0xc000
から開始していないとおかしいようだ。
reset時のprogram_counterの読み込みに失敗している?
nestest.nesのバイナリを確認すると、0x3ffc-0x3ffdに0xc004
が入っている。
正しく読み込めているようだ。
$ od -tx1z -Ax nestest.nes | less
003fb0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >................<
*
004000 00 00 00 00 00 00 00 00 00 00 af c5 04 c0 f4 c5 >................<
004010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >................<
*
004030 80 80 ff 80 80 00 00 00 80 80 ff 80 80 00 00 00 >................<
- 0x3ffcなのは0xfffc - 0x8000 - 0x4000された結果
- odでは0x3ffcではなく0x400cに
0xc004
が入っているように見えるが、これはnesファイルのヘッダ分、アドレスに+0x0010されているため
main.rsでprogram_counterを指定していた
0xc000
にするものらしい。
Start execution at $C000 and compare execution with a known good log
チャプター4まではこのようなprogram_counterの強制上書きは無いので注意。

チャプター5-1
RORのキャリーフラグが正しくない?
mynes.logとnestest_no_cycle.logの差分をとると、メインページに書かれているのと違う箇所で差分が発生していた。
$ diff -y -W 155 mynes.log nestest_no_cycle.log | less
CF51 6A ROR A A:01 X:55 Y:69 P:65 SP:FB CF51 6A ROR A A:01 X:55 Y:69 P:65 SP:FB
CF52 90 1E BCC $CF72 A:80 X:55 Y:69 P:E4 SP:FB | CF52 90 1E BCC $CF72 A:80 X:55 Y:69 P:E5 SP:FB
0xcf52のP(status)の値が違う。本来はE5だが、E4になってしまっている。
これは、キャリーフラグが立っていないということ。
ログはそれぞれ命令実行時のものなので、実行結果としてのフラグの変化は次のログに反映されている。
つまり、RORで正しくキャリーフラグが立っていない。
RORのキャリーフラグを立てる処理が間違っていた
ROLのキャリーフラグを立てる処理をそのままRORにコピーしてしまっていた。
ROLは対象の7ビット目がキャリーフラグを立てるかどうかに関係するが、RORは0ビット目だった。