MSX Datapack wiki化計画

3章 カートリッジソフトの作成法

 MSXには最低1つのスロットが表に出ており、ここに接続されるハードウェアを「カートリッジ」といいます。カートリッジには、

  1. アプリケーションプログラムやゲームなどのROMカートリッジ
  2. フロッピーディスクインターフェースやRS-232Cインターフェイスなどの入出力装置カートリッジ
  3. RAMを増やすための増設RAMカートリッジ
  4. スロットを増やすためのスロット拡張器

などいろいろと接続でき、これによりMSXは機能の拡張を簡単に行うことができます。また、BASICやマシン語プログラムをROM化(カートリッジ化)することも簡単です。この章では、ソフトウェアをカートリッジ化する方法を説明します。

  3.1 カートリッジヘッダ

 MSXのカートリッジは、16バイトの共通のヘッダを持っており、システムがリセットされると、このヘッダに記述された情報によりカートリッジの初期設定が行われます。BASICやマシン語のプログラムをROM化したカートリッジの場合は、このヘッダに書き込む情報によってオートスタートさせることも可能です。カートリッジヘッダの構成を図5.12に示します。


図5.12 プログラムカートリッジのヘッダ

■ ID
 ROMカートリッジであれば、この2バイトに「AB」(41H, 42H)というコードを入れておきます。ちなみにSUB ROMのIDは「CD」となっています。

■ INIT
 この2バイトには、カートリッジがワークエリアやI/Oなどの初期化を行うのであれば、その初期化ルーチンのアドレスを書き込み、行わなければ0000Hとしておきます。初期化ルーチンの中でワークエリアの確保など必要な処理を行ったら、「RET」で終了させて下さい。この時SP以外のレジスタは内容を破壊してもかまいません。なお、ゲームのようにカートリッジ内でループしていればよいマシン語プログラムの場合は、ここからそのまま目的のプログラムを実行することが可能です。

■ STATEMENT
 この2バイトには、カートリッジがCALL文の拡張を行うのであれば、ステートメント拡張ルーチンのアドレスを書き込み、行わなければ0000Hとしておきます。CALL文の拡張を行う場合、ステートメント拡張ルーチンは4000H〜7FFFHになければいけません。
 CALL命令は以下の書式で記述されます。

  CALL <拡張ステートメント名> [(<引数>[,<引数>…])]

 拡張ステートメント名は15文字以下でなければいけません。CALLの省略として「_」(アンダースコア)も使用できます。
 BASICインタープリタはCALL文を見つけると、ワークエリアの【PROCNM(0FD89H,16)】に拡張ステートメント名を入れ、ヘッダのSTATEMENTの内容が0以外のカートリッジにスロット番号の小さい方から順に制御を渡してきます。このときHLレジスタは拡張ステートメント名の次のテキストアドレスを指しています(図5.13-1)。
 拡張ステートメントの作成については、「第2部 5.5 拡張ステートメント」も参照して下さい。


図5.13 拡張ステートメント処理ルーチンの入出力

 ステートメント拡張ルーチンを作成する場合は、まずPROCNMに書かれた拡張ステートメント名を識別し、もしそれが自分の処理すべきものではなかった場合は、HLレジスタの変更はせずに、キャリーフラグを「1」にしてリターンします(図5.13-2)。拡張ステートメント名が自分の処理すべきものであった場合は、それに応じた処理をし、HLレジスタ(テキストポインタ)を自分が処理したステートメントの次(普通は00Hまたは3AHが入っているところ)に更新し、最後にキャリーフラグを「0」にしてリターンします(図5.13-3)。
 BASICインタープリタはキャリーフラグの状態によって、CALL文が処理されたかどうかを判定し、処理されていない場合は次のカートリッジを呼び出します。すべてのカートリッジが処理をしなかった場合(最後までキャリーフラグが「1」だったとき)は「SYNTAX ERROR」を表示します。ステートメントの引数評価には「第2部 5.4 BASICの内部ルーチン」を利用すると便利です。

