なぜ"サイクル正確"エミュレーションが必要なのか

いわゆるエミュレータはサイクル正確(cycle-accurate)なエミュレータと、機能レベル(function/functional accurate)エミュレータの2つに大別できる。
ゲーム機のエミュレータは一般的に前者であり、Nintendo64GameCube/Wiiエミュレータが例外的に後者に属する(内蔵DSPや周辺プロセサをエミュレートしない。コミュニティではHLEと呼ばれる。)。比べて、qemuや他のアーキテクチャエミュレータは後者が一般的と言える。

時間精度

サイクル正確なエミュレータは、全モジュールに共通した"エミュレーション時間"の概念があり、この時間の概念をどの程度厳密に管理するかが(とても)微妙な問題となる。
エミュレータの動作は、簡単には、

  1. CPUを1ステップエミュレーションする
  2. (実際のハードウェアにおける)1ステップの実行に掛かるはずの時間を算出する
  3. エミュレータ内の時間をその分進める
  4. 周辺チップの状態を更新する (★)

の繰り返しとなる。
エミュレータの時間精度は★の部分の更新をどの程度の頻度で行うかに依る。
例えば、いわゆる"ラスタスクロール効果"を再現するには、TV画面が1ラインを書くのに掛かる時間と同様の精度でエミュレーションを行う、つまり"ラインベースのエミュレーション"を行う必要がある*1
通常の感覚で言えば、CPUのクロックは多すぎて困ることはない。PCのゲームなら、1GHzのCPUでも3GHzのCPUでも、フレームレートやその他画質等の違いはあっても、ゲームが正常に動作することには代わりはない。
しかし、ゲームコンソールにおいては重要な問題になりうる。そして、そのときどのような問題が起こるかというのが、そのまま、サイクル正確なエミュレーションの必要性になる。

時間は未定義動作を定義する

それなりの数のゲームプログラムは"偶然"動作しているに過ぎない。
プロセサの世界では、"変数に値を代入した後、値が反映されるのは2クロック後"のような現象が多々ある。他にも、プロセサの時間的なバグに依存したコードであったり、未定義値に依存したコードであることもある。
これらの未定義な動作を決定付けるのが"時間"であり、これを正確にエミュレーションする必要がある。

*1:大抵のコンソールではこのようなタイミングを取るためのハードウェア機構があるので、それさえ正確にエミュレーションすれば十分に思える。しかしこのアイデアはなかなか上手く行かない。