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

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

[第385回]


●ZドライブのMBASICでファイルのSAVEを!

人間の慾にはきりが無いのでありまして、ここまで出来ると次はそこまで、という具合に際限がありません。
いい加減にしておかねばなりませぬ。
が、しかし。
前回まさかZドライブでMBASICが動くところまで出来るとは思っておりませんでしたが、それが動いてさらにMBASICでプログラムの作成や実行まで出来てしまったということになりますと。
やっぱりBASICプログラムのSAVE、LOADもできないものか、試してみたくなります。

あ。
CP/M互換DOSの機能といたしましては、これは全く余計な機能でありまして、ここまでできる必要は本来は無いものなのです。
純粋のCP/M互換DOSの機能としましては仮想FDDのA〜Dドライブを使うというのが当初からの設計思想でありまして、Zドライブといいますのは、あくまでWindowsとCP/M互換DOSとの間でファイルの受け渡しをするためのバッファのようなものです。
そういう当初の設計思想からしますとZドライブの上でプログラムを実行するといいますのは、言うなれば邪道ということになります。

まあ、しかし。
ここまで来てしまいますと。
当初の設計思想がどうあれ、また邪道であろうとなかろうと。
できるようにしてみたくなってしまうのであります。
困ったものでありますなあ。まったく。

で。
前回MBASIC上で作成して実行してみましたプログラムをSAVEしてみました。
プログラムの実行まではできても、Zドライブに対してファイルのSAVEまでは無理だろうと思っておりましたので、そのところの画像は保存しませんでした。
ですのでログファイルをお見せすることにいたします。

list
10 FOR A=0 TO 10
20 PRINT "a=";A,"sqrt(a)=";SQR(A)
30 NEXT A
Ok
run
a= 0          sqrt(a)= 0 
a= 1          sqrt(a)= 1 
a= 2          sqrt(a)= 1.41421 
a= 3          sqrt(a)= 1.73205 
a= 4          sqrt(a)= 2 
a= 5          sqrt(a)= 2.23607 
a= 6          sqrt(a)= 2.44949 
a= 7          sqrt(a)= 2.64575 
a= 8          sqrt(a)= 2.82843 
a= 9          sqrt(a)= 3 
a= 10         sqrt(a)= 3.16228 
Ok
save "SQRTEST"
 Ok
dir
Syntax error
Ok
system
 
Z>dir
Z: VFTST92  COM : VFTST9   COM : VFTST0   COM : VFTST25  COM
Z: VFTST24  COM : VFTST6-2 COM : VFTST205 COM : VFTST204 COM
Z: VFTST22  COM : VFTST21  COM : VFTST203 COM : VFTST202 COM
Z: VFTST107 COM : VFTST17  COM : VFTST14  COM : VFTST16  COM
Z: VFTST15  COM : VFTST19  COM : VFTST18  COM : VFTST13  COM
Z: VFTST12  COM : VFTST11  COM : VFTST105 COM : VFTST102 COM
Z: VFTST10  COM : VFTST8   COM : VFTST7   COM : VFTST6   COM
Z: VFTST4   COM : VFTST2   COM : VFTST5   COM : VFTST1   COM
Z: VFTEST1  COM : MBASIC   COM : VFTST23  COM : STRTRK2  BAS
Z: SQRTEST  BAS
Z>

MBASICでは拡張子を省略するとBASという拡張子で保存されます。
SAVE ”SQRTEST”[Enter]
と入力しました。

OK
と表示されたので、確認してみようと思いまして、つい
DIR[Enter]
と入力してしまいました。

Syntax error ???

あ、そうだった。
DIRはCP/Mのコマンドでした。
MBASICでは実行できません。
SYSTEM[Enter]
でMBASICを終了しました。
そこであらためてDIRコマンドで確認してみました。
おお。
SQRTEST.BASがSAVEできたようです。

ところで、何回も説明しておりますように、仮想FDDのA〜DドライブにSAVEしたファイルはCP/M互換DOSの上でしか開くことができません。
しかしZドライブに保存したファイルはWindowsから直接アクセスすることができます。
それなら。
ということで、さっそくSQRTEST.BASをTeraPadで開いてみましたところ。
ぐちゃぐちゃです。
むむ。テキストファイルではない…?

MBASICのMANUALで確認してみましたところ、SAVEコマンドでパラメータをつけない場合には、そのファイルはMBASICの中間コードでSAVEされることがわかりました。
テキストファイルで保存するためには、
SAVE ”SQRTEST”,A[Enter]
とする必要があります。
,AをつけるとリストイメージをASCIIコードでファイル出力します。
なるほど。納得です。

