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

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

[第379回]


●COPYコマンド作成中のトラブル

このところCOPYコマンドの機能拡充のための作業に取り組んでいます。
とんでもないバグの伏兵のために半日、1日を費やしてしまうことなどがあって、なかなかに大変です。
今回はそのお話を少々。

CP/M互換DOSはCP/M2.2(58KB版)の互換ソフトとして開発をしてきました。
CP/MはCCP、DOS、BIOSの3つのプログラムによって構成されていて、その開始アドレスが決まっています。
58KB版の場合、CCPのアドレスはCC00になっているようですので、それより前にシステムプログラムを置くわけにはいきません。
CCPとBIOSにはさまれる形になっておりますDOSもどうやらその居場所は決まっているようで、D400からになっているようです。
実際にはファンクションコールのアドレスの関係で、メインになるプログラムの先頭アドレスはD406からになります。
BIOSのアドレスはE200からのようです。

このように3つのプログラムを配置するとなりますと、機能拡張をするにもメモリアドレスの壁が出てきます。
CP/Mの場合、PIPコマンドはトランジェントコマンドでした。
トランジェントプログラムというのは、一般にユーザーに開放されている0100からのアドレスにロードされて実行されるプログラムのことで、トランジェントコマンドはシステムプログラムとして最初からメモリに常駐しているのではなくて、必要に応じてシステムディスクからトランジェントエリアにロードされて実行されるコマンドです。

CP/M互換DOSではPIPに代わるものとしてCOPYコマンドを用意しているのですが、それはトランジェントコマンドではなくて、最初からシステムに常駐しているビルトインコマンドです。
これには理由がありまして、まあ、卵が先か鶏が先かという悩ましい問題なのです。

CP/M互換DOSではプロッピーディスクの代わりにWindowsパソコンのハードディスク内に仮想フロッピーディスクドライブというものを作ってそれにアクセスします。
最初にCP/M互換DOSを立ち上げたときには、仮想FDDは空っぽです。
[2013.4.26追記]
CP/M互換DOSをインストールして、そのあと最初に起動したときに、という意味です。
毎回起動したときに空ということではありません。
CP/M互換DOSを起動して、そこでA〜Dの仮想FDDにプログラムファイル、データファイルをセーブしたあとは、次にCP/Mを起動したときには、その仮想FDDは空ではありません。
前にセーブした状態はそのまま維持されています。[追記ここまで]
システムはZB3BASIC上の /CPMコマンド によってND80ZV(ND80Z3.5)のRAMにロードされたのち起動します。
つまりシステムディスクなるものが存在しないのです。
A〜Dの仮想FDDをシステムディスクのように使うことは自由ですが、しかし、とにかく最初はそこは空ですから、まずそこにプログラムを入れてからでないと、トランジェントコマンドとして使うこともできません。
そこでWindowsのフォルダから仮想FDDにプログラムをコピーする機能として、COPYコマンドにCOPY Zという機能を付加しました。
当然、そのコピーコマンドは仮想FDDが空のときにも使えなくてはなりませんから、最初からシステムに常駐していなくてはいけないのです。

すると。
そのCOPYの機能を拡張するということになりますと、今度はさきほど書きましたように、メモリアドレスの壁が制約になってきてしまいます。
仕方がありませんから、最初はCCPに入れておりましたCOPYプログラムを切り離して、それをBIOSの後方に置くという改造に着手いたしました。
しかしBIOSの後方は、ZB3BASICのシステムワークが使っているところですから、気をつけないととんでもないトラブルになる可能性が出てきます。
狭いところでのやりくりはなかなかに大変です。
これまで割りといい加減に使っておりましたCP/M互換DOSのためのワークエリアも整理したり移動したりと、派生的な作業に結構時間を取られてしまいました。

で。
COPYコマンドをそのようにお引越ししまして、やっとなんとか試運転にかかりましたところ。
??????
おかしいのでありますね。
実に奇妙な、摩訶不思議なエラーに直面してしまいました。
プログラムを何回見直してもそんなおかしな結果にはならないはずなのですが。
結局、その意外な原因をやっと突き止めるまでにたっぷりと貴重な半日余りを費やしてしまいました。

とにかくCOPYの動作があまりにおかしい、どうにも納得がいきません。
で、ブレークポイントを設定しながら少しずつプログラムを進めてデバッグをしていきましたところ、ある時点までくると、変数の値がプログラムの通りになっていないところがでてきました。
異常な動作の原因はその変数の値によるものであることがわかりました。
しかし、なぜそれがプログラムの通りになってくれないのか?
その値を設定する前後を詳しく調べてみましたところ、なんと、プログラムが一箇所書き換わっているじゃありませんか!
具体的には、アドレスEA00が62でなければならないところがE2に化けてしまっています。
すわメモリ異常か?

そんなわけはないのですよね。
何回か試して確認しましたところ、CP/M互換DOSをロードしたときには、その場所(アドレスEA00)はちゃんと正しい値になっています。
ところが/CPMコマンドでCP/M互換DOSを起動した直後にブレークして確かめてみますと、E2に化けてしまっています。
どういうわけかCP/M互換DOSの初期動作のどこかでEA00にE2を書き込んでしまっているようです。
しかし、プログラムを何回確認してみましても、EA00などというアドレスは全く出てきません。

