趣味の数学・情報理論

2018/03/24

命令セットアーキテクチャを考える(番外編) 条件付き分岐

前の記事で、RISC Vの条件分岐命令について書きました。
今度はopenRISCについても調べてみました。
https://raw.githubusercontent.com/openrisc/doc/master/openrisc-arch-1.2-rev0.pdf

openRISCでは、条件分岐はbf(Branch if Flag)命令とbnf(Branch if Not Flag)命令があります。特殊レジスタのF(flag)ビットによって、分岐するかどうかを決めるようです。
ではFビットはどうやってセットされるかというと、さまざまな(※)Set Flag命令があり、条件分岐前に、sf*命令を使ってFビットをセットまたはクリアしておいて、bfまたはbnf命令で分岐する、という仕組みになります。

※ sf*命令には、大小イコール比較、符号付き/なし、第二オペランドがレジスタ/即値などのバリエーションがあります。

条件分岐以外にも、Fビットの値によってRaまたはRbの値がRdにセットされるという、cmov(Conditional MOVe)命令もあります。使い方によっては、分岐しないでパイプラインの乱れがなくてよさそうです。

例えば、先日の記事のmax/min命令相当の処理ならば、分岐命令を使わずに以下のように2命令で実装できます。
sfgts Ra,Rb : set flag greater than signed
cmov Rd,Ra,Rb : conditional move

| | コメント (0) | トラックバック (0)

2018/03/21

命令セットアーキテクチャを考える(番外編) 特殊レジスタの汎用レジスタへの割り当て

汎用レジスタが64本もあるので、特殊レジスタを汎用レジスタ番号に割り当てたらどうでしょうか。

とは言っても、他のアーキテクチャにあるような、乗除算専用のMHI/MLOレジスタや、ループカウント用のカウントレジスタのようなものは、私の考えたアーキテクチャにはなく、命令のオペランドで汎用レジスタを使用するようになっています。また、スタックポインタレジスタのようなものもありません。

残りのPC(プログラムカウンタ)とCCR(コンディションコードレジスタ)を汎用レジスタに割り当てたらどうだろうかというところです。

PCを汎用レジスタ番号に割り当てると、分岐命令のPCモードがシンプルになります。これがこの番外編の一番目の動機です。


二番目の動機であるCCRについては、RISC Vアーキテクチャを参考に考えてみました。
https://riscv.org/specifications/

RISC Vの条件分岐命令では、汎用レジスタのRs1とRs2(私のシリーズでの記述ではRsとRtに相当)の比較結果によって分岐するかどうかを決定します。CCRのような特殊レジスタを使いません。この方法では、比較と条件分岐が1命令になっているため、比較、条件分岐という2命令よりもコンパクトになります。
また、条件分岐命令とは別にSLT(set Less Than)/SLTU(Set Less Than Unsigned)命令やFLT(Floating-point Less Than)やFLE(Floating-point Less Equal)命令があり、汎用レジスタ同士、浮動小数点レジスタ同士の比較結果を汎用レジスタに設定することができます。これらの命令と組み合わせることにより(実行ステップは増えますが)より柔軟な条件分岐が実現できます。
RISC Vの仕様書には、以下のような説明(注釈)が書いてあります。

The conditional branches were designed to include arithmetic comparison operations between two registers (as also done in PA-RISC and Xtensa ISA), rather than use condition codes (x86, ARM, SPARC, PowerPC), or to only compare one register against zero (Alpha, MIPS), or two registers only for equality (MIPS). This design was motivated by the observation that a combined compare-and-branch instruction fits into a regular pipeline, avoids additional condition code state or use of a temporary register, and reduces static code size and dynamic instruction fetch traffic. Another point is that comparisons against zero require non-trivial circuit delay (especially after the move to static logic in advanced processes) and so are almost as expensive as arithmetic magnitude compares. Another advantage of a fused compare-and-branch instruction is that branches are observed earlier in the front-end instruction stream, and so can be predicted earlier. There is perhaps an advantage to a design with condition codes in the case where multiple branches can be taken based on the same condition codes, but we believe this case to be relatively rare.

