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

復活!CP/M ワンボードマイコンでCP/Mを!
CP/MがTK−80互換のワンボードマイコンの上で復活します
ND80ZVとMYCPU80の上でCP/Mが走ります

[第72回]

●ファンクションコール0BHの動作解析

今回の説明はちょっと難しいかもしれません。
私の頭の中では理解できているのですが、それをうまく説明できるかどうかがちょっと難しいように思います。

前回BIOSのコンソールステータスチェックルーチンにまずいところがあることがわかって、それを直したのですが、Ctrl−Sでポーズはするのですが、そのあとCtrl−D(本来はCtrl−C)を入力してもブレイクしてくれません。

ファンクションコール0BHの処理の中で何かおかしなことがおきているようです。
その処理ルーチンは前回もお見せしました、下のリストの部分です。



こういうときに通常ならばブレイクポイントを設定して、途中でブレイクさせながら、レジスタの中味を確認していくことで、問題の有る部分を炙り出すことができます。
しかし今回はそういうわけにはいきません。
キー入力を伴うプログラムにその手法は使えないことが多いのです。
肝心の部分はリアルタイムであることが要求されるからです。

そういう場合には、簡便な方法として、レジスタの値をワークメモリに書き込んでおいて、あとからそれを参照する、というテクニックを使います。
そこで、上のプログラムを下のように直しました。



ファンクションコール0BHをコールすると、このCKCONSOLルーチンが実行されます。
ここで想定外の何かがおきているようなので、何がおきているのかを可視化するための変更です。
適当なワークエリアを用意し、そこにポイントになる値を書き込むようにします。
CKCONSOLにエントリすると最初にCHARBUFの値をチェックします。
ここには、前回CKCONSOLが実行されたときに検出されたキー入力コードが収められています。
そこにすでに文字コードが入っていたら、BIOSをコールしないでAレジスタに01を入れて(つまりキー入力有りにして)リターンします。
このCHARBUFの値はテストプログラムでも参照しているのですが、念の為にWK1にも入れることにします。
それが1376のLD (WK1),Aです。

CHARBUFが空(00)のときは、BIOSのCONSTルーチン(コンソールステータスチェック)をコールします。
CONSTは前回修正して、キー入力有りのときは入力された文字コードのビット0を1にしてリターンします。
そのリターンされてきた値をWK2に入れます。
それが1380のLD (WK2),Aです。
その値のビット0が0ならば、入力無しの印として、Aレジスタを00にしてリターンします。
ここで入力有りならばあらためてBIOSのCONINルーチン(コンソール入力)をコールします。
ここでキー入力された文字コードをWK3に入れます。

以上のように変更して、それをCPM22I2.TXTというファイル名で保存します。
しかし今回テストのためにプログラムに追加修正をしたために、ほかにも直さなければならないところがでてきてしまいました。
プログラムの途中で命令を追加したために、BIOSのエントリアドレスが後にずれてしまいます。
3バイトのLD命令を3ヶ所追加しましたから、9バイト後にずれてしまいました。
これを補正しなければなりません。
なかなかに面倒です。
こういうことにならないように、必要なジャンプテーブルやワークアドレスはプログラムの先頭にまとめてしまうとよいのですが、CP/Mのソースプログラムがそのような形になっていないものですから、面倒でもそれに従うしかありません。

途中をなんとか9バイト縮めなければいけません。
さてどうするか?
そこで、[第67回]でシステムスタックを移動したことを思い出しました。
確か元のスタックエリアがそのまま残っていたはずです。
ここでした。



この部分を完全に削除してしまえば全体が16バイト縮まります。
そこで、1209行を下のようにコメント行にしました。



このままだと、16−9=7バイト分、逆にBIOSのエントリアドレスが前にきてしまいます。
そこで、今度はBDOSの最後の部分に7バイトのダミーを追加します。



さきほどのCKCONSOLのところで6行追加したために、行番号は変わってしまいましたが、元の3709行に7バイト追加を行なっています(新3715行)。
これであらためてCPM22I2.TXTとしてセーブしたうえで、アセンブルして、BIOSのエントリ部が移動していないことを確認しました。



●テストプログラムの変更作業

今度はテストプログラムの変更作業を行ないます。
ファンクションコール0BHの処理ルーチンで保存した値をモニタする部分をつけ加えます。
下がそのように変更したあとのテストプログラムです。
リストが長くなりますから、表示のためのサブルーチン部分は省略してあります。

