2021-04-14 23:54 — asano
カテゴリー:
なんとかSCIが動くようになったのでUniversal Monitorの移植に取り掛かれます。
SuperHファミリはここで取り上げるプロセッサとしてはモダンな部類ですが、アセンブリで書くとなるとかなり癖が強いですね。慣れるまでは結構てこずりました。
移植の過程で気になった点をいくつか上げてみます。
定数の制限
SuperHの大きな特徴の一つはすべての命令が16ビット長ということです。これはオペコード部の長さではなくオペランドを含めても16ビットということですから、大きな値やアドレスを持つことができません。
即値は一部の命令で8ビットのものがありますが、さすがに8ビット程度では意味がないので絶対アドレッシングは存在しません。
さすがにこれでは使いにくいのでアセンブラの工夫による救済があります。MOV #imm,Rn
命令で8ビットに収まらない値を使用すると自動的にMOV @(disp,PC),Rn
命令を生成して値はまとめて定数テーブルに置かれます。
ADD
などの命令ではこの形式は使えないので一旦レジスタに入れるしかありません。
メモリマップドI/Oやワークエリアなどを絶対アドレッシングでアクセスしたいときもアドレスを一旦レジスタに入れてアクセスします。
分岐も近傍ならPC相対で、届かないときはレジスタ間接を使うしかありません。幸いモニタ程度のサイズならPC相対で何とかなりました。
PC相対やレジスタ相対のディスプレースメントも短いので注意が必要です。無条件のBRA
, BSR
命令で12ビット、条件分岐命令やPC相対・GBR間接の場合で8ビット、汎用レジスタ間接の場合は4ビットしかありません。
ここで面白いのはディスプレースメントの少ないビットを有効に使うためにスケーリングされることですね。
レジスタの部分使用
レジスタは32ビット長ですが部分使用ができないというのもこのプロセッサの特徴です。
演算は原則として常に32ビットで行われます。メモリアクセスは8ビット・16ビットでも可能ですが、例えばメモリから8ビットで読むと32ビットに符号拡張されてからレジスタに格納されます。
やはりCで書くの前提みたいですね。
遅延分岐
一部の例外を除いて分岐命令は遅延分岐となります。
遅延分岐とはこういうことです。SuperHのようなパイプラインを活用したプロセッサでは分岐命令をフェッチ・デコードして分岐先がわかった時点では次の命令(分岐しなかったら実行していたはずの命令)をすでにフェッチしてしまっています。これを捨てるのはもったいないので実行してしまおうというわけです。
簡単な例をあげて見ましょう。
12/ 400004 : MAIN:
13/ 400004 : E001 MOV #1,R0
14/ 400006 : B009 BSR RADD
15/ 400008 : E102 MOV #2,R1
16/ 40000A : 2210 MOV.B R1,@R2
20/ 40001C : RADD:
21/ 40001C : 000B RTS
22/ 40001E : 310C ADD R0,R1
なんかRTS
の後にも命令があったりしてちょっと変ですよね。
MAIN:
から順に見ていきます。
まず13行でR0に1を入れるのは良いですね。
14行でRADD:
をサブルーチン呼び出ししますが、RADD:
からの最初の命令を実行する前にすでにフェッチされている15行の命令(R1に2を入れる)が実行されます。ちなみにBSR
命令でPRレジスタに退避される戻りアドレスは16行の40000Aです。
サブルーチン側の最初の命令はいきなりRTS
でPRレジスタのアドレスに戻りますが、その前に22行のADD
が実行されます。
この15行や22行のように遅延分岐命令の直後を遅延スロットと呼び、ここに配置できる命令にはいくつか制限があります。
まず遅延スロットに分岐命令を置くことはできません。置くとスロット不正命令です。
また遅延スロットでPC相対アドレッシングを使用すると分岐先のPCが使われるので注意が必要です。
まぁモニタなどにパフォーマンスは求めないのでNOP
を入れておくのが簡単で、最初はそうしていたのですが、途中からは分岐の直前の命令が遅延スロットに入れられるときは入れる方針に転換しました。もっと前の命令も入れられないか考えてもいいのですが、やりすぎると読みにくくなるので...
条件分岐
SuperHは条件分岐もちょっと変わっています。
多くのプロセッサでは演算などの命令でゼロ・キャリーなどいくつかのフラグが変更され、条件分岐命令ではどのフラグを参照するか選びます。しかしSuperHでは条件分岐に使えるのはT
ビットのみで、比較命令のほうで条件を選びます。分岐命令のほうではT
ビットが0のとき分岐するか1のとき分岐するかを選べるだけです。
演算命令のほうでスキップ条件を指定するMN1610系に少し似ていますね。
おそらく分岐先へのディスプレースメントに多くのビットを必要とする条件分岐命令の数を減らしたかったのかなぁ、と推測します。
その他
他にも以下のような点が気になりました。
- 使えるレジスタ・アドレッシングモードが限定されていることが多い
- アドレッシングモードによってディスプレースメントが符号付だったり無しだったりする
- サブルーチンの戻りアドレスはスタックではなく
PR
レジスタ - 論理シフト命令に2,8,16ビットの専用命令がある
やはり命令のビット長を有効に使うことを重視しているようです。
Universal Monitor
現在のところD(ump), S(et), G(o)の各コマンドが使えるところまでできています。あとL(oad)を実装すれば最低限の機能は完成といえるでしょう。
あとは他と同じようにレジスタ表示やトラップですかね。あとUBC(User Break Controller)なるものがあって命令の実行だけでなく読み書きでもブレークできるらしいのでこれも動かしてみたいですね。
コメントを追加