MSX C Magazine

 なんか、2つの雑誌が合体したようなタイトルですが、ここでは、MSXのC言語に関する情報を提供します。

[なぜ、C言語か]

 なぜ、本ページではC言語を取り上げるのでしょうか?
 MSXが商業ベースから離れて、はや数年、他機種も含めて、BASICの解説書はもはや店先でもあまり見かけなくなってきています。このため、今からMSX標準のBASICを勉強しようにも、参考にできるものが少なくなってきています。
 その反面、MSXが商業ベースから離れていることから、自分でプログラミングをするなり音楽データを作ったり、CG描いたりと自分で作ることを楽しめなければができなければ、MSXを使うこと、そして楽しむことができなくなってきているのは言うまでもありません。
 そこで、今からプログラムを作って楽しみたいと思った人の為にC言語の登場です。
 C言語は他機種でも主流なので、解説書も多数出ており、自分で勉強することも十分できます。その上、他機種からの移植の可能性も広がります。
 また、C言語は高級言語としての分かりやすい記述法に加えて、メモリへのポインタを利用した直接アクセスや、機械語プログラムとのライブラリを利用したシームレスな連携を利用してMSXのハードウェアに密着したプログラミングができるうえ、コンパイラー言語なのでBASICより実行速度も速く、MSXの能力を十二分に発揮することができます。
 このことから、本ページでは、MSXのプログラムをC言語で組むための必要な情報を自分の知っている限りで提供します。
 本ページがMSXのプログラマーの役に立てたら幸いです。

[目次]

御意見、御感想、御希望等ありましたら何でもE-Mailでどうぞ

This page is presented by Tatsuhiko Syoji(rxk16664@nifty.ne.jp)

Tatsu's MSX情報局目次に戻る

[C言語徹底比較]

 このコーナーでは、本コーナーを読むのに必要な、MSXのC言語について知って頂くと共に、現在手に入るMSXのC言語について、比較する事で、自分に合ったC言語の選択に役立つ事を目標にしております。

 現在手に入るMSX用のC言語としては、MSX-C Version 1.1/1.2(以下MSX-C)、SMALL-C Version 3.21(以下SMALL-C)、HI-TECH C Version 3.09(以下HI-TECH C)、Aztec-Cといった物が挙げられます。

比較1 価格及び入手性
 とりあえず、手に入らない事には、どうしようもないので、価格及び入手性について、書く事にします。
HI-TECH C:フリーソフトとして、パソコン通信上や埼玉大FTP,FUNETで手に入ります。使うのに必要な物はアセンブラ、リンカ、ライブラリアン、デバッガ、クロスリファレンサと一通り入っているので、他に何も手に入れる必要はありません。
SMALL-C:フリーソフトとして、パソコン通信上で手に入ります。アセンブラ、リンカはM80,L80が望ましいですが、フリーの互換アセンブラ、リンカを使う事で、その分のコストを減らす事が出来ます。MSXのコーナーで見つからない場合は、PC-88などZ80を使っている他のマシンのコーナーで探してみるとよいと思います。(山形大工学部のでんでんネットがその例)
MSX-C:昔はソフトベンダーTAKERU で売られていましたが、ソフトベンダーTAKERUが終了した今となっては合法的に手に入れる手段が無いと思います。Internet上には存在するようですが、合法性には疑問が残ります。
ちなみに、他に、M80,L80の入ったMSX-DOS(2) TOOLSも必要になります。
Aztec-C:Internet上で手に入ります。著作権に関するドキュメントが無いので、合法性には疑問が残ります。

比較2 インストール
 C言語の使い勝手を決める上で、インストールは出来れば、楽な方がいい。という意味で、次は、インストールについて書きます。
 ここで、一番楽なのはAztec-Cです。アーカイブをまっさらなディスクに解凍するだけで実行用ディスクになるのですから。
 MSX-Cもインストールは比較的楽な部類に入ります。必要なファイルを単にコピーするだけで、実行用ディスクが出来てしまいます。MSX-C Libraryのインストール用バッチファイルを使うと更に楽に出来てしまいます。
 SMALL-CはCP/Mのソフトである関係上、拡張子SUBのファイルを拡張子BATにリネームし、$(数字)を%(数字)に書き換える必要がありますが、大した作業ではありません。
 一番難しいのはHI-TECH Cです。MSXで使う場合、パッチを当てたりするなど、多くの手順が必要になります。また、ファイル数多く、ディスク容量を食うので、FDDベースの場合、使い易い構成にするのに苦労するかもしれません。

