MSX Datapack wiki化計画

3章 MSX-DOSの構造

 3.1 MSX-DOSの起動

 MSX-DOSは以下の手順で起動します。

1.MSXをリセットすると、始めにすべてのスロットを調べ、調べたスロットの先頭に「41H、42H」の2バイトが書き込まれていれば、そのスロットには何らかのROMプログラムが接続されていると判断し、ROMのヘッダ部分にアドレスを設定されたINIT(初期化)ルーチンを実行します。ディスクインターフェイスROMのINITルーチンの場合は、まずそのインターフェイスに接続されているドライブのために、ワークエリアを確保します。「第2部1章 ブートシーケンス」を参照して下さい。
2.すべてのスロットを調べ終わったら、【H.STKE(FEDAH)】を参照します。このアドレスの内容がC9Hでなければ、Disk BASICの環境を設定し、H.STKEにジャンプします。
3.もし、上記の調査で、H.STKEの内容がC9Hであれば、TEXTエントリを持つカートリッジを各スロットで捜し、あればDisk BASICの環境を設定した後、そのカートリッジのBASICプログラムを実行します。
4.ブートセクタ(論理セクタ0)の内容をC000H〜C0FFHへ転送します。このとき、「DRIVE NOT READY」か「READ ERROR」が発生したり、転送されたセクタの先頭が「FBH」か「E9H」ではなかったときは、Disk BASICが起動します。
5.C01EHに転送されたルーチンがCYフラグをリセットした状態でコールされます。通常は、このアドレスには「RET NC」のコードが書き込まれているため、何も実行しないでリターンします。
このとき、スロットの状態は以下のようになっています。しかし、BIOSコールやファンクションコールによって、ページ1をRAMに切り換えることはできないので、ユーザープログラムの起動には適当ではありません。
 
ページ内容
0BIOS ROM
1DISK ROM
2RAM
3RAM
 
6.RAMの容量を調べます。このときRAMの内容は壊れません。もし、RAMが64KB未満だったら、Disk BASICが起動します。
7.MSX-DOSの環境を初期化した後、CYフラグをセットした状態でC01EHがコールされます。通常は、このアドレスには「RET NC」の後ろに通常のブートプログラムが書き込まれています。この部分に任意の機械語プログラムのブートプログラムを書き込んでおけば、そのプログラムが自動的に起動します。
このとき、スロットの状態は以下のようになっています。
 
ページ内容
0RAM
1DISK ROM
2RAM
3RAM
 
また、レジスタには、以下の情報が入っています。
 
レジスタ内容
A 0ならばPOWER ON直後を示す
DEこの内容をコールすると、ページ1のFDD ROMがRAMに切り替わる
HLディスクエラー処理ルーチンへのポインタへのポインタ(「第2部 7.9.3 エラー処理」参照)
 
標準のブートプログラムは、MSXDOS.SYSを100Hからのアドレスにロードし、100Hにジャンプします。MSXDOS.SYSがないときには、Disk BASICを起動します。
8.MSXDOS.SYSは自分自身を高位アドレスに転送した後、COMMAND.COMを100Hからのアドレスにロードし、その先頭へジャンプします。COMMAND.COMがないときは、「INSERT A DISKETTE」のメッセージが表示されて、正しいディスケットがドライブにセットされるのを待ちます。
9.COMMAND.COMも自分自身をMSXDOS.SYSのすぐ下の高位アドレスに転送し、COMMAND.COM自身が実行を始めます。
10.MSX-DOSが最初に起動したとき、「AUTOEXEC.BAT」という名前のファイルがあれば、それをバッチファイルとして実行します。MSX-DOSが起動せず、Disk BASICが立ち上がったときは、「AUTOEXEC.BAS」という名前のBASICプログラムがあれば、それを実行します。

 3.2 プログラムの実行から終了まで

 MSX-DOSは外部コマンドの形でコマンドを追加・変更できる拡張性の高いオペレーティングシステムです。ユーザーの作ったプログラムも外部コマンドとして簡単に実行することができます。
 外部コマンドは、アセンブラやコンパイラなどを利用して作られた、「COM」という拡張子のついたファイルです。コマンドプロセッサは指定されたコマンド名+「COM」という名前のファイルをディスク上に見つけると、それをメモリ上にロードして実行します。このファイルの内容はメモリの100H番地からロードして、そのまま実行できるような形式になった機械語のプログラムです。

