MSX Datapack wiki化計画

2章 インタースロットコール

 前述のように、MSXではプログラムが異なったスロットに分かれているため、現在選択されているスロット上にないプログラムが必要になることもあります。これは主に以下のような場合が考えられます。

  1. MSX-DOSの環境から、MAIN ROMにあるBIOSを呼び出す。
  2. BASICの環境から、SUB ROMにあるBIOSを呼び出す(MSX2以降)。
  3. カートリッジソフトから、MAIN ROMあるいはSUB ROMのBIOSを呼び出す。

 これらの作業を行う際スロット切り換えが簡単かつ安全に行えるように、インタースロットコールという一群のBIOSルーチンが存在し、どのスロットに存在するルーチンでも呼び出せるようになっています。本説では、このインタースロットコールの使用法を説明しましょう。

 2.1 インタースロットコールの動作

 例えば、MSX-DOSからMAIN ROM上のBIOSを呼び出す場合、スロットの状態の遷移は以下に示すとおりです。

  1. 初めはMSX-DOSモードなので64Kのアドレス空間すべてにRAMが選択されており、このままではBASIC-ROMをアクセスできない(図5.6-1)。
  2. ROMのBIOSを呼び出すためにページ0をBASICのMAIN ROMに切り換え、アクセス可能な状態にする。そしてBIOSを呼びだす(図5.6-2)。
  3. BIOSの処理が終わったら再び元の状態に戻し、初めに呼ばれたアドレスにリターンする。


図5.6 インタースロットコールのされ方

 このとき、MSX-DOS側のプログラムが、ページ0以外に存在するならば話は簡単なのですが、呼びだす側のプログラムが呼びだされる側のBIOSと同じページ0に存在しているときは、非常に複雑になります。呼び出す方のプログラムがページ0を切り換えたとたんに自分自身がいなくなって暴走してしまう、ということのないように配慮しなければいけません。
 インタースロットコールでは、いったんページ3へ分岐してから実際のスロット切り換えを行うという方法で、この問題を解決しています。
 このような複雑な状況をインタースロットコールはサポートするので、ユーザーは簡単に他のスロットのプログラムを呼び出すことができます。

 2.2 インタースロットコールの使用法

 インタースロットコールは、以下に述べるいくつかの方法で行うことができます。これらはBIOSとしてMAIN ROM内に含まれているものですが、その中のいくつかはMSX-DOSの環境下においてもまったく同一のものが用意され、MSX-DOS使用時のインタースロットコールを可能としています(「2.2.2 MSX-DOSのインタースロットコール」参照)。

2.2.1 BIOSのインタースロットコールルーチン

RDSLT(000CH/MAIN)
機能
指定スロットの指定アドレスから値を読み出します。
コール手順
A スロット指定(図5.5と同じフォーマット)
HL読み出すアドレス
戻り値
A 読み出した値
変更レジスタ
AF, BC, DE
解説
指定したスロットの指定したアドレスの内容を読み出し、Aレジスタに格納します。スロットの指定はAレジスタによって図5.5の形式で行います。このとき、目的のスロットが基本スロットならば、上位6ビットはすべて「0」に設定し、下位2ビットでスロット#0〜#3を決めます。もし拡張スロットを指定するならば、同様にビット0とビット1で基本スロットを指定し、その基本スロットに接続されるどの拡張スロットかということをビット2とビット3で指定、さらにビット7を「1」にします。
WRSLT(0014H/MAIN)
機能
指定スロットの指定アドレスに値を書き込みます。
コール手順
A スロット指定(図5.5と同じフォーマット)
HL書き込むアドレス
E 書き込む値
戻り値
なし
変更レジスタ
AF, BC, D
解説
Aレジスタで指定したスロット(指定の形式は図5.5と同じ)のHLレジスタで指定したアドレスに、Eレジスタの値を書き込みます。
CALSLT(001CH/MAIN)
機能
指定したスロットの指定アドレスをコールする
コール手順
IY上位8ビットスロット(図5.5と同じフォーマット)
IXコールするアドレス
戻り値
呼び出し先プログラムの実行結果により異なる
変更レジスタ
呼び出し先プログラムの実行結果により異なる
解説
IYレジスタの上位8ビットで指定したスロット(指定の形式は図5.5と同じ)の、IXレジスタで指定するアドレスに存在するルーチンをコールします。
ENASLT(0024H/MAIN)
機能
スロットを切り換えます。
コール手順
A スロット(図5.5と同じフォーマット)
HL上位2ビットでスロット切り換えを行うページを指定する
戻り値
なし
変更レジスタ
すべて
解説
HLレジスタの上位2ビットで指定したページを、Aレジスタで指定したスロットに切り換えます。
CALLF(0030H/MAIN)
機能
指定スロットの指定アドレスをコールします。
コール手順
インラインパラメータ形式でスロットとアドレスを指定する
戻り値
呼び出し先のプログラムの実行結果により異なる
変更レジスタ
呼び出し先のプログラムの実行結果により異なる
解説
指定したスロットの、指定したアドレスをコールしますが、前述のCALSLTと異なり、スロットおよびアドレスの指定は次に示すように、インラインパラメータ形式で行います。すなわち、このCALLFを呼びだす命令の直後にスロットを指定する値1バイト(RDSLTと同じフォーマット)を置き、その次にアドレスを指定する数値2バイトを置くという形でパラメータを渡します。「CALL 0030H」の代わりに「RST 30H」というRST(リスタート)命令を使ってもかまいません。その場合、4バイトでインタースロットコールが実現可能になります。

リスト5.1 インタースロットコールの実行例

        rst      30h               ;interslot call
        db       00000000b         ;select slot#0
        dw       006ch             ;call address = 006ch
