2018-07-10 16:21 — asano
前回私がハマったところの詳細を残しておきます。
Z8にはレジスタファイルと呼ばれる256バイトの空間があります。これは通常のメモリ空間とは別に存在し、内蔵ペリフェラルのレジスタや汎用レジスタなどが配置されています。Z8613ではアドレス0x80~0xEFまでは未実装になっていますが、デバイスによってはフル実装されていたりバンク切り替えによって拡張されているものもあります。
このレジスタファイルへのアクセスには2種類あり、命令によってどちらが使えるかあるいは両方かが決まっています。
一つは8ビットのアドレスを指定する方法で、どこにでもアクセス可能な代わりに命令長は最低でも2バイト必要です。アセンブリ言語での記述は単に8ビットのアドレスを書きます。
もう一つはアドレスを(下位)4ビットだけ命令の中で指定し、アドレスの上位は別途RP(Register Pointer)レジスタで指定しておく方法です。アセンブリ言語での記述はr0~r15と書きます。命令長が短くなるほか、RPレジスタを変更することで割り込みでの退避・復帰を高速に行なうことも可能です。
私はアドレスを書けば必ず前者のコードが、r0~r15と書けば後者のコードが生成されるものと思っていました。
ところがアセンブラASは内部でRPがどこを指しているか仮定するようになっていました。そして8ビットのアドレスを記述した場合でも仮定しているRPを基に4ビットでアクセス可能なら後者のコードを生成するようになっていたのです。一種の最適化機能です。
テストプログラムではRP=0x10にしていました。この状態ではr0はアドレス0x10と、r8はアドレス0x18と同じになります。
ところがアセンブラはRP=0x00と仮定していました、RPをいくつに仮定するべきか指定する擬似命令を知らなかった(指定していなかった)のでデフォルト値が使われたようです。
この状況でパラレルポートのレジスタ(前回書いたようにアドレスは0x00~0x03)をアクセスする命令を書いたので、アセンブラはr0~r3でアクセス可能と判断して4ビットアドレスのコードを吐きました。
実際にはRP=0x10なのでアドレス0x10~0x13にアクセスしてしまい、動作しなかったというわけです。
タイマ関係のレジスタは0xF1,0xF4,0xF5にあるので影響を受けませんでした。
RP=0x10であることを正しく指定したあとは意図通りのコードが生成されるようになっています。
思い起こしてみると8086でも似たようなことで苦労したような気がします。
あの時はセグメントレジスタの値とセグメントプレフィックスだったかな。
どういうコードを吐いて欲しいかはわかっているのに、どういうソースを書けばアセンブラが思ったコードを吐いてくれるのかわからないという。純粋ソフト屋の友人には「お前の頭は変だ」と随分馬鹿にされたものです。
やはり根がハード屋なのかなぁ。
(コンパイラはともかく)アセンブラは余計な最適化とかしなくていいから素直にソース通りのコードを吐いて欲しいなとか思ってしまいますね。
コメントを追加