私の考えた条件分岐命令は、CCRのビット演算で柔軟に分岐できるように考えましたが、ハードウェア的には実装が面倒かもしれないと思い始めました。自分はハードウェアのことはわかりませんが、おそらく面倒でしょう。

それでは、私の考えたCCRに汎用レジスタ番号を割りつけたらどうでしょうか。そうすれば、CCR(汎用レジスタのうちの1本)に対するビット演算と、RISC V風の条件分岐命令で、柔軟な分岐が実現できます。
また、CCRのビットのうち、例外処理的なビットと、正負/零を示すビットを別の汎用レジスタ番号を割り当てれば、もっとシンプルになるかもしれません。

| | コメント (0) | トラックバック (0)

命令セットアーキテクチャを考える(番外編) max/min命令

命令コードのビットパターンに余裕があればですが、max命令/min命令を追加したいと思っています。

max [v] [b|h|w|d] Rs,{Rt|=imm},Rd

・RsとRtまたは即値を比較して小さくない方をRdにセットする。
・Rdにセットされる値に応じてCCRがセットされる。

基本的な命令を組み合わせて実現すると、以下のようなコードになります。
分岐命令が入るので、あまり好ましくありません。

mv Rs,Rd
comp Rs,Rt
bgt next
mv Rt,Rd
next *

min [v] [b|h|w|d] Rs,{Rt|=imm},Rd

・RsとRtまたは即値を比較して大きくない方をRdにセットする。


実は、max命令があれば、min命令はなくても、以下のように実現できます。3命令必要になりますが。
逆にmin命令があれば、max命令を実現できます。
また、キャリーやオーバーフローを考慮すると機械命令レベルではもうちょっと複雑になります。

min(a,b) = a + b - max(a,b)
max(a,b) = a + b - min(a,b)


整数データの場合、比較を行うので、符号付きと符号なしデータを命令コードレベルで区別する必要があります。

maxu [v] [b|h|w|d] Rs,{Rt|=imm},Rd
minu [v] [b|h|w|d] Rs,{Rt|=imm},Rd

水平演算命令も欲しいところです。

hmax [b|h|w|d] Rs,{Rt|=imm},Rd
hmin [b|h|w|d] Rs,{Rt|=imm},Rd
hmaxu [b|h|w|d] Rs,{Rt|=imm},Rd
hminu [b|h|w|d] Rs,{Rt|=imm},Rd

当然、整数演算だけでなく浮動小数点演算も欲しくなります。

fmax [v] [b|h|w|d] Rs,{Rt|=imm},Rd
fmin [v] [b|h|w|d] Rs,{Rt|=imm},Rd
fhmax [b|h|w|d] Rs,{Rt|=imm},Rd
fhmin [b|h|w|d] Rs,{Rt|=imm},Rd

命令コードのビットパターンに余裕がないので、レジスタ本数を32本(5bit)に減らさないと無理ですね。

| | コメント (0) | トラックバック (0)

2015/02/24

位相空間について

位相空間の定義(公理)について最初は全然理解できなかったのですが、ちょっと分かった気になってきました。

一般的な位相空間の定義は、以下のようなものです。(同値な定義はいろいろとできますが、下記の開集合を基にした定義が一般的と思います)

-----------------------------------------------------
集合 X の部分集合からなる族 τ で、以下の条件(公理)

1) 空集合 φ および全体集合 X は τ に属す
φ∈τ, X∈τ
2) τ に属する集合の有限個の共通集合はふたたび τ に属す
∀A,B∈τ ⇒ A∩B∈τ
3) τ に属する集合の任意個(無限濃度をも許す)の合併は τ に属す
∀A_λ∈τ ⇒ ∪A_λ∈τ (λ∈Λ(任意の添え字集合ラムダ))

