たまに書かないとなにをやっているかわからなくなってくるので書いてみる。
stack $01fa-$01ff の破壊原因
前回まで、発生原因は魔法の詠唱だと思っていたものは誤りで単なる攻撃が発生原因だった。前回発生した現象は、魔法の詠唱を選択したものの、先に攻撃の計算を行って、そのときに破壊したと考えるのが無難である。
ポイントは下記。
- 発生頻度は割と高く、1/2ぐらい。
- スタックを破壊してもプログラムは正常動作を続ける
- rts 実行後の復帰 PC address に相当する $01fb,$01fc に書き込まれるデータは闇雲に眺めると $00-$0f,$3a が多い
- この stack の下を壊すバグを利用することにして言えば、ベクタ $0100 の命令実行は邪魔
trace 調査
実行 trace に SP と scanline の表示をするとかなり理解しやすくなったので、魔法詠唱と攻撃の動作を追ってみた。共に再帰呼び出しをして、サブルーチンの中で同じサブルーチンを呼んで stack を高く積んでいることがわかった。
魔法詠唱の場合、再帰呼び出しをするサブルーチンの中での実行時間が長く、ベクタ命令部の $0100,$0101,$0102 を破壊した時点で、 NMI が発生してプログラムが暴走する。
攻撃の場合は、命令内容が魔法と比べてシンプル。$0100 を突き抜け、 $01fa を破壊するし場合によっては $01f5 まで破壊するが、 NMI 発生前に計算が終わる。 NMI 発生待ちに入る直前に $0100,$0101,$0102 を書き直すのでプログラムが動作し続ける。
攻撃時の再帰呼び出しのたびに stack を積む数が 5 なので、$01fa より先を壊しても、効果はない。これはフロア移動時の stack を積む数も 5 なので、破壊できる部分の先頭は移動時の X 座標になる。*1
ここまではわかったが、調査が雑なのは相変わらずで、攻撃元と対象がよくわかってない。プレイヤーキャラが発生原因ならパラメータを調整しやすいわけだが、敵が発生原因なら敵の選定もディストの洞窟内部だけで絞り込まないといけない。(魔法を唱える敵は暴走要因なので省くべきだし...)
またこの再帰サブルーチンがなにをやっているのがよくわかっていない。自分が攻撃の計算を知らないのと、抽象化されているのがよくわからない。
8F5E: pha sec sbc $02 tax inx stx $00 ldy #$01 ldx #$00 8F6A: txa sta ($06),y iny inx cpx $00 bne $8f6a pla 8F74: <= recursive call label sta $03 lda $00 pha ;-> PC bit15:8 lda $01 pha ;-> PC bit7:0 txa pha ;-> floor offset X ldx $02 stx $00 ldy $03 sty $01 (中略) dec $03 inc $02 bcs $8f8c 8FD8: ldx $02 cpy $00 beq $8fe8 bcc $8fe8 lda $00 sta $02 tya jsr $8f74 ; -> recursive call 8FE8: cpx $01 bcs $8ff3 ; -> resursive end condition stx $02 lda $01 jsr $8f74 ; -> recursive call 8FF3: pla tax pla sta $01 pla sta $00 rts
*1:さらにもう1周 $0100 を越えて壊せばずれるが、それをやっている途中に別の不具合が起こるだろう