■ DEVICE
 この2バイトには、カートリッジがデバイスの拡張(入出力装置の拡張)を行うのであれば、デバイス拡張ルーチンのアドレスを書き込み、行わなければ0000Hとしておきます。デバイスの拡張を行う場合、デバイス拡張ルーチンは4000H〜7FFFHになければいけません。デバイスは1つのカートリッジについて、4つまで持つことができます。また、拡張デバイス名は15文字以下でなければいけません。
 BASICインタープリタは定義されていないデバイス名を見つけると、【PROCNM(0FD89H,16)】にそれを格納し、AレジスタにFFHを入れて、DEVICEの内容が0以外のカートリッジにスロット番号の小さい方から順に制御を渡してきます(図5.14-1)。
 そこで、デバイス拡張ルーチンを作成する場合は、初めにPROCNMのファイルディスクリプタを識別し、もしそれが自分の処理すべきでないデバイスに対するものだった場合は、キャリーフラグを1にしてリターンして下さい(図5.14-2)。自分の処理すべきデバイスに対するものだった場合は、それに応じた処理を行い、装置ID(0〜3)をAレジスタに設定し、最後にキャリーフラグを0にしてリターンして下さい(図5.14-3)。
 BASICインタープリタはキャリーフラグの状態によって処理されたかどうかを判定し、もし処理されていない場合は次のカートリッジを呼び出します。すべてのカートリッジが処理をしなかった場合(最後までキャリーフラグが「1」だったとき)は「Bad file name」エラーを表示します。
 実際の入出力操作をするときには、BASICインタープリタは【DEVICE(0FD99H)】に装置ID(0〜3)を、Aレジスタにデバイスに対する要求(表5.1)を設定してデバイス拡張ルーチンを呼び出します。デバイス拡張ルーチンではそれを参照し、要求に応じた処理を行ってください。
 この拡張デバイス処理については、MSXの内部システムに関する深い知識が必要になるので、確固たる目的があるとき以外は、拡張ステートメントでデバイスをコントロールするのが現実的です。


図5.14 デバイス拡張ルーチンへの入出力

表5.1 デバイスに対する要求

Aレジスタ要求
0OPEN
2CLOSE
4ランダムアクセス
6シーケンシャル出力
8シーケンシャル入力
10LOC関数
12LOF関数
14EOF関数
16FPOS関数
18バックアップキャラクタ

■ TEXT
 この2バイトには、カートリッジ内のBASICプログラムをオートスタート(リセット時に実行)実行するのであれば、BASICプログラムのテキストポインタを入れておき、行わなければ0000Hとしておきます。プログラムのサイズは8000H〜BFFFHの16K以下でなければいけません。
 BASICインタープリタはイニシャライズ(INIT)を終え、システムを起動した後、ヘッダのTEXTの内容をスロット番号の小さい順に調べます。そして、そこが0000H以外であった場合、そのアドレスをBASICテキストポインタとしてそこから実行を始めるようになっています(図5.15)。このときのBASICプログラムは、中間コード形式で格納されている必要があり、またBASICプログラムの初め(TEXTが指すアドレス)にはプログラムの開始を示す00Hが付いていなければいけません。
 なお、GOTO文などの分岐先の行番号を、あらかじめ分岐先のテキストポインタの絶対アドレスにしておくと、プログラムの実行速度が上がります。


図5.15 BASICプログラムカートリッジの実行

BASICプログラムのROM化の方法

1. BASICのテキスト格納先頭アドレスを8021Hに変える。

	POKE &HF676,&H21:POKE &HF677,&H80:POKE &H8020,0:NEW
注意必ず1行にまとめて実行する。

2. 目的のBASICプログラムをロードする。

	LOAD"PROGRAM"

3. IDを作成する。

	AD=&H8000
	FOR I=0 TO 31
	  POKE AD+I,0  		IDエリアのクリアー
	NEXT I
	POKE &H8000,ASC("A")
	POKE &H8001,ASC("B")
	POKE &H8008,&H20
	POKE &H8009,&H80