比較3 互換性
 C言語は、他の機種でも広く使われており、他機種のプログラムを移植する際には、互換性に優れている方が移植しやすくなります。C言語では、ANSI規格が標準となっており、これに従っている方が良いでしょう。ここでは、ANSI規格への対応度など、互換性について、見てみましょう。
 ここで、最も強力な互換性を持つのは、HI-TECH Cです。ヘッダファイルの構成、関数宣言と関数呼出チェック機構、long型や浮動小数点演算のサポート等各所にANSI Cとの互換性があります。
 MSX-CはANSI Cには対応しておらず、関数呼出チェック機構、long型や浮動小数点演算のサポート(MSX-C Libraryの関数と構造体でサポート)と言ったところが独自であり、関数の引数の自動変換が行われないといった違いがありますが、他は一般的な書き方が通ります。Ver.1.1では、やや、関数の数が少ないのが気にかかるが、自分で書く事が出来るので(現に私はそうした)あまり、気にはならないでしょう。
 SMALL-Cは特殊で、関数のプロトタイプ宣言は通るものの、関数呼出チェック機構、long型や浮動小数点演算の非サポート、unsignedが無い事や、関数の仕様の違いが多い事など、互換性は低く、その互換性の低さが、ライブラリによるフォローを更に難しくしていると言えます。
 Aztec-Cは全体的に関数の数が少なく、関数レベルでの互換性が低い上、ANSI C非対応と言う弱点があります。ただ、数学関連の関数に強く、double型が使えるという特徴があります。

比較4 MSX用関数ライブラリ
 C言語は、移植性の観点から、どのコンパイラでも機種依存するライブラリは持たない事になっています。しかし、C言語の記述性と高速性から、MSXの機能を生かしたプログラムを組みたいと思うのは当然の理です。(MSX-C Libraryのマニュアルにもこの辺は書いてあります。)しかし、MSXの機能を生かすライブラリを一から組む事は大変な労力を要します。そこで、ここではMSX用関数ライブラリについて取り上げてみましょう。
 MSX-CにはMSX-C Libraryという拡張ライブラリが用意されていて、BASICライクなグラフィック、BIOSコール、浮動小数点演算、UNIX互換CURSESライブラリといった物がマニュアルと共に提供されます。その上、雑誌記事などによるライブラリを含めるとライブラリ量では最も充実しているのではないでしょうか。
 HI-TECH CにはMSX-C LibraryのBASICライクなグラフィック、BIOSコールライブラリが用意されますが、関数の仕様や使い方のリファレンスマニュアルが無い為、MSX-FANの1995年6月号を見る事になるでしょう。  SMALL-CにはこれらのC言語とは異なるライブラリが用意されているようですが、私はどんなものかは知りません。情報を下さい。
 Aztec-Cには特にMSX用関数ライブラリは存在しないので、自作するしかありませんが、アセンブラでの関数の書き方について書かれたマニュアルが無い事などから、MSXに特化したプログラムを組むのはC言語、アセンブラ、MSXのハードウェアに精通しないと厳しいでしょう。

比較5 各コンパイラ特有の特徴
HI-TECH C:何といっても、
The HI-TECH Z80 CP/M C compiler V3.09 is provided free of charge for any use,private or commercial strictly as-is.
とあるように同人ソフトなど、売る為のソフトを作る事が出来ます。これは他のC言語では出来ない事です。(MSX-Cでは特殊な手続きが必要であり、SMALL-Cでは全く認められない)それだけでも相当大きいですね。更に、CP/M用のC言語という事で、他の機種で、CP/Mエミュレータを使ったりしてクロス開発を考える人にとっては有利と言えます。
MSX-C:まず、何といっても、MSXで最も一般的に使われてきたという実績が特徴と言えます。そのため、外部ライブラリや雑誌記事など、周辺が充実しており、学習用にもってこいと言えます。また、アセンブラへ引数を渡す際、パラメータ数を固定にすると、レジスタ経由で引数が渡されるので、関数へのポインタを使ったシステムルーチンの呼び出し(BASIC環境で動くプログラムを書く時に良く使われる)やアセンブラで関数を書く事が楽になります。
SMALL-C:本来、CP/M用のC言語なので、CP/M用ライブラリがあり、クロスプラットフォームでの動作を考える人にとっては便利なのではないでしょうか。また、コンパイラはパッチ無しでCP/Mでも動くので、他の機種で、CP/Mエミュレータを使ったりしてクロス開発を考える人にとって有利ではないでしょうか。
Aztec-C:かなり古いC言語のせいか(ヘッダーファイルを見ると1984年と書いてある)、アセンブラがアセンブルできるニーモニックが8080用だけだったり、MSX-DOS1では動作するけど、MSX-DOS2で動作しないといった不都合があるようです。特に、MSX-DOS2非対応と言う事で、turbo Rの高速モードやMSX-DOS2のRAMディスク、階層化ディレクトリに対応しないという事は、コンパイルの高速化の観点からは致命的ともいえるかもしれません。

