2026.9.2
前へ
次へ
ホームページトップへ戻る


[新連載開始]W65C02マイコンボードの製作

〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
私としてはW65C02をさわるのは全く初めてです。何から何まで未経験です。さてどうなりますでしょうか。
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜

[第62回]



●BRK,NOP,STP

NOPはNo Operationです。
何もしない命令です。
実行によってフラグやレジスタに影響を与えません。
単にプログラムのアドレスを調整するとかパルス出力幅を調整する「時間稼ぎ」のためなどに使われます。
STPはプログラムの実行を停止して静止モードになります。
後の回で説明する予定のWAIと違って割込みによって静止を解除することはできません。
外部からのリセット入力によってのみ解除できます。
NOPとSTPはこれまでの回でテストプログラムに使ってきていますのであらためてテストプログラムは作成しません。
今回の主役はBRKです。
BRKの説明に入る前にまずは各命令のコードなどについて下にまとめておきます。
 ニーモニック  マシン語コード  アセンブラ書式 バイト数 クロック数
 BRK  00  BRK  1  7
 NOP  EA  NOP  1  2
 STP  DB  STP  1  −


BRKはソフトウェア割込み命令です。
BフラグとIフラグがセットされます。
Bフラグ(ビット4)はBreakフラグです。
Iフラグ(ビット2)は割込み禁止フラグです。
BRKはプログラムデバッグのための特殊な割込み命令として用意されたと理解しています。
Z80や8080のRST7(コードFF)と同じ用途です。
プログラムのデバッグをしたいときにブレークをさせたいところにこの命令(実用上は命令コード)を上書きします。
その使い方からデバッグの対象はRAM上のプログラムということになります。
RST7と違ってコードが00なのでROMのプログラムでも上書き可能であるという解説をネット上で見ました。
コードが00なのはそういう理由からかもしれません。
通常の割込みと異なり割り込み禁止フラグ(Iフラグ)の状態に関係なく実行可能です。
通常の割込みと同じで割込みジャンプテーブル(アドレスFFFE、FFFF)に記載されたアドレスにジャンプするので事前にBRKサービスプログラムのアドレスを書いておきます。
BRK割込みが発生するとその時点のPC(プログラムカウンタ)に+2した値とフラグレジスタの値をスタックにPUSHした後にBRKサービスプログラムにジャンプします。
そのあたりの確認ということも含めてテストプログラムを作成しました。

;w65c02test36 26/8/13
;
;BRK
;
        org $8000
;
        lda #$10
        sta $fffe
        lda #$80
        sta $ffff
        ldx #$fd
        txs
        cli
        bra start
;
braek:
        tsx
        stx $01
        stp
;
start:
        stx $00
        inc
        adc #$12
        sta $03
        brk
        tsx
        stx $02
        stp
;end

W65C02アセンブラでアセンブルしました。

下はアセンブルの結果作成されたアセンブルリストです。

0000        ;w65c02test36 26/8/13
0000        ;
0000        ;BRK
0000        ;
8000            org $8000
8000        ;
8000 A910       lda #$10
8002 8DFEFF     sta $fffe
8005 A980       lda #$80
8007 8DFFFF     sta $ffff
800A A2FD       ldx #$fd
800C 9A         txs
800D 58         cli
800E 8004       bra start
8010        ;
8010        braek:
8010 BA         tsx
8011 8601       stx $01
8013 DB         stp
8014        ;
8014        start:
8014 8600       stx $00
8016 1A         inc
8017 6912       adc #$12
8019 8503       sta $03
801B 00         brk
801C BA         tsx
801D 8602       stx $02
801F DB         stp
8020        ;end