を満足するものが与えられるとき、集合 X に τ の元を開集合とする位相が定まるといい、組 (X,τ) を X を台集合とし τ を開集合系とする位相空間と呼ぶ。

-----------------------------------------------------
Wikipediaの定義の項をもとに編集しました。
なお、τ(タウ)は位相(Topology)の頭文字Tに対応するギリシャ文字です。


いきなりこんな定義を書かれてもなんのことか分かりません。

また、Wikipediaには以下のような記述もあります。

-----------------------------------------------------
数学における位相空間(いそうくうかん、topological space)とは、集合に要素どうしの近さや繋がり方に関する情報(位相、topology)を付け加えたものである。この情報は関数の連続性や点列の収束といった概念の源といえる。

ユークリッド空間やその部分集合においては、点の間の距離をもちいて異なる点の間の近さを測ることができ、それに基づいた位相空間の構造が得られる。一般に、距離空間は最も想像しやすい種類の位相空間の例を与えているが、一方で距離空間の枠組みは柔軟性に欠ける面もある。
-----------------------------------------------------

ということで、位相空間とは距離空間で議論される連続や連結といった概念を距離を用いずに一般化したもの、ということになります。
私にはなかなか理解できませんでしたが、数学の本やサイトを乱読した結果、なんとなく分かったような気がしてきました。
今回もやはり単なる勘違いという可能性もありますが。


以下、私なりの理解をまとめてみます。

距離空間(X,d)から定義される開集合について

ε>0とし、点x∈Xの「ε近傍 Bε(x)」とは、
Bε(x)={y∈X | d(x,y)<ε}
すなわち、xから距離がε未満の点の集合であり、 「ε開円盤」「ε開球」といわれることもある。 (円盤/球は、二次元/三次元ユークリッド空間を想像するとよい)

集合A⊆Xが「開集合」であるとは、
∀x∈A, ∃ε, Bε(x)⊆A
すなわち、Aに属する任意の点xに対して、Aに含まれるようなε近傍が(xのそれぞれ毎に)存在する。


上記のように定義した開集合から、閉集合、開近傍、閉包、内部、境界、連続写像などの位相的概念の定義と定理が導かれます。例えば、

・閉集合とは、開集合の補集合
・x∈Xの近傍とは、xが属するような開集合
・Aの内部とは、Aに含まれるような近傍が存在する点の集合
・Aの境界とは、Aの内部でなく、Aの補集合の内部でもない点の集合
・Aの閉包とは、Aの内部とAの境界の和集合

など。


上記のように、開集合の最初の定義以外は、距離(から定義されるε近傍)を直接使わずとも、開集合さえあれば定義できます。


また、連続写像は、距離空間では最初はεδ論法を用いて、ε近傍で定義しますが、「写像が連続であることの必要十分条件は、開集合の逆写像が開集合であること」が導かれます。


距離から導かれる位相(開集合とそこから導かれる数学的概念)では、距離は(開集合の定義を導く以外には)直接的には不要ということが分かりました。


さらに、ε近傍から定義される開集合から以下の定理が成り立ちます。

Aが開集合 ⇔
∀x∈A, ∃B:開集合, x∈B⊆A
すなわち、Aに属する任意の点xに対して、xが属しAに含まれるような開集合Bが存在する

循環論法的な定理ですが、逆にいえば「最初に開集合ありき」とすれば、距離がなくても位相の議論ができることを示しています。


⇒開集合が満たすべき本質的性質(公理)はなにかと考えると、突き詰めると以下の三つの性質(開集合の公理)になる

1) X 自身および空集合は開集合である
2) 有限個の開集合 A_1, ..., A_n の共通部分は開集合である
3) 開集合の族 {A_λ|λ∈Λ}について,その和集合は開集合である
(非加算無限個であってもよい)

| | コメント (0) | トラックバック (0)

2014/07/12

命令セットアーキテクチャを考える(番外編) 飽和演算

