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

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

[第80回]

●ファンクションコール06(E=FE)

ファンクションコール06のテストをするために、CP/Mソースプログラムのファンクションコール06処理ルーチンを確認していましたら、EレジスタがFEの場合の処理ルーチンがあるということに気が付きました。

CP/Mソースプログラムのファンクションコール06のプログラム部分です。
とても短いプログラムです。
説明がついています。
direct console i/o と書いてあります。



その2行目には、次のように書いてあります。

IF (C) contains (FE) then this is a status request.

(C)はCレジスタのことです。
ファンクション06をコールするときには、Cレジスタに06を入れて、Eレジスタに値を入れるのですが、CP/M内部ではEレジスタからCレジスタに値が移されるようです。

なるほど。
Cレジスタ(Eレジスタ)にFFを入れてコールすると、直接(ダイレクトに)BIOSのCONINルーチンが実行され、FEを入れてコールすると、CONSTルーチンが実行され、その他の値を入れてコールするとCONOUTルーチンが実行されるということのようです。

しかし、EレジスタにFEをセットしてファンクションコール06を実行することについては、「応用CP/M」(村瀬康治著。アスキー出版局)では、何も書かれていません。
さて?
どういうことでしょう。

むむむ。
上のソースリストを見ますと、確かにCレジスタがFEのときにはCONSTにジャンプしています。
1641〜1642行のところです。

どういうことになるのか、テストプログラムを作って試してみました。
こちらがソースプログラムFUNC06T6.TXTです。

; BDOS function06 test 6
;2012/4/2
;
	ORG $8100
	FCALL=$8005
;
LOOP:LD C,06
	LD E,FE
	CALL FCALL
	OR A
	JP Z,LOOP
	CALL B2HEXDP
	JP LOOP
;

こちらがアセンブルリストです。
表示のためのサブルーチンは今までのテストプログラムと同じですから省略してあります。

2012/4/2  11:35  fnc06t6.txt
END=8174
              ; BDOS function06 test 6
              ;2012/4/2
              ;
              	ORG $8100
              	FCALL=$8005
              ;
8100 0E06     LOOP:LD C,06
8102 1EFE     	LD E,FE
8104 CD0580   	CALL FCALL
8107 B7       	OR A
8108 CA0081   	JP Z,LOOP
810B CD3981   	CALL B2HEXDP
810E C30081   	JP LOOP
              ;


たったこれだけの簡単なプログラムです。
EレジスタにFEを入れてファンクション06をコールします。
コンソール入力があるとAレジスタのビット0が1になるはずですから、そのときだけ、Aレジスタの値を16進で表示します。
それ以外のときは何もしないでプログラムの先頭に戻ります。

CP/Mを起動して、いままでのテストプログラムと同じように、まずRAMディスクにセーブしてから、実行してみたのですが…。

全く応答がありません。
実行中に繰り返しキー入力を行なってみたのですが、全く反応がありませんでした。

しかし。
確かにCP/Mソースプログラムを見る限りでは間違い無くBIOSのCONSTにジャンプしています。
それよりも何よりも、上のコメントには、はっきりと「コンソールステータスをリクエストする」と書かれているのですから、コンソールステータスが得られて当たり前のはずなのですが…。

むむむ。
何かが食い違っているようです。
そういうことになりますと、定番のデバッグです。
こういうときには、ZB3BASICシステムのマシン語デバッグツールが役に立ちます。

●ZB3BASICのマシン語デバッグツール

現在ND80ZVの上で実行しておりますCP/Mは、まずZB3BASICシステムにエントリして、それからCP/Mを起動しています。
BASICですけれど同時にマシン語デバッグも行えるようになっています(便利です)。
CP/Mが起動すると、CP/Mシステムだけで動いているように見えますが、その下にはND80ZVのZB3BASICシステムがあって、必要なときにはいつでもその機能が使える状態にできるのです。

百聞は一見にしかず。
CP/Mのファンクションコール06処理ルーチンにブレークポイントを設定して、どのように処理が行なわれるのか、調べてみることにいたします。

その前に。
こちらはCPM22J.TXTをアセンブルしたときに作成されたアセンブルリストCPM22J.PRNの、その部分です。
以下の作業では、このリストを参照しながら進めていきます。



アドレスC6D6に最初の分岐命令(JP Z)がありますから、ここにブレークポイントを設定します。

いつものようにログファイルで説明をすることにいたします。

logfile nd80zlog\04021135.txt open

ND80ZVに接続しました
0001 0000 - z
1000 00C3 - 
*** nd80z3 basic ****
>bp c6d6
>jp d233

a>fnc06t6

A F  B C  D E  H L  A'F' B'C' D'E' H'L'  PC   SP   IX   IY  I  SZ H PNC
FFA8 00FE D1FE C6D4 0044 0000 0000 0000 C6D6 C73F 0044 F1A1 FF 10101000
>bp d297
>rt

