命令のオーバーラップ

あるByteがオペコードとオペランドを兼ねることがある、というお話。

任天堂『ゴルフ』より抜粋:

D422 : A9 00            lda     #$00
D424 : 2C A9 40         bit     $40A9
...

このルーチンにおいて $D425 はオペコードとオペランドを兼ねており、

jsr $D422

として呼び出すと A=0x00 で処理を行い、

jsr $D425

として呼び出すと A=0x40 で処理を行います。BIT 命令を NOP 的に使うことで、オペランド内に別の命令を埋め込む、というテクニックのようです。BIT 命令は CMP, CPX, CPY あたりでも代用できると思います。

ただしこれは BIT 命令のオペランドがI/Oポートのアドレスにならないことが条件となります。$40A9 というのはI/Oポートのミラーだったりしないのかなと思いましたが、NesDevWikiによると:

Unlike the addresses of PPU registers and mapper registers, CPU register addresses are completely decoded, which means that the entire space from the end of CPU registers to the top of address space ($4018 through $FFFF) is available to the Game Pak.

とのことなので大丈夫なようです。

まあ、こんなコードはほとんど見かけない(『ゴルフ』以外にもう1つあった気もするが失念)ので割とどうでもいいのですが、逆アセンブラなどのツールを作る際は一応頭の片隅に入れておくべきかも。