「ぼくのかんがえたさいきょうのめいれいせっと」では、SIMD演算(ベクトル演算)モードでは、自動的に飽和演算(サチュレート演算ともいう)となります。その6の整数加算命令ではSIMDモードについて以下のように書きました。

> ・condition code bitは変化しない。加算結果が最大値を超えた場合には最大値が、最小値(負数で絶対値が最大のもの)を超えた場合は最小値がセットされる(飽和演算)。

同様に、その7の浮動小数点加算命令のSIMDモードでも、以下のように書きました。

> ・SIMDモードの場合、CCR1は変化しない。結果の絶対値が最大値を超えた場合には符号付きの最大値が、計算できない場合にはNaNが返る。

飽和演算って言葉は普通は整数データにしか使わないような感じもするのですが、浮動小数点データだって、最大値付近のデータを加算すれば指数ビットがオーバーフローすることもありえます。ましてや乗算なら。

このような仕様にしたのは、演算結果の状態に応じてフラグをセットするためのCondition Code Registerが1組しかないのに、SIMD演算命令では同時に複数の演算結果が得られるため、CCRをセットしなくても良いようにしようという発想からであり、積極的に飽和演算機能を備えようと思ったからではありません。CCRが複数あると、条件付き分岐命令の際にどのCCRを見ればいいかとか、ややこしくなることも頭にありました。

普通の計算処理においては、計算結果がオーバーフローなどしたら変に丸めたりしないで、別の処理をとる必要があることがほとんどと考えています。その場合にはSIMDモードは使用できず、スカラーモードで繰り返し計算をしていただく必要があります。

つまり、「ぼくのかんがえたさいきょうのめいれいせっと」アーキテクチャではSIMD演算命令は自動的にすべて飽和計算モードになってしまい、それが嫌ならスカラーモードで繰り返し計算してください、という考え方です(でした)。


前置きが長くなってしまいましたが、「これでよかったのかなぁ」というのがこの番外編のテーマです。

「飽和演算になってしまうのは嫌だけど、SIMD(ベクトル)演算は必要だ」というニーズが多ければ、考え直さなければなりません。

その場合には、CCRをスカラー演算用セットの他に、ベクトル演算用にあと7セット(SIMD演算モードは最大8個のデータ処理を同時に行なうため)または8セット(スカラー演算用CCRとは別にする場合)追加すれば可能です。演算結果のどれかが例外割り込みが必要になった場合には、割り込み処理を呼び出し、あとは割り込みルーチン内でどの演算結果が(複数個の場合も含めて)例外になったのかどうかを判断して処理してもらえればいいでしょう。そのためには、CCRの内容を汎用レジスタに転送する特殊命令も必要そうです。
なお、条件付き分岐命令ではSIMD命令でセットされるCCRは見ないことにしてしまいましょう。


逆に、SIMDではない普通の(スカラー)演算で、飽和演算モードは必要でしょうか。
飽和演算モードが必要な場合、別の命令コードを起こしたり命令モードビットを立てるのは、命令フォーマットに余裕がないことから避けたいです。

その3の丸めモード指定レジスタを拡張して、飽和演算モードビットを追加するのが良さそうです。

> [Rounding Mode Register(Read/Write)]
> ・浮動小数点演算の丸め処理のモードを指定する
> ・特権モードでのみ設定可能、ユーザプログラムからは読み取りのみ可能。

その3を書いた時点では、この特殊レジスタはシステムに1個(各スレッドで共通)という想定でしたが、プログラムで丸めモードを変更するということになると、ユーザプログラムからも設定可能で、スレッド切り替え時には退避されるようにする必要があります。

| | コメント (0) | トラックバック (0)

2014/06/29

命令セットアーキテクチャを考える (番外編) 積和演算命令について再考

その4(命令コード)で、

> ・積和演算命令は備えない(4オペランド必要になるので)

