3D ダンジョン マシン語版(前編)

今回は特に描画負荷が高いこともあって、BASIC ではすぐに速度的な限界が見えてしまいました。

一方で「マシン語は BASIC の 100 倍速」などと言われており、なんでも 100 倍速になるわけではないですが、誇張でもありません。200~300 倍速になることもあります。

ただ、PC-8001 実機や PasocomMini PC-8001 上でマシン語開発するのは非常に大変です。Windows 上で動作するエミュレータの利用を強く推奨します(実機を持っていない場合、ROM データの著作権問題がありますが……)。

なお、用語としては「マシン語」「機械語」「アセンブリ言語」 (「アセンブラ」と言う人も多いですが)などが使われますが、 ここでは「マシン語」で統一します。




はじめに

PC-8001 の CPU は Z80(厳密には互換 CPU)で、詳細は「Z80 講座」で解説しています。まずはそちらを熟読してください。

アセンブラは自作で、Windows のコマンドプロンプトから実行することを想定しています。

他のアセンブラと文法的に違う部分もある (ラベルやマクロなど)ので注意してください。

16 進数表記は「~H」も「$~」も通りますが、 今回は解説も含めて$~」で統一します (特にデータを記述する際、こちらの方が文字数が揃って便利なので)。

今回作成したのは、短い BASIC プログラムと、マシン語ソース 2 つです。3D 描画部分が長いので分けました(メインから INCLUDE しています。



メモリ配置

PC-8001 のメモリ配置は、だいたい以下の図のようになっています (システム領域の中には使える部分もありますが、推奨しません)。


画像 01

マシン語を使う際は、このうち「BASIC 領域」の末尾を CLEAR 命令で狭める必要があります。たとえば $8FFF までにするなら、

?fre(0)
 26786 
Ok
clear100,&h8fff
Ok
?fre(0)
 3946 
Ok

といった感じです。これで $9000~$E9FF をマシン語で使用できます。

なお CLEAR の第 1 パラメータは文字列領域のサイズ(詳しくはこちらを参照)です。ちなみに起動直後は 300 バイト確保されています。




BASIC 部分

オールマシン語でもいいのですが、実行は BASIC から RUN するのがわかりやすいので、最低限の BASIC プログラムを作ります。

10 CLEAR 100,&H8FFF:WIDTH 40,25:CONSOLE 0,25,0,1:COLOR 7,0,0:PRINT CHR$(12)
20 DEF USR=&H9000:A=USR(0)

画面の初期化をマシン語でやるのは面倒なので、ついでに BASIC でやっておきます。

マシン語は $9000 から配置することにします。くれぐれもマシン語部分を用意する前に RUN しないでください。 何が起こるかわかりません。




最低限のマシン語

まずは BASIC にすぐ戻るだけのプログラムを書いてみます。 なお自作アセンブラ z80asm 用なので、他のアセンブラでは通らないかもしれません。

	ORG $9000

ENTRY:
	RET

PROG_END:
	END

ラベルは左端に記述し、 命令はタブもしくはスペースをいくつか入れて記述します。

最後の END は無くてもいいですが、 ここで終了ということをわかりやすくするために入れています。

このプログラムをファイル名 test.z80s で保存し、z80asm をコマンドプロンプトなどから実行します。

.\z80asm test.z80s test.cmt -m test.map
Input file : test.z80s
Pass 2...
Output file : test.cmt
Output map file : test.map
Complete.

これでカセットテープイメージ test.cmt と、マップファイル test.map が出力されます。test.map の中身は、

9000	ENTRY
9001	PROG_END

このようになります。試しに test.cmt をロード対象にして(具体的な手順は省略)、

mon
*L  (読み込み)
* (CTRL+B)
Ok

とした後、先ほどの BASIC プログラムを RUN してみて、画面初期化後すぐ Ok が出ることを確認してみてください。




疑似命令

z80asm がサポートしている疑似命令(Z80 のコードではない命令)などについて軽く解説しておきます。



ワークエリア

BASIC 版で使用している数値変数を、 マシン語版ではソースの最後の方でまとめて確保することにします。

WORK_START:

PL_X:		; PX
	DS 1
PL_Y:		; PY
	DS 1
PL_Z:		; PZ
	DS 1
PL_DIR:		; PD
	DS 1
(中略)
WORK_END:

BASIC の整数変数は 16 ビット(2 バイト)ですが、8 ビットの範囲しか使っていないものは 1 バイトだけ確保しています。

数値変数は初期値 0 なので、マシン語版でも最初に、

ENTRY:
	LD HL,WORK_START
	LD DE,WORK_START+1
	LD BC,WORK_END-WORK_START-1
	LD (HL),0
	LDIR

として、一気に 0 で埋めています(ただしこのコードはワークサイズが全部で 2 バイト以上無いと暴走するので注意)。




定数定義

BASIC 版ではマップ要素の値を毎回プログラムに直書きしていましたが、 マシン語では EQU 疑似命令で定数を定義しておくことで、 途中で値の変更がしやすくなり、意味もわかりやすくなります。

MP_SPACE	EQU 1
MP_WALL		EQU 2
MP_OGATE	EQU 3
MP_DSTAIRS	EQU 4
MP_USTAIRS	EQU 5
MP_START	EQU 6
MP_WARP		EQU 7
MP_TRE1		EQU 8
MP_TRE2		EQU 9
MP_CGATE	EQU 32
MP_KEY		EQU 64

今回はこれくらいしか定義しませんでしたが、BASIC と違って実行速度や実行プログラムサイズへの影響は無いので、 積極的に利用することをおすすめします。




データ定義

文字列データや DATA 文の内容の多くは、各ソースの後ろの方に固めてあります。

たとえばメッセージ類は「MSG_」 で始まる名前で定義してあります。

MSG_MOVES:
	DB "Moves:",0
MSG_KEY:
	DB "Key:",0
MSG_TREASURE:
	DB "Treasure:",0
(中略)
MSG_START:
	DB $C0,$B6,$D7,$D3,$C9,$A6,$20,$D0,$C2,$B9,$C3,$20,$D3,$C1,$B6,$B4
	DB $DB,$B3,$21,0

MSG_START の内容は、開始時のメッセージ「タカラモノヲ ミツケテ モチカエロウ!」です。ASCII コード($20~$7E)の範囲外を含む文字列データは、 このように文字コードを並べています(文字コード一覧はこちら)。

ここまでは下準備といったところです。 必要なワークやデータを先にまとめて用意しておくと、 コードを書くことに専念しやすいかと思います。



マシン語版(後編)へ続く


inserted by FC2 system