RSLREG(0138H/MAIN)
機能
基本スロット選択レジスタの内容を読み出します。
コール手順
なし
戻り値
A読み込んだ値(図5.5と同じフォーマット)
変更レジスタ
A
解説
基本スロット選択レジスタの内容を読み出し、Aレジスタに入れます。
WSLREG(013BH/MAIN)
機能
基本スロット選択レジスタへ値を書き込みます。
コール手順
A書き込む値(図5.5と同じフォーマット)
戻り値
なし
変更レジスタ
なし
解説
基本スロット選択レジスタにAレジスタの値を書き込み、スロットを選択します。
SUBROM(015CH/MAIN)
機能
SUB ROMの指定したアドレスをコールします。
コール手順
IXコールするアドレス、PUSH IX (「A.1.2 SUB ROM」参照)
戻り値
呼び出し先のプログラムの実行結果により異なる
変更レジスタ
裏レジスタとIX, IYレジスタは保存される
解説
BASICのSUB ROMを呼びだすためのルーチンです。SUB ROMの存在するスロットはBIOSが自動的に調べます。普通は、次のEXTROMを使います。
EXTROM(015FH/MAIN)
機能
SUB ROMの指定したアドレスをコールします。
コール手順
IXコールするアドレス
戻り値
呼び出し先のプログラムの実行結果により異なる
変更レジスタ
裏レジスタとIYレジスタは保存される
解説
BASICのSUB ROMを呼び出すためのルーチンです。上記のSUB ROMとこのEXTROMとは、IXレジスタの値をpushするか否かという点だけが異なります。

2.2.2 MSX-DOSのインタースロットコール

 MSX-DOSでは、以下に示す5種類のインタースロットコールが用意され、MSX-DOSジャンプベクタにそのエントリアドレスが定義してあります。これらはBIOS内の同名のルーチンとまったく同じものですから、機能や使用法に関しては、前述のBIOSをご覧下さい。
 なお、MSX-DOSからSUB ROM内のルーチンを呼びだす場合は、これらのルーチンは使用せず、「2.2.3 MSX-DOSからのSUB ROMコール」の方法を使います。

RDSLT(000CH) 指定スロットの指定アドレスから値を読み出す
WRSLT(0014h) 指定スロットの指定アドレスに値を書き込む
CALSLT(001Ch)指定スロットの指定アドレスを呼び出す
ENASLT(0024h)指定スロットを使用可能な状態にする
CALLF(0030H) 指定スロットの指定アドレスを呼び出す

リスト5.2 MSX-DOSからBIOSを呼び出す

calslt    equ    001ch             ; inter slot call
exptbl    equ    0fcc1h            ; slot address of MAIN ROM

          ld     iy,(exptbl-1)     ; load slot address of the MAIN ROM
                                   ; in high byte of IY
          ld     ix,address of the BIOS jump table
          call   calslt

2.2.3 MSX-DOSからのSUB ROMコール

 MSX-DOSの環境からSUB ROMを呼ぶ場合は、以下のような特別な配慮が必要です

  1. CALSUBのエントリ条件は、IXにアドレスを入れるだけです。
  2. スタックはページ0以外でなければなりません。
  3. 割り込み禁止は必要ありません。
  4. 終了後、NMIフックの解除は必要ありません。

 ここで問題となるのは、EXTROMに必要なIXレジスタの値が渡せないことです。したがって、BIOS ROMが呼び出された後にIXがセットされ、EXTROMにジャンプする必要があります。
 具体的には、スタック上に次のようなルーチンを用意し、NMIのフックからジャンプさせるようにしておきます。次に、BIOSのNMIエントリ(フックは用意されているが使用されない)をインタースロットコールします。リスト5.3を参照して下さい。

リスト5.3 DOSからのSUB ROMコール

;       +0    inc    sp
;       +1    inc    sp
;       +2    ld     ix,<sub-ROM entry>
;       +6    nop
;       +7    jp     extrom
calslt    equ    001ch
extrom    equ    015fh                 ; Non-maskable interrupt
nmi       equ    0066h                 ; Hook for NMI
exptbl    equ    0fcc1h
;
_calsub::
          exx                          ; Save argument registers over setup
          ex     af,af'
          ld     hl,extrom
          push   hl
          ld     hl,0c300h             ; jp xxxx, nop
          push   hl
          push   ix                    ; SUB ROM entry
          ld     hl,021ddh             ; ld ix,xxxx
          push   hl
          ld     hl,03333h             ; inc sp, inc sp
          push   hl
          ld     hl,0
          add    hl,sp
          ld     a,0c3h
          ld     (h.nmi),a
          ld     (h.nmi+1),hl
          ex     af,af'                ; Restore registers
          exx
;
          ld     ix,nmi
          ld     iy,(exptbl-1)
          call   calslt
          ei
;
          ld     hl,10                 ; Throw away the interface routine
          add    hl,sp
          ld     sp,hl
          ret
          
          end

 2.3 スロットの状態を知るためのワークエリア

 スロットに関するワークエリアには、以下のものがあります。

【EXBRSA(FAF8H,1)】SUB ROMのスロットアドレス


図5.7 SUB ROMのスロットアドレス

【EXPTBL(FCC1H,4)】基本スロットの拡張の有無


図5.8 基本スロットの選択

【SLTTBL(FCC5H,4)】拡張スロット選択レジスタ値の保存エリア


図5.9 拡張スロットの選択

【SLTATR(FCC9H,64)】各スロット、ページにおけるアプリケーションの有無


図5.10 アプリケーションの有無

【SLTWRK(FD09H,128)】アプリケーション用ワークエリア


図5.11 アプリケーション用ワークエリア