第2部  プログラム開発上の注意


   第1章 開発上の主な注意

 MSXでは、ほかの機種よりもプログラムを開発するときに注意すべきことが多く、
下手にプログラムを組むと、別の会社の機械では動かなかったというような現象がよく
起こります。ここでは、基本的なシステムでの注意事項を述べます。特定のオプション
機能については、別なところで述べます。


    2.1.1 ROMカートリッジの暴走

 ディスク内蔵機などで、ROMカートリッジが暴走する現象が知られています。これ
は主に、内蔵のディスクインターフェイスがスロット0の拡張スロットに置かれている
YIS−805や、HB−F500で起こります。シフトキーを押しながら立ち上げれ
ば、ちゃんと立ち上がるのですが、はっきりいって不便です。これは、ROMカートリ
ッジよりディスクインターフェイスが先に初期化を済ませてしまい、フリーエリアが減
っているにもかかわらず、そのままプログラムを実行してしまうために起こります。こ
れを回避するためには、ROMカートリッジが最初に
  LD SP,F380H
 としてスタックを初期化すればよいわけです。ただし、これはカートリッジヘッダの
INITから直接実行を開始する場合です。また、ディスクドライブなどの機能を全く
使わないプログラムの場合だけ、この方法が使えます。このほかの場合にはスタックの
場所を変更するなどの方法が必要になります。


    2.1.2 裏RAMの検索

 裏RAMをワークエリアに使ったり、機械語サブルーチンを置いたりする場合には、
裏RAMのあるスロットを探さなくてはなりません。中には、ページ3のRAMと同じ
スロットに裏RAMがあると思い込んでいて、裏RAMが別のスロットにある場合や、
拡張RAMカートリッジを使っている場合に動かないソフトがありました。コンピュー
ターの専門家がそんな間違いをするとはあまり思えないのですが、思い込みが強すぎる
とこういうことになってしまうようです。MSXでは、理論的に、すべてのページのR
AMが、全く違うスロットにあることがありえますので、十分注意してください。
 ところで、ディスクをつないでいる場合と、そうでない場合は、裏RAMの検索の仕
方が変わります。順に説明しましょう。

 1.ディスクがつながっている場合。
 このときには、F341H番地からF344H番地までにRAMのあるスロット番号
が書かれています。F341H番地がページ0の、F344H番地がページ3のRAM
のあるスロットということになります。ただし、ディスクのブートセクターを書き換え
て立ち上げた場合には、ゴミが入っている場合があります。また、MSX1で、RAM
32K以下の機械では、裏RAMが存在しないために裏RAMのスロットを調べても意
味のある値は入っていません。

 2.ディスクがない場合
 ディスクがない場合や、本体のRAMが64Kであるかを調べるときは、次のような
方法を使います。
 調べたいスロットに値を書き込んで、読みだせるかどうかをチェックする。

 かなり原始的な方法ですが、これ以外に有効な方法がありません。
 具体的には、調べたいスロットから値を読んで、それを反転させて書き込み、再び読
んで書き込んだ値が読み込めるかどうかをチェックします。そして、元の値を再び書き
込みます。これは、DOSのワークエリアを書き換えたりすると異常な動作をするため
です。これを、0010H番地から0001H番地まで、0410H番地から0401
H番地まで、以下、3C10H番地から3C01H番地まで繰り返し、すべての番地で
正常に読み書きできたときには、そのスロットのそのページには、RAMが存在するこ
とになります。ページ1のRAMの有無を調べるときには4010H番地から同じよう
に調べてください。これは、MSXマガジン1987年9月号に紹介されたアルゴリズ
ムです。なぜ、検索するアドレスが飛び飛びなのかというと、例えば7FFDH番地な
どはディスクインターフェイスのメモリマップドI/Oなどが使っているためです。ま
た、特定の1バイトにRAMがあっても、そのRAMはソフトが使う特殊なS−RAM
である場合があります。そこで16Kバイトほぼ全域を検索するようです。また、将来、
S−RAMを32Kバイト搭載したゲーム用データ保存カートリッジや音源カートリッ
ジのようなものが、メモリマップドI/Oでない方式で出てくることも考えられますが、
ソフトの説明書に「余分なS−RAMカートリッジやROMカートリッジは外しておい
てください」と書いておけばいいでしょう。


   2.1.3 VDP

 ここでは、VDPを使用する際、特に問題になりがちな機能について簡単に箇条がき
します。
 MSX2になってから、VDPにビットブロックトランスファという、VRAMから
メモリやディスクに直接データを転送できる機能がつきました。ただ、VRAMと裏R
AM間では転送が出来ません。(BIOSを使った場合)これは、この機能が使われる
ときは、ROMが表に出ているためです。DOS上でこの機能を使うときは注意してく
ださい。
 MSX2ではパレット機能がつきました。VDPの命令や、BIOSのSETPLT
で、パレットを変えることが出来ます。ただ、BIOSのSETPLTでパレットを変
更するときは、システムが自動的にパレットテーブルをVRAM上の特定のアドレスに
作成します。したがって、ハードウェアスクロールを使うソフトなどが、パレットをB
IOSで書き換えようとすると、画面にゴミが出てしまいます。カラーパレットを変え
るソフトでは、パレット設定はVDPを直接操作して行なってください。この方法につ
いては、「MSX2テクニカルハンドブック」163ページに掲載されています。
 MSX2では、画面を切り替えても画面の初期化は行なわれません。画面の初期化は
ソフトウェア側で行なってください。特に、画面は消しても、スプライトを初期化して
いないために、画面にゴミスプライトが出るソフトがあります。スプライトの初期化は
忘れずにやってください。
 「MSX2テクニカルハンドブック」のVDP関係の追加説明です。210ページの
図4.66で、「R#5 A14 A13 A12 A11 A10  1  1  1」と書いてありますが、本当
はこうでなくて 「R#5 A14 A13 A12 A11 A10 A9  1  1」です。ただし、A9には必
ず1を指定しなければなりません。それじゃあ、本と変わらないじゃないか、と思う人
がいるかも知れませんが、全然違います。例えば、R#5に&B11110111を、R#11に&B00000
011を代入したとすると、マニュアルの解釈では、アトリビュートテーブルに&H1F800を
代入するという意味になってしまいますが、実際にはそのような場所にはアトリビュー
トテーブルは作成されず、&H1FA00に作成されます。このあたりはかなり苦しんだ人が大
勢いて、このおかしな動作のために機械語からスプライトを扱うことをあきらめた人を
著者は何人か知っています。もう一か所、この本にはとんでもない間違いがあるのです
が、そちらのほうは第8部のほうを参照してください。


☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆ はみ出しコラム ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
 この本の初版本にはあまり意味のない情報だけをひたすら並べていたコーナーがあり
ました。第2版では、そのような部分は真っ先に削除されてしまう予定でしたが、少し
は役に立つ情報も載っていたので、このようなはみ出しコラムとして残ることができま
した。何といってもページの余った部分に陣取っているので、長い能書きをたれている
暇がありません。とっとと本文に突入します。(とかいいながら5行も使ってしまった)
 システムワークエリアのNEWKEY(FBE5H)にはキーボードマトリクスの状
態がそのまま入っているのでキーの情報がリアルタイムで読み込めます。キーボードマ
トリクス表はMSX2テクニカルハンドブックの284ページに載っています。
 BASICのプログラムをロードしてからTXTTAB(F676H,2)の値+2、
+3番地に255を書き込むとそのプログラムはLISTが取れなくなりますが、普通
に実行できます。ここの2バイトに0を書き込むとLISTが取れるようになります。


   第2章 システムのバグとその回避

 MSXにはシステムにいくつかのバグがあり、プログラムにバグがないのに正常に動
作しないことがあります。
 ここでは、それらのバグの回避方法について説明します。
 なお、RS−232Cのバグについては、第4部を参照してください。


    2.2.1 サブROMコール

 MSX2で、DOS上からサブROMをコールすると暴走することがあります。(し
ないこともあります)これは、DOSのスロット切り換えルーチンにバグがあるためで
す。したがって、DOSからサブROMを呼び出すときは、次のような、大変に面倒な
方法を使わなくてはなりません。

●DOSからサブROMを呼び出す方法
 1.ページ0のRAMがスロット0の拡張スロットにある場合と、MSX2バージョ
   ンアップアダプターを使っている場合は、DOSのCALSLT(001CH)
   ルーチンで直接呼び出します。

 2.そのほかの場合は、スロット切り換えプログラムをページ2かページ3に置いて、
   サブROMを呼び出すときは直接サブROMを呼び出すのではなく、そのスロッ
   ト切り換えプログラム(後述)を呼び出します。

 ページ0のRAMがスロット0の拡張スロットにある場合は、異常動作が起きないた
め、普通にCALSLTでサブROMを呼び出せます。また、バージョンアップアダプ
ターでは、DOSのスロット切り換えのバグの対策が立てられているので、これも普通
にサブROMが呼び出せます。

 切り換えプログラムの内容ですが、まずページ0をDOSのENASLTでメインR
OMに切り換え、そこから値をいれてEXTROMルーチンをコールします。サブRO
Mから実行が帰ってきたら、(この時点ではページ0はメインROMになっている)メ
インROMのCALSLTでページ0をRAMに切り換えます。なぜENASLTを使
わないかというと、メインROMのENASLTはページ0を切り換えることができな
いためです。(DOSのENASLTはページ0も切り換えることができます)
 この、ページ2またはページ3にスロット切り換えプログラムを置く方法は、スロッ
ト0の拡張スロットにRAMがある場合に暴走しますので、プログラムでは必ず二つの
方法を別々に用意してください。

 このような面倒なことをしなければ、DOSからサブROMは呼び出せません。サン
プルプログラムに、DOSからサブROMを呼びだすプログラムを用意しておきました
ので、そちらのほうも参考にしてください。なお、こんな面倒な方法は使っていられな
い、という方は、DOSからはサブROMは呼びださないか、I/OのA8H番地とF
FFFH番地のメモリマップドI/Oを直接操作してサブROMを呼びだしてください。
これらのI/Oポートは、将来にわたっても変更されることはないので、安心して直接
操作することができます。
 なお、MSX2+,turboRでは、異常動作が起きないようなスロット構成をするよう
に決められましたので、安心してサブROMを直接インタースロットコールできます。


    2.2.2 割り込みフック

 MSXではキー入力やいろいろな処理を割り込みによって処理しています。そして、
割り込みフックを書き変えれば、ユーザーが自分で割り込みを処理できるようにもなっ
ています。(フックの使い方に関しては「MSX2テクニカルハンドブック」第2部4
章を参照)ところが、DOS上で割り込みフックを使うと、一部の機種では暴走するこ
とがあります。これは、割り込みプログラムをDOSが処理する場合に、一時的にペー
ジ0がメインROMに切り換わるために、スロット構成によってはうまく切り換えが出
来ないためです。これを回避する方法は次のとおりです。

●DOS上でプログラムを組む場合、割り込みプログラムはページ0には置かない。ま
た、割り込みフックにJP命令を置かない(必ずRST 30Hでインタースロットコ
ールする)

 この現象も、2.2.1と同じく、DOSのインタースロットコールルーチンに異常
があるのが主な原因です。異常を起こす機種は、ソニーHB−F500、ヤマハYIS
−805などの、ページ0のRAMがスロット0の拡張スロットにある機種です。


    2.2.3 メガROM

 メガROMは、ROM内部のあるアドレスがメモリマップドI/Oになっていて、そ
こにLD命令などで値を書き込んで、8Kバイトまたは16Kバイトごとにメモリを切
り替えることができるROMです。最大32Mビットまでのメモリが一本のROMカー
トリッジの中に納められます。拡張スロットは使っていないため、拡張スロットに差す
ことも出来ます。切り換え方式が何種類かあって、会社ごとにメモリマップドI/Oの
アドレスや切り換え方が微妙に違います。
 この、メガROMですが、一部のMSX1では、動作不良を起こすことが知られてい
ます。この原因ははっきりと調べたわけではないのですが、本体からスロットに信号を
送るときに、一部の機種では特殊な場合に信号をカットしてしまうことがあるためと、
バスのタイミングが機種ごとにかなりばらつきがあるためのようです。これは、ハード
をメーカーに修理に出すほかに回避する方法がありません。また、メガROMを差すと、
動作はしてもかなり機嫌が悪くなる機種もあります。MSX2ではバスのタイミングな
どが統一されているので関係ありません。


    2.2.4 T社の機種のみに現われる現象

 T社のMSXは、電源をいれてからBASICが立ち上がるまでの間に、画面に女性