比較6 性能に関して
 いくら、うわべの性能が優れていても、コンパイルや、実行ファイルのスピード、サイズなどの性能が優れていないと使い物にはなりません。そこで、今回は、下のサンプルプログラムを各コンパイラの標準状態、Z80CPU、MSX-DOS1、FDDベースでコンパイルする事で特性について書いてみたいと思います。

#include	<stdio.h>
int main(int argc,char *argv[])
{
	printf("Welcome to C Language world !!\n");

	return 0;
}

 正確には計っていませんが、コンパイルのスピードはSMALL-Cが一番速かったです。
 何といっても、コンパイラ・M80でのアセンブル・L80でのリンクと言う3パスなので、起動時間や中間ファイルをセーブする時間が短くて済むのが特徴です。
 続くのがAztec-Cでコンパイラ・アセンブラ・リンカの3パスでコンパイラが構成されている事から、妥当な線です。
 その次はMSX-C Ver.1.1で、コンパイラが2パスと1つのチェッカー、アセンブル、リンクを通している割にはAztec-Cにも割合と近く、プログラムががんばっている印象を受けました。
 一番遅いのがHI-TECH Cで、プリプロセッサ、構文解析、コード生成とコンパイラだけで3つのパスを通している上、アセンブル、リンクを通すというパスの多い構成になっている上、リンカが遅く感じました。速度的には、MSX-Cとの間にも大きな差が開きました。高度な事をやっている分、仕方ないのでしょうが。
実行ファイルの大きさでは、SMALL-CとHI-TECH Cが短いプログラムのせいか、4,224バイトで並んでおり、MSX-C Ver.1.1は6,784バイトと、やや大きくなってしまいました。
 MSX-C Ver.1.1のスタートアップモジュールはDOS1でリダイレクトをソフトウェア的に実現するプログラムをデフォルトで含んでいるので、その分がマイナスになっているのでしょうが、やや、サイズ効率が悪い気がします。
 各コンパイラとも最適化の手段は色々ともっているので、それらを使うとまた違った結果になるかもしれません。
 (MSX-Cは最適化のサイズ重視とスピード重視の切替、関数の再帰呼出をしないようにする。SMALL-Cはサイズ重視の最適化。HI-TECH Cは専用のアセンブラソースファイルオプティマイザ(何と、このサンプルでもファイルサイズが小さくなった。)を起動する。)
 ただ、コンパイル時間に関しては、動作環境が絡むので、(CP/Mエミュレータ+486SX-33Mhzマシンでも、HDDやRAMディスク、ディスクキャッシュを使うとHI-TECH Cが相当速く動く!)ので、環境次第で、かなり変わります。

結論
 コンパイルが遅いと言う弱点はありますが、機能面を考えるとHI-TECH Cが現段階では一番薦められます。インストールの難しさに関しても、拙作のHI-TECH C Easy Patcherを使う事で、簡単になってきました。ANSI C対応なので、市販の解説書で勉強できるのも大きな利点です。
合法的に手に入るなら、MSX-Cを選ぶのがもっとも間違いの無い選択になります。MSX-FANの記事などで勉強出来る上、使い勝手のバランスが良いのが特徴です。が、現状では手に合法的には手に入れづらいのがマイナスです。
SMALL-Cは機能的には見るべき物がありませんが、ディスクの消費が少ない、ただで手に入る、コンパイルが速い、モジュール構成が単純と言ったところから、金はないが、C言語を使いたい、でも面倒なのはイヤという金や労力をケチりたいひとにお勧めします。
Aztec-CはInternetに存在するアーカイブは合法性に難がある上、ドキュメントが無い、癖が多いなど、MSXで利用するにはあまり勧められません。

