2023-11-20 22:50 — asano
カテゴリー:
前回プログラムが動き始めたので、例によってUniversal Monitorの移植を行なっています。似ているプロセッサとしてMC68000をベースに、HEXファイル関係については長いアドレスに対応したH8/300Hが元にしています。
現時点でD(ump), G(o), S(et), L(oad), P(unch)の各コマンドが動作するようになっており、引き続きR(egister)の実装を進めているところです。
ということで気付いたことを書いてみようかと思います。
バイトオーダー
NS32000のバイトオーダーはリトルエンディアンなのですが、命令語に含まれる即値やディスプレースメントなどはビッグエンディアンで格納されます。
面白いのはディスプレースメント(絶対アドレッシングのアドレスも含む)は可変長で、最初のバイトの最上位ビットが"0"なら符号付7ビット、上位2ビットが"10"なら符号付14ビット、"11"なら符号付30ビットになることです。
また"11100000"は将来のための予約なのでさらに16Mバイト分狭くなります。
この長さ識別ビットを上位に置きたいというのがビッグエンディアンになっている理由なのかもしれませんね。
まぁこの辺りはアセンブラに任せておけば通常は気にしなくて良いのですが......
ASは良くできたアセンブラですが、このようなマイナーなプロセッサでは出力コードの実機確認が不十分なこともあり、動かないと一応疑ってしまいます。過去にZ8000のCALRの件もありますし、今回も疑似命令についてちょっとありました。
フラグ
NS32000はフラグの動きも特徴的です。
まず演算命令ではCarryは変化しますが、Zeroは変化しません。
逆に比較命令(CMPi)ではZero, Low(符号無し), Negative(符号付き)は変化しますが、Carryは変化しません。
最初これを知らずにCMPiのあとでBCSやBCCを使ってしまい、しばらく悩んでしまいました。正しくはBHI, BLSを使います。
あと0か判定するのにZ80の癖でORB R0,R0
などと書いてしまいましたが、これも無意味です。CMPi命令で0と比較すればいいのですが、即値は可変長ではないので32ビット比較だと0のために4バイトも付いてしまいます。何かうまい手はないものか、レジスタに余裕があるならどれかに0を入れておく(XORD R0,R0
は使えます)しかないのかな。
Top of Stackアドレッシングモード
アドレッシングモードのTOS(Top of Stack)も面白いですね。
MOVi命令のソースのように読み出しに指定するとスタックからPOPされます。MC68000の(A7)+
に相当します。
MOVi命令のデスティネーションのように書き込みに指定するとPUSHされます。MC68000の-(A7)
に相当します。
ADDi命令のデスティネーションのようにリード・モディファイ・ライトに指定するとスタックトップにアクセスします。MC68000の(A7)
に相当です。
何の命令・どのオペランドかによってこの動作は自動的に切り替わるので、マニュアルには各オペランドごとにどのタイプか明記されています。
プリデクリメント・ポストインクリメントはスタックに対して使うことが多いのでこうしたのでしょうが、私がMC68000に慣れているせいか普通のポストインクリメントも欲しかったですね。
モジュール機能
NS32000ファミリ最大の特徴と言えるのがこのモジュール機能でしょう。
当初モニタ程度なら必要ないだろうと思っていましたが......
ブレークポイントを実装するためにはトラップのハンドリングが必要になります。トラップの際にはモジュールの切り替えが発生するので最低限の対応を行ないました。モニタとトラップハンドラを共通のモジュールとしてStatic BaseとProgram Baseを設定しています。
シフト・ローテート
左右の区別はなく、シフト量が正なら左へ・負なら右へシフト(ローテート)されます。
ちょっと不便なのはキャリを含めたローテートが無いこと、モニタでは必要ありませんが32ビットを超えるととたんに面倒になりそうです。
スタックポインタ
スタックポインタはSP0, SP1の二つがありますが、特権モードか否かで切り替わるのではなくPSRのSビットで切り替わる(例外発生時には自動的にSがクリアされSP0が選択される)のでMC68020のISP,MSPに近いように思います。
モニタはSがクリアされた状態で実行されますが、このままSP1にはアクセスできないようです。参考にしているマニュアルによればLPRi, SPRi命令でアクセスできそうなのですが、それができるのはNS32532のみでNS32016などではSビットを弄らないといけないようです。
COMi, NEGi, NOTi
演算命令は基本的に2オペランドなのでCOMi, NEGi, NOTiといった多くのプロセッサでは1オペランドになるようなものも2オペランドになっていてソースとデスティネーションを別に指定できます。もちろん同じものを指定してもOKです。
その他
他にも特徴的な命令は多数あります。
モニタでは必要ないのでマニュアルをざっと読んだだけですが、次のようなものが目にとまりました。
- 立っているビットを探す FFSi
- 多次元配列のインデックスを計算する INDEXi
- 変換テーブルを参照しながらストリングをコピーする MOVST
探せばまだまだあるでしょう。
コメントを追加