としていますが、積和演算命令は科学技術計算や画像処理・信号処理などで多様されるので、やはり実装したほうがいいのかなと考えてみました。

「ぼくのかんがえたさいきょうのめいれいせっと」では、積和演算が必要な場合、特に短精度データ(単精度の間違いではありません)の場合には、SIMDモード命令と水平演算命令を組み合わせることで、比較的高性能(少ない命令数と少ないクロック数)で実現できると考えていました。

例えば、単精度実数による4次元ベクトルA=(a1,a2,a3,a4)とB=(b1,b2,b3,b4)の内積を計算する場合には以下のようにプログラミングできます。

アドレスAから連続する4ワードにa1,a2,a3,a4が格納され、アドレスBから連続する4ワードにb1,b2,b3,b4が格納されており、その内積をアドレスCに格納するとします。

A: dc float"a1","a2","a3","a4" # dcは定数を定義する(define constant)アセンブラ命令
B: dc float"b1","b2","b3","b4" # 同上
C: da float # daは領域確保を定義する(define area)アセンブラ命令

lea R0,=A,R1 # R1にアドレスAを格納する : offset値(=A)は、アセンブラがPC相対アドレスを計算する
lea R0,=B,R2 # R2にアドレスBを格納する : 同上
lea R0,=C,R3 # R3にアドレスCを格納する : 同上

fldm 2 R1,=0,FR2 # FR2,FR3にベクトルAを格納する
fldm 2 R2,=0,FR4 # FR4,FR5にベクトルBを格納する

fadd v sp FR0,FR0,FR6 # FR6,FR7,FR8,FR9に単精度実数0.0×8個を格納する
fmul v sp FR2,FR4,FR6 # FR6,FR7にa1*b1,a2*b2,a3*b3,a4*b4を単精度実数として計算し、格納する
fhadd sp FR6,FR1 # FR1の下位32bitに、FR6,FR7,FR8,FR9に格納されているa1*b1,a2*b2,a3*b3,a4*b4と0.0*0.0×4個の総和を計算して格納する

fstore sp R3,=0,FR1 # FR1の下位32bitの内容をアドレスCに格納する

アドレス計算やload/store、それにSIMDモード命令のパックドデータ数の調整のためのレジスタクリアを除けば、SIMDモード乗算命令と水平加算命令の計2命令で実現できます。積和演算というくらいなのでベクトル演算を除けば乗算と加算命令で実現できるのは当たり前ですが。ただ、ややこしいといえばややこしいので、積和演算命令(SIMDモード付き)ができれば当然そのほうがプログラマ的にも便利でしょう。


積和演算命令を備えない理由として、4オペランド必要になることを挙げていました。
が、上記の内積計算のように、多くの積和計算処理では各要素データの乗算結果の総和をとるような計算が多いので、A×B+C→DでなくてA×B+C→Cでも、多くの場合、Cの元の値を別レジスタに保存しておく必要はなさそうです。ディストネーションオペランドの意味が微妙に違ってきてしまいますが、眼を瞑ることにして、命令コードフォーマットの問題はひとまず解決とします。


ところが、浮動小数点演算命令はすでに16種類あり、命令コードを「綺麗な形式」で浮動小数点積和演算命令を追加することができません。整数演算命令も命令コードのビットパターンに空きがありません。
命令コードが綺麗な形式で定義できないと、前提条件で書いたような「ダンプデータをみてもプログラムが読める」目的からはずれていってしまいますので好ましくありません。

浮動小数点演算命令の場合は、番外編の「本当の汎用レジスタセット」に書いたように、汎用レジスタと浮動小数点レジスタ間の単純データ転送命令(ビットパターンのままの転送命令)を省略することができれば、この問題は解決します。

(修正)命令数を数え直したら、浮動小数点演算命令は全部で15種類でした(その13は修正しました)。ということで、上記のような変更を加えなくても、命令の追加は可能です。また、逆数の近似値命令と平方根の逆数の近似値命令を、即値ビットを使ってモード指定するようにすれば、命令コードをもう一つ空けることもできます。