参考文献
MSX-FAN1995年6月号、HI-TECH Cのドキュメントファイル、1995TAKERU名作文庫ソフト全カタログ


[MSX-C部屋]


MSX-Cの正体見たり!!

MSX-CとLSI Cの両方を使った事のある人は分かると思いますが、この2つはモジュール構成やファイル名、表示など結構似ているなと思いますよね。
 実は、これ、CF.COMかCG.COMをダンプすると分かることですが、
Copyright (C) 1985 by LSI JAPAN Co., Ltd.
 とあるように、LSI C-80セルフ版の OEM供給版を MSX-DOSに合わせて改造した物であるという事が分かります。これで、何故、MSX-C がLSI C に似ているかという疑問が解けましたね。

入出力について

  MSX-DOSの機能を利用した高水準/低水準入出力はシステムコールに全てbdos(),bdosh()関数を利用しているので、この2つの関数を差し替えると、様々なことが出来るようになります。例えば、 BASIC環境でのファイル入出力を高水準/低水準入出力関数で行えるようにしたり、自前で、高水準/低水準入出力関数による入出力のハードウェアエラー処理ルーチンを書いたりといった事ができます。ちなみに、ハードウェアエラー処理ルーチンはアドレス4000Hから7FFFH(ページ1)には置けないので、リンク時にL80の/Pオプションを使う等して配置を工夫しましょう。

MSX-C on MSX-BASIC

 マニュアルには、Disk-BASICで動くプログラムを書く方法がありますが、ここでは、もう少し実戦的な方法を書こうと思います。
1.引数の受け取り方
 C言語だけの時は、引数は文字列型しか扱えないので、その他の型を扱うときにはアセンブラで、Cのルーチンを呼び出すプログラムを書き、 BASICではCのルーチンを呼び出すプログラムを USR関数で呼び出すようにします。この場合、どの型でも統一的に呼び出せる様にすると使い回しが効いて便利だと思います。
 サンプルをここに示します。

アセンブラ
	.z80
	extrn bmain@
bk@::
	cp 3	;文字列以外の時はhlとdeを交換して2番目の引数で扱えるようにする
	jp	z,p2
	ex	de,hl
p2:	call	bmain@
	ret
	end


VOID bmain(type,ptr)
char type; /* 引数の型を示す */
char *ptr; /* 引数へのポインタ */
{
	/* ここでやりたい処理を書く */
}

BASIC
モジュールがD000H番地以降にある場合
10 clear ,&hcfff:'ロードエリア確保
20 'アセンブラとCで書かれたルーチンをここでロードする。
30 defusr=&hd000:u=usr(0):'usrはシンボルbk@のアドレス
40 end

2.biosコール
 BASIC環境でも MSX-C Libraryの関数は使えますが(ページ0のインタースロットコールで異常が出なければかな?少なくとも家の2+では大丈夫だった。)、 BASICではBIOS-ROMが表に出ているのでcall()やcalla() といった関数を使ってコールするなり、関数へのポインタを使ってBIOSを直接コールしたほうがインタースロットコールをしないで済むので効率が上がります。

3.メモリについて
  BASIC環境ではスタックがあまり大きくない上、使いすぎると、 BASICプログラムを破壊する危険性が有るのでauto変数やmalloc()関数はあまり使わないほうが良いかもしれません。

4.ディスク入出力について
 前にも述べたように、bdos(),bdosh()関数の2つの関数を差し替える事で、 BASICでも MSX-Cの関数が使えるようになります。 BASICではリダイレクトなどは考えなくてもよいので低水準入出力の方が使い易いと思います。

