いまだにちゃんと動かないソフト/ハードの解析情報

2020年前後になぜか活発になったファミコンでドラゴンクエスト3とかファイナルファンタジーとかでバグを利用するために、ドクターマリオやファミリーベーシックを電源いれたまま交換する理由の解説です。

※2021年の FF2 の RTA に関しては筆者は当事者です.

本体の中の CPU 用の SRAM の初期値

これらのテクニックの原点は初期化前の不定とされている RAM の初期値を利用することです. この RAM は本体の中の CPU 用の SRAM のことです.

教科書としては「安定動作のため不定値は必ず初期化する」ですみますが、現実には条件によっては初期化を省略したり、意図的に初期化せず乱数として利用するプログラムが実在し、それがバグが起きたときや乱数参照で都合よく進行させるために重要なこととなっています.

SRAM の初期値の傾向

わたしは SRAM の設計者ではないので詳しいことはわかりませんが、初期値は個体ごとに決まっているようです. よくある言及としてはファミコンの種類が紅白機なのかAV対応機なのかツインファミコンなのか非公式互換機なのかを書いていらっしゃいますが、 SRAM の型番で比較するほうが精度の高い比較ができるはずです.

AV対応ファミコン特有の事例

AV対応ファミコンではなぜか初期値に個体差がでない報告があり、自分がためしたところ初期値は報告通り FCEUX の default と同じでした.

AV対応ファミコンによくにた Toploader NES でも同じ部品が使われているという前提で記載しますが、 利用されている RAM は LH5216AD-10L か BR6216B-10LL です。
https://console5.com/techwiki/index.php?title=Nint...

私の所持する機種は (C)1995 Nintendo HVCN-CPU-02 で、U1 と U4の RAM は BR6216C-10L です.

U3に BU3266S や BU3270S という IC が増えていますが、これ自体は 74LS139 と 74LS368 を統合する目的のためで、端子から見るには SRAM を初期化する機能は含まれていません.

非公式互換機特有の事例

互換機ではSRAMはメインICの中に取り込まれていて、個別の部品がなく判断がし辛い傾向にあります. それに加えて互換機の種類はたくさんあり把握することは難しいです.

特定のソフトが RAM の初期値をしない理由

リセットボタンを押したと判断したため

これは非常によくある事例で、電源投入直後とリセットボタン押したのかを区別できます. ハイスコアが残っていたり、FF2 の様にオープニングデモを省略するというのもこの仕組みを利用しています.

ファミコンにはリセットボタンが押されたかをソフトから直接確認する手段はありません. ソフトとしてはどちらの状態でも CPU は RESET の例外処理が始まり、 RAM が初期化されているかで分岐します. ソフトが RAM が初期化されていないと判断した時は RAM をすべて 0 クリアしたあと、特定のアドレスに初期化済みのしるしをいれます.

リセットボタンが押されたあと初期化済みのしるしがあれば初期化やゲームとしての進行を省略するようにソフトを作ることができます. ここが重要で初期化済みのしるしを本来の手順ではなく別の手段によって作ることができます.

不定値を乱数として利用する

https://www.nesdev.org/wiki/Tricky-to-emulate_game...
NESdev wiki 内の Tricky-to-emulate games の記事で書かれています. スクウェア開発作品以外にもわりと利用されているようです.

ファイナルファンタジーシリーズで作品によって詳細は異なりますが、どれも address $00e0-$00ff を本体初期化ルーチンでは意図的に初期化していません. (うち半分程度は未使用でないようで実際に使う前に初期化しているようです)

前項の電源投入直後かリセットボタンを押したかは区別していますが、それに加えて意図的に初期化をしていません. また初期化をしてない区間はモンスターがでてくるグループ番号(address $00f0-$00f7 あたりにある傾向)にしたり、address $0000-$00ff の総和を戦闘内部での乱数の seed に利用しています.

RAM の初期値を操作する方法

特定の短い時間電源を切って再投入する