A F  B C  D E  H L  A'F' B'C' D'E' H'L'  PC   SP   IX   IY  I  SZ H PNC
2020 00FE D1FE C6D4 0044 0000 0000 0000 D297 C73F 0044 F1A1 FF 00100000
>cr

A F  B C  D E  H L  A'F' B'C' D'E' H'L'  PC   SP   IX   IY  I  SZ H PNC
2020 00FE D1FE C6D4 0044 0000 0000 0000 D297 C73F 0044 F1A1 FF 00100000

6120 00FE D1FE C6D4 0044 0000 0000 0000 D297 C73F 0044 F1A1 FF 00100000

A F  B C  D E  H L  A'F' B'C' D'E' H'L'  PC   SP   IX   IY  I  SZ H PNC
6120 00FE D1FE C6D4 0044 0000 0000 0000 D297 C73F 0044 F1A1 FF 00100000
>bp d299
>rt

A F  B C  D E  H L  A'F' B'C' D'E' H'L'  PC   SP   IX   IY  I  SZ H PNC
6122 00FE D1FE C6D4 0044 0000 0000 0000 D299 C73F 0044 F1A1 FF 00100010
>cr

A F  B C  D E  H L  A'F' B'C' D'E' H'L'  PC   SP   IX   IY  I  SZ H PNC
6122 00FE D1FE C6D4 0044 0000 0000 0000 D299 C73F 0044 F1A1 FF 00100010

6222 00FE D1FE C6D4 0044 0000 0000 0000 D299 C73F 0044 F1A1 FF 00100010

A F  B C  D E  H L  A'F' B'C' D'E' H'L'  PC   SP   IX   IY  I  SZ H PNC
6222 00FE D1FE C6D4 0044 0000 0000 0000 D299 C73F 0044 F1A1 FF 00100010
>bp d2a3
>rt

A F  B C  D E  H L  A'F' B'C' D'E' H'L'  PC   SP   IX   IY  I  SZ H PNC
6324 00FE D1FE C6D4 0044 0000 0000 0000 D2A3 C73F 0044 F1A1 FF 00100100
>cm bb07
BB07 62-
>dm c730,c74f
C730  10 A6 06 81 11 10 10 A6-06 81 11 FE 00 D4 C6 74  .ヲ.....ヲ.....ヤニt
C740  D1 00 00 FE D1 00 00 21-0B C4 5E 23 56 EB E9 0C  ム...ム..!.ト^#V...
>bp d174
>rt

A F  B C  D E  H L  A'F' B'C' D'E' H'L'  PC   SP   IX   IY  I  SZ H PNC
6324 00FE D1FE C6D4 0044 0000 0000 0000 D174 C741 0044 F1A1 FF 00100100
>cm d1de
D1DE 00-
>bp d177
>rt

A F  B C  D E  H L  A'F' B'C' D'E' H'L'  PC   SP   IX   IY  I  SZ H PNC
0024 00FE D1FE C6D4 0044 0000 0000 0000 D177 C741 0044 F1A1 FF 00100100
> 

以上がデバッグを行なった全てです。
いきなり全部ですと、ちょっと説明するのにも読んでいただくのにも不自由しますから、
少しずつ再掲しながら説明を加えていくことにいたします。

logfile nd80zlog\04021135.txt open

ND80ZVに接続しました
0001 0000 - z
1000 00C3 - 
*** nd80z3 basic ****
>bp c6d6
>jp d233

a>fnc06t6

A F  B C  D E  H L  A'F' B'C' D'E' H'L'  PC   SP   IX   IY  I  SZ H PNC
FFA8 00FE D1FE C6D4 0044 0000 0000 0000 C6D6 C73F 0044 F1A1 FF 10101000

ND80ZVをUSB接続して、[z][Enter]で、ZB3BASICにエントリします。
このときBASICとマシン語モニタの両方がそのまま使える状態になっています。
何の準備も不要です。
いきなりBP C6D6[Enter]でブレークポイントを設定してしまいます。
それからJP D233[Enter]でCP/Mを起動します。

えっ?そんなことができるの?
そんなことができるのです。
こういうところがZB3BASICシステムの超便利なところなのです。

ご覧いただいての通り、FNC06T6[Enter]でテストプログラムを実行すると、その直後(実時間、リアルタイム)に、設定したブレークポイント(アドレスC6D6)でブレークしました。
このブレーク機能は、トレースでもシミュレートでもありません。
ブレークポイントまではリアルに実行されますから、遅延は一切ありません。

アドレスC6D6の命令(JP Z,DIRC1)の直前でブレークして、そのときのCPUの全レジスタの内容が表示されています(レジスタダンプです)。

ブレークポイントでのレジスタダンプはマシン語プログラムのデバッグには欠かせない基本的な機能なのですけれど、ここは、「OSであるCP/Mそのものに対してもこういうことができてしまう」、というところに「おおおっ」と素直に感動していただきたい、という場面なのであります。

複雑に進化してしまったWindowsシステムなどでは、逆立ちしたってできっこないことでありますから、逆に「いまさら8ビット」の優位性が、嫌が上にも際立つ場面ではなかろうか、と愚考する次第であります。