クロス開発の勧め

 クロス開発と行ってもここでいうのは、特殊な器材を使うものではありません(もちろん、使ってもいいけど)。例えば、ソースファイルを他機種のエディタで書いてディスクを使って MSXに持っていくとか(EOFには気をつけよう)、 MSX-Cのプリプロセッサは貧弱なので、プリプロセッサの処理はLSI C のCPP.EXE を使うとかといったことです。使えるものは何でも使ってしまいましょう。
 ちなみに、MSX-DOS TOOLS(DOS2 TOOLSではない!)のM80.COM,L80.COMはCP/Mエミュレーターでも動くので、最近のMS-DOSマシンなら、ハードディスクやRAMディスク、ディスクキャッシュを使う事で、本物のMSXより高速なアセンブル、リンクが実現出来るのではないでしょうか?

ごった煮ライブラリ計画?

 MSX-Cのライブラリが物足りない、MSX-C Libraryは買う気がしない、等の症状に陥ったら(そうでなくとも良いが)色々なところからライブラリをかき集めて自分の物にしてしまいましょう。当たり前と言えば、当たり前だが。例えば、MSX-C Ver.1.1 のサンプルq.com に使われた関数やMSX・FAN に掲載されたRUMANIA(伊藤直輝作)のアセンブラソースファイルなどソースファイルのあるものはチェックして、汎用性のあるものはライブラリとしてまとめましょう。そうすると、案外使えるライブラリが出来るかもしれません。ただ、前提となるものは持っている必要があるでしょう。こういう作業にはマルチファイル・テキストエディタが欠かせません。

MSX-C Ver.1.1の内部関数について

 MSX-C Ver.1.1のCLIB.REL にはライブラリが呼び出す内部関数というマニュアルには載っていない関数があります。その多くはライブラリが呼び出して意味を為すが、単体では使う意味が無い物です。しかし、一部は、単体でも使いみちが有ると思われるのでそういった関数について分かる範囲で説明しようと思います。

BOOL _isfn(c)
char c;
 文字c がファイル名として使える文字の時、真を返し、そうでない時偽を返します。

STATUS _chkdrv(c)
char c;
 c の番号のドライブ(A:は1、H:が8)がオンラインの時OKを、オフラインの時ERROR を返します。ちなみに、0はカレントドライブとして見られているらしく、必ずOKを返します。

STATUS _seek(fd,off,mode)
FD fd;
int off;
char mode;
 低水準入出力のファイルポインタをシークします。ファイルハンドルfdで示されたファイルのファイルポインタをmodeに従ってoff の分だけ移動します。
 modeは0の時、ファイルの先頭から、1の時現在の位置から、2の時ファイルの終わりから移動を始めます。
 off がint 型であることから一度に移動できる移動量が小さいのが難点です。他の処理系では、lseek() という名前の関数に相当します。MSX-Magagine1991年9月号にこの情報が有ることから、知っている人は多いと思います。

VOID _swp(width,x,y)
size_t width;
char *x;
char *y;
 xで示される所からwidthバイトのメモリの内容をyで示される所からwidthバイトのメモリの内容と交換します。

char getch()
 MSX-DOS のファンクション08Hを使い、1文字コンソールから入力します。その際、エコーバックは行いません。この関数と次のgetche()関数は先頭に _が付く訳でもなく、stdio.h に型の宣言も有るので、一般の関数と同等の扱いにもかかわらず、何故かマニュアルには使い方が書いてないという不幸な(^^)関数です。更に、不幸なことにこのgetch() 関数はMSX-C LibraryのCURSESにも同じ名前の機能の異なる関数が有るので、MSX-C Libraryと一緒には使えません。ただ、getch() 関数は、マニュアルの71頁に名前だけは登場しています。これで、MSX-C Version 1.1のマニュアルの謎が解けますね(^^)。

char getche()
 MSX-DOS のファンクション01Hを使い、1文字コンソールから入力します。エコーバックを行います。getch() 関数と比べると影が薄いなぁ。

char *_skipsp(s)
char *s;

 文字列sのスペース及び、タブを除いた先頭を返します。

 これらの関数のFPC.COM用の型情報はマニュアルに有る関数同様、LIB.TCOの中に入っています。そのため、型の宣言をしておけば、自由に利用することができます。_seek()とかは普通マニュアルに書いてあるべきだと思うのですが???

MSX-C Libraryの内部関数について

 MSX-C LibraryのMLIB.REL にもライブラリが呼び出す内部関数というマニュアルには載っていない関数があります。その多くはライブラリが呼び出して意味を為すが、単体では使う意味が無い物です。しかし、一部は、単体でも使いみちが有ると思われます。他にもマニュアルに無い関数も有るので、そういった関数について分かる範囲で説明しようと思います。

