ワークエリアとスタック

アセンブラでプログラムを書くメリットは、実行速度もさることながら、
最も重要なのは、CPUの仕事の手順を事細かに記述でき、思い通りに操作できること
ではないかと思います。

そのかわりに、プログラマはコンピュータとシステムについて熟知する必要がありますが、
X68000というパソコンは、それが楽しく思えるコンピュータだと思います。

さて、今回は、ワークエリア(作業領域)とスタックを扱います。

68000CPUはレジスタ数が多い方だと思いますが、大抵のプログラムでは、
必要に応じて作業の状態や途中経過などをメモリ上に保存し、また参照することを繰り返します。

その場合、メモリ上のどこの番地に読み書きしたらよいのか、ということについては、
アセンブラプログラミングに関してはプログラマが把握してさえいれば、有効なメモリ上の
どこでも自由に使うことができます。

ただし、68000CPUで効率的に作業変数を管理するには、ちょっとしたテクニックがあります。
今回は、そのあたりを中心に解説してみようと思います。

ワークエリアの確保の方法

68000のアセンブラでプログラムを書くとき、作業用の変数領域をメモリ上に持ちたければ、
例えばこのような書き方が可能です。

	.data
posX:	.dc.w	0
posY:	.dc.w	0
score:	.dc.l	0

これらの変数をアクセスしたければ、

	move.w	posX,d0		* posXをd0にロードする
	move.w	d1,posY		* d1をposYにストアする
	add.l	#100,score	* スコアに100加算する
という風に書くことができます。また、これら3つのワークエリアは、プログラムコードの一部として
初期値付きで確保されますので、非常に手軽な方法ではあります。

しかし、この書き方をするとコンバータCV.Xで拡張子Rのファイルに変えることができなくなります。
理由は、アドレッシング先の一部に、メモリにプログラムをロードするまで決まらない
プロセス相対アドレスが含まれているからです。

Rファイルにこだわりがなければ良いですが、管理人の場合は無駄にこだわっていますので、
こういう風に書きます。

	.offset	0
posX:	.ds.w	1
posY:	.ds.w	1
score:	.ds.l	1

	.text
	.even
	lea	WORKAREA(pc),a6
	move.w	posX(a6),d0		* posXをd0にロードする
	move.w	d1,posY(a6)		* d1をposYにストアする
	add.l	#100,score(a6)		* スコアに100加算する

	.bss
	.even
WORKAREA:

いくつかポイントがあります。
まずは、.offsetというところですが、これは、posX,posY,scoreというラベルの値を、
0,2,4と、データサイズ分ずつ増加するように宣言する書き方です。

それぞれのラベルは、.dc.w,dc.lではなく.ds.w,ds.lとしていますが、
(1)書いた位置に初期値を埋め込む → .dc.w 初期値
(2)ラベルの値を宣言して値をサイズ分増加する → .ds.w ワード数
という違いがあります。

まあ、とにもかくにも、posX=2, posY=4, score=6 になるわけです。


次に、lea WORKAREA(pc),a6 という記述です。
この記述はWORKAREAのアドレスを、アドレスレジスタA6に参照する命令です。

WORKAREAというラベルは、末尾の.bssの後にあります。
.bssというのは、「ブロックストレージセクション」と言いますが、名前はともかく、
プログラムコード(.text:テキストセクション)、データ(.data:データセクション)の後の、
未開のメモリ領域の先頭が、WORKAREAのアドレスになります。

WORKAREA(pc)というふうに、(pc)を付けているのは、そのアドレスと参照している
命令コードとの位置関係はどこのアドレスにロードされても変わらないという性質を使い、
命令のある場所(PC)からの相対アドレッシングにすることによって、
ロード時に再配置処理を行わなくても良いようにしているのです。

なんだかわけのわからないことを書きましたが、こういうふうにすると、
*.Rのファイルが作れるようになります。

なお、A6にワーク先頭アドレスを参照していますので、A6を基準とするアドレッシングにより、
posXなどの変数も自由にアクセスできるようになります。
ただし、WORKAREA以降が自由に使える領域である場合に限りますが、その話は改めてします。

ちなみに、move.w posX(a6),d0については、move.w WORKAREA+posX(pc),d0として、
A6レジスタを使わずに参照することができます。しかし、move.w d1,WORKAREA+posY(pc)はできません。
このように、値を書き込むデスティネーションオペランド(右側)にはPC相対アドレッシングは使えません。


ちょっとおさらいしておきますと、

  1. プログラム中で変数を確保するためには、ラベル名(例ではposXなど)とデータサイズを指定する
  2. .dc.b/w/l で確保した場合は、プログラムコードと同じで初期値が実行ファイルに埋め込まれている
  3. .ds.b/w/l で確保する場合には、ラベルにオフセット値が付くだけになる
  4. プログラム中に絶対アドレスへのアクセスがあると、再配置処理が必要になる(Human68kが面倒を見てくれる)
  5. 絶対アドレスを使わないで済ますには、アドレスレジスタを使ったインデックス付き相対アドレッシングを使う
  6. アドレスレジスタは、汎用のa0〜a6はもちろん、pcも使うことができる
  7. ただし、pc相対アドレッシングは、データの書き込み先(デスティネーションオペランド)には使えない決まりがある。
と、こんな具合いです。一見意味不明ですが、慣れればどうってことはありません。

スタック

DOSコールなどで使うスタックですが、小規模なプログラムであれば、特に何も考えずに
親プロセスのcommand.xが確保したスタック領域を使っても構わないのですが、
無用なトラブルを避けるためには、スタック領域については、自分のプログラムの管理下に確保することを
お勧めします。

具体的には、上で示したワーク変数の確保方法を応用して、

	.ds.l	1024
MySTACK:
のような書き方をしますと、MySTACKの値は、そこまでのワーク変数領域のアドレスに
1024ロングワード分加算したオフセット値になります。そこで、プログラムの頭で
	lea	WORKAREA(pc),a6
	lea	MySTACK(a6),sp
としてやることで、自分のプログラムのワークエリアの一部をスタック領域として
割り当てたということになります。

スタック領域が1024ロングワードで足りるか足りないかは、実際に行うプログラムの内容
(サブルーチン呼び出しの深さやパラメータの引き渡し方法、レジスタ保存状況)に配慮して、
プログラマの責任で管理します。

まとめ

Human68kの実行プログラムは、最大12MBあるリニアなメモリ空間の一部に領域確保されてロードされ、
実行開始アドレスから処理が渡される仕組みになっています。

プログラマ的には、深く考えずとも、ソースコードの先頭からプログラムが実行されると思って、
ソースコードのどこかに書いたワーク変数を読み書きしながら処理すれば十分なのですが、
今回の解説のように、メモリのアドレスとそのアクセス方法を意識しながらコーディングするのは、
一見面倒に見えますが、アセンブラプログラミングの味わい深い側面ではないかと思います。

解説が地味で下手で申し訳ありませんが、ゲームなどの大規模プログラミングに進む前に、
是非とも押さえておきたい基本事項なので、十分に実験をして理解しておくことが大事です。


トップページへ

Copyright©2014 甘亀庵管理人

inserted by FC2 system