の顔のデジタイズのようなものが一瞬だけ現われることがあります。この場合、その機
械には悪霊が取り憑いていますので、近くの神社でお祓いを受けることが必要になりま
す。(メーカーに修理に出しても、異常なしといわれてしまう)
 これはT社の機械だけに現われる現象なので、そのほかの機種では関係ありません。
著者の回りにはT社の機械を持っている人物がいないので、直接この現象を確かめたわ
けではないのですが、放っておくとワークエリアが壊されたり、VDPやI/Oポート
に出るはずのないデータが出力されたりするようです。


    2.2.5 ソフトウェアリセット

 MSXでは、0番地ジャンプでリセットすると、(ソフトウェアリセットという)漢
字ROMが使えなくなることがあります。これは、デバイスイネーブル機能が原因とな
っています。
 デバイスイネーブルというのは、バス競合を防ぐための機能です。例えば、内蔵の漢
字ROMがある機種に、外付けの漢字ROMを接続すると、同じI/Oポートに二つの
機器が差さっていることになり、漢字ROMからの信号が競合して、最悪の場合MSX
本体を破壊することがあります。これを防ぐためにI/OポートのF5H番地に用意さ
れたのがデバイスイネーブルで、これの働きは次のようになっています。
 電源が投入されると、BIOSは内蔵の漢字ROMを切り離した状態で漢字ROMの
状態を調べます。内蔵の漢字ROMは切り離されているので、漢字ROMが存在すれば
それは外付けの漢字ROMということになります。
 外付けの漢字ROMがなかった場合、MSXはI/OポートのF5H番地のビット0
に1を書き込んで、内蔵の漢字ROMを有効にします。(「MSX2テクニカルハンド
ブック」391ページを参照)これによって、漢字ROMを内蔵した機種でも、外付け
の漢字ROMを差すことが出来るわけです。RS−232Cにも同じような機能があり
ます。
 ところが、プログラムが“JP 0H”などで0番地に飛んだときは、内蔵漢字RO
Mが接続された状態で漢字ROMの状態を調べるルーチンにいってしまいます。すると、
MSXは内蔵漢字ROMを外付けだと思って切り離してしまいます。こうして漢字RO
Mが使えなくなるわけです。電源が投入されたときや、リセットボタンが押されたとき
は内蔵漢字ROMが切り離された状態で外付けのものがあるかどうかを調べるルーチン
に行くので問題はないのですが、プログラムがリセットをかけたいとき、すなわち0番
地ジャンプをするときには、何らかの処置を施さなくてはなりません。具体的には次の
ようにします。

●ソフトウェアがリセットをかけるときは、次のようにする。

 LD  A,00H
 OUT (F5H),A
 JP  0H

 もともとI/OのF5H番地は「MSX2テクニカルハンドブック」にも書かれてい
るようにユーザーが読み書きしてはいけないことになっているので、あまりよい方法で
はありませんが、これ以外には回避する方法がありません。ちなみに、この処理を行な
っても動作不良が直らない可能性がありますが、それはその機種ではI/OのF5H番
地の動作がほかの機種と違うためです。(もともと直接アクセスすることを考えていな
いのでこういうこともありうる)
 なお、MSX2+では、ここに0を書き込めば必ず内蔵のものが切り離されるので、
安心して0を書き込めます。

 また、MSX2+では、リセットの状態を調べることができるようになりました。こ
れには、増設されたBIOSを使います。

●MSX2+でリセットの状態を調べるには、次のようにする。

 CALL 017AH

 このとき、返ってきたAレジスタのビット7が立っていれば”JP 0H”でのリセ
ット(ソフトウェアリセット)で起動されたと分かります。このビットが立っていなけ
ればハードウェアリセットです。ソフトのほうがハードウェアリセットかソフトウェア
リセットか調べられないといろいろと不都合が生じるので、このような機能が増設され
たようです。実際には、I/OのF4H番地にリセットを調べるハードが追加されて、
このBIOSの内部では、そこを読み書きしています。
 この機能を安全に使用するためには、リセットをかけるソフトウェア側であらかじめ
ここに値を書き込んでおく必要があります。それにも、MSX2+になって新たに追加
されたBIOSを使用します。

●MSX2+でリセットするときは、次のようにする。
 CALL 017AH     ’現在のリセットの状態をAレジスタに書き込む
 OR   80H       ’リセットフラグをセットする
 CALL 017DH     ’新たな値を書き込む
 JP   0H        ’0番地ジャンプ

 ちなみに、MSX2+より前の機種ではソフトウェアリセットとハードウェアリセツ
トを区別する方法はありません。


    2.2.6 汎用I/Oポート

 MSXでは、汎用I/Oポート1にマウスを差したままPAD(0)関数を呼び出す
か、ポート2にマウスを差してPAD(4)を呼び出すと、システムが停止してしまい
ます。これを回避する方法は以下のとおりです。

●マウスをポートから抜く


    2.2.7 算術演算ルーチンMATH−PACK

 算術演算ルーチン群MATH-PACKは、ページ0及び1がメインROMであることを期待し
てプログラムされているので、DOS上から使用しようとすると動作しません。DOS
上からMATH-PACKを使用する場合は、次のルーチンを必ず組み込んでおいてください。

          ORG  406FH                          ORG  5597H
          LD   IX,406FH                GETYPR:LD   A,(0F663H)
          JP   0159H                          CP   8
          ORG  4666H                          JR   NC,DOUBLE
          LD   IX,4666H                       SUB  3
          JP   0159H                          OR   A
          ORG  4EB8H                          SCF
          LD   IX,4EB8H                       RET
          JP   0159H                   DOUBLE:SUB  3
          ORG  5439H                          OR   A
          LD   IX,5439H                       RET
          JP   0159H                          ORG  66A7H
                                              POP  AF
                                              RET


☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆ はみ出しコラム ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
 BASICのプログラム中に、0が2バイト続くようなデータを書き込むと、そこか
らあとの行はLISTが出なくなります。
 PC−98シリーズで2DDフォーマットしたディスクをMSXで読もうとすると、