あらためて、,AでSAVEしなおしたあと、TeraPadで開いてみました。



うむむ。
ファイルにNull(コード00)が含まれているようです。
ま、しかし。
なんとか開くことはできたようです。

参考までに。
,Aをつけた場合とつけない場合の両方でSAVEをして、そのファイルの中身をそれぞれ確認してみました。



上が,Aをつけた場合で、下がつけなかった場合です。

●ZドライブのMBASICでファイルのLOADを!

さてそれではいよいよLOADです。
SAVEができたのでありますから、当然LOADもできるはず…。
だったのでありますが、世の中というものはそんな甘いものではありませぬ。
LOAD ”SQRTEST”[Enter]
を実行しますと、すぐに
OK
は表示されるのですけれど、
LIST[Enter]
と入力しても何も表示されません。

実は。
Zドライブに対するアクセスはZBIOSのレベルではなくて、その上のZBDOSで処理をしております。
それも例外的といいますかちょっと変則的な処理をしておりますので、たまたまSAVEまではできたとしましても、LOADができなくても、それはそれで仕方がないことなのです。
ま。
上のほうでも書きましたように、そもそもZドライブはバッファのようなものでありますから、その上でプログラムを実行することはいわば想定外なのでありまして、そこでたまたま実行できたMBASICで、これもたまたまうまくSAVEまでできたのに、LOADができなくてもそれはそれで仕方がないことなのであります。

いやあ。
残念でありました。
でも、ここまでできたら、十分ではありませんか、ねえ。

と、いうところまでで、昨日は作業を終わりまして寝てしまったのでありますが。
今朝になりますと。
むむ。
やっぱり面白くないのでありますねえ。

おおお。
やるのか?そこまで。
そりゃあ、ちょいと、ホネだぞお。
もう、いい加減にCP/M互換DOSも完了しないといかんだろうよ。

そ。それはそうなのでありますが…。
このままでは、どうにも気持ちが悪いので…。
ま。
どこに遊びに行くのでもなし、連休の合間の半日くらいは、無駄に費やしたとしても、よいのでは。

で。
MBASICの解析にかかってしまいました。

●MBASICの解析

下はMBASICの逆アセンブルリストです。
もう1年ほど前にMBASIC.COMをダウンロードしたときに、CP/M互換DOSで走らせようとして、当初はうまく走ってくれなかったために、動作解析をする目的で逆アセンブルしたものです。

A4用紙で250枚ほどもあります。
沢山ついている付箋のほとんどは、STARTREKを最初に実行しましたときに、とんでもないトラブルに遭遇してしまって(あ。このことを書くつもりで、まだ書いておりませんが)、そのときにデバッグするためにつけたものです。

こんなすごいものをどうやってデバッグするのでしょう。
ええ。
まともに始めから解析していったのではどれだけ時間があっても足りません。
実は。
ZB3BASIC+CP/M互換DOSには、こんなときのためのデバッグ機能がちゃんと組み込んであるのです。

こちらが、今回のMBASICのファイルLOADをデバッグしたときのログです。

logfile nd80zlog\05010557.txt open
ND80ZVに接続しました
0001 0000 - z
1000 00C3 - 
*** nd80z3 basic ****
>/cpm
loading zbds3d.bin ...19d1(6609)bytes loaded,from CC00 to E5D0
drive D ................................
drive C ................................
drive B ................................
drive A ................................

A>zb3
end of ZBDOS
>bp cc03
>jp e248
BPはZB3BASICのマシン語デバッグ機能のひとつです。
任意のアドレスにブレークポイントを設定できますが、それはCP/M互換DOSの上でも有効です。
ただ使い方にはちょいとしたコツがあります。
CP/M互換DOSは普通は/CPMで起動しますが、そのときCP/M互換DOS本体を再ロードしてしまいます。
するとせっかくブレークポイントを設定しておいても、再ロードによってクリアされてしまいます。
そこで上のログにありますように、まずはCP/M互換DOSをメモリにロードするために、最初に/CPMコマンドを実行します。
そのあとすぐにZB3コマンドでZB3BASICに戻ります。
ここでアドレスCC03にブレークポイントを設定します。

MBASICやユーザープログラムは最初に0100番地にロードされて、それから実行されます。
そのロードよりも前にそのプログラムにブレークポイントを設定することはできません。
アドレスCC03にブレークポイントを設定しておくと、プログラムがロードされた直後にブレークします。

