第１４章

## 第１４章　スタック

### 初期化

ここまで、あまりちゃんと初期化していませんでしたが、少し見直そうかと思います。 ファミコンのリセットの初頭では以下のような記述をするのが一般的のようです。

    Start:
    	sei			; 割り込み不許可
    	cld			; デシマルモードフラグクリア
    	ldx #$ff
    	txs			; スタックポインタ初期化(Xレジスタ→Sレジスタ)

IRQ/BRK割り込み(NMI割り込みとは別)を禁止し、デシマルモードフラグをクリアしています。（ただしファミコンはデシマルモードは無い） そしてスタックポインタを$FF番地(実際は$1FF)に初期化します。 このサイト程度のプログラムではあまりちゃんと初期化しなくても動きますが、ファミコンの初期化では最初にこれを行うのが常識的らしいので、 素直に記述したほうがよいのでしょう。

またIRQ/BRK割り込みは、使わない場合でも以下のように記述するのが一般的のようです。

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

    IRQ:
    	rti

そして、ここまで作ってきたプログラムは、ゼロページを初期化してないので、リセットしてもその状態で実行されてしまいます。 今回クリアすることにします。 スプライトDMA転送領域も初期化すべきですが、これは今回は見送ります。

### ローカルラベル

ラベルが増えてくると、ラベル名が重複しないように一意にするのが大変です。そういう時は、以下のようにローカルラベルを使用しましょう。 "."で始まる名前を使うと、":"が後ろに付く従来のグローバルラベル２つの間に、他の場所で重複している名前を使うことができます。

    AKEYSound:
    	; サウンド待ちカウンタAが0でない場合はサウンドを鳴らさない
    	lda <Sound_A
    	beq .soundSub
    	rts
    .soundSub
    	lda #10			; 1/6秒に1回鳴らす
    	sta <Sound_A

### スタック

RAMの$100〜$1FFがスタック領域と以前説明しました。（スタックの概念自体はここでは説明しないので、わからない人は調べてください） この領域を使わないのは勿体ないのですが、何も気にせず使うことはできません。 NMI割り込みが発生すると、発生前の上位アドレス、下位アドレス、ステータスレジスタの内容がスタックに保存され、rtiで復帰したときにスタックポインタが戻されます。 また、jsrで移動すると、移動した上位アドレス、下位アドレスが保存され、rtsで戻ったときにスタックポインタが戻されます。 スタックをPUSHしたままサブルーチンや割り込みから復帰するとスタックの整合性が破綻して暴走してしまうので、PUSHした同じ回数だけPULLして元の位置に戻します。

ここまでのプログラムでは、スタックを使う必要性は特に無いのですが、無理矢理使いましょう。 前章までのプログラムを、キー入力の値をスタックに次々とPUSHして、後でPULLして参照するように直します。

    	; パッド入力チェック
    	lda $4016  	; Aボタン
    	pha		; AをPUSH
    	lda $4016  	; Bボタン
    	pha		; AをPUSH
    	lda $4016  	; Selectボタンをスキップ
    	lda $4016  	; Startボタンをスキップ
    	lda $4016  	; 上ボタン
    	pha		; AをPUSH
    	lda $4016  	; 下ボタン
    	pha		; AをPUSH
    	lda $4016  	; 左ボタン
    	pha		; AをPUSH
    	lda $4016  	; 右ボタン
    	pha		; AをPUSH

以上のように、キー情報を取得してphaでスタック領域に格納し、

    	pla		; AをPULL(右ボタンの内容)
    	and #1     	; AND #1
    	beq pull_A1	; 0ならばPull_A1へジャンプ
    	jsr RIGHTKEYdown
    pull_A1:
    	pla		; AをPULL(左ボタンの内容)
    	and #1     	; AND #1
    	beq pull_A2	; 0ならばPull_A2へジャンプ
    	jsr LEFTKEYdown
    pull_A2:
    	pla		; AをPULL(下ボタンの内容)
    	and #1     	; AND #1
    	beq pull_A3	; 0ならばPull_A3へジャンプ
    	jsr DOWNKEYdown
    pull_A3:
    	pla		; AをPULL(上ボタンの内容)
    	and #1     	; AND #1
    	beq pull_A4	; 0ならばPull_A4へジャンプ
    	jsr UPKEYdown
    pull_A4:
    	pla		; AをPULL(Bボタンの内容)
    	and #1     	; AND #1
    	beq pull_A5	; 0ならばPull_A5へジャンプ
    	jsr BKEYSound
    pull_A5:
    	pla		; AをPULL(Aボタンの内容)
    	and #1     	; AND #1
    	beq setSpr	; 0ならばsetSprへジャンプ
    	jsr AKEYSound

そしてこのように、plaでAレジスタにキー情報を次々と戻して判定します。これがソースです。 注意する点は、A→B→上→下→左→右の順で格納し、右→左→下→上→B→Aのように逆順で取り出してるところです。
しかし、このように1bitずつで済む情報に1byteずつ領域を使っていては、残りの7bitが無駄です。 キー入力処理は、1ビットずつバッファにビットシフトしながらためていって、あとで取り出すやり方のほうが良いです。
興味がある人は、これをダウンロードしてgetPadBitラベル以下を見てください。

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

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