3.2.1 プログラムの起動

 MSX-DOSの基本的な動作は、コマンド行を入力し実行させる、という処理の繰り返しです。この時、コマンド行の入力からコマンドの解釈実行までのユーザーインターフェイスを受け持つのがコマンドプロセッサである「COMMAND.COM」というプログラムです。入力したコマンドが外部コマンドのとき、コマンドプロセッサは、それを以下のようにして実行に移します。

  1. コマンド行のパラメータについて、その長さをシステムスクラッチエリアの80H番地に、実際の文字列を81H番地以降に格納する。さらに最初の2つのパラメータをファイル名とみなし、それをFBCの形式でそれぞれシステムスクラッチエリアの5CH番地および6CH番地以降に格納する。
  2. 外部コマンドを100H番地以降に読み込む。
  3. 100H番地にジャンプする。

MSX-DOSでは、システムとプログラムとの間でデータを受け渡すために、メモリの0〜FFH番地を使っています。これをシステムスクラッチエリアといいます。
 コマンドプロセッサはまず、コマンド行のパラメータを渡すために、システムスクラッチエリアの設定を行います。外部コマンドは、システムスクラッチエリアを参照することにより、渡されたパラメータを知ることができます。このために2つの方法が使われます。

  1. 5CH番地または6CH番地はそのままファイルのアクセスに使える形式になっているので、ファイル名をパラメータとするようなプログラムではこの方法が便利です。ただし、この方法では両FCB(5CH、6CH)の先頭アドレスが16バイトしか離れていないので、完全なFCBとして使用できるのはどちらか片方だけになります。FCBについては、「3.3.2 ファイルの入出力」の項で詳しく説明します。
  2. 80H番地には全パラメータがそのまま入っているので、ファイル名以外をパラメータとしたり、3つ以上のファイル名を扱うようなプログラムではこの方法を使用します。


図3.8 システムスクラッチエリア

 図3.8はシステムスクラッチエリアの内容です。これは、

A>test yyy.dat a:zzzz.* b:*.www

というコマンドを入力して、外部コマンド「test」を実行したときの例です。80H番地以降にはこのコマンドに渡すパラメータとその長さが入っているのがわかります。また、前述したように、5CH番地と6CH番地に最初の2つのパラメータが形式を整えられて入っています。先頭1バイトには、ドライブが無指定のときは「0」、A:であれば「1」、B:なら「2」・・・という値が入ります。また、小文字は大文字に変換され、「*」は複数の「?」に展開されます。システムスクラッチエリアの5CH〜FFH番地は、このようにパラメータを渡すために使いますが、プログラムが実行を開始した後は、ワークエリアとして使うこともできます。
 図3.9はプログラムが実行を開始したときのメモリマップです。00H〜FFH番地はシステムスクラッチエリアで、プログラムはその直後の100H番地からロードされます。100H番地から始まり、06H〜07H番地の内容で示されているアドレスの1バイト手前までの領域は、TPA(Transient Program Area=一時プログラム領域)と呼ばれ、プログラムで自由に利用してよい領域です。
 システムスクラッチエリアの先頭の方には、いくつかのジャンプ命令が置かれています(図3.8参照)。プログラムはこれらの決められたアドレスをコールすることで、MSXシステムの持つ各種の機能が実行できます。00H番地にあるのがウォームスタートのためのエントリ、05H番地にあるのが4章で解説するファンクションコールのためのエントリです。この2つはMSX-DOSが持っている機能をプログラムから利用するために用意されています。またRDSLT、WRSLT、CALSLT、ENASLT、CALLFおよびINTRPTは、MSX BIOSにある同名のファンクションと同じ機能を持っています。INTRPTは割り込み時に使われますが、その他のエントリはMSX BIOSと同様に利用できます。MSX-DOS自身もこれらのエントリを使用しているので、0H〜5BH番地(の部分)を破壊するとシステムダウンにつながります。


図3.9 外部コマンド実行時のメモリマップ

 05H番地はファンクションコールのためのジャンプ命令です。06H〜07H番地はジャンプ先のアドレスで、これがTPAの上限を示しているということは、ジャンプ先がMSXDOS.SYSの先頭になっているということです。つまり、05H〜07H番地はジャンプ命令であると同時にTPAの上限を示すという2重の働きを持っています。

