にゃごすwiki

techhan/3.4

%第1版第9第刷

4章 システムコールの使用法


 システムコールとは、MSX-DOS の基本的な入出力操作を行う BDOS を、汎用のサブルーチンとしてまとめたもので、あらかじめ決められた手順にしたがってシステムコールを呼び出すことによって MSX のディスクシステムが持つ基本的な機能が簡単に実行できます。
 システムコールの役割には、大きく分けると次の 2 つがあります。1 つは、基本的な機能をあらかじめ用意することによってユーザーの負担を少なくすること。もう 1 つは、すべてのプログラムが基本的な機能を共有することによって、移植性や汎用性を高めることです。システムコールを自由自在に活用することによって、プログラムの開発の期間は短縮され、できあがったプログラムは移植性の高いものとなります。
 システムコールを実行するには、Z80CPU の C レジスタに決められたファンクション番号を入れ、次のアドレスをコールします。

0005H ……………………………………… MSX-DOS
F37DH (&HF37D) ………………………… MSX DISK-BASIC

 たとえば、ファンクション番号が 01FH であり、前準備として A レジスタに 00H をセットすることになっているシステムコールがあるとすると、MSX-DOS の場合、このシステムコールは次のようにして呼び出します。

LD	A, 00H
LD	C, 01FH
CALL	0005H
:

 CALL 文の後には、戻り値 (処理の結果) を受け取ったり、退避していたレジスタを復帰させたりする事後処理が続きます。システムコールは DISK-BASIC から利用することもでき、その場合は F37DH 番地がエントリ・アドレスとなります。この場合には、実際は CLEAR 文で確保した領域にマシンコードを格納し、その先頭アドレスを USR 関数で呼び出してやることになります。


●システムコールの形式

本章では、以下の書式によってシステムコールの使用法を紹介します。

ファンクション : ファンクション番号
          設定 : システムコールを行う前にレジスタやメモリ上にセットすべき値
        戻り値 : システムコールから戻った時にセットされている値

ファンクション:
 ファンクション番号とは、さまざまなシステムコールの種類を判別するためのもので、それぞれのシステムコールに対応する番号が決められています。システムコールを呼び出すときには、このファンクション番号を C レジスタにセットします。

設定:
 また、システムコールの前準備として、レジスタやメモリに必要な値をセットしなければならないことがありますが、これを本章では "設定:" の部分に示します。

戻り値:
 システムコールの結果得られた値は、多くの場合レジスタやメモリの内容にセットされることになります。これを、本章では出力と呼びますが、この出力がどこに、どのようにセットされているかを "戻り値:" の部分に示します。
 ただし、システムコールを使用した後では、この戻り値としてセットされているレジスタやメモリ以外のレジスタの内容が破壊されていることがあります。そこで、システムコールを使用する場合には、そのシステムコールを呼び出す前に、破壊されては困るレジスタの内容を、適当な場所 (スタックなど) に退避させておくようにしてください。

 MSX のシステムコールは表 3.11 に示す 42 個ありますが、本章ではこれらを次の 4 つに分類して説明します。

・周辺機器との I/O
・環境設定
・アブソリュート READ/WRITE (セクタの直接アクセス)
・FCB を用いたファイルアクセス

ファンクション No機能
00Hシステムリセット
01Hコンソールから 1 文字入力 (入力待ちあり、エコーバックあり、コントロールコードチェックあり)
02Hコンソールへ 1 文字出力
03H補助入力装置から 1 文字入力
04H補助出力装置へ 1 文字出力
05Hプリンタへ 1 文字出力
06Hコンソールから 1 文字入力 (入力待ちなし、エコーバックなし、コントロールコードチェックなし) / 1 文字出力
07Hコンソールから 1 文字入力 (入力待ちあり、エコーバックなし、コントロールコードチェックあり)
08Hコンソールから 1 文字入力 (入力待ちあり、エコーバックなし、コントロールコードチェックあり)
09H文字列出力
0AH文字列入力
0BHコンソールからの入力チェック
0CHバージョン番号の獲得
0DHディスクリセット
0EHデフォルト・ドライブの選択
0FHファイルのオープン
10Hファイルのクローズ
11Hワイルドカードに一致する最初のファイルの検索
12Hワイルドカードに一致する 2 番目以降のファイルの検索
13Hファイルの抹消
14Hシーケンシャルなファイルの読み出し
15Hシーケンシャルなファイルの書き込み
16Hファイルの作成
17Hファイル名の変更
18Hログイン・ベクトルの獲得
19Hデフォルト・ドライブ名の獲得
1AHDMA アドレスの設定
1BHディスク情報の獲得
1CH〜20H無効
21Hランダムなファイルの読み出し
22Hランダムなファイルの書き込み
23Hファイルサイズの獲得
24Hランダムレコード・フィールドの設定
25H無効
26Hランダムブロック書き込み
27Hランダムブロック読みだし
28Hランダムなファイルの書き込み (不要部を 00H で埋める)
29H無効
2AH日付の獲得
2BH日付の設定
2CH時刻の獲得
2DH時刻の設定
2EHベリファイ・フラグの設定
2FH論理セクタの読み出し
30H論理セクタの書き込み

