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

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

[第69回]

●ファンクションコール0BH(2)

前回はファンクションコール0BHについて説明をしましたが、Windows側のプログラムの都合で、期待通りの動きにはなりません、と書きました。

ファンクションコール0BHはコンソールのステータスをチェックしてキー入力があったかどうかを調べます。
キー入力があった場合には、その直後にファンクションコール01(コンソール入力)を実行することで、キー入力待ちをすることなくコンソールからキー入力文字を受取ることができます。
これはBASICのINKEY$と同じ動作です。

ところが実際にテストプログラムを作って実行してみましたら、どうもキーからの読み込みが思わしくないのです。
キーによっては全く読み込んでくれないものもあります。
これは、おそらくWindows側のプログラム(ZB3.exe)がそのように作られていないためだと思いました。

で、前回はそのように書いたのですけれど。
本日になりましてから、あれ?おかしいぞ。
おかしなことに気が付いてしまいました。

INKEY$はZB3BASICにもあります。
でも。
確か、こんなに読み取りが悪いことは無かったはず…。
むむむ。
確認してみました。

logfile nd80zlog\03230647.txt open

ND80ZVに接続しました
0001 0000 - z
1000 00C3 - 
*** nd80z3 basic ****

>10 A$=INKEY$
>20 IF A$=" "THEN PRINT "*";ELSE PRINT A$;
>30 GOTO 10
>run
********************************************************************************
**********************a*****************************a****a**********************
**********a****a***********a****a****a****a******a******************b******b****
b*******b*b**b*b*********b****b******b***b****b******b*******************b****b*
***b****b**b*******bc**************c*********c****c*c***************c***********
*c*******c********c*************************************c*************c****c****
*************************************d***************d******d****d****d****d****
**d***********d****d*d**d*d*d*********d*d****d***e*************e****e****e****e*
*****************e******e****e****e*******e**e*e**e****e******e***********e*****
*e*************************************************************^B

break in 10

INKEY$の本来の動作からすれば、キーを押している間は連続してそのキーの文字が表示されるはずなのですが、このように飛び飛びになってしまうのは、おそらくキー入力がオートリピートになっていることと、C++にはINKEY$に相当する命令がなくて、そこでちょっと無理をしていることが原因になっていると思います。
それはともかくとして、この程度なら、INKEY$でもちゃんとキー入力を受け付けています。

そういうことになりますと、問題はWindows側のプログラムにあるのではなくて、CP/Mの側にある、ということになります。
果たしてそうなのか、どうなのか、Windows側のプログラム(ZB3.exe)にちょっと細工をして、確かめてみることにしました。

まずは、上で作ったBASICプログラムで、確認してみました。

logfile nd80zlog\03230731.txt open

ND80ZVに接続しました
0001 0000 - z
1000 00C3 - 
*** nd80z3 basic ****
>help
TEXT 8004-8049
ヘンスウ DFF7-DFFF
>list
    10 A$=INKEY$
    20 IF A$=" "THEN PRINT "*";ELSE PRINT A$;
    30 GOTO 10