うまく読めないことがあります。98とMSXでディスクを共用するときにはMSXで
フォーマットしたほうが安全です。98は通常8セクターフォーマットを、MSXは9
セクターを使うのでうまく読めないと思う人もいるかも知れませんが、実はどちらの機
種も両方のディスクを読み書きできるように設計されているので困りません。
 ディスクファイルのディレクトリーエリアのタイムスタンプの日付の部分の所を全部
0で埋めると、ディレクトリーを取ったときタイムスタンプが出なくなります。
 ディスクのFAT中にFF8H〜FFFHのいずれかの値があったら、そこがファイ
ルの終了クラスタであるということを意味します。FF7Hならばそのクラスタは不良
クラクタで、以後そのクラスタは使用されません。
 MSX,MSX2では、自分自身をページ1またはページ2のRAMに転送し、あた
かもそこがROMカートリッジであるかのように振る舞うソフトを起動すると、次に電
源を入れたときに、システムがRAMに残っている内容を見てそれがROMカートリッ
ジであると誤認してしまうことがあります。そうなった場合、何度リセットしてもその
ソフトが必ず起動してしまい、システムが起動しなくなることがあります。このような
場合は、一旦電源を切り、コンセントを外して、さらに内蔵タイマー用の電池を外して
20分程度放っておくと、RAMの内容が消失して再びシステムが起動できるようにな
ります。なお、MSX2+以降の機種は、システムが起動時にRAMに書かれた内容を
RAMと間違えないように、RAMの内容を消去するので、この異常動作は起こりませ
ん。具体的には、RAMに書かれたROM IDの内容を消去しています。
 インタースロットコールから戻ってきたとき、MSX1では割り込みは禁止されてい
ますが、MSX2以降の機種では割り込みはコール前の状態になっていることになって
います。しかし、まれにEI状態でインタースロットコールしたのにDI状態で戻って
くることがあります。これは、Z80CPUの特性によるものです。EIである必要の
あるソフトは、インタースロットコール直後にEIしておいたほうが安全です。
 MSXでは、今まで、I/Oポートは8ビットとして使用してきましたが、実は、仕
様上、16ビットI/Oポートを使用しても構わないということが判明しました。現在
は存在しませんが、後々16ビットI/Oを使用したハードが登場する可能性がありま
す。


☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆ はみ出しコラム ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
 MSX2,VRAM64Kの機種は、ほとんどの市販ソフトが動かないのでとても淋
しいのですが、日立と東芝の機械はメーカーが128K拡張サービスをやってくれてい
たので、ありがたや、市販ソフトが動くようになります。たまに、VRAM128K用
のソフトが「日立MB−H3、東芝HX−23では動作しません」などと書いているの
をみて変だな、と思った鋭い人がいるかも知れませんが、そういうわけなのです。キヤ
ノンや三洋もVRAM64Kの機械を出していましたが、こちらがバージョンアップサ
ービスをしていたかどうかはわかりません。でも、半田ごてがあれば割りと簡単に拡張
できます。
 漢字コード222FH〜227FH、2320H〜232FHまでのコード(特殊記
号)は、機種によって違う場合があるので注意してください。MZなどの機種では、全
然違う記号がここのコードに割り当てられています。
 BASICのPUT KANJIやBIOSのKNJPRTで漢字を表示する前に、
PSET命令で点を打てば、そこが始点になります。(OPEN”GRP:”で文字を
表示するときと同じです)
 メモリマッパの説明がよく分からなかったかも知れないので、改めて詳しく解説しま
す。メモリマッパ内蔵機にマッパRAM拡張カートリッジ(具体的にはDOS2カート
リッジ)を差すと、I/OのFCHからFFH番地には2つの機器が差さっていること
になります。ここで、たとえばFDHに値を書き込むと、内蔵、外付けの両方のメモリ
マッパに信号が伝わり、両方のマッパが切り換わります。もちろん、両方とも自分のス
ロットのRAMだけを切り換えます。こういうことができるという恐ろしい仕様になっ
ているのです。DOS2のマッパは標準のマッパとは仕様が違う、というような報道が
されたことがありますが、仕様自体は同じです。ただし、システムが自分用に32Kの
領域を確保することと、上に述べた2つの機器が同時に接続されている場合を予期して
プログラムを組まないと、マッパ対応にしても、DOS2では動作しません。FCH〜
FFHのI/Oから値を読むことができないのも、一度に2つの機器が接続されている
ことがあるためです。(MSXでは、1つのポートに2つの機器が接続されている場合、
そのポートから値を読むと異常な動作をする)なお、最高8つまでのマッパRAMを同
時に接続できることになっています。ちなみに、通常のコンピューターは2つの機器が
同時に同じポートに接続されている、などということは絶対にありえないように設計す
るのが普通です。1つのポートに8つまでの機器が並列につながる、というのは尋常で
はありません。
 それで思い出しましたが、DOS2の256KRAM内蔵版を2つ差すと、512K
で立ち上がります。マッパ内蔵機ではもっとRAMが増えます。
 MSX2+では、VDPがまだ前の処理を終えていないときにVDPをアクセスする
と、VDPからウェイト信号が来て、その間実行が停止します。turboRでは、8μ秒以
内の間隔でVDPをアクセスするとシステムのほうが自動的にCPUにウェイトをかけ
るようになっています。なお、これらの保護機能はMSX,MSX2には付いていませ
ん。あまりVDPを酷使すると、異常動作を起こすことがあるので、少しばかり注意が
必要です。
 アスキーのMSX−View用のソフトは、C言語を使ってアプリケーションを組も
うと思っても、MS−DOS上で動くCを使わなければ組めませんでしたが、ようやく
MSX−Cで組むためのソフトが開発されたようです。MSX−Datapack t
urboR版のユーザーには無償でディスクの書き換えサービスを行なっているようで
す。ので、興味のある方はアスキー社まで問い合わせるといいかもしれません。
 MSX−DOS2 TOOLSのファイルの内容は、出荷時期により相当変わってい
ます。これもアスキーに問い合わせないと最新版は手に入りません。
 付属サンプルプログラムディスクに収録されていて、第7部では触れられていないソ