表 3.11 システムコール一覧



●使用上の注意
 システムコールのファンクション番号は 00H から 30H までですが、この中には以下に示す 7 個の無効なシステムコールがあります。

  1CH〜20H, 25H, 29H

 これらの無効なシステムコールを呼び出した場合には、A レジスタに 00H がセットされる以外は何も行いません。また、ファンクション 31H 以降のシステムコールは未定義であり、使用した場合の結果は不定 (安全性を保証できない) となりますので注意してください。

リスト 3.3 ユーティリティ・ルーチン

;============================================================
;
;  List 3.3   utility.mac
;
;   these routines are used in other programs
;
;   GETARG,  STOHEX,  PUTHEX,  PUTCHR,   DUMP8B
;
;============================================================
;
	PUBLIC	GETARG			本プログラムリストに含まれる 5 つのユーティリティー・ルーチンは、後述のサンプルプログラム無いで利用される。
	PUBLIC	STOHEX
	PUBLIC	PUTHEX
	PUBLIC	PUTCHR
	PUBLIC	DUMP8B

BDOS	EQU	0005H
DMA	EQU	0008H

;----- DE := ADDRESS OF ARG(A)'S COPY -----

GETARG:	PUSH	AF			デフォルトの DMA 領域 (0080H〜) に格納されてコマンドラインの第 n パラメータ (n は A レジスタで指定) とメモリに取り込み、その先頭アドレスを DE レジスタに返す。
	PUSH	BC
	PUSH	HL

	LD	C,A
	LD	HL,DMA
	LD	B,(HL)
	INC	HL
	INC	B

SKPARG:	DEC	B
	JR	Z,NOARG
SKP1:	LD	A,(HL)
	INC	HL
	CALL	TRMCHK
	JR	NZ,SKP1
SKP2:	LD	A,(HL)
	INC	HL
	CALL	TRMCHK
	JR	Z,SKP2
	DEC	HL
	DEC	C
	JR	NZ,SKPARG

CPYARG:	LD	DE,BUFMEM
CPY1:	LD	A,(HL)
	LD	(DE),A
	INC	HL
	INC	DE
	CALL	TRMCHK
	JR	NZ,CPY1

	DEC	DE
	LD	A,'$'
	LD	(DE),A
	LD	DE,BUFMEM
	JR	EXIT

NOARG:	LD	DE,BUFMEM
	LD	A,'$'
	LD	(DE),A

EXIT:	POP	HL
	POP	BC
	POP	AF
	RET

TRMCHK:	CP	09H
	RET	Z
	CP	0DH
	RET	Z
	CP	' '
	RET	Z
	CP	';'
	RET

;----- HL := hexadecimal value of [DE] -----

STOHEX:	PUSH	AF			DE レジスタで指される 16 進文字列を 2 バイト整数に変換し、HL レジスタに格納する。
	PUSH	DE
	LD	HL,0000H
	CALL	STOH1
	POP	DE
	POP	AF
	RET

STOH1:	LD	A,(DE)
	INC	DE
	SUB	'0'
	RET	C
	CP	10
	JR	C,STOH2
	SUB	'A'-'0'
	RET	C
	CP	6
	RET	NC
	ADD	A,10
STOH2:	ADD	HL,HL
	ADD	HL,HL
	ADD	HL,HL
	ADD	HL,HL
	OR	L
	LD	L,A
	JR	STOH1

;----- print A-reg. in hexadecimal from (00-FF) -----

PUTHEX:	PUSH	AF			A レジスタの内容を 16 進 2 桁で表示する。
	RR	A
	RR	A
	RR	A
	RR	A
	CALL	PUTHX1
	POP	AF
PUTHX1	PUSH	AF
	AND	0FH
	CP	10
	JR	C,PUTHX2
	ADD	A,'A'-10-'0'
PUTHX2:	ADD	A,'0'
	CALL	PUTCHR
	POP	AF
	RET

;----- put character -----

PUTCHR:	PUSH	AF			HL レジスタで示すアドレスから 8 バイト文のメモリの内容を、16 進およびキャラクターコードでダンプする。
	PUSH	BC
	PUSH	DE
	PUSH	HL
	LD	E,A
	LD	C,02H
	CALL	BDOS
	POP	HL
	POP	DE
	POP	BC
	POP	AF
	RET

;----- dumps 8byte of [HL]~[HL+7] in hexa & ascii form -----

DUMP8B:	PUSH	HL
	LD	B,8
DUMP1:	LD	A,(HL)
	INC	HL
	CALL	PUTHEX
	LD	A,' '
	CALL	PUTCHR
	DJNZ	DUMP1
	POP	HL
	LD	B,8
DUMP2:	LD	A,(HL)
	INC	HL
	CP	20H
	JR	C,DUMP3
	CP	7FH
	JR	ZN,DUMP4