VOID offcur();
VOID oncur();

それぞれ、カーソルをオフ/オンする為の関数です。CURSESの中に有る関数ですが、ヘッダファイルでは宣言されてないので、自分で宣言してあげましょう。

VOID memmove(d, s, n)
char *d;
char *s;
unsigned n;

 メモリのs番地からnバイトのメモリの内容を d番地に転送します。sとdの領域が重なっていても正しくコピーされます。他の処理系でも割と一般的な関数ですがMSX−CシリーズではLibraryのCURSES.Hの中でひっそりと宣言されて入っていました。何で、こんな所にいるのでしょうか?この関数は汎用性が割と高いと思われるので標準関数に有るべきだと私は思います。なにはともあれ、こういう汎用性の有る関数はガンガン使ってあげましょう。
 さらに、mem うんたらの関数について言えば、MSX−CVer.1.1のmovmem()関数は引数sourceとdestの順番が入れ代わったmemcpy()関数としても使えて、stdio.hできちんと宣言されていて、FPC.COM 用の型情報も有るという事もマニュアルには書いてありません。setmem()関数と引数countとbyteを交換した、memset()関数も同様です。アセンブラで書かれたソースファイルを見るとライブラリの開発者のANSI規格との兼合いに関する苦悩が見え隠れしています。Ver.1.2では正式に存在していることから、開発者がANSI規格を知っていて、MSX-C Ver.1.1をどこまで使い込んでいるかユーザーに挑戦した跡が伺えます。
 getch(),getche()両関数といい、mem うんたらの関数といい、マニュアルって、結構当てになりませんね(^^;)。無いよりはマシだけど。
 これらの関数のFPC.COM用の型情報はマニュアルに有る関数同様、MLIB.TCO の中に入っています。そのため、型の宣言をしておけば、自由に利用することができます。

非互換性について

 多くの人が直面していると思いますが、MSX-Cのgets(),puts()関数は他の処理系の同名関数と書式、振る舞いが異なります。そこで、他の処理系の同名関数と書式、振る舞いを同じにしたgets(),puts()関数を作ってリンク時に乗っ取るなり、標準ライブラリを差し替えるなりした方が良いかもしれません。ちなみに、私はfgets()関数は好きではありません。

MSX-C LibraryのMSX規格違反について

 MSX-C LibraryのグラフィックライブラリはVDPの読み込み用ポートと書き込み用のポートのアドレスが同じ物と決め打ちして片方のみを調べて使っています(さて、どっちでしょう?)。じっさい、VDPの読み込み用ポートと書き込み用のポートのアドレスが違うマシンは聞いたことが無いから実害はないのでしょうが、規格を決めたアスキー社のライブラリーがこのようなことで良いのでしょうか?まあ、いやな人は規格に適合した上で、互換性を持つginit()関数を書いて、自分の作る関数ではきちんと規格を守るようにすれば良いのではないでしょうか?(私はそうしている。)

ライブラリの乗っ取りについて

 リンカのL80 はコマンドラインの左側から順にライブラリ関数をリンクしますが、同名のライブラリ関数が複数有る場合は最も左側のファイルに有るほうがリンクされます。
例)alib.rel,blib.relにtest関数が有るとき
l80 user,alib/s,blib/s,user/n/y/e
 この場合user.comにはalib.relのtest関数がリンクされます。
 この性質を使うと、clib.relやmlib.relにある標準(的な)関数を自作の関数にすげ替える事ができます。MSX-C Ver.1.1 では全てのファイル入出力はbdos,bdoshの2つの関数が最終的には入出力を行うので、自作の関数にすげ替えて、ハードウェアエラーの処理を加えるといった用途が考えられます。

グローバル変数へのアセンブラによるアクセスのしかた


グローバル変数は、アセンブラからは関数名と同じ形式(のマニュアル参照)のシンボルとして見えるので、
int _glo1;
というCのグローバル変数は、アセンブラでは、

public @glo1@
ld hl,2
...
ld (@glo1@),hl
 というような感じでアクセスできます。

ちなみに、
int _glo1;
int _GLO1;
というような、大文字小文字を区別しないと同名になるグローバル変数は、アセンブラソースへの変換では何の配慮もなく展開されるので(下の例参照)、

