高速、標準両モードいけるウエイトの掛け方

MSX2で程良い速さでも、MSX turbo Rだと速過ぎてゲームにならない、いちいち標準モードにするのは面倒だということはありませんでしたか。 ここでは「FOR-NEXT」にかわる、ビーバー流「高速、標準両モードでいけるウエイトの掛け方」を提案してみたいと思います。

目次

MSXの適当手帳 MSX駅 西山駅

TIME関数を利用する

TIME関数とは、MSX-BASIC特有の、かつ便利な関数の一つで、この関数があるという理由でMSXを使い続けている教授もいるほどです(いつぞやのM.FANの「Mファンにいいたい放題!」参照)。
TIME関数は、約60分の1秒毎にインクリメント(値が1増える)される関数で、値を書き込むこともできます。 TIME関数は0-65535までの整数をとり、65535の次は0に戻ります。

ウエイトとしての応用は、まずメインループの先頭でTIME関数をリセットし(0にする)、ループ内の一通りの処理が終わったら、TIME関数が一定値になるまで待ってから、メインループの先頭に戻るようにします。
TIME関数でウエイトをとるメリットは、メインループ内で多少処理量が増減しても、速度変化があまり起こらない(遅くなることはあるが一定以上速くなることはない)ということ、また、機種毎の処理速度の違い、標準モードと高速モードの違いを吸収できるということです。
個人的には、このTIME関数を利用してウエイトを掛けることが多いです。過去AVFで採用された自分の作品のいくつかも、この方法でウエイトを掛けています(例:「歯車」)。

ちなみに、「BASICコンパイラ」(ハート電子社製)はTIME関数にも対応しているので、TIME関数を利用したウエイトが掛けられます。内容にもよりますが、メインループ1周1/60秒というのも簡単でしょう。 「MSXべーしっ君」シリーズでも使えるかな?

(戻る)

SET SCROLL命令を利用する(MSX2+以降)

SET SCROLL命令は、続けて実行すると、前に使った時から必ずN/60秒(Nは自然数)の間隔をあけて実行されます(走査線が関係していると思われます)。 そこで、メインループのどこか(はじめのほうがよいか)でSET SCROLL命令を使うようにすれば(「SETSCROLL0」とダミーで書いてもよい)、メインループの1周には、どんなに速くても1/60秒のウエイトが掛かるというわけです。 ま、この方法では任意に2/60秒以上のウエイトを掛けることはできないし、あまり実用性はないかもしれません。 SET SCROLL命令をいじくってて思い付いたというだけです、はい。

(戻る)

バージョンチェックをする

MAIN-ROMの2Dh番地には、そのMSXのバージョン番号が入っています。2Dh番地の内容と機種との対応は以下の通りです。
00h:ver1.0(MSX)
01h:ver2.0(MSX2)
02h:ver3.0(MSX2+)
03h:ver4.0(MSX turbo R)
この2Dh番地の内容を確認することによって(BASICならPEEK関数で調べられます)、1ループの処理速度を決めたり、また機種毎に異なった対応をしたりすることができるでしょう。
この場合でもFOR-NEXTループによる方法は避けた方がよいでしょう。 もし将来、より高速な処理が可能なMSXが現れたとしたら(一応そういうことにしといて(^_^;))、FOR-NEXTループによる方法はやはりまずいといえます。 また、こうした事態(^_^;)に備えて、2Dh番地の内容が、上記以外の場合でも動作するよう、工夫した方がよいでしょう。
ところでMSX turbo Rの場合、2Dh番地の内容を調べるだけでは、今、高速モードなのか標準モードなのかは分かりません(ROMだもんね)。 それを調べる方法もありますが、ここで詳しく述べるのは避けます(自分がやったことないだけ(^_^;))。 ただ、機械語の知識が必要だったと思います。 「MSX テクニカルガイドブック」(アスキャット)あたりを参考にして下さい。

ついでにVRAM容量を調べる方法も書いておきましょう。 システムワークエリアのMODE(FAFCh)のビット1、2(ビット0、1ではない)を調べれば分かります。対応は以下の通りです。
00b:16K
01b:64K
10b:128K
※「b」は2進数を表します。念のため。

(戻る)

機械語ではどうする?

SET SCROLL命令を利用する(MSX2+以上)方法は、機械語では対応する機能はありません(多分)。 VDPのコントロールレジスタをいじってスクロールさせても、N/60秒の間隔が開くわけではないので意味がありません。

バージョンチェックをする方法は、機械語でもやることは同じでしょう。

BASICでいうところのTIME関数を利用する方法についてですが、これはタイマ割り込みをうまく利用すればいいと思います(BASICのTIME関数も、タイマ割り込みを利用していると思われます)。 具体的には、タイマ割り込みフックから、任意のアドレスをインクリメントするプログラムにジャンプするようにし、メインループではこの任意のアドレスを、BASICでいうところのTIME関数として使うようにすればよいと思います。 このとき、1ループが必ずN/60秒(Nは最低ウエイト時間「以上」の「整数」)となるように工夫すれば(例えば本来1/60秒で1周するループで、1.5/60秒で1周を終えた場合は、2/60秒後に次の周に入る)、走査線によるちらつき等も比較的おとなしくなるのではないかと思います。 BASICのシステムワークエリアを使う方法もあったような気がしますが、詳細は分かりません。

(戻る)

その他

秒間コマ数(メインループの1秒当りのループ回数)を、60コマを大きく上回るものにしても意味がないと思います。 というのは、テレビの表示は秒間約60コマで行われるからです。

ここで取り上げたウエイトの掛け方は、他機種でのプログラムにも、ある程度応用できるのではないかと思います。 特にPC98やDOS/Vは、さまざまな処理速度のマシンがありますから、ウエイトの掛け方というのは大事になってくると思います。 現実問題としては、タイマ割り込みを利用する方法や、ベンチマークを行なう方法(VRAMまわりも調べる)、あるいはOSの機能を使ってウエイトを掛けることになると思います。

(戻る)

ウエイトはどれくらい掛ければいいか

ウエイトは基本的に、小さいほどよい(1/60秒)ですが、やむをえない場合は、1/30秒か1/20秒でもいいでしょう。 1/20秒を下回る(BASICならそうなる可能性が高いですが)と、キーレスポンス等に影響が出てくるので、その辺の工夫も必要になるかもしれません(シューティングゲームのショットのような操作は自動連射にするなど)。

ウエイトは、基本的には標準モードで実行する場合を想定して決めます。 標準モードではどうしても決められない(処理が重い)場合は、高速モードでこれ以上速くなっては困るという時間にすればよいでしょう。

(戻る)