DUMP3:	LD	A,'.'
DUMP4:	CALL	PUTCHR
	DJNZ	DUMP2
	LD	A,0DH
	CALL	PUTCHR
	LD	A,0AH
	CALL	PUTCHR
	RET

; ----- work area -----

BUFMEM:	DS	256

	END


 4.1 周辺装置との I/O


 入出力に利用するシステムコールであり、コンソール (画面/キーボード) や AUX (外部入出力)、プリンタなどに関する制御を行います。文字列入力やプリンタ出力などのサブルーチンを作成するのは、多くのプログラムに必要なルーチンワークですが、本節のシステムコールを利用することにより、簡単に汎用的なプログラムを組むことができます。

●コンソール入力

ファンクション : 01H
     設定 : なし
    戻り値 : A レジスタ ← コンソールから入力した 1 文字

 入力がない場合 (キーが押されておらず、入力バッファも空の場合) には、入力待ちを行う。入力された文字はコンソールにエコーバックされる。以下に示すコントロールキャラクタの入力が可能であり、Ctrl-C を受け付けるとプログラムの実行を中断して MSX-DOS のコマンドレベルに戻る。Ctrl-P を受け付けると、以後の入力はすべてプリンタにもエコーバックされるようになり、この状態は、Ctrl-N を受け付けることで解除される。

Ctrl-C システム・リセット
Ctrl-P プリンタへのエコー開始
Ctrl-N プリンタへのエコー停止


●コンソール出力

ファンクション : 02H
          設定 : E レジスタ ← 出力する文字コード
        戻り値 : なし

E レジスタで指定した文字を画面に表示する。Ctrl-S の入力があると表示動作を停止するが、任意のキーを押すことによって再び表示動作を開始する。


●外部入力

ファンクション : 03H
          設定 : なし
        戻り値 : A レジスタ ← AUX デバイスから読み込んだ 1 文字


●外部出力

ファンクション : 04H
          設定 : E レジスタ ← AUX デバイスに出力するキャラクタコード
        戻り値 : なし


●プリンタ出力

ファンクション : 05H
          設定 : E レジスタ ← プリンタに出力するキャラクタコード
        戻り値 : なし


●直接コンソール入出力

ファンクション : 06H
          設定 : E レジスタに 0FFH をセットすれば入力、0FFH 以外をセットすれば出力となる。E レジスタに 0FFH 以外の値がセットされていた場合は、セットされた値をキャラクタコードとみなしてコンソールに出力する。
        戻り値 : E レジスタが 0FFH にセットされていた場合 (入力) には、A レジスタに入力の結果がセットされる。A レジスタにセットされる値は、キーが押されていた場合はそのキャラクターコード、押されていなかった場合は 00H となる。E レジスタが 0FFH 以外にセットされていた場合 (出力) には、戻り値はなし。

コントロールキャラクタのサポート、入力のエコーバックは行わない。


●直接コンソール入力 その 1

ファンクション : 07H
          設定 : なし
        戻り値 : A レジスタ ← コンソールから入力した 1 文字

コントロールキャラクタのサポートは行わない。エコーバックは行わない。


●直接コンソール入力 その 2

ファンクション : 08H
          設定 : なし
        戻り値 : A レジスタ ← コンソールから入力した 1 文字

エコーバックは行わない。コントロールキャラクタはファンクション 01H と同様に処理する。


●文字列出力

ファンクション : 09H
          設定 : DE レジスタ ← メモリ上に用意した、コンソールに出力すべき文字列の先頭アドレス
        戻り値 : なし

文字列の最後には、終端記号として 24H ("$") を付加しておく必要がある。ファンクション 02H (コンソール出力) と同様に Ctrl-S を処理する。


●文字列入力

ファンクション : 0AH
          設定 : 最大入力文字数 (1〜0FFH) をセットしたメモリのアドレスを、DE レジスタにセットする。
        戻り値 : DE レジスタに示されたアドレスに 1 を加えたアドレスにはコンソールから実際に入力された文字数を、DE レジスタに示されたアドレスに 2 を加えたアドレス以降には、コンソールから入力された文字列をセットする。

リターンキーの入力をコンソールからの入力の終端とみなす。ただし、入力文字数が指定の文字数 (DE レジスタで示されるアドレスの内容 = 1〜255) を越える場合には、指定の入力文字数までを入力文字列とみなしてメモリにセットした後、処理を終了する。次の文字からリターンキーまでの入力は無視される。このシステムコールによる文字列入力時には、テンプレートによる編集が可能である。


●コンソールの状態チェック

ファンクション : 0BH
          設定 : なし
        戻り値 : キーボードが押されていた場合には 0FFH を、押されていなかった場合には 00H を、A レジスタにセットする。


 4.2 環境の設定と読み出し


デフォルト・ドライブの変更やシステムのさまざまなデフォルト値のセットなど、MSX システムの環境設定を行うためのシステムコールです。


●システム・リセット

ファンクション : 00H
          設定 : なし
        戻り値 : なし

