これまで説明したように、MSX BASICは強力な機能を備えていますが、さらに実行速度を上げたり、MSX2のハードウェア機能を限界まで引き出す場合は、マシン語を使用しなければなりません。この章では、その必要が生じた時のために、BASICからマシン語プログラムを呼び出す方法、およびその際に知っておくべき情報について説明します。
BASICからのマシン語の呼び出しは、以下の手順で行います。USR関数のカッコの中の値は、引数としてマシン語に渡すためのものです。引数は数式、文字式いずれでもかまいません。
- DEF USR文で、マシン語プログラムの実行開始アドレスを指定する。
- USR関数でマシン語を呼び出す
- マシン語からBASICに戻る場合はRET命令(C9H)を実行する
C000H番地が実行アドレスであるマシン語プログラムを呼び出す。
DEF USR=&HC000
A=USR(0)
BASICからマシン語に引数を渡す場合、マシン語側ではレジスタAの内容でその型を判断します(表2.18)。目的の値は引数の型により、図2.27のような形式で格納されていますから、それに応じて値を受け取ります。例として、文字列型の引数を受け取るプログラムをリスト2.5に示します。
表2.18 レジスタAに代入される引数の型
| 2 | 2バイト整数型 |
| 3 | 文字列型 |
| 4 | 単精度実数型 |
| 8 | 倍精度実数型 |
リスト2.5 文字型の引数の使用例
;
; USR関数で渡した文字列をそのまま表示する
; 使用法:DEF USR=&Hxxxx: A$=USR("STRING")
;
chput equ 00a2h ; character output
rdarg::
cp 3
ret nz ; parameter is not string
push de
pop ix ; IX:= string descripter
ld a,(ix+0) ; get string length
ld l,(ix+1) ; get string pointer(low)
ld h,(ix+2) ; get string pointer(high)
or a
ret z ; if length = 0
rd1:
push af
ld a,(hl) ; get a character
call chput ; get a character
pop af
dec a
ret z
inc hl
jr rd1
end
逆に、引数として渡された値をマシン語の中で処理することによって、USR関数の値としてBASICに引き渡すこともできます。この場合、【VALTYP(0F663H)】を変更することにより、戻り値をBASICからの引数の型以外のものに変更することも可能です。ただし、文字列型の場合、文字数を変えることはできません。
MSXでは現在「CMD」と「IPL」という予約語が未使用となっており、この予約語のフック(それぞれFE0DH、FE03H)を自分で作成した任意のマシン語ルーチンにジャンプするよう書き換えるだけで、新しい命令を作成することができます。簡単な例をリスト2.6に示します。
リスト 2.6 CMD命令の増設
;
; CMDコマンドの使用法(CAPSのON/OFF)
; コマンドの初期化: DEF USR=&Hxxxx: A=USR(0)
; コマンドの使用法: CMD
;
chgcap equ 0132h ; CAPS LAMP on/off
capst equ 0fcabh ; CAPS LOCK status
hcmd equ 0fe0dh ; CMD HOOK
; CMD コマンドの増設
start::
ld bc,5 ;NEW HOOK SET
ld de,hcmd
ld hl,hdat
ldir
ret
; HOOK に書き込むデータ
hdat:
pop af
jp capkey
nop
; CMD コマンドの実体
capkey:
call chgcap
ld a,(capst)
cpl
ld (capst),a
ret
end
フックに書き込む最初の「pop af」は、「CMD」の実行時にスタックに積まれるエラー処理アドレスを捨てるためのものです。これを入れておかないと、「RET」命令でBASICに戻るはずが、エラー処理ルーチンにジャンプしてしまいます。ユーザールーチン内でエラーを出したい場合は、このアドレスを取っておくのも1つの方法です。
なお、これらのフックは本来は将来の拡張用にリザーブしてある場所なので、商用のアプリケーションプログラムで使用してはいけません。
より複雑なステートメントの拡張を行うには、CMD命令にも引数を渡せると便利です。マシン語を呼び出した際、HLレジスタがBASICテキスト中の「CMD」の次の位置を指していますから、これを利用して後に続く文字列の評価を行えば目的は果たせます。これらを行うために有効な内部ルーチンを以下で説明します。
テキストから1文字取り出します。
HL テキストを指すアドレス
HL 取り出した文字のアドレス
A 取り出した文字
Zフラグ 文末(「:」または00H)ならばON
CYフラグ 0〜9ならばON
(HL+1)の場所のテキストから1文字取り出します。スペースはスキップされます。