3.2.2 プログラムの終了

 プログラムは実行が終わると、次の3つの方法のいずれかで、MSX-DOSのコマンドレベルに戻ることができます。

  1. スタックポインタを変更していない場合、「RET」を実行する。
  2. 後述のファンクションコールを使って、「システムリセット」を行う。
  3. 00H番地(ウォームスタートのためのエントリ)にジャンプする。

 コマンドプロセッサはスタックの先頭に0を置いて、外部プログラムを呼び出すので、1.は2.と同じ結果になります。ただし、ソフトウェアデバッガ(MSX-SBUGなど)を使って、デバッグ作業を行うときは、スタックがこのように設定されていないことがあるので、注意が必要です。

 コマンドプロセッサの実体は「COMMAND.COM」というプログラムで、TPAの内側にあります。コマンドプロセッサが必要なのは、プログラムの実行が終わって、次のコマンドを入力するときで、プログラムの実行中は、コマンドプロセッサの機能は必要ないので、プログラムでコマンドプロセッサがロードされている領域を使用(破壊)してもかまわないわけです。このため、ウォームスタートの際には、コマンドプロセッサがプログラムによって壊されている可能性があるため、いったんMSXDOS.SYSが制御を受け取ります。MSXDOS.SYSは、チェックサムを用いてCOMMAND.COMが壊されているかどうかを調べてから、コマンドプロセッサに制御を渡します。COMMAND.COMが破壊されていたときは、再びディスクからロードしますが、破壊されていないときは、ディスクからのロードは行われないので、コマンドレベルに戻るのが早くなります。
 こうして、再びコマンドプロセッサが次のコマンド行の入力待ちになります。

 3.3 MSX-DOSの入出力

3.3.1 周辺装置との入出力

 MSX-DOSの持つ機能は、ディスク上のファイルを扱うものだけではありません。それだけでは、オペレーティングシステムの持つ重要な機能の1つであるユーザーインターフェイスの機能が限られてしまいます。そのため、MSX-DOSでは、コンソールスクリーン、キーボードやプリンタなどの周辺装置の制御を行う機能を豊富に用意しています。これらの装置は、基本的には1文字単位で入出力を行うものですが、コンソールに関しては、各種のオプションを持った複数の入出力機能に加えて、行入力や行出力の機能も用意しています。

3.2.2 ファイルの入出力

 ファイルの入出力(アクセス)の特徴は、データの位置をディスク上のアドレスのような具体的数値で表現するのではなく、「名前」を用いて指定できるという点にあります。MSX-DOSはディスク上に書かれたディレクトリなどの情報を元に、ファイルのデータがどこにあるかということを常に把握しています。目的のデータがディスク上のどんなアドレスに存在しているか、ということはすべてMSX-DOSにまかせ、プログラムはただファイル名を指示するだけで、ファイルのアクセスができます。
1.FCB(ファイルコントロールブロック)
 どのファイルをアクセスするか、ということを指示するために、MSX-DOSではFCB(ファイルコントロールブロック)を使います。
 FCBは、ファイルを扱う際必要となる情報を格納しておく領域で、1つのファイルを扱うごとに1つ、図3.10や図3.11のようなメモリエリアをプログラム上で用意します。
 FCBはプログラムで許された範囲でメモリ上のどこに置いても構いませんが、MSX-DOSの機能を活かすため、しばしば5CH番地が使われます。


図3.10 FCBとして使うメモリエリア(CP/M互換)


図3.11 FCBとして使うメモリエリア(MSX-DOS互換)

2.ファイルのオープン
 FCBを用いてファイルの入出力を行うには、最初にファイルを「オープン」する手続きが必要です。「オープン」とは、ファイル名フィールドだけが設定された不完全なFCBを、ディスク上に記された情報を用いて、完全なFCBに変換することを意味します。図3.12は「オープンされていないFCB」の違いを表しています。

図3.12 FCBオープンの前後

3.ファイルのクローズ
 ファイルをオープンして書き込みを行ったとき、それに伴って、ファイルサイズを始めとするFCBの各フィールドの内容が変更されます。この更新されたFCBの情報をディレクトリ領域に戻しておかないと、次回ファイルをアクセスする際に、ディレクトリの情報と実際のファイルの内容が異なってしまいます。更新されたFCBの情報をディレクトリに戻すというこの操作が「ファイルのクローズ」です。