上で書きましたように本来はデバッグするのが目的なのでプログラム中に書いておくのではなくでデバッグのときにブレークしたいところにBRKコードを上書きするという使い方になるかと思いますが今回はテストなのでプログラム中に置いてあります。
BRKはソフトウェア割込みであることを除けば通常の外部割込み(IRQ端子から入力)と同じです。
後でわかったことですが外部割込みと違ってBRKはIフラグの状態に関係なく実行可能なのだそうです(後で確認します)。
BRKが実行されるとシステムジャンプテーブルFFFE、FFFFに書いてあるアドレスにジャンプします。
今回のテストプログラムではプログラムの先頭でBRKプログラムの先頭アドレス(8010)をFFFE、FFFFに入れておきます。
そしてスタックポインタにスタックの先頭アドレスとしてFDを入れるとともに記録として$00にも同じスタックポインタの値(FD)を入れます。
スタックについてちょっとまだ迷いがあったころに書いたプログラムなのでFDなどというハンパな値を設定しています。
最初にこのプログラムを書いた時点ではBRKの実行にはIフラグ=0が条件かと誤解していましたのでCLI命令を使っています。
BRKプログラムによってスタックに保存されるフラグレジスタの値を確認する目安になるようにBRK命令の直前に実行される演算の結果の値(アキュムレータの値)を$03にセーブしておきます。
プログラムはアドレス801Bでブレークします。
BRKプログラムが実行されたことがわかるようにアドレス$01にそのときのスタックポインタの値を入れます。
BRKプログラムの最後にSTPがありますからそこで停止します。
BRKが正しく実行されればアドレス801Cから後ろは実行されないはずです。
もし実行されたら$02にそのときのスタックポインタの値が入ります。

65c02test36.binをロードしました。
実行前に$00〜$03をFFにしておきます。

/RUNでプログラムを実行しました。
実行後に/CMで確認したところ次の通りでした。
0000 FD   プログラム開始時のスタックポインタの値
0001 FA   BRKプログラムにエントリしたときのスタックポインタの値
0002 FF   変化なし
0003 93   アキュムレータの値
0002が変化なしなので801C以後は実行されなかったことがわかりました。

/DM 01を実行してスタックエリアを表示させました。


BRKが読み込まれたときのプログラムカウンタの値+2がスタックに保存されます。
BRKは801Bにあります。
スタックにはその値+2が入りますから801B+2=801Dです。
おお。
合ってますね。
次はフラグです。

01FBにはフラグレジスタの値が入ります。
B0です。
BRKの直前にINCとADC #$12が実行されています。
その前のアキュムレータの値は$80です。
80+1+12=93ですから$03の値と一致しています。
そのときのフラグはN=1、V=0、Z=0、C=0ですがBRKの実行によってB(ビット4)とI(ビット2)がセットされますから10110100(B4)になるはずなのですが。
あれ?
ビット2が0?
で。
Google様にお聞きしましたら。
Iフラグは直前の値をそのままスタックに退避するのだそうです。
なるほどそれで0になるということか。
その後にCPU内部で割込み禁止にするためIフラグがセットされるのだそうです。
ついでにDフラグ(ビット3。十進モードフラグ)は強制的にクリアされるのだそうです。
うむむ。
よくわからん仕様であります。

上の方に書きましたが。
確かGoogleで確認したときBRKはIフラグに関係なく実行されると書いてあったような。
再確認したところ確かにそう書いてありました。
ならば。
再テストするよりほかはないでしょう。
そこを意識してあえてIフラグをセットしてテストしました。
CLIをSEIに変更しました。

;w65c02test36b 26/8/13
;
;BRK
;
        org $8000
;
        lda #$10
        sta $fffe
        lda #$80
        sta $ffff
        ldx #$fd
        txs
        sei
        bra start
;
braek:
        tsx
        stx $01
        stp
;
start:
        stx $00
        inc
        adc #$12
        sta $03
        brk
        tsx
        stx $02
        stp
;end

W65C02アセンブラでアセンブルしました。

0000        ;w65c02test36b 26/8/13
0000        ;
0000        ;BRK
0000        ;
8000            org $8000
8000        ;
8000 A910       lda #$10
8002 8DFEFF     sta $fffe
8005 A980       lda #$80
8007 8DFFFF     sta $ffff
800A A2FD       ldx #$fd
800C 9A         txs
800D 78         sei
800E 8004       bra start
8010        ;
8010        braek:
8010 BA         tsx
8011 8601       stx $01
8013 DB         stp
8014        ;
8014        start:
8014 8600       stx $00
8016 1A         inc
8017 6912       adc #$12
8019 8503       sta $03
801B 00         brk
801C BA         tsx
801D 8602       stx $02
801F DB         stp
8020        ;end

先ほどと同じようにテストしました。
65c02test36b.binをロードしました。
$00〜$03をFFにしてから/runを実行しました。

/CMコマンドで$00〜$03を確認して先ほどと同じ結果であることが確認できました。
$01がFAになりましたからIフラグがセットされていてもBRKが実行されることが確認できました。

/DMコマンドでスタックを表示させました。


W65C02マイコンボードの製作[第62回]
2026.9.2 upload

前へ
次へ
ホームページトップへ戻る