さて。
ダイレクトコンソールIOルーチンにエントリした最初のプログラム部分です(下記)。

C6D4 79      DIRCIO:LD A,C
C6D5 3C            INC A
C6D6 CAE0C6        JP Z,DIRC1

Cレジスタの値(FE)をAレジスタに入れて、それを+1(INC A)しています。
そのあとのアドレスC6D6の実行直前(C6D5の実行直後)でブレークしました。
CレジスタにはFEが入っています。
Aレジスタは+1しましたからFFです。
結果は0ではありませんから、Z(ゼロフラグ)はセットされません(フラグはレジスタダンプの右端に表示されています)。
ゼロフラグはセットされませんから、このJP Zはパスされます。

そうすると、その次の命令が実行されることになります。
下のプログラム部分です。

C6D9 3C        INC A
C6DA CA06D2    JP Z,CONST

ここではもう一度 INC A が実行されますから、その結果Aレジスタの値は、FF+1=00になります。
今度はゼロフラグがセットされますから、JP Z,CONSTが実行されます。
CONSTはBIOSのコンソールステータスチェックルーチンです。

むむ。
今度はBIOSのプログラムリストが必要になってきますね。
そこで。
BIOSのエントリ部分です。

                    	;
  D200  C381D2        	BOOT:	JP	BOOTJ
  D203  C388D2        	WBOOT:	JP	WBOOTJ
  D206  C38FD2        	CONST:	JP	CONSTJ

BIOSのCONST(アドレスD206)は、そこからCONSTJ(アドレスD28F)にジャンプします。

そこで。
今度は、CONSTJ(コンソールステータスチェックルーチンの本体)です。


                    	;
                      	;CONSOLE STATUS
                      	;
  D28F  3E07          	CONSTJ:LD A,07
  D291  CDAB10        		CALL SOUT
  D294  CDAE10        		CALL SIN
  D297  FE20          		CP 20H
  D299  C29ED2        		JP NZ,CONSTJ2
  D29C  AF            		XOR A
  D29D  C9            		RET
  D29E  3207BB        	CONSTJ2:LD (CONSTDT),A
  D2A1  F601          		OR 01
  D2A3  C9            		RET
                      	;


ZB3BASICシステムのコンソールステータスチェックはシステムの都合でキー入力無しのときはコード20Hを返します。
アドレスD297では20Hかどうかを判定します。
さきほどブレークしたところから、アドレスD297までは真っ直ぐに実行されるはずですから、次のブレークポイントはD297に設定します。

>bp d297
>rt

A F  B C  D E  H L  A'F' B'C' D'E' H'L'  PC   SP   IX   IY  I  SZ H PNC
2020 00FE D1FE C6D4 0044 0000 0000 0000 D297 C73F 0044 F1A1 FF 00100000

BP D297[Enter]で、次のブレークポイントをアドレスD297に設定します。
RT[Enter]と入力すると、ブレークしたときのCPUレジスタの状態をそのまま変化させないで、ブレークしたアドレスに戻って実行が再開されます。

実行を再開した直後に次のブレークポイント(アドレスD297)でブレークして、またレジスタダンプが行なわれました。
PCには現在のプログラムカウンタの値が表示されています。
D297になっています。

30年以上も昔に開発されたわずか8ビットのCPUで、こんなことができるなんて驚きではありませんか?
しかもこの原型はなんと、TK−80のモニタプログラムに、すでに実装されているのです。

さて。
Aレジスタの値を見ますと、20になっています。
瞬時にして、アドレスD291のCALL SOUTとその次のCALL SINが実行されて、コンソールステータスがUSB経由で受信された結果です。
Aレジスタの値が20ということは、キー入力無しということです。

ところで、今回のデバッグの目的は、キー入力しているのにそれが受け付けられないのはどうしてか、を探ることにありました。
その目的からすれば、ここでキー入力無しというのはちょっと都合が悪い、ということになります。

あ。
いえ。
BIOSのCONSTJルーチンに問題がある、ということではありません。
ここがちゃんと機能している、ということは今までのテストプログラムで確認できていますから、そこに問題はありません。
問題は、ここで「キー入力有り」の情報を得ても、それを持ってリターンしたその先のどこかでその情報が失われてしまうのではないか、というあたりにあります。
果たしてそうなのかどうなのか、それを確認するためには、ここでキー入力無しというのは都合が悪い、のです。

さすがにしかしここでブレークする直前にすばやくキー入力して、それをセンスする、というのは無理です。
でも、CONINからリターンしてきた今、入力されたデータ20を別のものに書き換えてしまって、それが本当の入力データだったということにして、ここから先の実行を続ける、ということならできます。

そんな都合のよいことができるのか?
できるのです。

ZB3BASICのマシン語モニタには、ブレーク中にレジスタの値を強制的に書き換えてしまって、そこから実行を再開する機能もあるのです。

説明の途中ですが、本日は時間がなくなってしまいました。
この続きは次回にすることにいたします。

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

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