そこで。
またしても、ブレークポイントを設定してCP/M互換DOSを少しずつ進めつつ、アドレスEA00の値を確認するという退屈な作業を続けました。
その結果、ALV(アローケーションベクタ)の設定中にEA00が変化するということがわかりました。

むむむ。
なぜこんなところで?
CP/Mはディスクの使用状況のマップ(それがALVです)をディスク上にではなくて、RAM上に展開します。
MSDOSでFATと言っている情報エリアです。

CP/Mではセクタをまとめてブロックという単位で管理します。
仮想FDDの場合1ブロックは16セクタで、ディスク全体は1024ブロックで構成されます([第219回]参照)。
ディスクの割り当てはブロック単位で行なわれますが、どこのブロックが使用済みかということを常に管理していなければなりません。
CP/Mではディスクドライブの1ブロックをメモリの1ビットに割り当てて1024/8=128バイトをALVエリアとして管理します。
MSDOSでFATとよんでいる同様のエリアはディスク上に置かれますが、CP/Mではそれはメモリ上に置かれます。
メモリですから電源を切ったら消えてしまいます。

それじゃディスクの情報も消えてしまうではないか、ということなのですが、そこでCP/Mでは新たにディスクドライブにディスクがセットされるたびに、ディスクのディレクトリエリアを全部サーチして、使用状況を読み取って、その情報をもとにメモリ上にALVエリアを再構築するのです。
このためディスクを交換したり装着したりするたびにその作業に時間が費やされることになります。

その方式の是非はさておき、本題のトラブルの結末です。
実は、それよりも前にCOPYプログラムを変更する過程で何回かテストを行なって、そのたびに仮想FDDの中身も書き換わっていました。
最初のうちはバグだらけですから、仮想FDDの中身もそれなりにメチャクチャに壊されてしまったところがでてきていましたが、まあ、テストだからいいか、ということで、構わずそのままテストを続けておりました。

ちっともよくはなかったのでした。
テストの過程でバグのために、ディレクトリのFCB(32バイトずつに区切られたファイルコントロールブロック)の中のブロックアドレスが書かれているエリアが破壊されていて、ありえない値になってしまっていたのでした。
本来はディスク全体で1024ブロックしかありませかんから、あるプログラムが書き込まれているブロックのナンバーとしては0000〜03FFの間の値になります。
そこに2000というとんでもない値が書き込まれてしまっていました。

AドライブのALVエリアはアドレスE600〜E67Fに置かれています。
ブロックナンバー2000(16進数です)をそこに割り当てようとしますと、1ビットが1ブロックですから2000H/8を計算して400、それをE600に加算しますと。
おお、EA00になりました。
つまり、本来ならばありえない2000Hなどというブロックナンバーが使用済みであるとしまして、本来のALVエリアを大きく逸脱したEA00にその情報が書き込まれてしまったのでした。

いやはや、おかげでたっぷりと半日以上を浪費してしまいましたが、しかし、ものは考えようで、たまたまCOPYプログラムを移動して、そしてたまたま今回のトラブルに遭遇したために、ALVエリアが作成されるときに、ディスクの情報が破壊されていたりすると、思わぬ場所が書き換わってしまうというプログラムの「脆弱性」が明らかになったわけでありまして、これがもし全くそのことに気がつかないままユーザー様に配布してしまったあとで、そういう事態が発生したりしますと、それこそ原因追及のために思いっきり悩んだことでありましょう(あなおそろしや)。

さっそく、ALVエリアを作成するときにその範囲をチェックするようにプログラムを修正しました。
と同時にディスクディレクトリのどこに異常があるかを表示できるようにしました。
前回お見せしましたCP/M互換DOS起動時の各ディスクドライブの表示の後ろに表示されている....がその表示です。
.(ドット)のひとつが16セクタあるディレクトリの各1セクタを示しています。

その機能を検証するために、わざとAドライブのディレクトリの一部を書き換えてみました。
下の画面でディレクトリのブロックエリアに2221H、2423Hという異常な値を書き込んでいます。
普通はこういうことはできません。
ZB3BASICのマシン語デバッグ機能を利用しています。

DIRコマンドで表示させても、その異常はわかりません。
一度ZB3コマンドでCP/M互換DOSを終了したあと、もう一度CP/M互換DOSを起動しました(デバック機能を利用中ですから/CPMではなくてJP命令でBIOSにエントリしています)。
drive Aの表示で前から2番目に ! が表示されています。
ディレクトリの2番目のセクタに異常があることを示しています。

このことはVFDUMPで確認することができます(VFDUMPはCP/M互換DOSに同梱予定のソフトウェアです)。

表示されたセクタの一番下の行が書き換わっています。

いやあ。
なかなかに。
骨が折れる作業です。

ワンボードマイコンでCP/Mを![第379回]
2013.4.25upload
2013.4.26追記

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