例)
          dseg
@glo1@:   defs 2
@GLO1@:   defs 2

 M80とL80を使う限りではグローバル変数と関数名は大文字、小文字の区別が無い6文字までに制限されることになります。(悪いのはM80とL80だよ)グローバル変数、関数の名前と長さには注意しましょう。ちなみに、MSX-Cでは、関数名に関しては、ライブラリの作成側がマクロなどを使って、M80とL80には6文字までの関数名を、Cのソースを書く側には制限の無い関数名を提供しています。(ヘッダファイルを見てみましょう。)ライブラリを作る側にとっては、何とも面倒くさい話です。

MSX-Cのコード生成について

MSX-Cは、C言語でかかれたコードをM80でアセンブルできるZ80アセンブラ言語のソースにコンパイルしますが、実は、その時のコードは、ニーモニックはZ80の物ですが、コードは、Z80の前身である、8080のコードしか使っていないようです。Z80のコードを使えば、より速く、よりコンパクトな実行ファイルの生成が可能なはずです。そこで、使えるのが、埼玉大Anonymous FTP等で手に入るMSX-C用コードオプティマイザ、optim11.pmaです。(8080のコードしか使っていない事実もここで知った)
コードオプティマイザは、8080のLD命令を、Z80で拡張された、高速かつ、コンパクトなものに置き換える事で、より速く、よりコンパクトな実行ファイルを作る、アセンブラコードを生成するようにします。また、コードオプティマイザは、C言語のシフトを、アセンブラサブルーチンの代わりに、ルーチンを埋めこんで、アセンブラのCALL,RETの分の速度面でのオーバーヘッドを減らしたり、掛け算にR800専用命令を使う事による、実行ファイルの高速・省メモリ化といった事を行います。
使い方も簡単なので、一度手に入れてみてはいかがでしょうか?

割り込みに挑戦!!

ゲームで、BGMを流す時などは、どうしても、割り込み処理が必要になります。このコーナーでは、プログラムの際に注意すべき事について、書こうと思います。
まず、割り込みの接続、切り離しルーチンや割り込みから、Cの関数を呼び出すルーチンをアセンブラで書きます。この際、注意して欲しいのが、割り込みプログラムの置き場所と、フックの書き方です。割り込みプログラムをDOSのシステムが処理する際、メモリページ0(0000H-3FFFH)が一時的にメインROMに切り替わるので、ページ0に自分のルーチンを置いてもうまく処理されない事になります。そのため、割り込みから呼ばれる関数や、関数が呼び出すライブラリ関数、参照するグローバル変数はページ1以降に置く必要があります。L80の/P,/Dオプションをフル活用する日が来ました。
また、割り込みフックは、アセンブラのJP命令ではなく、RST 30H命令で、割り込みルーチンを置く必要がある為、スロット指定をフックのプログラムとL80でのアドレス指定で決め打ちするなり(汎用性はないがプログラムが楽)、割り込み接続ルーチンが割り込みルーチンのページを自動識別する必要があります。
あとは、解説書やMSX-Cのマニュアルにあるような手順でプログラムをすれば、自分のプログラムで、BGMを流したり、特殊効果を出したりする事が出来ます。割り込みの時間はそう長くないので、なるべく、CALL-RETのオーバーヘッドを減らすなどの工夫があるとよりベターです。
他に、気をつけなければならないのは、Cの既存の関数が、割り込みをどう扱うかです。MSX-C Libraryの関数や、BIOSの多くが勝手に割り込みを許可する事から、二重割り込みの事を考えると、これらの関数は、割り込み内では使えないと言う事になります。このことから、割り込み内で使う関数を自作する場面が多くなると考えられます。
サンプルをここに示しておきます。このサンプルでは、Cからinton()関数を呼び出す事で、タイマー割り込みフックにintmain:以下のプログラムが接続され、ユーザーがC言語で書いたtimint()関数が呼び出されるという仕組みになっています。割り込みを終了する際は、intoff()関数を呼び出して、ユーザープログラムを切り離すという仕掛けになっています。このルーチンは、ページ1(4000H-7FFFH)に置かれる事を念頭においています。ついでに、割り込みに適したPSGレジスタ書き込み関数も一緒に置いて、ユーザーの関数から、呼び出せるようにしております。

        .z80
        cseg
