現在地

Z8000 CALR命令


カテゴリー:

前回予告したように今回はCALR命令について書いてみようと思います。

CALR命令は相対サブルーチンコール命令で、JPに対してJRがあるようにCALLに対してあるのがこれです。同様に相対番地でメモリアクセスするLDR命令や、アドレスを取得するLDAR命令もあります。

Z80の位置独立なコードを書けない(著しく困難)問題に対処しています。

さて、Universal Monitorの移植にあたりいつものようにコンソールドライバを書いたあとオープニングメッセージの表示に必要な最小限を書いてテストしていました。ドライバの初期化や1文字出力の呼び出しにはCALRを使っていました。位置独立のためではなく単に短く速いからです。

ところがまったく表示されません。

最初はZ85230 ESCCの初期化パラメータを疑ったりしていたのですが、ふとESCCのCE端子にカウンタを繋いでみたところ0のままでESCCへのアクセスが一切されていないことがわかりました。

そうなると初期化ルーチンが呼ばれていない可能性が高くなります。

相対番地の命令というのは基準アドレスがどこかなど間違いの起こりやすい箇所です。そもそも愛用のアセンブラASがZ8000を新たにサポートしたことがきっかけで作っているわけで、アセンブラはまだ成熟しているとはいえません。

そこでCALR命令をすべてCALLに書き換えたところ無事動き始めました。モニタが動くようになるまでは実験などやりづらいので、とりあえずCALRを避けて移植作業を進めました。幸いJRDBJNZといった他の相対分岐命令は問題出ませんでした。

その後モニタのR(egister)コマンドも使えるようになり実験の準備が整ったので調査開始です。

短いテストプログラムをアセンブルさせたものとハンドアセンブルしたものを比較してみても特に問題なさそうに見えます。おかしいなと思ってシャープのマニュアルをよく読みなおしていたところ、動作としてとんでもないことが書かれていました。

非セグメント・モード
SP←SP-2
@SP←PC
PC←PC-(2×disp)

えっ、マイナス!? PCに足すのではなく引くの!?

てっきり足すのだと思ってハンドアセンブルしてましたし、ASもそういうコードを吐いていました。

ASのメーリングリストで指摘したところ、作者の方より参照している資料では足すことになっているとの回答がありました。

プラスとマイナス双方の資料が存在するなら実機確認してみるしかありません。以下のようなコードを走らせてみました。

8000 : DFFF  CALR (disp = -1)
8002 : 7FFF  SC #255 (BREAK)
8004 : 7FFF
8006 : 7FFF

すると8004Hでブレークがかかりました。基準アドレス8002H - (2×-1) = 8004Hと考えれば辻褄が合います。

8000HをD000 (disp = 0) にすると8002Hでブレークかかりました。

8000HをD001 (disp = 1) にするとハングアップ、自分のアドレスをコールし続けて無限ループを形成したようです。リセットしてメモリを確認するとRAMが8002H(戻りアドレス)で埋められていました。

この情報を元に再度報告したところ次回リリースにて修正予定とのことでした。

ソースのCALL命令のうち変更可能なもの(レジスタ間接アドレッシングのできない特殊入出力命令をRAMに書き込んでコールしている箇所以外すべて変更可能でした)をCALR命令に書き換えてリリースを待っているところです。

参考文献・関連図書: 
『Z8000ユーザーズ・マニュアル 1 CPU/MMU編』, シャープ.
"Z8000 Data Manual First Edition", Zilog.

コメントを追加

Plain text

  • HTMLタグは利用できません。
  • ウェブページアドレスとメールアドレスは、自動的にハイパーリンクに変換されます。
  • 行と段落は自動的に折り返されます。
※ コメントは原則公開です。個別のご相談などは「ご意見・ご要望」からお願いします。