4.DTA(ディスク転送アドレス)
 ディスクの入出力では、基本的には文字単位の入出力である周辺装置と違って、一度に複数のバイトを読み書きします。そのため、ディスクの入出力には「バッファ」が必要になります。MSX-DOSでは、このバッファとして使用されるメモリ領域の先頭アドレスをDTA(Disk Transfer Address=ディスク転送先アドレス)と呼びます。
 ディスクの入出力では、DTAを先頭とするメモリ領域をバッファとして使用します。DTAの値は、初期設定では0080Hですが、任意のアドレスに設定し直すことができます。

5.レコード
 ファイルの大きさは、ディスク容量の許す限りいくらでも(最大1Gバイト)大きくすることができるので、メモリに全体が読み込めることは期待できません。そのため、ファイルの入出力では、ファイルをレコードと呼ばれる適当な大きさのデータ単位に分割して、レコード単位で読み書きする方法がとられています。


図3.13 ファイルとレコード

 したがって、ファイルのアクセスを行うためには、さらにどのレコードをアクセスするかという指示が必要になります。このレコードの指示方法はファンクションコールの種類により、大きく2つのグループに分けられます。1つのグループはCP/Mとの互換性を保つために用意された入出力で、もう1つのグループはMSX-DOSの独自のランダムブロック入出力です。この2つは、FCBの使用方法が異なっているので、同じFCBに対して同時に使用することはできません。

6.CP/M互換のレコードアクセス
 CP/Mとの互換性を保つため、MSX-DOSではCP/Mと同様のファイルアクセス方式をサポートしています。CP/Mでは、2つの全く異なるアクセス方式があります。また、レコードサイズは128バイトに固定されています。

■シーケンシャルアクセス(カレントレコード+カレントブロックによるレコード管理)
 CP/Mとの互換性を保つための1つめの方法が、「カレントレコード」と「カレントブロック」で管理されるシーケンシャルアクセスです。ファイルのアクセスは常に先頭から順(シーケンシャル)に行い、アクセスしたレコード数はFCBのカレントレコードフィールドでカウントされます。カレントレコードフィールドの値は128になると0にリセットされ、その桁上がりがカレントブロックフィールドにカウントされます。このアクセス方式では、「ランダムレコード」は使いません。

■ランダムアクセス(ランダムレコードによるファイル管理)
 CP/Mとの互換性を保つための2つめの方法が、「ランダムレコード(3バイト)」で管理されるランダムアクセスです。「ランダムレコード」を変更することで、任意の位置のレコードをアクセスすることができますが、別のレコードをアクセスするためには、毎回この操作が必要です。

7.ランダムブロックアクセス(論理レコードによるファイル管理)
 MSX-DOSには、「ランダムブロックアクセス」という、大変に有能な入出力方式があります。これは、MSX-DOS独自のファンクションコールで、次のような特徴があります。

  • レコードサイズを任意に設定できる。
  • 複数のレコードを一度にアクセスできる。
  • シーケンシャルアクセスとランダムアクセスを任意に切り換えられる。

 ランダムブロックアクセスでは、FCBの「レコードサイズ」を用いて、レコードの大きさを指示し、レコード位置を「ランダムレコード」で指示します。レコードサイズの2バイトには任意の値を入れることができます(1〜65535)。ファイル全体を1レコードとして扱うことも、1バイトを1レコードとして扱うことも、128バイトを1レコードとして扱うこと(CP/M方式)も可能です。
 このアクセス方式では、ランダムレコードのフィールドがアクセスの終わったレコードの次のレコードを指すように、常に更新されます。したがって、ランダムレコードを1度セットするだけで、任意レコードからレコードまでをシーケンシャルに読み書きすることが簡単にできます。

