MSX Datapack wiki化計画

12章 外部プログラムの環境

※
※ このページは書きかけです。以下の可能性があります。
※ ・誤字、脱字等のチェックをおこなっていません。
※ ・テキスト、表などフォーマットがされていない。
※ ・画像が抜けている。
※

 本章はMSX-DOSの下で外部プログラムが実行される環境について説明し、プログラムのエントリや終了、メモリの使用法などについて記述します。

 12.1 MSX-DOSからのエントリ

 外部プログラムが開始されるときのZ80のレジスタの内容は未定義です。RAMの0番地から始まる最初の256バイトは12.3「ページ0の使用法」で説明されるような種々のパラメータとコードでセットアップされています。

 外部プログラムが開始されるときには割り込みはイネーブルで、一般的にはイネーブルのままにしておかなければなりません。MSX-DOSのファンクションコールは外部プログラムが割り込みを禁止している場合でも、割り込みを許可して戻ります。

 12.2 MSX-DOSへのリターン

 外部プログラムは以下の4つの方法で終了させることが出来ます。

  1. 呼び出し時のスタックポインタでリターン
  2. 0000H番地へジャンプ
  3. MSX-DOSの「プログラムの終了」ファンクションコール(P.269参照)
  4. MSX-DOSの「エラーコードを返して終了」ファンクションコール(P.320参照)

 1番目の方法で行うと以下のようになります。COMMAND2.COMは、外部プログラムをTPAの始めである0100H番地からロードし、スタックポインタをTPAの最後から数バイト下に設定し、0100H番地から実行します。このときスタックトップには0000Hがプッシュされています。スタックポインタをプログラム側で再設定しないでリターンすると、MSX-DOSに戻れるのはこのためです。

 スタックポインタを

LD       sp,(0006H)

で再設定すると、可能な限りのRAMをスタックとして使用できますが、この場合はリターンでMSX-DOSに戻ることはできません。

 スタックポインタを上記のように再設定することに不都合が有るのならば、外部コマンドは自分自身のスタックをTPA中にとらなければなりません。

 最初の2つはMSX-DOSの下では同一で、CP/MおよびMSX-DOS1と互換性があります。3番目の方法もCP/MとMSX-DOS1と互換性があり、エラーコード0の「エラーコードを返して終了」ファンクションコールを実行するのと同様です。

 4番目の「エラーコードを返して終了」ファンクションを使用すると、プログラムはMSX-DOSにエラーコードを返すことができますが、最初の3つの終了の方法は常にエラーコード0(エラーなし)を返すだけです。

 新たにMSX-DOS2で作成されるプログラムや、CP/Mプログラムでも新しくMSX-DOS2の環境に移植する場合は、エラーコードとして0を返す場合でも、4番目の「エラーコードを返して終了」ファンクションを使用して下さい。

 プログラムは、その制御の範囲外で発生したイベントによっても終了することがあります。イベントとは、例えば、CTRL+CやCTRL+STOPをキーボードから入力した場合や「Abort(中止)/Retry(再試行)/Ignore(無視)」のディスクエラーメッセージに対する応答として「中止」をユーザーが選択した場合、あるいは標準I/Oチャンネルでエラーが発生した場合などです。その場合、適当なエラーコードがMSX-DOSに返されます。

 外部プログラムでは「アボートルーチン」を定義することができます。

 これは「プログラムの終了」あるいは「エラーコードを返して終了」ファンクションによってプログラムが終了したとき、あるいは中止エラー(上記参照)の後でコールされ、プログラムの異常終了を正しく処理することができます。このルーチンの定義の仕方およびどの場合に使用できるかについては17.3「ファンクションの説明」で説明されています。

 12.3 ページ0の使用法

 外部コマンド起動時に、種々のパラメータ領域がRAMの最初の256バイトに外部プログラムのためにセットアップされます。この領域のレイアウトは以下の通りで、MSX-DOS1と互換性があり、MSXのスロット切り換えルーチンのために使用される領域を除いてCP/Mと互換性があります。

 0000H番地には外部プログラムを終了するために使用できるジャンプ命令があります。このジャンプの先はBIOSのジャンプベクタを見つけるために使用することもできます。(12.4「BIOSジャンプテーブル」を参照)。このジャンプアドレスの下位バイトはCP/Mとの互換性のため、常に03Hです。