MSX-DOS 上からコールした場合には、0000H に分岐することによってシステムがリセットされる。MSX DISK-BASIC 上からコールした場合には、MSX DISK-BASIC がウォームスタート (Warm Start) する。つまり、ロードされているプログラムを破壊せずに BASIC のコマンドレベルに戻る。


●バージョン番号の獲得

ファンクション : 0CH
          設定 : なし
        戻り値 : HL レジスタ ← 0022H

このシステムコールは、CP/M における、さまざまな CP/M のバージョン番号を獲得するためのものであるが、MSX-DOS の場合には、一律に 0022H がセットされる。


●ディスクリセット

ファンクション : 0DH
          設定 : なし
        戻り値 : なし

変更されたがまだディスクに書き込まれていないセクタがあれば、それをディスクに書き込んだ後、デフォルト・ドライブを A ドライブにセットし、DMA を 0080H にセットする。


●デフォルト・ドライブの変更

ファンクション : 0EH
          設定 : E レジスタ ← デフォルト・ドライブ番号 (A=00H, B=01H, …)
        戻り値 : なし

システムコールによるディスクアクセスは、特に指定しない限りデフォルト・ドライブ番号で示されるデフォルト・ドライブに対して行われる。ただし、システムコールを呼び出す際に指定された FCB にセットされているドライブ番号が 00H 以外であった場合には、本システムコールによってセットされているデフォルト・ドライブの設定は無視される。


●ログイン・ベクトルの獲得

ファンクション : 18H
          設定 : なし
        戻り値 : HL レジスタ ← オンライン・ドライブ情報

オンライン・ドライブとは、MSX に正常な状態で接続され、かつその電源が投入されているドライブを指す。このシステムコールを実行すると各ドライブがオンラインであるか否かを調べ、その結果を図 3.22 のように HL レジスタに入れて返す。それぞれのビットが "1" ならば対応するドライブはオンラインであり、"0" ならばそうでないことを示す。

レジスタ名	H	L
ビット番号	7 6 5 4 3 2 1 0	7 6 5 4 3 2 1 0
ドライブ名	MSX-DOS では意味を持たない	H: G: F: E: D: C: B: A:
オンライン/オフライン	各ビットについて、オンなら 1 が、オフなら 0 がセットされる。

図3.22 ログイン・ベクトル


●デフォルト・ドライブ番号の獲得

ファンクション : 19H
          設定 : なし
        戻り値 : A レジスタ ← デフォルト・ドライブ番号 (A=00H, B=01H, …)

●転送先アドレスの設定

ファンクション : 1AH
          設定 : DE レジスタ ← 設定する転送先アドレス (DMA アドレス)
        戻り値 : なし

DMA アドレスは、システムリセット時に 0080H に初期化されるが、このファンクション 1AH のシステムコールを用いることによって、任意のアドレスに設定し直すことができる。


●ディスク情報の獲得

ファンクション : 1BH
          設定 : E レジスタ ← 目的のディスクが入っているドライブ番号
                 (デフォルト・ドライブ=00H, A=01H, B=02H,…)
        戻り値 : A レジスタ ← 1 クラスタあたりの論理セクタ数
                 (E レジスタの設定が不適当だった場合 FFH)
                 BC レジスタ ← 論理セクタのサイズ
                 DE レジスタ ← クラスタの総数
                 HL レジスタ ← 未使用クラスタの総数
                 IX レジスタ ← DPB の先頭アドレス
                 IY レジスタ ← メモリ上の FAT の先頭アドレス

指定ドライブのディスクの情報を得るシステムコールである。ドライブ番号に 00H を指定するとデフォルト・ドライブの指定になる。それ以外は、A ドライブなら 01H、B ドライブなら 02H、…を指定する。

このシステムコールは MSX-DOS 用に変更されたもので、CP/M との互換性はない。


●日付の獲得

ファンクション : 2AH
          設定 : なし
        戻り値 : HL レジスタ ← 年
                 D レジスタ  ← 月
                 E レジスタ  ← 日
                 A レジスタ  ← 曜日

このシステムコールは MSX-DOS 用に増設されたもので、CP/M との互換性はない。


●日付の設定

ファンクション : 2BH
          設定 : HL レジスタ ← 年
                 D レジスタ  ← 月
                 E レジスタ  ← 日
        戻り値 : 設定が成功したかどうかを A レジスタにセットする。成功なら 00H が、失敗なら 0FFH がセットされる。

このシステムコールは MSX-DOS 用に増設されたもので、CP/M との互換性はない。


●時刻の獲得

ファンクション : 2CH
          設定 : なし
        戻り値 : H レジスタ ← 年
                 L レジスタ ← 分
                 D レジスタ ← 秒
                 E レジスタ ← 1/100 秒

このシステムコールは MSX-DOS 用に増設されたもので、CP/M との互換性はない。


●時刻の設定

ファンクション : 2DH
          設定 : H レジスタ ← 年
                 L レジスタ ← 分
                 D レジスタ ← 秒
                 E レジスタ ← 1/100 秒
        戻り値 : 成功なら 00H が、失敗なら 0FFH が A レジスタにセットされる。