整数演算命令の命令コードビットパターンは、load/store/分岐命令が7種類、ビット演算命令も7種類なのでここに埋め込むことも可能です。あまり「綺麗な形式」とはいえませんが。できれば、四則演算命令のパターンのところに追加したいのですが、四則演算というくらいなので命令4種類、それぞれに符号付き二進数と符号なし二進数の場合があるので合計8種類になり、空きがありません。
符号付きと符号なしをどこかの空きビットを使ってモード設定できればいいのですが、その空きビットもありません。即値を10bit指定から減らせば可能ですが、分岐命令のoffset範囲が半分に減っちゃうのは結構影響が大きいように思います。

スワップ命令(1)をビット演算命令(7)のグループと一緒にして、水平演算命令(7)のグループに積和演算命令を追加するのが、比較的綺麗そうですね。


ところで、整数の積和演算命令って必要ですかね。
信号処理などのデジタル化データの場合は浮動小数点データではなくて整数の場合も多いと思います。この命令セットではDSPのような用途は想定していませんけど、静止画像処理とか動画像処理とかは、「普通の」PCやワークステーションでも多く利用される用途でしょう。ってことはやはりあったほうがよさそうです。それに、浮動小数点データのみに積和演算命令を追加というのは、綺麗じゃないですよね。

結論はでないまま、今日のところはここまで。

| | コメント (0) | トラックバック (0)

2014/06/28

命令セットアーキテクチャを考える (番外編) 本当の汎用レジスタ

ほとんどのCPUアーキテクチャでは、整数演算/論理演算/ビット操作等用の汎用レジスタと、浮動小数点レジスタは別構成となっています。「ぼくのかんがえたさいきょうのめいれいせっと」シリーズでもそれにならって、汎用レジスタ×64本と浮動小数点レジスタ×64本の構成としました。

汎用レジスタと浮動小数点レジスタを別構成にするというのは、おそらく浮動小数点演算ユニットが電子回路的に複雑でチップ面積をたくさん必要とするとか、処理クロックもたくさん掛かるとかなどで、浮動小数点演算ユニットが使うレジスタも、汎用レジスタとは別回路として演算回路の近くに配置しよう、というような理由じゃないかと想像しています。というか、浮動小数点演算はコプロセッサとして別チップだったという歴史的な背景もあるように思います。

一方で、アプリケーションプログラマからみると、汎用レジスタも浮動小数点レジスタも、演算用にデータを一時的に置いておくところという意味では同じです。別になっていなければならない理由はありません。むしろ、load/store型アーキテクチャでは、浮動小数点レジスタにどのようにデータを詰め込むか、あるいは取り出すかということを、汎用レジスタとは別に考えなければならなくなります。
「ぼくのかんがえたさいきょうのめいれいせっと」アーキテクチャでも、浮動小数点レジスタ用のメモリデータアクセス(load/store)命令と、汎用レジスタ⇔浮動小数点レジスタ間のビットパターン転送命令を追加しました。

電子回路的なことは無視すると、同一のレジスタを整数演算命令が操作するときは整数データとして、浮動小数点数演算命令が操作するときは浮動小数点数データとして扱うようにできれば、便利になりそうです。

「ぼくのかんがえたさいきょうのめいれいせっと」アーキテクチャは、64本ものレジスタを持っており、最近主流のCPUアーキテクチャはだいたい32本であることを考えると、64本が汎用/浮動小数点レジスタ兼用という「本当の汎用」レジスタにしても、レジスタ本数が少なくて不便ということは少ないと考えられます。

| | コメント (0) | トラックバック (0)

2014/06/21

命令セットアーキテクチャを考える13 (命令コード)

命令コードフォーマットのうちopcode 6bitの割り当て概略案です。

opcodeの構成(上位3bit)