考案者のピロ彦さんの解説を読みますと、ドラゴンクエスト3(初期バージョン, EFC-D3-0)の場合はRAM初期化済みフラグの一部がカートリッジの中のバッテリーバックアップされた RAM にある(つまり、電源を切っても初期化済みフラグ保持されている) など複数の要因が重なって本体 RAM の初期化を省略してしまうようです.

さらに偶然は続き、本来はセーブデータから本体RAMにコピーされるプレイヤーのたちのパラメータや所持アイテムの初期化も省略されてゲームが再開されるようです. このために本体の RAM の初期値が重要となり、都合よいパラメータを生成するために本体内SRAMの個体差や温度やコンデンサの放電進行度が密接に関係してるようです.

電源の切り方も本体の電源スイッチではなくACアダプタを抜くのが再現手順ですので、ACアダプタの中の大きいコンデンサが放電時間を延長できていると考えられます.

それらを技術的な観点から調査するには高度な知識と計測器が必要なので私はこれ以上詳しく説明できません.

https://pirohiko.hatenablog.com/entry/ar1731086

電源を入れたままカセットを交換してしまう

スーパーマリオをいれて電源をいれ、電源を切らずにカセットをテニスに交換しプレイヤーを数歩歩かせ、再度電源を切らずにカセットをスーパーマリオに交換し、リセットボタンを押すと World 選択ができる. これは有名な裏技で下記の手順で行われます.
  • スーパーマリオで RESET 直後に address $07ff に data $a5 があるか確認.
    • 初期化済みのしるしがないので RAM 全体を data 0 で初期化. その後初期化済みのしるしを追加.
  • テニスでは無条件で RESET 直後に address $0000-$06ff を 初期化.
    • ゲームをある程度進めると歩数 (address $07fd) は更新されるが address $07ff は更新されない
  • 再度スーパーマリオで address $07ff に data $a5 があるか確認.
    • 今度は初期化済みのしるしがあるので address $0000-$06ff を初期化するので、 address $07fd は更新されない.

メーカー公式としては本来はやってはいけないのですが ROM を電源を入れたまま交換するのは本体へのダメージは少なく、RAM の値を保持できる手段であります.

FF2 での例

ファイナルファンタジー2の乱数調整ではドクターマリオを利用していますが、これは2種類の初期化として利用しています.

1つ目は FF2 では初期化しない領域をドクターマリオのプログラムから data 0 で初期化することで SRAM の初期値の個体差をなくします. これは不定値を利用しない場合ならどのソフトでもやっている基本的な初期化です.

2つ目は FF2 では address $00f7 の敵グループ番号がドクターマリオでは同じアドレスが1P 扱いのジョイパッドの入力データとして利用しているので、どの敵がでてくるか操作をするためです.

address $00f7 を操作できればどのソフトでもよくて私はコナミのソフトから数本できそうなのをみつけましたが、偶然別の乱数操作にも利用されていたドクターマリオが使えるとピロ彦さんに教えてもらえました.

FF2 に関しては未初期化データの意図した初期化が目的で FF2 としての初期化済みのしるし(address $00fa, data $77) はドクターマリオで書き換えられています.

ファミリーベーシックを使う

プログラムコードのようにほしい値が大量にある場合は市販品のゲームを利用するのは現実的ではありません. このため本体の改造なしに正規品だけで意図したプログラムを書き込む手段として、ファミリーベーシックが最適です.

入力が遅くてもよいのでしたら POKE 命令で任意のアドレスへ任意のデータが書き込めます. アドレスに関してはファミリーベーシックとしての制限があります. (ピロ彦さんの場合は早い入力のために制限が多いキャラコードをいれています)

単純に値を書き込むなら POKE 命令ですが、そこに書いた命令を実行、そこから制限を抜けるアドレスへ欲しい値を作り出す、交換したゲームソフトで無理やり動かすとなると BASIC ではなくアセンブラレベルでのファミコンのプログラミングの知識が必要となります.

SRAM とバッテリーバックアップ

たまに SRAM はバッテリーバックアップがされている RAM と思っている方がいるのですが、フリップフロップで構成されていれば SRAM です. SRAM はバッテリーバックアップが可能な RAM の種類です.

メンバーのみ編集できます