フトの紹介をちょっとします。これはSRAMVJEという名前で、アスキー、松下の
MSX−JE用の内蔵SRAMをディスクファイルに保存するソフトです。松下の機種
は、どうもSRAMが消えやすい機種があるようなので、そういう機種をお持ちの方は
ご利用ください。名前のとおりSRAMのアスキー、松下版です。
 メインROMの0004H番地から2バイトにフォントの先頭アドレスが入っていま
す。ワークエリアのCGPNT(F91FH,3)には、フォントのあるスロット番号
と開始アドレスが入っていますが、ここを書き換えたあともとに戻すときはこの値を参
考にすると面倒がなくていいです。ワークエリアを2バイト節約することができます。
 DOSからBASICにいって、CALL KANJIで漢字ドライバを起動し、C
ALL SYSTEMでDOSに戻ります。すると、TYPEコマンドで漢字ファイル
が読めるようになります。ただ、この状態からMEDなどを起動させると暴走してしま
います。たぶんMEDがVRAMを直接いじっているのでしょう。
 アスキー社製ハードディスクインターフェイスを接続した状態でマスタースロットの
4029H番地をコールすると、ハードディスクのシッピングを行います。ソフトでシ
ッピングを行いたいときに使用してください。


   第3章 メモリマッパ


    2.3.1 メモリマッパ概要

 MSX2では、I/OポートのFCH番地からFFH番地までをメモリマッパに割り
当てています。これは、RAMをページごとに(16Kごとに)一瞬にして切り換えて
しまうという機能です。ただし、標準仕様ではないので、機種によってはこの機能がな
い場合もあります。メモリマッパがあるかどうかは、次の方法で調べられます。

 BASICから OUT 255,1 を実行する
 暴走すれば、メモリマッパがある。

 本体RAM128Kバイト以上の機種には、必ずついています。また、MSX2+で
はすべての機種についているようです。
 使い方としては、I/OのFCH番地がページ0の、FDHがページ1の、FEHが
ページ2の、FFHがページ3のRAMの切り換えに使われています。
 システムは、リセット時に、FCH番地に3を、FDHに2を、FEHに1を、FF
Hに0を書き込みます。そして、ページ0に3番の、以下、ページ1に2番、ページ2
に1番、ページ3に0番のRAMがそれぞれ割り当てられます。(RAMはすべて16
Kごと)ここで、例えばFDHに0を出力したとします。すると、ページ1のRAMが
一瞬にしてページ3と同じ0番のRAMに切り換わってしまいます。ここで、RAMの
5000H番地に値を書き込むと、同時にD000H番地の内容も書き変わってしまい
ます。先ほどの、メモリマッパがあるかどうかを調べる方法は、ページ3のRAMを切
り換えるということなので、その結果ワークエリアが消失して暴走するわけです。メモ
リマッパがない機種では、元々I/OのFFH番地には何もつながっていないので、何
も変化がなく実行が返ります。
 メインRAM64Kの機種では、16KのRAMを4個しか持っていないので、この
くらいしか利用価値がありませんが、RAM128Kの機種では、RAMの番号に0か
ら7までが指定できます。256Kの機種では0から15までが指定できます。そこで、
普段は隠れていて見えないRAMをデータエリアに使ったりすることができます。
 以下にスロット3−1にRAMがある場合について例を図示します。

  SLOT 3−1       3−1      3−1

  ページ0 RAM3番    RAM3番    RAM5番
  ページ1 RAM2番    RAM0番    RAM0番
  ページ2 RAM1番    RAM1番    RAM1番
  ページ3 RAM0番    RAM0番    RAM0番

      電源投入時    OUT 0FDH,0を    RAM128K以上の機種でさらに
               実行したとき    OUT 0FCH,5を実行したとき

 本体RAMがいくらあるのかを調べるにはひたすらRAMを切り換えながらデータを
書き込んで、ちゃんと読み込めるかどうかをチェックしていくという大変に原始的な方
法を使ってください。(MSX2+の起動時にも、この方法が使われています)FCH
〜FFHから値を読み込むという方法もありますが、この方法を使うと、DOS2カー
トリッジなどのマッパRAM拡張カートリッジを接続した場合にバス競合が起こって本
体を破壊する恐れがあるので、これらのI/Oポートから値を読み込むのは絶対に避け
てください。(バス競合は読み込むときだけ起こるので、書き込みはしても大丈夫です)

 以上がメモリマッパの使い方ですが、これではもともとメモリマッパがない機種では
マッパが使えません。また、RAMのI/Oバスが直接CPUに接続されている必要が
あります。つまり、64K増設RAMカートリッジなどを接続しても、マッパRAMは
増えないのです。そこで、DOS2カートリッジなどでは内蔵RAMに直接FCH〜F
FH番地のI/Oがつながっています。これは普通のマッパと同じ使い方もできますが、
最後の2つのRAM(RAM128Kの機種なら6番と7番、256Kの機種なら14
番と15番)は、DOS2システムが使っているので、ここをユーザープログラムが使
おうとすると暴走します。また、そうやって拡張していくと、ユーザープログラムの負
担がかなり重くなるので、DOS2には拡張BIOSでRAMを切り替える方法が用意
され、こちらを使用してマッパRAMを操作することが推奨されています。この拡張B
IOSコールを用いたマッパRAMの使い方については、次の第2節を参照してくださ
い。


    2.3.2 メモリマッパ拡張BIOS

 MSXで64Kバイトを越えるRAMを使用するときは、I/OのFCH〜FFH番
地のメモリマッパ用のI/Oを使って切り換えます。しかし、この方式を使うと、若干
の問題が出てきます。具体的には、次のようなものです。
 1.ユーザープログラムがRAMの容量を調べるのが難しい
 2.メモリマッパを使用したプログラムを二つ以上同時に使用しようとすると、使用
するセグメントが衝突して動作しないことがある
 ユーザープログラムがRAM容量を調べようとした場合、ひたすらセグメントを切り
換えながらその番号のセグメントがあるかどうか調べるという原始的な方法を取らざる
をえません。これはかなり面倒な方法であり、暴走の危険も生じます。
 そこで、マッパRAMを管理するための拡張BIOSが用意されました。これを使っ