このシステムコールは MSX-DOS 用に増設されたもので、CP/M との互換性はない。


●ベリファイ・フラグの設定

ファンクション : 2EH
          設定 : ベリファイ・フラグをリセットする時には、E レジスタ ← 00H
                 ベリファイ・フラグをセットする時には、E レジスタ ← 00H 以外の値
        戻り値 : なし

ベリファイ・フラグを設定すると、以後のディスクに対する書き込みがベリファイ付きで行われるようになる。つまり、書き込んだ後でその内容をディスクから読み出して、書き込むべき内容と比較して等しいかどうかをチェックする。

このシステムコールは MSX-DOS 用に増設されたもので、CP/M との互換性はない。


 4.3 アブソリュート READ/WRITE (セクタの直接アクセス)


MSX では、"論理セクタ" と呼ばれるものを最小の単位としてディスクを管理しています。論理セクタとは、ディスクの物理的なセクタと無関係に定められたセクタであり、第 0 論理セクタから最大論理セクタ (ディスクの種類によってその数は異なる) までの一連の番号が付けられています。

この論理セクタのおかげで、MSX-DOS や MSX DISK-BASIC のユーザーは、ディスクのメディアタイプによって異なる 1 トラックごとの物理セクタ数の違いを考慮せずにディスクをアクセスすることが可能となっています。実際には FCB (ファイル・コントロール・ブロック) を介するシステムコールを用いることで、論理セクタさえも意識しない手軽でキメ細かなファイルの取り扱いができますから、この論理セクタを実際に使用する必要はありません。しかし、論理セクタを用いたアクセスも用途によっては必要であり、MSX-DOS および MSX DISK-BASIC では、論理セクタのアクセスするシステムコールも用意しています。

本節では、この論理セクタのアクセスを行うシステムコールを説明します。


●論理セクタを用いた読み出し

ファンクション : 2FH
          設定 : 読み出しを開始する論理セクタの番号 (複数の場合はその先頭の論理セクタ番号) を DE レジスタにセットする。読み出す論理セクタの個数を H レジスタに、読み出すディスクのドライブ番号  (A=00H, B=01H, …) を L レジスタにセットする。
        戻り値 : 読み込んだ内容を DMA バッファにセットする。

指定ドライブの指定論理セクタから、指定された個数の (連続した) 論理セクタを読み出し、その内容を DMA 以降のメモリに格納する。その際、格納されるメモリ領域は、ファンクション 1AH (転送先アドレスの設定) によって十分な量 (読み出す論理セクタの個数×論理セクタのサイズバイト以上) を確保しておく必要がある。

このシステムコールは MSX-DOS 用に増設されたもので、CP/M との互換性はない。


●論理セクタを用いた書き込み

ファンクション : 30H
          設定 : 書き込む内容を DMA で示されるアドレス以降のメモリ領域にセットする。書き込みを始める論理セクタの番号を、DE レジスタにセットする。書き込む論理セクタの個数を H レジスタにセットする。書き込むドライブ番号 (A=00H, B=01H, …) を L レジスタにセットする。
        戻り値 : なし

このシステムコールは MSX-DOS 用に増設されたもので、CP/M との互換性はない。

リスト 3.4 クラスタ・ダンプ

;============================================================
;
;   List 3.4    cluster dump
;
;               this program must link List 3.3
;
;============================================================
;
	EXTRN	GETARG		コマンドラインで指定した任意のクラスタの先頭の 128 バイトをダンプする。
	EXTRN	STOHEX
	EXTRN	PUTHEX
	EXTRN	PUTCHR
	EXTRN	DUMP8B

BDOS	EQU	0005H

;----- program start -----

	LD	A,1
	CALL	GETARG		;[DE] := 1st argument of commnad line
	CALL	STOHEX		;HL := evaluate [DE] as hexadecimal
				;      this is target cluster No.
	PUSH	HL		
	LD	E,00H		;request the default drive
	LD	C,1BH		;get disk information
	CALL	BDOS
	POP	HL
	CP	0FFH		;fail ?
	JR	NZ,L2		;if not fail, A := sector/cluster and goto L2

	LD	DE,ERMSG1	;[DE] := 'Cannot get Disk information'
	LD	C,09H		;string output function
	CALL	BDOS
	RET			;error return

L2:	LD	E,(IX+12)	;DE := 1st sector of data area
	LD	E,(IX+13)
	DEC	HL
	DEC	HL		;HL := cluster Np. -2
	LD	B,H		
	LD	C.L		;BC := cluster No. -2
LOOP:	DEC	A		;Count N times
	JR	Z,RESULT
	ADD	HL,BC
	JR	LOOP
RESULT:	ADD	HL,DE		;HL := sector of target cluster
	PUSH	HL		;save target sector
	LD	DE,NEWDMA	;we reserved 1024 bytes area for DMA
	LD	C,1AH		;set DMA address function
	CALL	BDOS
	LD	C,19H
	CALL	BDOS		;default drive?
	LD	L,A
	POP	DE		;DE := target sector
	LD	H,1		;H := 1 (read 1 secter onlu)
	LD	C,2FH		;abusolute read function
	CALL	BDOS		;data will be set into DMA