もっとも今回はユーザープログラム(ここではMBASIC)にブレークポイントを設定して、そこからデバッグを始めるのではなくて、最初はZBDOSのファイルOPENにブレークポイントを設定しますから、MBASICのロード直後に最初のブレークを設定する必要はありませんでした。

ま、とにかくそのように設定して、それからCP/M互換DOSを起動させますが、このときは互換DOSを再ロードさせないように、途中のポイント(E248番地)にジャンプするようにします。

CP/M互換DOSが起動しました。
drive D ................................
drive C ................................
drive B ................................
drive A ................................

A>z:
Z>dir
Z: VFTST92  COM : VFTST9   COM : VFTST0   COM : VFTST25  COM
Z: VFTST24  COM : VFTST6-2 COM : VFTST205 COM : VFTST204 COM
Z: VFTST22  COM : VFTST21  COM : VFTST203 COM : VFTST202 COM
Z: VFTST107 COM : VFTST17  COM : VFTST14  COM : VFTST16  COM
Z: VFTST15  COM : VFTST19  COM : VFTST18  COM : VFTST13  COM
Z: VFTST12  COM : VFTST11  COM : VFTST105 COM : VFTST102 COM
Z: VFTST10  COM : VFTST8   COM : VFTST7   COM : VFTST6   COM
Z: VFTST4   COM : VFTST2   COM : VFTST5   COM : VFTST1   COM
Z: VFTEST1  COM : MBASIC   COM : VFTST23  COM : STRTRK2  BAS
Z: SQRTEST  BAS
Z>mbasic

A F  B C  D E  H L  A'F' B'C' D'E' H'L'  PC   SP   IX   IY  I  SZ H PNC
194A 0003 E107 E88E 0000 0000 0000 0000 CC03 F7FE 0000 0000 FF 01001010
>bp@d7c5
>rt@
Zドライブに移動して
Z>MBASIC[Enter]
と入力します。
するとMBASICが0100番地にロードされた直後にアドレスCC03でブレークしました。
これからがデバッグの本番です。

BP@D7C5[Enter]
でD7C5番地にブレークポイントを設定して
RT@[Enter]
で中断したところからプログラムの実行を再開します。
ZB3BASICでは0000〜7FFFのアドレス範囲はROMが選択されていますが、BP@やRT@を実行すると、RAMが選択されます。

アドレスD7C5はZBDOSのファイルOPENのエントリアドレスです。
              ;
              ;DISK FILE OPEN FCALL 0F
              ;
D7C5 CD4AD8   OPEN:CALL SRCHFST
D7C8 FEFF       CP FF
D7CA C8         RET Z
D7CB E5         PUSH HL
D7CC 010C00     LD BC,$000C
D7CF 09         ADD HL,BC
D7D0 7E         LD A,(HL);extent No.
D7D1 E1         POP HL
D7D2 B7         OR A
D7D3 CAEAD7     JP Z,OPEN2
D7D6 CDC3D8     CALL SRCHNXT
D7D9 FEFF       CP FF
D7DB C8         RET Z
D7DC E5         PUSH HL
D7DD 010C00     LD BC,$000C
MBASICのLOADコマンドでファイルロードをするとき、最初に必ずファイルOPENがCALLされるはずです。

RT@を実行すると、MBASICのロード直後から実行が再開され、MBASICが起動しました。
BASIC-80 Rev. 5.21
[CP/M Version]
Copyright 1977-1981 (C) by Microsoft
Created: 28-Jul-81
28728 Bytes free
Ok
load "SQRTEST"

A F  B C  D E  H L  A'F' B'C' D'E' H'L'  PC   SP   IX   IY  I  SZ H PNC
C580 D4A4 5D8B D7C5 0000 0000 0000 0000 D7C5 E0FC 0000 0000 FF 10000000
そこで
LOAD ”SQRTEST”[Enter]
を入力しました。

狙った通りにファイルOPENのところ(アドレスD7C5)でブレークしました。
さて。
ここを手がかりにして、MBASICに突入します。
MBASICの「侵入経路」を調べます。
どうやって?

CP/M互換DOSのファンクションコールは、呼ばれたときにスタックをユーザースタックからシステムスタックに切り換えます。
そのときにSPの値をシステムのワークエリアに保存します。
その値を確認するのです。
>cm e004
E004 F6-
E005 D3-
>dm d3f0,d3ff
D3F0  AB 5D 8B 5D 00 5D 74 59-8A 5D 62 01 A0 52 44 00  ォ].].]tY.]b.RD.
ファンクションコールが実行されたときのSPの値はE004〜E005に保存されています。
その値をCMコマンドで確認します。
D3F6です。