4. 8000H〜BFFFHをそのままROMに焼き込む。

  3.2 カートリッジ用ソフトの作成に関する諸注意

3.2.1 カートリッジで使用するワークエリアの確保

 他のカートリッジに入っているプログラムといっしょに実行する必要がないプログラム(ゲームカートリッジのようなスタンドアロンのソフトウェア)では、BIOSの使用するワークエリア(F380H)よりアドレスの小さい部分は自由に使用することができます。
 しかし、BASICインタープリタの機能を利用して実行されるプログラムでは、同じ領域をワークエリアとして使用するわけにはいきません。その対策としては以下の3つの方法があります。

  1. カートリッジ自体にRAMをのせてしまう(最も安全確実な方法)。
  2. 必要なワークエリアが1バイトあるいは2バイトならば【SLTWRK(FD09H〜)】の自分に対応する2バイトをワークとして使用する。
  3. 必要なワークエリアが3バイト以上ならばBASICで使用するRAMから確保する。具体的には、まず【BOTTOM(FC48H)】の内容を【SLTWRK(FD09H〜)】の対応するエリアに書き写し、BOTTOMの値を必要なワークエリア分増やし、そこをワークエリアとして確保する(図5.16)。


図5.16 ワークエリアの確保

2.と3.については添付のフロッピーディスクに入っている「GETWORK.MAC」を参考にして下さい。

3.2.2 フック

 MSX-BASICが使用するワークエリアのFD9AH〜FFC9Hには「フック」というBASICの機能拡張のための領域があります。1つのフックは5バイトあり、そこには普通「RET」が書かれています。
 MSX-BASICはある処理(ワークエリアのフックの説明で示すような処理)を行うと、そこから一度このフックをコールします。「RET」の場合はすぐ戻ってしまいますが、その5バイトをあらかじめイニシャライズ(INIT)ルーチンによりカートリッジ内のプログラムにインタースロットコールするよう書き換えておけば、BASICの機能を拡張することができるわけです(図5.17参照)。
 添付のフロッピーディスク内の「HOOK.MAC」は、割り込み処理専用のH.KEYIというフックをカートリッジが利用する場合のプログラムです。


図5.17 フックの設定

3.2.3 スタックポインタの初期化

 ディスク内蔵のMSXの場合、スロットの位置によってはカートリッジよりもディスク・インターフェイスROMの方が先に初期化動作を行い、ワークエリア確保のためスタックポインタを下位アドレス方向に下げることがあります。このとき、ディスクを使わないソフトウェアはカートリッジに制御が渡ってきてからもう一度スタックポインタを設定し直さないと、スタック領域がなくなり暴走などのトラブルを生じる可能性があります。プログラムの初めにはスタックポインタのイニシャライズを忘れずに行って下さい。

3.2.4 拡張スロットでの動作チェック

 一般の市販ソフトウェアが拡張スロットに差し込まれた場合やRAMが拡張スロットにある場合に、アプリケーションプログラムが動作しないという問題があります。MSX2の多くの機種は本体内部で拡張スロットを使用しているので、拡張スロットでの動作不良は致命的です。市販されるソフトウェアは、それが拡張スロットに入れられている場合とRAMが拡張スロットにある場合について、必ず動作チェックを行って下さい。
 特にFFFFH番地には拡張スロットレジスタが置かれますので、そこをRAMのつもりで参照してはいけません。例えば、プログラム中で「LD SP,0」を行ってFFFFH番地にスタックを設定すると、そのプログラムは拡張スロットを用いた機種では暴走します。

3.2.5 CALSLT使用時の注意

 CALSLTおよびCALLFでインタースロットコールを行うと、IX、IY、および裏レジスタの内容は破壊されます。また、このルーチンから返ってくるとき、MSX1では割り込みが禁止されていますが、MSX2では呼び出す前の状態に戻ります。