DUMP:	LD	HL,NEWDMA	;HL := DMA address
	LD	DE,0000H	;DE := relative address from cluster top
	LD	B,16		;dump 16 lines
DLOOP:	PUSH	BC
	LD	A,D
	CALL	PUTHEX
	LD	A,E
	CALL	PUTHEX
	LD	A,' '
	CALL	PUTCHR
	PUSH	HL
	LD	HL,8
	ADD	HL,DE
	EX	DE,HL		;DE := DE+8
	POP	HL
	CALL	DUMP8B		;8 bytes dump subroutin (in another file)
	POP	BC
	DJNZ	DLOOP		;all work habe done.
	RET

;----- work area -----

NEWDMA:	DS	1024		;Private DMA area
ADRS:	DS	2

ERMSG1:	DB	'Cannot get Disk information.$'
ERMSG2:	DB	'Cannot read that cluster.$'

	END


 4.4 FCB を用いたファイルアクセス


前節で述べた論理セクタを直接読み書きをするタイプのシステムコールでは、ファイル単位のアクセスが非常に困難であり、ファイルを基本としたディスクアクセスを行うためには、FCB を介するシステムコールを使用する必要があります。

FCB を用いるシステムコールには、大きく分けて次の 3 つの種類が存在します。1 つはシーケンシャル・ファイルアクセスであり、もう 1 つはランダム・ファイルアクセスです。この 2 つは CP/M との互換性を保つために用意されたシステムコールであり、MSX-DOS が持っている力を十分に引き出すものとはいえません。それに対して、3 つ目のランダム・ブロック・アクセスは MSX システムの独自のシステムコールになっています。このランダム・ブロック・アクセスは、次のような特徴を持っています。

・レコードサイズを任意に設定できる
・複数のレコードをランダムにアクセスできる
・ファイルの大きさをバイト単位で管理できる

本節では、このランダム・ブロック・アクセスを含む、FCB を利用したファイルアクセスのためのシステムコールを説明します。


●ファイルのオープン

ファンクション : 0FH
          設定 : DE レジスタ ← オープンされていない FCB の先頭アドレス
        戻り値 : ファイルのオープンが成功すれば 00H を、失敗すれば 0FFH を A レジスタにセットする。ファイルのオープンが成功した場合には、指定された FCB の各フィールドの設定が行われる。

ドライブ番号に 00H をセットすると、ファンクション 0EH (デフォルト・ドライブの設定) によって設定されているデフォルト・ドライブによる指定が有効になる。デフォルト・ドライブ以外のファイルをオープンする場合には、A ドライブなら 01H、B ドライブなら 02H、…のように指定する。

このシステムコールを利用してファイルをオープンすると、ディスク上のディレクトリ領域の情報から、レコードサイズ、カレントブロック、カレントレコード、ランダムレコードの各フィールドを除く、すべての FCB のフィールドが設定される。設定されてないフィールドについては、本システムコール実行後にユーザーが必要に応じて設定する必要がある。FCB の各フィールドがセットされたこの状態が、FCB を介するシステムコールを利用するユーザーにとって真に "ファイルがオープンされた状態" だり、以下に説明する、FCB を用いたファイルアクセスを行うシステムコールが利用できるようになる。


●ファイルのクローズ

ファンクション : 10H
          設定 : DE レジスタ ← オープンされた FCB の先頭アドレス
        戻り値 : ファイルのクローズが成功すれば 00H を、失敗すれば 0FFH を A レジスタにセットする。さらに FCB のドライブ番号を設定する。

現在のメモリ上の FCB の内容をディスク上の該当するディレクトリ・エリアに書き込むことによって、ファイルの更新に関する整合性を保つ。ファイルに対して読み込みしか行っていない場合には、このシステムコールを使ってファイルをクローズする必要はない。


●ファイルの検索 その 1

ファンクション : 11H
          設定 : DE レジスタ ← オープンされていない FCB の先頭アドレス
        戻り値 : ファイルが見つかった場合には 00H を、見つからなかった場合は 0FFH を A レジスタにセットする。見つかった場合にはさらに、DMA で示される領域にそのファイルのディスク上のディレクトリ・エントリ (32 バイト) をセットする。また FCB のドライブ番号もセットする。

ファイル名にはワイルドカード・キャラクタを使用することができる。たとえば、ワイルドカード・キャラクタを使って "????????.c" という指定を行うと、「先頭の文字列はなんてもよいが、末尾に ".c" が付くファイル名」を検索し、最初にマッチしたファイルのディレクトリ情報を DMA 以降に書き込む。マッチするすべてのファイルを検索したい場合や、マッチするファイルが 1 個だけかどうかを知りたい場合には、次に紹介するファンクション 12H を利用する必要がある。


●ファイルの検索 その 2

ファンクション : 12H
          設定 : なし
        戻り値 : 見つかった場合には 00H を、見つからなかった場合には 0FFH を A レジスタにセットする。見つかった場合にはさらに、DMA で示される領域にそのファイルのディレクトリ・エントリ (32 バイト) をセットする。