; BDOS function0B test fnc0bt2
;2012/3/26
;
	ORG $8100
	FCALL=$8005
	CHARBUF=$C707
	WK1=$8300
	WK2=$8301
	WK3=$8302
;
LOOP:LD C,0B
	CALL FCALL
	PUSH AF
	LD A,(WK1)
	CALL B2HEXDP
	LD A,(WK2)
	CALL B2HEXDP
	LD A,(WK3)
	CALL B2HEXDP
	POP AF
	PUSH AF
	CALL B2HEXDP
	LD A,(CHARBUF)
	CALL B2HEXDP
	POP AF
	OR A
	JP NZ,KEYIN
NEXT:CALL SPDP
	JP LOOP
KEYIN:LD A,2A;'*'
	CALL ADP
	LD C,01
	CALL FCALL
	PUSH AF
	LD A,3A;':'
	CALL ADP
	POP AF
	PUSH AF
	CALL B2HEXDP
	POP AF
	PUSH AF
	CALL ADP
	POP AF
	CP 1A;^Z
	RET Z
	JP NEXT
;

こちらはアセンブルリストです。

2012/3/26  20:6  fnc0bt2.txt
END=81B2
              ; BDOS function0B test fnc0bt2
              ;2012/3/26
              ;
              	ORG $8100
              	FCALL=$8005
              	CHARBUF=$C707
              	WK1=$8300
              	WK2=$8301
              	WK3=$8302
              ;
8100 0E0B     LOOP:LD C,0B
8102 CD0580   	CALL FCALL
8105 F5       	PUSH AF
8106 3A0083   	LD A,(WK1)
8109 CD7781   	CALL B2HEXDP
810C 3A0183   	LD A,(WK2)
810F CD7781   	CALL B2HEXDP
8112 3A0283   	LD A,(WK3)
8115 CD7781   	CALL B2HEXDP
8118 F1       	POP AF
8119 F5       	PUSH AF
811A CD7781   	CALL B2HEXDP
811D 3A07C7   	LD A,(CHARBUF)
8120 CD7781   	CALL B2HEXDP
8123 F1       	POP AF
8124 B7       	OR A
8125 C22E81   	JP NZ,KEYIN
8128 CD5981   NEXT:CALL SPDP
812B C30081   	JP LOOP
812E 3E2A     KEYIN:LD A,2A;'*'
8130 CD5B81   	CALL ADP
8133 0E01     	LD C,01
8135 CD0580   	CALL FCALL
8138 F5       	PUSH AF
8139 3E3A     	LD A,3A;':'
813B CD5B81   	CALL ADP
813E F1       	POP AF
813F F5       	PUSH AF
8140 CD7781   	CALL B2HEXDP
8143 F1       	POP AF
8144 F5       	PUSH AF
8145 CD5B81   	CALL ADP
8148 F1       	POP AF
8149 FE1A     	CP 1A;^Z
814B C8       	RET Z
814C C32881   	JP NEXT
              ;

プログラムの先頭でファンクション0Bをコールしますが、その結果はPUSH AFでスタックに一時退避させておいて、さきほどファンクションコール0BHの処理ルーチンに追加したWK1〜WK3の値を読み込んで16進表示します。
そのあとでスタックに退避させておいたファンクションコール0BHの結果を16進表示し、それからCHARBUFの値も16進表示します。

もしファンクションコール0BHの結果が01であった場合には、コンソール入力(ファンクションコール01)を実行します。
ここではちょっとややこしいことをしています。
入力された文字が表示されるタイミングを確認するために、ファンクションコール01の直前に’*’を表示し、直後に’:’を表示します。
そのあと、入力された文字コードを16進表示してから、文字としても表示します。

ところで。
CP/MソースプログラムにWK1〜WK3の部分を追加したため、CHARBUFのアドレスも変わってしまいました。
CP/Mソースプログラムをアセンブルしたときに作成されたアセンブルリストを確認して、CHARBUFのアドレスも忘れないように変更しておきます。



もとのテストプログラムではCHARBUFのアドレスはC70EHだったのですが、C707Hに変わっています。

以上のように変更して、これをFNC0BT2.TXTとして保存します。
そのあと、ZASM.COMでアセンブルして、バイナリファイルFNC0BT2.BINを作成しました。

本日はプログラムの説明に時間がかかってしまいました。
このように変更したプログラムを実際に実行してみた結果については、次回に説明することにいたします。

ワンボードマイコンでCP/Mを![第72回]
2012.3.26upload

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