てRAMを管理することにより、マッパを使うプログラムを同時に実行することができ
ます。また、セグメント数の計算や、プログラムごとのセグメントの割り付けもマッパ
BIOSがやってくれますので、ユーザー側の負担が大幅に軽減されます。
 現在、DOS2がこのメモリマッパ拡張BIOSを内蔵しています。DOS2では動
作するのに最低32KバイトのワークRAMを必要とするためです。DOS2上で動か
すことが明らかなソフトは、メモリマッパは直接I/O切り換えでなく、拡張BIOS
を使用してください。DOS2の利用するセグメントをうっかり使用したりすると暴走
します。

   マッパテーブルの呼び出し方法

 メモリマッパ拡張BIOSは、常にページ3に置かれ、いくつのマッパRAMが接続
されていて、いくつのセグメントが使用できるのか、という内容が保存されているマッ
パテーブルも、やはりページ3に常に存在しています。マッパテーブルがどこにあるの
かを調べるには、第2部第7章で紹介したFFCAH番地コールを使用します。FB2
0H番地のビット0を見て拡張BIOSコールが可能かどうかチェックしてから、次の
方法で調べてください。

●マッパテーブルの先頭アドレスを得る方法
 Aレジスタに0、Dレジススタに4、Eレジスタに1を入れてFFCAH番地をコー
ルする
 戻ってきたAにプライマリマッパのスロット番号(システムが使用しているメインR
AMのスロット番号)、HLにマッパテーブルの先頭アドレスが返る。DEは保存され
る。裏レジスタ及びIX,IYレジスタは破壊される
 もし、戻ってきたAの値が0だったら、メモリマッパ拡張BIOSは存在しない
 マッパテーブルの内容は以下のとおりです。


 アドレス 内容                                
  HL+0 マッパスロットのスロット番号         (複数のマッパRAMが
    +1 16KバイトRAMセグメントの総数(1〜255)     存在する場合、先頭は
    +2 未使用の16KRAMセグメントの数          プライマリマッパにな
    +3 システムに割り当てられた16KRAMセグメントの数  る。セグメントの数は
    +4 ユーザーに割り当てられた16KRAMセグメントの数  一つのマッパRAMに
  +5〜+7 現在未使用。予約                1〜255まで)
  +8〜  他のマッパのスロット番号。ない場合+8は0              

 マッパサポートルーチンを使用するには、ページ3の特定のアドレスをコールします。
その番地は不定なので、以下の方法で調べる必要があります。

●マッパサポートルーチンの先頭アドレスを得る方法
 Aに0、Dに4、Eに2を入れてFFCAH番地をコールする
 戻ってきたAにプライマリマッパの総セグメント数、Bにプライマリマッパのスロッ
ト番号、Cにプライマリマッパの未使用セグメント数、HLにジャンプテーブルの先頭
アドレスが返る。DEは保存される。裏レジスタ及びインデックスレジスタは破壊され
る
 マッパサポートルーチンはジャンプテーブルになっており、その内容は以下のとおり
です。


 アドレス エントリ名 機能                          

  HL+0H ALL_SEG   16Kのセグメントを割り付ける
    +3H FRE_SEG   16Kのセグメントを開放する
    +6H RD_SEG   セグメント番号Aの番地HLの内容を読む
    +9H WR_SEG   セグメント番号Aの番地HLにEの値を書く
    +CH CAL_SEG   インターセグメントコール(インデックスレジスタ)
    +FH CALLS    インターセグメントコール(インラインパラメーター)
   +12H PUT_PH   Hレジスタの上位2ビットのページを切り換える
   +15H GET_PH   Hレジスタの上位2ビットのページのセグメント番号を得る
   +18H PUT_P0   ページ0のセグメントを切り換える
   +1BH GET_P0   ページ0の現在のセグメント番号を得る
   +1EH PUT_P1   ページ1のセグメントを切り換える
   +21H GET_P1   ページ1の現在のセグメント番号を得る
   +24H PUT_P2   ページ2のセグメントを切り換える
   +27H GET_P2   ページ2の現在のセグメント番号を得る
   +2AH PUT_P3   何もせずに戻る
   +2DH GET_P3   ページ3の現在のセグメント番号を得る


   マッパサポートルーチンの使用方法

 プログラムはマッパRAMを使用する場合、まず、ALL_SEGを使って自分用の
セグメントを確保しなければなりません。そうしないと、他のプログラムと使用するセ
グメントが衝突して、暴走する可能性があります。割り付けには、ユーザーセグメント
として割り付ける方法と、システムセグメントとして割り当てる方法があります。ユー
ザーセグメントは、プログラムが終了すると自動的に開放されますが、システムセグメ
ントはFRE_SEGで開放しないかぎり開放されません。通常のプログラムはユーザ
ーセグメントとして割り付けるのが良いでしょう。システムセグメントは、プログラム
が終了したとき次のプログラムにデータを引き渡す場合や、後で再び起動したときのた
めに前のデータを保存しておきたい場合などに使用します。DOS2が使うワークRA
Mなどは、システムセグメントとして割り付けられています。プログラムは、解放した
セグメントを使用し続けてはなりません。
 なお、これら二つのルーチンを使用する場合、スタックはページ1またはページ3に
置かなければなりません。

●ALL_SEG (セグメントを割り付ける)
   入力 A:0ならユーザーセグメントとして割り付け
        1ならシステムセグメントとして割り付け
        B:0ならプライマリマッパに割り付ける
        0以外は複数マッパの場合の割り付け
        FxxxSSPPの形でスロット番号を指定する。bit6〜4は以下の割り付け方
        法の指定に使用する
        xxxが000のとき:指定スロットのみ割り付け
        xxxが001のとき:指定のスロット以外で割り付け
        xxxが010のとき:指定のスロットで割り付けを試み、
        失敗の場合、あれば他のスロットで割り付ける
        xxxが011のとき:指定のスロット以外で割り付けを試み、
        失敗の場合は指定のスロットで割り付ける
   出力 Cy,セットなら未使用セグメントがない
         リセットなら割り付けに成功
      Aに割り付けられたセグメント番号
      Bにマッパスロットのスロット番号(入力でB=0だった場合は0)

●FRE_SEG (セグメントを開放する)
   入力 Aに開放するセグメント番号
      B:0ならばプライマリマッパ
        0以外ならマッパのスロット番号
   出力 Cy,セットなら失敗
         リセットなら成功

 マッパRAMの値を読み書きするには、次のRD_SEG,WR_SEGを使用しま