このシステムコールは、ファンクション 11H のワイルドカード・キャラクタによるファイル名の指定とマッチした複数のファイルを検索する時に使用するもので単独で使用しても意味がない。

このシステムコールを使用すると、ファンクション 11H によってマッチした複数のファイルのディレクトリ情報を、1 つずつ順番に得ていくことができる。


●ファイルの抹消

ファンクション : 13H
          設定 : DE レジスタ ← オープンされた FCB の先頭アドレス
        戻り値 : 抹消が成功した場合には 00H を、失敗した場合には 0FFH を A レジスタにセットする

ファイル名にワイルドカード・キャラクタを使用して、複数のファイルを一度に抹消することができる。


●シーケンシャルな読み出し

ファンクション : 14H
          設定 : DE レジスタ ← オープンされた FCB の先頭アドレス
                 FCB のカレントブロック ← 読み出しを開始するブロック
                 FCB のカレントレコード ← 読み出しを開始するレコード
        戻り値 : 読み込みが成功すれば 00H を、失敗すれば 01H を A レジスタにセットする。成功した場合には、読み込んだ 1 レコードを DMA で示される領域にセットする

FCB のカレントブロックとカレントレコードは、読み込み後に自動的に更新される。つまり、連続して読み込む場合には、カレントブロックとカレントレコードをセットする必要はない。読み込むレコードサイズは 128 バイト固定。


●シーケンシャルな書き込み

ファンクション : 15H
          設定 : DE レジスタ ← オープンされた FCB の先頭アドレス
                 FCB のカレントブロック ← 書き込みを開始するブロック
                 FCB のカレントレコード ← 書き込みを開始するレコード
                 DMA 以降の 128 バイト  ← 書き込むデータ
        戻り値 : 書き込みが成功すれば 00H を、失敗すれば 01H を A レジスタにセットする。

FCB のカレントブロックとカレントレコードは、書き込み後に自動的に更新される。


●ファイルの作成

ファンクション : 16H
          設定 : DE レジスタ ← オープンされていない FCB の先頭アドレス
        戻り値 : ファイルの作成が成功すれば 00H を、失敗すれば 0FFH を A レジスタにセットする

FCB 中のレコードサイズ、カレントブロック、カレントレコード、ランダムレコードの各フィールドについては、これらを本システムコールの実行後に必要に応じてセットしておく必要がある。


●ファイル名の変更

ファンクション : 17H
          設定 : 旧ファイル名に対応する FCB の 18 バイト目 (FCB のファイルサイズ・フィールドの 2 バイト目=旧ファイル名の 16 バイト後方) からの 11 バイトに (18〜28 バイト) 新ファイル名をセットし、その FCB アドレスを DE レジスタにセットする
        戻り値 : ファイル名の変更が成功すれば 00H を、失敗すれば 0FFH を A レジスタにセットする

新旧ファイル名に、ワイルドカード・キャラクタ "?" を使用できる。たとえば、旧ファイル名に "????????.o" を、新ファイル名に "????????.obj" を指定すれば、".o" という拡張子を持つすべてのファイルについて、拡張子を ".obj" に変更することができる。


●ランダムな読み出し

ファンクション : 21H
          設定 : DE レジスタ ← オープンされた FCB のアドレス
                 FCB のランダムレコード ← 読み出すレコード
        戻り値 : 読み込みが成功すれば 00H を、失敗すれば 01H を A レジスタにセットする。読み込みが成功した場合には、DMA で示される領域に読み込んだ 1 レコードの内容をセットする

レコードの大きさは 128 バイト固定長。


●ランダムな書き込み

ファンクション : 22H
          設定 : DE レジスタ ← オープンされた FCB の先頭アドレス
                 FCB のランダムレコード ← 書き込むレコード
                 DMA 以降の 128 バイト ← 書き込むデータ
        戻り値 : 書き込みが成功すれば 00H を、失敗すれば 01H を A レジスタにセットする

レコードの大きさは 128 バイト固定長。


●ファイルサイズの獲得

ファンクション : 23H
          設定 : DE レジスタ ← オープンされた FCB の先頭アドレス
        戻り値 : ファイルサイズの獲得が成功すれば 00H を、失敗すれば 0FFH を A レジスタにセットする。獲得が成功すれば、FCB のランダムレコード・フィールドに、指定されたファイルの 128 バイト単位のサイズをセットする。

ファイルのサイズは 128 バイト単位で計算されます。つまり、200 バイトであれば 2 が、257 バイトであれば 3 がセットされます。


●ランダムレコード・フィールドの設定

ファンクション : 24H
          設定 : DE レジスタ ← オープンされた FCB の先頭アドレス
                 FCB のカレントブロック ← 目的のブロック
                 FCB のカレントレコード ← 目的のレコード
        戻り値 : ランダムレコード・フィールドに、指定された FCB のカレントブロック・フィールドとカレントレコード・フィールドから計算したカレントレコード・ポジションをセットする。


