第１０章

## 第１０章　VBlank割り込み

### サブルーチン

ソースが長くなってくると、何度も行う処理は一箇所にまとめて、他から呼び出すようにしたくなります。 Cで言えば関数、VBで言えばFunctionと同じことをやるにはどうしたらよいのでしょうか。それにはjsrとrtsを使用します。第９章のソースgiko009.asmを見ると、62行目以降の「２番目のスプライト座標初期化」と、125行目の「２番目のスプライトの座標更新」はほぼ同じことをしています。 これを一箇所にまとめましょう。以下のようにします。このように共用するための処理ブロックをサブルーチンと呼びます。

    setSprite2:
    	; ２番目のスプライトの座標更新サブルーチン
    	lda Sprite1_X
    	adc #8 		; 8ﾄﾞｯﾄ右にずらす
    	sta Sprite2_X
    	lda Sprite1_Y
    	sta Sprite2_Y
    	rts

そして、今までスプライト２の更新を行っていた２箇所を、以下のコードに差し替えます。

    	; ２番目のスプライト座標更新サブルーチンをコール
    	jsr setSprite2

ソースはこれです。jsrでサブルーチンへジャンプして、rtsでjsrの次の行に戻る仕組みということです。

### VBlank割り込みハンドラ

VBlankについては、第５章で既に説明しましたが、1/60秒毎にVBlank同期待ちをしてから処理を行うのは、ファミコンのプログラムでは一般的では無いようです。 実際のファミコンゲームでは、VBlank割り込みを使用することが多いようです。割り込みについては第２章で少し説明しましたが、 ファミコンの6502はVBlank突入のタイミングで、必ずNMI割り込みを発生させることができます。このNMI割り込みハンドラにメインループのアドレスを登録しておけば、 1/60毎に処理を行うことが可能です。

上のnesasm010.asmをさらに改造しましょう。まず、割り込みベクタテーブルは以下のように直します。

    	.bank 1      ; バンク１に切り替える
    	.org $FFFA   ; $FFFAから開始

    	.dw mainLoop ; VBlank割り込みハンドラ(1/60秒毎にmainLoopがコールされる)
    	.dw Start    ; リセット割り込み。起動時とリセットでStartに飛ぶ
    	.dw 0        ; ハードウェア割り込みとソフトウェア割り込みによって発生

Startは、最初にNMI割り込み禁止にします。初期化中にmainLoopが実行されたらまずいからです。VBlank待ちも従来通り行います。 そして今までどおり初期化した後、以下のようにNMI割り込みを許可します。第３章で説明したとおり、$2000の7ビット目を1にします。

    	; PPUコントロールレジスタ1の割り込み許可フラグを立てる
    	lda #%11001000
    	sta $2000

$2000は書き込み専用レジスタなので、$2000をロードしてoraすることはできません。私は間違えてハマってしまいました。

そして、後は無限ループで待ちます。1/60秒毎に割り込みが発生して、mainLoopが呼び出されます。

    infinityLoop:	; VBlank割り込み発生を待つだけの無限ループ
    	jmp infinityLoop

最後に、mainLoopの終わりに割り込み復帰命令を記述します。mainLoop処理が終わると、上のinfinityLoopに戻るようになります。

    NOTHINGdown:
    	; ２番目のスプライト座標更新サブルーチンをコール
    	jsr setSprite2

    	rti	; 割り込みから復帰

VBlank割り込みに対応したソースがこれです。実行しても特に見た目は変わりませんが・・・。

### シーケンス図

ところで、直しているうちに現在作っているサンプルの処理の流れが分からなくなってしまった人が多いのでは無いでしょうか。コメント付きソースを配布してるとはいえ、 我ながらかなり不親切になってきたかなと思います。そこで、UMLの シーケンス図でgiko010b.asmのフローを表現してみました。 まー、昔からあるフローチャート図でもいいんですけどね。

トップページ 前のページ 次のページ

FC2 |  | キャッシング 花 | 無料 掲示板 無料ホームページ