>run
[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*
[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*
[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[61]a
[00]*[00]*[00]*[00]*[61]a[00]*[00]*[61]a[00]*[61]a[00]*[00]*[00]*[00]*[00]*[00]*
[61]a[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[61]a[00]*[00]*[00]*[61]a[00]*
[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[61]a[00]*[00]*[00]*[00]*[00]*
[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*
[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[62]b[00]*[00]*[00]*[00]*[62]b
[00]*[00]*[00]*[00]*[62]b[00]*[62]b[00]*[00]*[00]*[00]*[62]b[00]*[00]*[62]b[00]*
[00]*[00]*[00]*[62]b[00]*[00]*[00]*[00]*[62]b[00]*[00]*[00]*[00]*[00]*[00]*[00]*
[00]*[00]*[62]b[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[62]b[00]*
[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[62]b[00]*
[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*
[63]c[00]*[00]*[00]*[00]*[63]c[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[63]c
[00]*[00]*[00]*[00]*[00]*[00]*[00]*[63]c[00]*[00]*[00]*[00]*[63]c[00]*[00]*[00]*
[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*
[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*
[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*
[64]d[00]*[00]*[64]d[00]*[00]*[00]*[00]*[00]*[00]*[64]d[00]*[64]d[00]*[00]*[00]*
[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*
[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]*[00]
*[00]
>0000 00C3 - 
リモート接続を終了しました
logfile closed at Fri Mar 23 07:33:32 2012

[]付きの表示はWindows側のプログラムでキーチェックを行なった結果の表示です。
[00]はキーが押されていないことを、そして[61]はキー’a’が押されていることを示しています。上のログファイルでは[62](キー’b’)、[63](キー’c’)、[64](キー’d’)も見えます。
*、a、b、c、dはBASICプログラムの表示です。
これを見ると、BASICのINKEY$は、Windows側のプログラムでのキーチェックの結果をそのまま受取っていることがわかります。

それでは同じことをCP/Mで実行してみるとどうなるでしょうか。

logfile nd80zlog\03230735.txt open

ND80ZVに接続しました
0001 0000 - z
1000 00C3 - 
*** nd80z3 basic ****
>jp d233
[00][00]
[00]a[00]>[00]d[00]i[00]r[00][00][00]
[00]A[00]:[00] [00]F[00]N[00]C[00]0[00]B[00]T[00]S[00]T[00] [00]C[00]O[00]M[00][
00] [00]:[00] [00]F[00]N[00]C[00]0[00]B[00]T[00]2[00] [00] [00]C[00]O[00]M[00][0
0] [00]:[00] [00]F[00]N[00]C[00]0[00]B[00]T[00]3[00] [00] [00]C[00]O[00]M[00][00
] [00]:[00] [00]F[00]N[00]C[00]0[00]B[00]T[00]4[00] [00] [00]C[00]O[00]M[00][00]
[00]
[00]A[00]:[00] [00]F[00]N[00]C[00]0[00]B[00]T[00]1[00] [00] [00]C[00]O[00]M[00][
00][00]
[00]a[00]>[00]f[00]n[00]c[00]0[00]b[00]t[00]1[00][00][00]
[00][00]0[00]0[00]0[00]0[00] [00][00]0[00]0[00]0[00]0[00] [00][00]0[00]0[00]0[00
]0[00] [00][00]0[00]0[00]0[00]0[00] [00][00]0[00]0[00]0[00]0[00] [00][00]0[00]0[
00]0[00]0[00] [00][00]0[00]0[00]0[00]0[00] [00][00]0[00]0[00]0[00]0[00] [00][00]
0[00]0[00]0[00]0[00] [00][00]0[00]0[00]0[00]0[00] [00][00]0[00]0[00]0[00]0[00] [
00][00]0[00]0[00]0[00]0[00] [00][00]0[00]0[00]0[00]0[00] [00][00]0[61]061 0161[0
0]a[61]a 0161[00]a[00]a[00] [00][00]0[00]0[00]0[61]0 0161[00]a[00]a[00] [00][61]
0061 0161[00]a[00]a[00] [00][00]0[00]0[00]0[00]0[00] [00][00]0[00]0[00]0[00]0[00
] [00][00]0[00]0[00]0[61]0 0161[00]a[00]a[00] [61]0161[00]a[00]a[00] [00][61]006
1 0161[00]a[61]a 0162[00]b[00]b[00] [00][00]0[00]0[00]0[00]0[00] [00][00]0[62]0[
00]0[00]0[00] [00][62]0[00]0[00]0[00]0[00] [00][00]0[00]0[00]0[00]0[00] [00][62]
0[00]0[62]0[00]0[00] [00][00]0[62]0[00]0[00]0[00] [00][62]0[00]0[00]0[00]0[00] [
62][00]0[00]0[00]0[00]0[00] [00][62]0[00]0[00]0[62]0[00] [62][00]0[00]0[00]0[00]
0[00] [00][00]0[00]0[00]0[00]0[00] [00][00]0[00]0[00]0[00]0[00] [00][00]0[00]0[0
0]0[00]0[00] [00][00]0[00]0[00]0[63]0 0163[00]c[00]c[00] [00][00]0[00]0[00]0[00]
0[00] [63]0163[00]c[00]c[00] [00][63]0063 0163[00]c[00]c[00] [00][63]0063 0163[0
0]c[63]c 0163[00]c[63]c 0163[00]c[00]c[00] [00][00]0[00]0[00]0[00]0[00] [00][00]
0[00]0[00]0[00]0[63] 0163[00]c[00]c[00] [00][00]0[00]0[00]0[00]0[00] [00][00]0[0
0]0[00]0[00]0[63] 0164[00]d[00]d[00] [00][00]0[00]0[00]0[00]0[00] [00][00]0[00]0
[00]0[64]0[00] [64][00]0[00]0[64]0[00]0[00] [00][00]0[00]0[00]0[00]0[00] [00][00
]0[64]0[00]0[00]0[00] [00][00]0[00]0[00]0[00]0[64] [00][00]0[64]0[00]0[64]0[00] 
[00][00]0[00]0[00]0[00]0[00] [00][00]0[00]0[00]0[00]0[00] [00][00]0[00]0[00]0[00
]0[00] [00][00]0[00]0[00]0[00]0[65] 0165[00]e[00]e[00] [00][65]0065 0165[00]e[00
]e[65] 0165[00]e[65]e 0165[00]e[00]e[00] [00][65]0065 0165[00]e[65]e 0165[00]e[6
5]e 0165[00]e[00]e[00] [00][00]0[00]0[00]0[00]0[00] [00][00]0[00]0[00]0[65]0 016
6[00]f[00]f[00] [00][00]0[00]0[00]0[00]0[00] [00][00]0[00]0[00]0[00]0[00] [00][0
0]0[00]0[00]0[66]0[00] [00][00]0[00]0[00]0[00]0[00] [00][00]0[00]0[00]0[00]0[00]
 [00][00]0[00]0[00]0[00]0[00] [00][00]0[00]0[66]0[00]0[00] [00][00]0[66]0[00]0[0
0]0[00] [00][00]0[00]0[00]0[00]0[00] 

こちらは、さきほどのBASICと同じように、ちょっと細工をして[]付きでWindows側のキーチェックの結果を表示させるようにしたZB3.exeを実行して、前回と同じファンクションコール0BHのテストプログラムを実行してみた結果です。

これを見ますとCP/MはDIR表示などを1文字ずつコンソール出力していることがよくわかります。
コンソール側(Windowsプログラム側)では1文字を受け取ってそれを表示する間にキーチェックを行なっています。
この部分をさきほどのBASICと比べてみてください。
BASICではシステムの表示はまとめて行なっていますから、間にキーチェックは行なわれていません。

あ。
このログファイルのCP/Mにエントリする前の部分も、そうでした。
表示のみ行なわれていてキーチェックはありません。

それはともかくとしまして、Windows側のキーチェックと、その結果を受けているはずのファンクションコール0BHの実行の結果を確認してみましたら、推測しました通り、Windows側ではキー入力を確認しているのに、CP/M側ではそれが反映されていないところがあることがわかります。
コード[62][64][66]はほとんど無視されてしまっています。
それから[00]になっているのにCP/M側では入力文字として表示されているところもちらほらあります。

前回も説明しましたように、ファンクションコール0BHは、コンソールの状態をチェックして、そのあとあらためてコンソール入力を実行しています。
Windows側のプログラムに細工をして[]で表示しているのは、コンソールチェックに相当する部分で、コンソール入力に相当する部分ではありません。
そこに時間的なアクセスのずれが加わって上のような結果になっているのだと思われます。

実はWindows側のプログラム(ZB3.exe)のキーチェックルーチンではキーチェックと同時にそのキーのコードも取得します。
BASICのINKEY$は、そのキーコードも同時に受取るために、CP/Mのような「ずれ」は生じません。

さて。
そのずれを考慮しても、おかしなことに、キーコードが偶数のものの反応が悪い(というかほとんど入力されない)のはなぜでしょうか。

おおお。
そういえば、確か、どこかで、おかしなことをやっているなあ、と思ったような…。

調べてみて、やっとわかりました。
ファンクションコール0BHの処理ルーチンの中で、BIOSのコンソールステータスをコールしているところがあります。
BIOSルーチンからリターンしてきたあと、Aレジスタの値をチェックしてコンソール入力の有無をチェックしているのですが…。
この部分です。



1375のCALL CONSTがBIOSのチェックコンソールです。
そのあと1376のAND 01Hで、Aレジスタのビット0をチェックしています。

私はそこを見落としていて、てっきりAレジスタにキーコードを入れてリターンすればいいものとばかり思ってBIOSルーチンを作りましたから、まさかビット0を見ているなどとは思いませんでした。

いえ。
そのところは、もう2ヶ月も前に、CP/Mの内部ルーチンを確認しているときに、見たはずで、頭の隅にはそれが残っていたのですけれど、まさかここでこういうふうに影響してくるとは思ってもみませんでした。

そんなことはどこかに飛んでしまっていて、私は普通にAレジスタの00か非00かをチェックすればいいはず、と勝手に思い込んでしまいましたから…。
OR A
を使えばせっかくのAレジスタの中味を破壊することなく、00か00でないかがわかります。

BIOSのコンソールステータスルーチンは、BASICのINKEY$をそのまま利用したため、キー入力が無いときはAレジスタに00を、キー入力があったときは、そのキーコードをAレジスタに入れてリターンするように作っていました。

ところがCP/MではそのAレジスタのビット0のみを見るために、
AND 01
を実行していたのです。
そのため、コード62H、64H、66Hは、AND 01の実行によって全て00になってしまい、「キー入力無し」ということになってしまったのでした。

それで。
このファンクションコール0BHのテストプログラムでは[Ctrl][z]の入力でブレイクするようになっていたのですが、[Ctrl][z]を入力しても全く反応がなかったわけがわかりました。
[Ctrl][z]のキーコードは1AHです。
AND 01 によって、00になってしまいます。

やっと原因がわかりましたから、BIOSのルーチンを修正することにいたしました。

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

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

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