●ランダムな書き込み その 2

ファンクション : 26H
          設定 : DE レジスタ ← オープンされた FCB の先頭アドレス
                 FCB のレコードサイズ ← 書き込むレコードサイズ
                 FCB のランダムレコード ← 書き込みを開始するレコード
                 HL ← 書き込むレコード数
                 DMA 以降のメモリ領域 ← 書き込むデータ
        戻り値 : データの書き込みに成功すれば 00H、失敗すれば 01H を A レジスタにセットする

書き込みが終わると、ランダムレコード・フィールドの値が自動的に更新されて、最後に書き込んだレコードの次のレコードを指す。ひとつのレコードの大きさは FCB のレコードサイズ・フィールドによって 1 バイトから 65535 バイトまで任意に設定できる。

このシステムコールは MSX-DOS 用に増設されたもので、CP/M との互換性はない。


●ランダムな読み出し その 2 (ランダム・ブロック・アクセス)

ファンクション : 27H
          設定 : DE レジスタ ← オープンされた FCB の先頭アドレス
                 FCB のレコードサイズ ← 読み出すレコードサイズ
                 FCB のランダムレコード ← 読み出しを開始するレコード
                 HL ← 読み出すレコード数
        戻り値 : データの読み出しに成功すれば 00H、失敗すれば 01H を A レジスタにセットする。さらに HL レジスタに、実際に読み込んだレコードの個数をセットする。

読み込みが終わると、ランダムレコード・フィールドの値が自動的に更新される。このシステムコール実行後、HL レジスタには実際に読み込んだレコードの総数がセットされる。つまり、指定した数のレコードを読み終わる前にファイルの終わりに達した場合には、それまでに読み込んだ実際のレコード数が HL レジスタに入ることになる。

このシステムコールは MSX-DOS 用に増設されたもので、CP/M との互換性はない。


●ランダムな書き込み その 3

ファンクション : 28H
          設定 : DE レジスタ ← オープンされた FCB の先頭アドレス
                 FCB のランダムレコード ← 書き込むレコード
                 DMA 以降の 128 バイト ← 書き込むデータ
        戻り値 : 書き込みが成功すれば 00H を、失敗すれば 01H を A レジスタにセットします。

レコードの大きさは 128 バイト固定長。

本システムコールでは、書き込みによってファイルが大きくなる場合、追加されたレコードを 00H で埋めて、指定されたレコードに書き込みを行う。この点を除けばファンクション 22H (ランダムな書き込み) と同じである。


リスト 3.5 ファイル・ダンプ

;============================================================
;
;   List 3.5     file dump
;
;                this program must link List 3.3
;
;============================================================
;
	EXTRN	GETARG		コマンドラインで指定した任意ファイルをダンプする。
	EXTRN	STOHEX
	EXTRN	PUTCHR
	EXTRN	PUTHEX
	EXTRN	DUMP8B

BDOS	EQU	0005H		コマンドラインの第 1 パラメータとして指定したファイル名は、デフォルト  FCB エリア (005CH〜) に格納される。
FCB	EQU	005CH

;----- program start -----

	LD	DE,FCB		;DE := default FCB address
	LD	C,0FH		;open file function
	CALL	BDOS
	OR	A		;success ?
	JR	Z,READ		if so, goto READ

	LD	DE,ERMSG1	;[DE] := 'Cannot open that file'
	LD	C,09H		;string output function
	CALL	BDOS
	RET			;error return

READ:	LD	A,2
	CALL	GETARG		;get 2nd argument of command line
	CALL	STOHEX		;HL := value of the argument
	LD	(ADRS),HL	;set address counter

	LD	DE,NEWDMA
	LD	C,1AH		;set DMA address function
	CALL	BDOS

	LD	HL,8
	LD	(FCB+14),HL	;record size := 8

	LD	HL,0
	LD	(FCB+33),HL
	LD	(FCB+35),HL	;random record := 0

RD1:	LD	HL,NEWDMA	;clear DMA area
	LD	B,8
RD2:	LD	(HL),' '
	INC	HL
	DJNZ	RD2

	LD	HL,1		;read 1 record
	LD	DE,FCB
	LD	C,27H		;random block read function
	CALL	BDOS
	OR	A		;success ?
	JR	Z,DUMP		;if so, goto DUMP

	LD	DE,ERMSG2	;[DE] := 'Ok.'
	LD	C,09H		;string output function
	CALL	BDOS
	RET

DUMP:	LD	HL,(ADRS)
	LD	A,H
	CALL	PUTHEX
	LD	A,L
	CALL	PUTHEX
	LD	A,' '
	CALL	PUTCHR
	LD	DE,8
	ADD	HL,DE
	LD	(ADRS),HL

	LD	HL,NEWDMA
	CALL	DUMP8B		;dump 8 byte

	JR	RD1

;----- work area -----

ADRS:	DS	2
NEWDMA:	DS	8

;----- error message -----

ERMSG1:	DB	'Cannot open that file.$'
ERMSG2:	DB	'Ok.$'

	END