PCEエミュレータの実行速度を速くしたい
PCEエミュレータの実行速度を速くしたい。
どんなゲームでも普通、V-Blankとの同期をとって動作している。
つまり1/60秒の周期でウエイトを入れて、一定の速度でゲームが進行するようにしているわけだ。
PCエンジンのような昔のゲーム機は、マルチタスクでソフトが動いていないので、タイミング待ちのウエイトはビジーループで待つのが普通だ。
ビジーループというのは、ループ以外になにもしない無限ループのことである。
1/60秒に相当するPCエンジンのCPUクロック時間ごとに、ほぼ必ずビジーループが存在し、現状ではこれも忠実にエミュレーションしていることになる。
ちなみにPCエンジンのCPUはHuC6280という名前である。
ゲームの重さによりけりだが、例えばHuC6280のCPUパワーの8割を使っているゲームがあるとしよう。
その場合、残り2割のCPUパワーは、ビジーループでぐるぐるとなにもしないループを回すことに使われている。
エミュレータの場合、これを忠実にエミュレーションするのはとても無駄なCPUパワーを使ってしまう。
エミュレータではCPU以外にもグラフィックスや音源のエミュレーションを実行しなければならない。
ビジーループで暇潰ししてないで、CPU以外のハードウェアをエミュレーションする処理にさっさと移ることができれば理想的だ。
そのためには、V-Blank待ちのビジーループに入ったことを何らかの方法で検出して、そのビジーループを除去してやる必要がある。
V-Blank待ちのビジーループを検出するのはちょっとむずかしい。
確率的には、V-Blankが発生した瞬間に実行していたコードは、V-Blank待ちのビジーループである可能性が高い。
しかし、処理落ちしていた場合とか、初期設定時とか、場面遷移時などの場合は、上に該当しない。
なのでV-Blank待ちのビジーループを確実に検出することは難しい。
V-Blankの瞬間に実行していたコードが、前方へ戻る分岐命令かつ、そのコードがV-Blankの瞬間にかなりの割合で実行されていたら、これはV-Blank待ちのビジーループである、とたぶん言える。
そんな統計的な方法で検出するしかないと思われる。
そのコードを、適当な未定義命令に置き換えておき、その未定義命令をV-Blank待ちに入ったことを示すハンドラとして使うことを検討している。
ビジーループと思われる部分のコードを、エミュレータ側で強引に書き換えてしまうわけだ。
かなりアグレッシブというか、一歩間違うと動かなくなってしまうような最適化だ。
HuC6280の未定義命令は22種類ある。
そのうち1つをハンドラとして使う。
具体的には、未定義のOpcodeは以下の通りである。
$0B, $1B, $2B, $33, $3B, $4B, $5B, $5C, $63, $6B, $7B, $8B, $9B, $AB, $BB, $CB, $DB, $DC, $E2, $EB, $FB, $FC
さて、うまくいくだろうか。