す。動作速度を維持するために、セグメント番号が有効かどうかのチェックは行われま
せん。指定セグメントが存在するかどうかのチェックはユーザープログラムの責任にな
ります。
 マッパサポートルーチンはページ2を使用して読み書きするため、スタックをページ
2に置くことはできません。また、ページ2は読み書きするマッパスロットに切り換え
ておいてからコールしなければなりません。動作速度を維持するために、マッパサポー
トルーチンがスロット切り換えを行わないためです。AF以外のレジスタは保存されま
す。割り込みは禁止されて戻ります。HLレジスタで指定されるアドレスの上位2ビッ
トは無効です。セグメントが16Kバイト単位で扱われるからです。

●RD_SEG  (指定セグメントから値を読む)
   入力 Aに読み出すセグメント番号
      HLにセグメント内のアドレス(上位2ビットは無効)
   出力 Aに指定アドレスの値
 レジスタ F?

●WR_SEG  (指定セグメントに値を書く)
   入力 Aに書き込むセグメント番号
      HLにセグメント内のアドレス(上位2ビットは無効)
   出力 なし
 レジスタ AF

 セグメント内に機械語プログラムを置いて、ちょうどMSXシステムのインタースロ
ットコールのように、インターセグメントコールすることができます。使い方もインタ
ースロットコールと似ています。インターセグメントコールには、以下に挙げるCAL
_SEG,CALLSの二つのルーチンが用意されています。
 これらのルーチンを使用する場合、指定セグメントが存在するかどうかのチェックは
行われません。これは、動作速度を維持するためです。また、コールする前に指定ペー
ジを使用するマッパRAMのスロットに切り換えておくのもユーザープログラムの責任
になります。
 ページ3へのインターセグメントコールは実行することができません。もし指定した
場合、単に指定アドレスがコールされます。ページ0をコールする場合割り込みルーチ
ンなどのエントリーがあるので、コールは慎重に行う必要があります。
 この二つのルーチンは、割り込みの状態を変化させません。従って、コールされたル
ーチンが割り込みの状態を変化させない限り、呼び出し時と同じ状態で戻ります。
 この二つのルーチンは、裏レジスタ及びインデックスレジスタを内部で使用します。
従って、これらのレジスタを使ってコール先にパラメーターを受け渡すことはできませ
ん。

●CAL_SEG (インターセグメントコール)
   入力 IYの上位8ビットでセグメント番号を指定
      IXでコールするアドレスを指定(上位2ビットでページを指定)
      AF,BC,DE,HLがコールされたルーチンに渡される
      裏レジスタ及びインデックスレジスタは破壊される
   出力 AF,BC,DE,HL,IX,IYがコールされたルーチンから返される
      裏レジスタは破壊される

●CALLS    (インターセグメントコール・インラインパラメーター)
   入力 AF,BC,DE,HLがコールされたルーチンに渡される
      裏レジスタ及びインデックスレジスタは破壊される
 コール手順: CALL CALLS
        DB   セグメント番号
        DW   コールするアドレス
   出力 AF,BC,DE,HL,IX,IYがコールされたルーチンから返される
      裏レジスタは破壊される

 上に挙げたルーチンの他、直接セグメントの状態を切り換えてしまうルーチンが用意
されています。連続してセグメントを読み書きしたり、他のセグメントにあるデータを
転送せずにそのまま使用する場合などに利用します。これらのルーチンは高速なのでプ
ログラムの効率に影響することはありません。(と、アスキーは言っている)
 これらの直接セグメント切り換えルーチン(ダイレクトページングルーチン)は、指
定されたセグメントが存在するかどうかのチェックは行いません。指定セグメントが存
在するかどうかのチェックはユーザープログラムの責任になります。
 PUTルーチンは、セグメントを切り換え、同時にメモリ上に書き込んだ値を保存し
ます。GETルーチンは、現在のマッパセグメントの状態を返すルーチンで、PUTル
ーチンでメモリ上に記録された値が返され、I/Oから値を読むことはしません。これ
は、マッパRAMが複数存在する場合、I/Oから値を読むことによってバス競合が起
こる可能性があるためです。従って、DOS2上で動くプログラムや、メモリマッパ拡
張BIOSを使用しているプログラムは、I/OのFCH〜FFHを直接使用してセグ
メントを切り換えてはなりません。
 PUT_P3ルーチンは、存在はしますが、実際にはマッパを切り換えずに、何もせ
ずに戻ります。これは、ページ3を切り換えると暴走するためです。
 プログラムはこれらのルーチンでセグメントを切り換える前に、現在のセグメントの
状態を保存しておき、プログラム終了時には必ず元の状態に戻す必要があります。プロ
グラムが起動したときに、セグメントの状態が常に同じとは限らないからです。
 PUT_PH,GET_PHは、HLレジスタに何らかのアドレスを入れ、その上位
2ビットでページを指定するとき有用なルーチンです。

●PUT_Pn  (ページnのセグメントを切り換える)
   入力 nはページ番号(0〜3)
      Aにセグメント番号
   出力 なし
 レジスタ なし

●GET_Pn  (ページnのセグメントの状態を得る)
   入力 nはページ番号(0〜3)
   出力 Aにセグメント番号
 レジスタ なし

●PUT_PH  (セグメント切り換え・Hの上位2ビットでページを指定)
   入力 Hの上位2ビットでページを指定
      Aにセグメント番号
   出力 なし
 レジスタ なし

●GET_PH  (セグメントの状態を得る・Hの上位2ビットでページを指定)
   入力 Hの上位2ビットでページを指定(ページ3を指定しても無効になる)
   出力 Aにセグメント番号
 レジスタ なし

 DOS2カートリッジに搭載されているものと、turboRに搭載されているものでは、
マッパBIOSの動作が若干異なります。例えば、DOS2カートリッジ版では最も容
量が大きくて最もスロット番号の若いマッパがプライマリマッパになりますが、turboR
では必ず内蔵RAMがプライマリマッパになります。


   第4章 漢字ROM

 ここでは、主に、漢字ROMのアクセスの仕方について説明します。


    2.4.1 漢字ROM入出力

 MSXで漢字ROMを操作するときは、直接I/OのD8HからDBHまでをアクセ