000 : load/store(4) + 分岐(branch/jump)命令(4)
001 : 整数演算命令(四則演算)(6)
010 : 水平演算(7) + スワップ命令(1)
011 : 論理演算命令(3) + シフト命令(5)
100 : 浮動小数点演算命令(15)
101 : 同上
110 : bit操作命令(7)
111 : special

# loop命令を追加したため、分岐命令の数を3→4に変更しました。(2018/03/21)
# add/subの符号なし命令を削除したため、整数演算命令の数を8→4に変更しました。(2018/03/21)

これで上位3bitを見るだけで、どういった命令かがわかるようになります。

その4で書いた、命令コードフォーマットのちょっと変態なビット割り付けの理由がここでわかります。

最初の前提条件で書いたように、「16進ダンプを見てもプログラムがわかるのが理想」なのですが、いろいろとやって見ても難しかったので、それじゃぁ「8進ダンプならどうか」って考えました。実は、64本というレジスタ本数も6bitで表現できるということが理由です。8bit(256本)にしたらもっと良かったのですが、残念ながら3オペランド命令形式では、レジスタ指定ビットだけで24bit使っちゃうので、命令コードが入りません。

その4で書いた命令コードフォーマットですが、ちょっと変則的に16bit(2バイト)単位に下位から3bitずつ区切ると区切りやすいようなっています。


[命令コードフォーマット]

bit[31:28] : Mode(1+1+2) :vector/PC相対/increment,imm/offset,データ長
bit[27:22] : OPcode(6)
bit[21:16] : Rs(6)
bit[15:6] : imm/offset(10) : imm/offsetとRtはどちらか一方
bit[11:6] : Rt(6)
bit[5:0] : Rd(6)


とりあえず、このシリーズはいったん終了です。

| | コメント (0) | トラックバック (0)

2014/06/20

命令セットアーキテクチャを考える12 (特殊命令)

その他、特殊命令関係です。知識がないため未検討です。多分こんな命令が必要なはず、と想像しています。


[モード遷移命令群]
・supervisor-mode/user-mode切り換えなど

[同期/排他制御用命令群]
・セマフォ、バリア命令など

[暗号化支援]
・暗号化/復号化、キー生成

[仮想化支援]
・よくわかりません

[特殊レジスタアクセス命令]
・よくわかりません

[省電力支援]
・よくわかりません


とりあえず、前提が、アプリケーションプログラマから見た命令セットということで始めましたので、上記のような機能はOSのサービスを呼び出すということでゴニョゴニョ…

| | コメント (0) | トラックバック (0)

2014/06/16

命令セットアーキテクチャを考える11 (分岐命令)

ようやく終わりに近づいてきました。分岐命令です。


[Jump/Branch]:4命令

条件付き分岐はbranch(br)、無条件分岐はjump(jmp)と称する

brl [pc] Rs,=imm,Rd

・CCR0/CCR1の状態がimmで指定される条件に合致する場合に、Rsで指定したアドレスに分岐し、Rdには戻りアドレスとして現在のPCの値が格納される(branch and link)。
・pcモードの場合は、PCの内容とRsの内容を加算したアドレスに分岐する。
・CCR0/CCR1は変化しない。

・imm(10bit)による分岐条件の詳細は以下の通り。
・bit9:CCR0かCCR1を指定(どちらか一方のみ)
・bit8:bit0-bit7が、CCR0/CCR1の各ビットと複数マッチした場合に、その論理積(and)をとるか論理和(or)をとるかを指定
・bit7-bit0:CCR0またはCCR1の対応するビットが"1"である場合に条件成立とする

・ここで、CCR0とCCR1の内容を再掲しておきます。

[CCR0]
bit4: Overflow/Carryover(o) : Overflow
bit3: Underflow/Borrow(u) : Underflow
bit2: positive/plus(p) : Positive
bit1: zero(z) : Zero
bit0: negative/minus(m) : Minus