画像ファイルが存在しません。
 0003Hと0004Hの2つの予約バイトはCP/MにおけるIOBYTEとカレントドライブ番号+ユーザー番号です。MSX-DOS2はCP/Mとの互換性のために、最新のカレントドライブバイトを記憶していますが、MSX-DOS用のプログラムではこれを参照せずに、「カレントドライブの獲得」のファンクションコールを使用して下さい。
図2.2 ページ0のレイアウト

 IOBYTEとユーザー番号はI/OのリダイレクションがCP/Mと同一の方法では行われておらず、MSX-DOSにユーザー番号の概念は存在しないためサポートされていません。

 0005H番地にはMSX-DOSコールを実行するために使用されるMSX-DOSの常駐部分の開始番地へのジャンプ命令があります。このジャンプのアドレスは同時にプログラムが使用できるTPAの上限+1を表します。言い換えると、プログラムが使用できるのは0100H番地から、0006H番地と0007H番地で示される番地マイナス1までです。TPAのサイズはディスクインターフェイスカートリッジの種類や数によって異なりますが、一般的には約53Kです。

 このジャンプ先の下位バイトはCP/Mとのとの互換性のため常に06Hで、CP/Mでは、その直前の6バイトがCP/Mのバージョン番号とシリアル番号を保持しています。

 0008H〜0028HまでのZ80のリスタート命令の飛び先は、ユーザー用にそれぞれ4バイトが予約されていて、そこにジャンプ命令を置くことができます。ただし、リスタートの間の各々4バイトはMSXスロット切り換えルーチンへのエントリポイントとして使用されます。

 0038H〜005BHまでの全領域は、MSXの割り込みと拡張スロット切り換えコードのために使用されますので、ここを変更してはいけません。大部分のCP/Mのデバッガ(ZSIDやDDTなど)は38H番地をブレークポイントエントリとして使用していますので、これらのプログラムは異なったリスタートを使用するように、変更しなければなりません。RST28Hを使うことを推奨します。

 005CH番地と006CH番地に設定されている2つのFCBは、コマンド行の最初の2つのパラメータをファイル名として解釈した有効なオープンされていないFCBです。どちらのファイル名も使用する場合、2番目のものは最初のものがオープンされると重ね書きされてしまうため、メモリ中の別の場所のFCBへコピーしなければなりません。FCBのフォーマットについては13.5「ファイルコントロールブロック(FCB)」を参照して下さい。

 コマンド行全体(最初のコマンドを除いたもの)は0080H番地のデフォルトのディスク転送領域にストアされます。最初の1バイトには渡された文字数が入っており、最後にヌルが付加されます。(ヌルの長さのバイトは、長さには含まれません)。この文字列はCP/Mとの互換性を確保するため、先頭にいくつかの空白文字が入力されていてもそれを含みます。MSX-DOS1との互換性を確保するため通常、文字列はそのまま(大文字に変換されずに)ストアされますが、CP/Mとの互換性を重視して環境変数UPPER(8章参照)をONに設定しておくと大文字に変換されます。

 MSX-DOS用の新しいプログラムはCP/MのFCBを使用すべきではありません。なぜなら、より使うのが簡単なMSX-DOSコールが用意されていて、それを使えばディレクトリをアクセスしたりパス名の処理を行ったりすることができるからです(これらの機能についての詳細は17.3「ファンクションの説明」を参照)。

 コマンド行にアクセスするのに、より改善された方法を使うこともできます。環境変数「PARAMETERS」には、コマンド行が大文字に変換されずに保持されています。別の環境変数「PROGRAM」によって、プログラムは自分がロードされたドライブ、ディレクトリ、およびファイル名を知ることができます。これらの環境変数、環境変数一般についての詳細は13.6章を参照して下さい。

 12.4 BIOSジャンプテーブル

 0000H番地のジャンプは常にその下位バイトが03Hであるアドレスへのジャンプです。このアドレスには別のジャンプ命令があり、これは17エントリあるジャンプテーブル中の2番目のエントリです。これはCP/M 2.2のBIOSジャンプテーブルに完全に対応しています。

 テーブル中の最初の8つのエントリはリブートと文字入出力のためにあります。これらのルーチンはCP/Mと同一の仕様でインプリメントされています。残りのジャンプはCP/Mにおける低レベルのディスク関係のファンクションですが、MSX-DOSではファイルシステムが全く異なるため同等のものが存在しません。これらのルーチンはレジスタ(AF、BC、DEおよびHL)を変更し、可能な場合にはエラーを返すことを除いて、何もせずに単にリターンします。

 BIOSコールを実行中、MSX-DOSは内部のスタックに切り換えるため、ユーザーのスタックは小さな領域(8バイト)しか必要ありません。

 ジャンプテーブルは常に256バイトのページ境界にありますが、TPA(0006H番地の内容によって決まる)の上限からCP/M 2.2で言うところの「正しい」距離にあるわけではないことに注意して下さい。これはきちんと作られたCP/Mプログラムでは決して問題になりませんが、一部のプログラムはCP/M 2.2のBDOSのサイズに依存しているものもあるということです。それらのプログラムでは変更が必要でしょう。
 BIOSのジャンプベクタ中のエントリを次に示します。