スします。
 漢字のフォント・データを読みだすには、漢字コードと呼ばれる12ビットのデータ
を使います。これは、JISコードや区点コードとは別物ですので、まず目的の漢字コ
ードを求める必要があります。

●漢字コードの求め方
 漢字のJISコードの上位バイトから32を引いた値を区、下位バイトから32を引
いた値を点と呼びます。(これが、いわゆる区点コードです)
 第一水準の場合、区が15以下なら、(区*96+点)が漢字コードになります。区
が16以上なら、(区*96+点−512)が漢字コードになります。
 第二水準の場合、((区−48)*96+点)が漢字コードになります。

 次に、求めた漢字コードを元にI/Oポートをアクセスします。第一水準と第二水準
で読み出し方が違いますので、順に説明しましょう。

●第一水準漢字を読みだす場合
 I/OポートのD8H番地に漢字コードの下位6ビットを、D9H番地に上位6ビッ
トを出力します。そして、D9H番地から32回連続して値を読み込むと、それがその
漢字のフォントになります。

●第二水準の場合は、I/OポートのDAH番地に漢字コードの下位6ビットを、DB
H番地に上位6ビットを出力します。そして、DBH番地から連続して32回読み込み
ます。これが漢字フォントになります。

 フォントの並びは、まず左上に8バイト並べて、次に右上に8バイト並べます。次に
左下に8バイト、右下に8バイトという順番になります。

 データ列          フォント
 1番目           1番目          9番目
  :    A        :            :
 9番目            :   A   B    :
  :    B       8番目         16番目
17番目          17番目         25番目
  :    C        :            :
25番目            :   C   D    :
  :    D      24番目         32番目
32番目

 MSXでは、通常、I/Oポートへの直接入出力は禁じられています。しかし、漢字
ROMではほかに方法がありません。MSX2になってから追加されたBASICのP
UT KANJI命令やBIOSのKNJPRTは、第一水準しかサポートしていない
上に、(MSX2+では第二水準もサポートしています)画面に表示するだけなので、
漢字フォントを直接いじりたいとき、例えば、16*16ドットのフォントを12*1
6ドットに圧縮したいときや、漢字フォントをプリンターに直接ビットイメージ印字し
たいときに使えません。また、スクリーン2や4のモードをサポートしていません。そ
れにMSX1では、漢字ROMをアクセスするためのBIOSが用意されていません。
そんなわけで、漢字ROMのアクセスについては、I/Oポートを直接操作しているわ
けです。
 なお、御存知の方も多いと思いますが、漢字ROMの空白部分をアクセスすると、空
白ではなく、関係ない文字のフォントが返ってきます。全角のスペースはJISコード
の2121Hを使うようにしてください。半角文字については、JISコードの202
1H〜207EH、2921H〜295FHのフォントの左半分だけを使います。ただ
し、これらの半角フォントは漢字ドライバやPUT KANJI命令ではサポートして
いません。


    2.4.2  漢字ROMの存在の有無

 漢字ROMがないのに漢字入出力を行なおうとすると、画面に豆腐(16*16ドッ
トの四角のこと)が現われてとても悲しい目に合います。そこで、漢字ROMの存在の
有無を確認することが必要になってきます。
 
●第一水準漢字ROMが存在するかどうかを確かめる方法
 漢字ROMのJISコード2140H(1区32点)のフォントの最初の8バイトは、
必ず、順に00H,40H,20H,10H,08H,04H,02H,01Hになっ
ています。そこで、このコードのフォントを読みだして、最初の8バイトがこれに一致
すれば、第一水準の漢字ROMが存在することになります。

●第二水準漢字ROMの存在の有無
 漢字ROMのJISコード737EH(83区94点)のフォントを読みだして、最
初の8バイトの値の合計を256で割った余りが149(95H)ならば、第二水準漢
字ROMが存在します。

 ソフトウェアでは、必ず漢字ROMの存在の有無を調べ、漢字ROMがない機種でも
使えるように、半角文字のメッセージを用意しておきましょう。第二水準漢字ROMが
ある機種では「國」とか「炬燵」とか「靨」とか難しい漢字を山のように使い、ない機
種では「国」とか「こたつ」とか表示するソフトも考えられますが、今のところ見たこ
とはありません。


    2.4.3  シフトJISコード

 MSXでは、漢字ファイルはシフトJISコード(マイクロソフト漢字コード)を使
います。これは、MS−DOSでは漢字ファイルはマイクロソフト漢字コードで扱うこ
とになっているので、それと同じフォーマットを使っているMSXでも、同じコードを
使っているわけです。
 シフトJISコードでは、漢字開始、終了のコードがなく、半角文字と全角の漢字を
一緒に使えるようになっています。
 ここでは、JISコードからシフトJISコードに変換するアルゴリズムを紹介しま
す。

●JISコードからシフトJISコードへの変換
 JISコードの上位バイトをJIH、下位バイトをJILとします。シフトJISコ
ードの上位バイトをSJH、下位バイトをSJLとします。

 1.JIHが5EH以下だったならば、 INT((JIH−1)/2+71H) が
   SJHになります。そうでなかったら、INT((JIH−1)/2+B1H)
   がSJHになります。

 2.JIHが2で割りきれるなら、 (JIL+7EH) がSJLになります。そう
   でないときには、まず、 (JIL+1FH) をSJLにします。そして、この
   SJLが7FH以上だったら、さらにSJLに1を足します。7FHより小さか
   ったらそのままです。

●シフトJISからJISへの変換

 1.SJHがA0Hより小さかったら、SJHから71Hを引いたものをHとします。
   A0H以上だったら、SJHからB1Hを引いたものをHとします。そして、ど
   ちらの場合でも、 H*2+1 をあらためてHに代入します。

 2.SJLが7FHより大きかったら、 SJL−1 を、そうでなかったらSJLを
   Lとします。次に、Lが9EHより小さかったら、 L−1FH をLとします。
   Lが9EH以上だったならば、L−7DH をLにして、H+1をHにします。

 3.Hの値がJISコードの上位バイトに、Lの値が下位バイトになります。


※個人的以外の使用および無断転載を禁止します。

Copyright(C) 1996 by ASCAT All rights reserved.

ホームページに戻る 目次に戻る