[CCR1]
bit7: 非正規化数(s) : Subnormal number
bit6: 無限大(i) : Infinite number
bit5: NaN(n) : Not a number
bit4: Overflow : Overflow
bit3: Underflow : Underflow
bit2: positive/plus(p) : Positive
bit1: zero(z) : Zero
bit0: negative/minus(m) : Minus


・戻りアドレスを格納しない(branch and linkではない)branch命令はない。戻りアドレスが不要な場合はRdとしてR0を指定する。


jmpl [pc] Rs,{Rt|=offset},Rd

・Rs及びRtまたはoffsetで指定したアドレスに分岐し、Rdには戻りアドレスとして現在のPCの値が格納される(jump and link)。
・分岐先アドレスの計算は、RsとRtの和、またはRsと(offset値の4倍)の和となる。
・アセンブラ言語ソースプログラムではoffsetの値はそのまま記述し、アセンブラが1/4してoffset領域に設定する。
・pcモードの場合は、さらにPCの内容を加算したアドレスに分岐する。
・CCR0/CCR1は変化しない。

・戻りアドレスを格納しない(jump and linkではない)jump命令はない。戻りアドレスが不要な場合はRdとしてR0を指定する。

# 命令コードに余裕がありましたので、loop命令を追加しました。(2018/03/21)

loop [pc] Rs,{Rt|=offset},Rd

・Rdの内容を1減算し、0でなければRs及びRtまたはoffsetで指定したアドレスに分岐する。
・1減算後のRdの内容が0であれば、なにもしない。
・分岐先アドレスの計算は、RsとRtの和、またはRsと(offset値の4倍)の和となる。
・アセンブラ言語ソースプログラムではoffsetの値はそのまま記述し、アセンブラが1/4してoffset領域に設定する。
・pcモードの場合は、さらにPCの内容を加算したアドレスに分岐する。
・CCR0/CCR1は変化しない。

lea Rs,{Rt|=offset},Rd

・分岐ではないが、おなじようにアドレス計算するということで、ここの括りに入っています。
・PCとRsとRtの和、またはPCとRsと(offset値の4倍)の和を計算し、Rdに格納する。
・アセンブラ言語ソースプログラムではoffsetの値はそのまま記述し、アセンブラが1/4してoffset領域に設定する。


[擬似命令]

nop → jmpl pc R0,R0,R0

・PCの指すアドレス(次の実行番地)にジャンプするのでnop(No Operation)となる。
・そもそも、すべて固定長命令フォーマットであり、かつ遅延スロットもないのでnopは不要なような気もしますが…
・copy R0,R0,R0でも代用可能。但し、condition codeが変化する


opfch → brl Rs,=#3ff,R0 :

・opfch(operation code fetch)命令は、必ず不成立となる条件付き分岐命令に変換される。
・分岐は必ず失敗するが、分岐先アドレスの命令データfetch処理が途中まで進むため、L1命令キャッシュが読み込まれる。

br [r] Rs,=imm → brl [pc] Rs,=imm,R0
jmp [r] Rs,Rt → jmpl [pc] Rs,Rt,R0

・戻りリンク無しの分岐命令はないが、アセンブラ言語ソースプログラムの見やすさのため、リンク無し分岐命令のような擬似命令を用意した。アセンブラがリンクアドレス格納レジスタをR0と設定する。


branch命令の条件コードをimm値として記述するのはややこしいため、アセンブラで以下のような擬似命令を備える。

brleq Rs,Rd → brl Rs,=#102,Rd : z-flg on
brlne Rs,Rd → brl Rs,=#005,Rd : p-flg on or m-flg on
brlge Rs,Rd → brl Rs,=#006,Rd : p-flg on or z-flg on
...
breqf Rs → br Rs,=#302 : z-flg on
brnef Rs → br Rs,=#105 : p-flg on or m-flg on
brgef Rs → br Rs,=#106 : p-flg on or z-flg on
...

| | コメント (0) | トラックバック (0)

より以前の記事一覧