3.3.3 日付と時刻の設定

 MSX-DOSは、ファイルの内容が変更されたときには、自動的にファイルの最終更新日付・時刻を現在の日付・時刻に書き換えます。これは、MSX-DOS自身には何の意味もないのですが、ユーザーがファイルを管理する目的には、非常に有用です。このため、MSX-DOSには、日付・時刻の読み出しや変更を行うファンクションコールがあります。

 3.4 ディスクファイルの構造

 ファンクションコールを使用すれば、手軽にキメ細かくファイルを取り扱うことができます。ユーザーは、ディスク上でファイルがどのような方法で管理され、どのような形式で記録されているか、といった情報を詳しく知る必要はありません。しかし、場合によっては、ディスクの管理情報を取り出したり、それをもとにファイルとは無関係にディスクを直接アクセスしたりする手段が必要になることがあります。
 MSX-DOSでは、このような目的のために、ディスクの管理情報を得たり、「論理セクタ」を直接アクセスするファンクションコールを用意しています。

3.4.1 ディスク上のデータ構造

 セクタを直接アクセスする場合には、どのセクタにどういった情報が書き込まれているか、という基本知識が必要になります。

1.論理セクタ
 MSX-DOSでは、3.5インチフロッピーディスクでもハードディスクでも、あるいはその他のドライブでも基本的にはアクセスすることができます。それぞれのドライブやメディアの種類によりセクタの大きさ、トラック毎のセクタ数、記録面の数などは違っていますが、これを統一的に管理するため、MSX-DOSでは、ディスク上の物理的な境界にとらわれず、すべてのセクタに連続した通し番号をつけて、その番号でセクタを管理する方法を採用しています。これを「論理セクタ」と呼びます。
 「論理セクタ」(以下、セクタ)の番号は0からそのディスクの総セクタ数-1(ディスクの種類によって異なる)までの一連の番号によって指定します。
 MSX-DOSでは、ディスクの中のセクタを表3.5に示す4つの領域に分けています。最初の3つの領域にはデータを管理するための情報が書き込まれ、ファイルデータの本体は「データ領域」の部分に書き込まれます。これらの位置関係は図3.14のとおりです。ブートセクタはかならずセクタ0にありますが、

  • FAT
  • ディレクトリ
  • データ領域の開始セクタの位置

はメディアによって異なります。ただし、これらの情報は、ブートセクタを読み出せば得ることができます。
表3.5 ディスクの領域

領域 内容
ブートセクタディスク固定の情報とMSX-DOSの起動プログラム
FAT ディスク上のファイルの位置情報
ディレクトリディスク上のファイルの管理情報
データ領域 実際のファイルデータ

図3.14 ディスク上の領域の位置関係

2.クラスタ
 ディスクの入出力は、前述のとおりセクタが基本単位です。ただし、ファイルに対してディスク上のセクタを割り当てるときには、セクタではなく複数のセクタからなる「クラスタ」という単位が使われます。それぞれのファイルには、そのファイルサイズに応じて必要な数のクラスタが割り当てられます。1クラスタよりも大きなサイズのファイルの場合、データは複数のクラスタにまたがって記録されます。1クラスタ未満の部分については、たとえそれが1バイトであっても1クラスタ分のデータ領域が割り当てられます。クラスタは論理セクタと同様に連続した番号で指定されていますが、FATの項で述べる理由で、2から始まる通し番号になっており、データ領域の先頭がクラスタ#2の位置に相当します。

3.ブートセクタとDPB(ドライブパラメータブロック)
 MSX-DOSでは、接続されている個々のドライブごとに「DPB」という領域がメモリ上のワークエリアに設けられ、各ドライブに固有の情報が記録されます。MSX-DOSはどのようなタイプのディスクドライブにも対応できますが、それはこのDPBを参照して個々のドライブに対応した処理を行うことによって、メディア間の差異が吸収できるからです。
 DPBに書き込まれる情報は、ブートセクタに記録されているもので、それがMSX-DOSの起動時やメディアが交換される毎に変更されます。ただし、ブートセクタとDPBは、図3.15と図3.16に示すように、形式が異なっています。


図3.15 ブートセクタの情報


図3.16 DPBの構造