timi    equ     0fd9fh
jpcode  equ     0f7h
public  inton@,intoff@,wtpsgx@
extrn   timint@
intsav: nop
        nop
        nop
        nop
        ret
inton@: di               ;書換中に割り込みが起こったらそりゃ、まずいわな
        ld      hl,timi
        ld      de,intsav
        ld      bc,5
        ldir
        ld      a,jpcode
        ld      (timi),a
        ld      a,(0f342h)
        ld      (timi+1),a
        ld      hl,intmain
        ld      (timi+2),hl
        ei               ;割り込み開始!!
        ret
intoff@:di               ;上のdiに同じ
        ld      hl,intsav
        ld      de,timi
        ld      bc,5
        ldir
        ei
        ret
intflag:db      0ffh     ;二重割り込みチェックフラグ
intmain:di               ;多重割り込みが掛からない様にする
        push    af       ;CPUのレジスタ待避
        push    hl
        push    de
        push    bc
        push    ix
        push    iy
        ld      a,(intflag) ;二重割り込みになった場合はルーチンを抜ける
        and     a
        jp      z,qrtint
        xor     a
        ld      (intflag),a
        call    timint@     ;ユーザーのCで書いた関数を呼び出す。
        call    intsav      ;システムもフックを使っていたかもしれないので、古いフックの内容を呼び出す。
        ld      a,0ffh
        ld      (intflag),a
qrtint: pop     iy       ;CPUのレジスタ復帰
        pop     ix
        pop     bc
        pop     de
        pop     hl
        pop     af
        ei               ;次からの割り込みを許可する
        ret
wtpsgx@:out     (0a0h),a        ;direct sound port write
        ld      a,e
        out     (0a1h),a
        ret
        end

主な用途としては、BGMドライバーの製作、呼び出しや走査線割り込みによる特殊効果といったものが挙げられます。それでは、皆さんも頑張って下さい。

作ったプログラムをカスタマイズ可能にしよう!

テキストエディタを作っていて、キーアサインを自由に変更できるようにしたい時などは、既存のカスタマイザを使うと楽にできると思います。今回は、XMARK/さやか/Ayaka対応のソフトを作る時に注意すべき点を幾つか挙げようと思います。
XMARK/さやか/Ayaka対応のソフトの作り方はマニュアルを参照するとして、まず、プログラム先頭のワークエリアのデータはCK.RELを改造するなりして作ります。問題となるのがL80の振る舞いです。L80は最初にJP xxxx命令を挿入するので、それを考慮しないとCK.RELを改造する時に失敗します。

悪い例)
	extrn	@custt

WBOOT   equ     0000h           ;MSX-DOS warm boot entry

xmain:
	JP	xmain2
	db	0f0H
	dw	@custt - 100H
	dw	0000H
xmain2:

 この場合、最初がC3 (xmainのアドレス) C3 (xmain2のアドレス) f0 ...となって、カスタマイズ時にエラーが出ます。

良い例)
	extrn	@custt

WBOOT   equ     0000h           ;MSX-DOS warm boot entry

;JP	xmain ;Insert by L80
	db	0f0H
	dw	@custt - 100H
	dw	0000H
xmain:

 この場合、最初がC3 (xmainのアドレス) f0 ...となって、無事にカスタマイズができます。
あとは、グローバル変数の命名規則などを参考に、カスタマイズするデータの部分をアセンブラで書けば、カスタマイズできるソフトが完成します。例を示しておくので、これを参考に、色々と試して見ましょう。

例)
	public	@custt	;プログラム先頭から見えるように
	public	pat@,col1@,col2@	;C言語から見えるように

	dseg
;ここを書き換える
pat@:
	db	0ffH,0ffH,0H,0ffH,0ffH,7eH,3cH,18H
col1@:
	db	15,15,15,15,15,15,15,15
col2@:
	db	 4, 4, 4, 4, 4, 4, 4, 4
;どこをカスタマイズするか?
@custt:
	db	0f0H
	db	1
	dw	pat@ - 100H
	dw	0000H

参考文献:
MSX2/2+早分かり小辞典(日本文芸社)
MSXテクニカルガイドブック第4版(ASCAT)
MSX-C Version 1.1,MSX-C Library(ASCII)
XMARK及びさやかのドキュメントファイル