表2.9 BIOSのジャンプベクタ中のエントリ

アドレス 命令 意味
xx00H JMP WBOOT ウォームブート
xx03H JMP WBOOT ウォームブート
xx06H JMP CONST コンソールステータス
xx09H JMP CONIN コンソール入力
xx0CH JMP CONOUT コンソール出力
xx0FH JMP LIST リスト出力
xx12H JMP PUNCH パンチ(補助)出力
xx15H JMP READER リーダ(補助)入力
xx18H JMP RETURN CP/Mにおけるホーム
xx1BH JMP RETURN CP/Mにおけるディスクの選択
xx1EH JMP RETURN CP/Mにおけるトラックのセット
xx21H JMP RETURN CP/Mにおけるセクタのセット
xx24H JMP RETURN CP/MにおけるDMAアドレスのセット
xx27H JMP RETURN CP/Mにおけるセクタのリード
xx2AH JMP RETURN CP/Mにおけるセクタのライト
xx2DH JMP LSTST リストステータス
xx30H JMP RETURN CP/Mにおけるセクタ変換

 12.5 RAMページング

 外部プログラムがロードされたときには、4つのページすべてにマッパーRAMのスロットが選択され、基本の64Kを構成する4つのRAMセグメントがページングされています。MSX-BIOS ROM互換のスロット処理エントリポイントがページ0で利用でき、種々のマッパーサポートルーチンがページ3で利用できます(これらの仕様については15章を参照)。

 プログラムは実行中に任意にスロットの切り替えやページングを行うことができます。もちろんプログラムはページ0を変更する場合には割り込みおよびスロット切り換えのエントリポイントについて注意をしなければならず、また絶対にページ3を変更してはいけません。

 MSX-DOSのファンクションコールやMSX-DOSのBIOSファンクションコールを実行する場合、任意のスロットおよびRAMセグメントをページ0、1、および2に選択でき、また、スタックも任意のページ中に置くことができます。現在のページの状態はエラー状態であっても、すべてのファンクションコールで保存されます。任意のパラメータをその時選択されているページから渡すことができますが、環境変数をディスク転送だけはスロットの選択にかかわらず、ファンクションコールが実行されているときにページングされているRAMセグメント(それが元のTPAセグメントでなくても)に対して実行されます。

 外部プログラムがTPA以上のRAMを使用したい場合、マッパーサポートルーチン(15章参照)を使用してそれ以上のRAMを獲得できます。4つのTPAセグメント以外のRAMを使用する前に、プログラムはマッパールーチンに新しいセグメントの割り付けを命じます。これによって新たにRAMセグメントを使用しようとするプログラムとRAMディスクなどですでに使用中のセグメントとの競合を避けることができます。

 セグメントはプログラムが終了すると自動的に解放されるように、通常「ユーザーセグメント」として割り付けて下さい。「システムセグメント」は、外部プログラムが終了した後も使用中として残しておく必要がある場合にのみ、割り付けます。

 追加のセグメントを割り付ければ、プログラムはそれをページングしたり、マッパーサポートルーチンを使用してアクセスしたりできます。通常、外部プログラムは、必要な場合に再び元のページに戻せるように、元のTPAセグメントのセグメント番号を記憶する必要があります。セグメント番号は通常0、1、2、および3ですが、これらの番号を使用しているものと仮定して外部プログラムを作成してはなりません。外部プログラムは必ず別のものページングする前に、「GET_Pn」マッパールーチンを使用してセグメント番号を知っておかなければなりません。