4.FAT(ファイルアロケーションテーブル)
 MSX-DOSでは、1クラスタよりも大きなサイズのファイルは、複数のクラスタにまたがって記録されますが、そのとき連続した番号のクラスタが使用されるとは限りません。特に、ファイルの作成・削除を何度も繰り返した後では、使われなくなったクラスタがディスク上のあちこちに散在した状態になります。この状態でサイズの大きなファイルを作成すると、データは飛び飛びのクラスタに分散して置かれます。そこで、「何番目のクラスタは何番目のクラスタに続いている」というリンク情報を記録しておく場所が必要になります。それがFATの役割です。また、未使用クラスタの位置や、不良クラスタが発見されたときに以後そこをアクセスしないように記録する目的にもFATが利用されます。
 FATに記録されるこのようなクラスタのリンク情報や不良クラスタ情報は、ディスクファイルを管理するうえで不可欠なものであり、一部でも破損してしまうとディスク全体が使用できなくなる恐れがあります。そのためFATは常に複数個のコピーが用意され、万一に備えています。
 FATの例を図3.17に示します。FATには、

  • 先頭の1バイトは「FAT ID」と呼ばれ、ディスクのメディアタイプを示す値
  • 次の2バイトはダミー値のFFH
  • その次から、1クラスタにつき12ビットというフォーマットで実際のリンク情報を記録しているFATエントリ

が記録されます。0番と1番に相当する3バイトが「FAT ID」に使われていますので、ファイルのデータに対応するFATエントリは2番から始まります。FATエントリの番号は、それに対応するクラスタの番号でもあります。FATエントリに記録された12ビットのリンク情報は、図3.18のように並んでいます。リンク情報は、次に続くクラスタ番号を示す値です。もし、FFFHとなっているときは、そのクラスタでファイルが終了したことを意味します。
 図3.17の例では、クラスタ#2→クラスタ#3→クラスタ#4という3クラスタ分の大きさのファイルと、クラスタ#5→クラスタ#6の2クラスタ分のファイルが存在していることがわかります。なお、クラスタ番号の小さい順にリンクしているのは図を見やすくするためで、実施には番号順であるとは限りません。


図3.17 FATの実例

図3.18 FATの読み方

5.ディレクトリ
 FATはデータの位置関係などを表すものであり、ファイル自体に関する情報は含んでいません。したがって、そのファイルの名前やそれに付随する情報を知るには、FATとは別の情報源が必要です。これが「ディレクトリ」です。
 ディレクトリはディスク上のディレクトリ領域に記録されていて、図3.19のように32バイトごとにディレクトリエントリ(ディレクトリの格納場所)が並んでいます。ファイルを作成すると、使われていないディレクトリエントリの中で、いちばん番号が小さいところに目的のファイルのディレクトリが作られます。ファイルが削除されると、該当するディレクトリエントリの最初の1バイトにE5Hが書き込まれ、そのディレクトリエントリが空いたことを示します。ディレクトリエントリがすべて使用されてしまうと、データ領域がいくら残っていても新しいファイルを作ることはできません。


図3.19 ディレクトリ領域の構造

 ディレクトリエントリは図3.20のような構造で、それぞれファイル名、ファイル属性、作成・更新の日時、ファイルの先頭クラスタ番号、ファイルサイズの情報を記録しています。
 ファイル属性は、ファイルに各種の属性を与えるものです(図3.21参照)。MSX-DOSでは属性を持ったファイルを作ることはできません。ただし、既存のファイルに不可視・システム・ボリューム・ディレクトリのいずれかの属性が付けられていると、そのファイルはファンクションコールではアクセスできないようになります。読み出し専用(書き込み禁止)属性は無視されます。
 日付と時刻は図3.22と図3.23のように、それぞれ2バイトの領域を3つのビットフィールドに分割して記録しています。「年」は7ビットに0〜99の値を設定することで、西暦1980年〜2079年を表します。「秒」用のビットフィールドは5ビットで、時間の分解能は2秒です。


図3.20 ディレクトリの構造

図3.21 ファイル属性

図3.22 日付を表すビットフィールド

図3.23 時刻を表すビットフィールド

6.クラスタからセクタへの換算
 FATやディレクトリでは、ディスク上のデータの位置はクラスタ単位で表されています。クラスタで示されたこれらのデータをファンクションコールでアクセスするためには、あるクラスタが何番のクラスタに対応しているか、という関係を求めなければなりません。これは、データ領域がクラスタ#2から開始していることを元に、以下のように計算することができます。

  1. 与えられたクラスタ番号をCとする。
  2. データ領域の開始セクタを調べ、これをS0とする。
  3. 1クラスタが何セクタに相当するか調べ、これをnとする。
  4. 求めるセクタ番号Sは、S=S0+(C-2)*nの計算で得られる。