ということは。
ファンクションコール実行後にMBASICに戻るときの戻り先のアドレスがD3F6にPUSHされているはずです。
それをDMコマンドで確認しました。
戻り先は5974であることがわかりました。
そこがMBASICのLOADコマンドの在り処(ありか)です。

さきほど写真でお見せしましたMBASICの逆アセンブルリストのその部分です。

おお。
アドレス5974の直前に、
LD C,0F
CALL $0005
があります。
ファイルOPENのファンクションコールです。

あっ。
今気がついたのですけれど、MBASICのスタックがD3FXに置かれているってことは…。
そこはZBDOSの直前、つまりZCCPの後ろじゃありませんか。
ZBDOSはD406から始まります。
おおお。
MBASICはCCPを破壊してしまうのですねえ。
そういうプログラムがあったりするので、ウォームブート時にはCCP(とBDOS)の再ロードが必要なのです。
なるほど。納得。

それはともかくといたしまして。
LOADの糸口がつかめれば、あとはそれをたどって少しずつブレークポイントを設定しながら進めば、何をやっているのかがおおよそつかめてきます。

>bp@5987
>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
0162 0600 5D8A 5D97 0000 0000 0000 0000 5987 D3FC 0000 0000 FF 01100010
>bp@598d
>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
0148 0600 5D8A 5DAF 0000 0000 0000 0000 598D D3FA 0000 0000 FF 01001000
>bp@5999
>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
0193 0600 5D8A 5D8A 0000 0000 0000 0000 5999 D3FC 0000 0000 FF 10010011
>bp@577a
>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
0142 0600 5D8A 5D8A 0000 0000 0000 0000 577A D3FA 0000 0000 FF 01000010
>dm@5d80,5d9f
5D80  9F 0A 7E B7 C2 9A 52 C3-87 0D 01 00 53 51 52 54  ..~キツ.Rテ....SQRT
5D90  45 53 54 20 42 41 53 00-00 00 00 00 00 00 00 00  EST BAS.........
>bp@57bb
>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
0148 001A 5DB3 5D8B 0000 0000 0000 0000 57BB D3EE 0000 0000 FF 01001000
>bp@579f
>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
2144 0000 5D8B 5E32 0000 0000 0000 0000 579F D3F6 0000 0000 FF 01000100
>

おおお。
わかりました!



開けてびっくり玉手箱。
想定外の展開です。
なんと。
シーケンシャルREADのはずなのに。
ファンクション21H(ランダムREAD)がコールされておりました!
上のログの最後、アドレス579FでブレークさせたときのAレジスタの値が21Hになっています。
$5A9EのサブルーチンではAレジスタの値をCレジスタに入れてファンクションコール$0005を実行しています。

ふむむむむ。
それでようやくわけがわかりました。
実は。
ZドライブではWindowsのファイルシステムをそのまま利用しておりますために、CP/Mのランダムファイルはアクセスできませんから、当然のことながらランダムREAD、ランダムWRITEはZドライブについては対策をしてありませんでした。

しかしこういうことになりますと。
ランダムREADもZドライブに対応するようにしておかねばなりませぬ。
あ。
もちろんランダムアクセスファイルをZドライブ上に作る、ということではありません。
そこまでやってはやりすぎです。

どうやらMBASICではランダムアクセスとシーケンシャルアクセスを兼用するために、ファイルロードにはランダムREADを使っているようです。
そこでZドライブをアクセスするときにはランダムREADをシーケンシャルREADにパイプしてしまうようにZBDOSプログラムを直しました。
そういうことでうまくいくかどうかわかりませんでしたが、とにかく、やってみなくちゃわかりませんものね。

あれえ。
でもSAVEについては、ランダムWRITEも未対策だったのに、ちゃんとZドライブにファイルが作成されてしまいましたよ。
うむむむむ。
どうやら、SAVEのときは、シーケンシャルWRITEを使っているようですなあ。
ま。それはそうでしょう。
出来上がるのはシーケンシャルファイルそのものなのですから、それをわざわざランダムWRITEで作成する意味はありませんものね。

さて、ZBDOSをそのように直しましてから、MBASICを再度実行してみました。

おお。
今度はちゃんとロードできました。

この通り、実行することもできました。


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

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