公開日:2026/02/07
title.png

38th Season


#38-1 Nihoniumパイプライン実装(You)

 Cmod A7ボード(FPGA)を使って開発しているオリジナル32ビットCPUコアNihoniumの実装方式として、パイプライン方式を採用してみたいと思います。

 前回、レジスタファイルのアーキテクチャを決定し、資源が競合する場合について検討しました。今回は、分岐命令がパイプラインを乱す場合の事例研究を進めたいと思います。

分岐ハザード

 ここからはパイプラインの乱れ(ハザード)の一つ、分岐ハザードに付いて考察して行きます。

 条件分岐命令🌱(beq命令)を例に分岐不成立時のパイプライン実行図を以下に示します。

a381_pipe_brnot.png

 条件が不成立で分岐しないのだから、何もしないnop命令と同じです。

 問題は、条件が成立して分岐する場合で、以下図となります。

a381_pipe_brtkn.png

 連続してフェッチしていた次命令<next instruction>のパイプラインを破棄して、新たに分岐先アドレスからIFステージを起動するため、+2サイクルの分岐ペナルティが発生します。本来実行されるはずだった、次命令<next instruction>のIFから、分岐先命令のIFまでが分岐ペナルティです。

遅延分岐

 分岐ハザードを軽減するため、ARMや日立のSuperH等が採用しているのが、遅延分岐と言うアーキテクチャです。
 前節分岐成立時のパイプライン実行図で、分岐判定前に開始してしまったIFステージが、次のIDステージで乗っ取られて破棄されていましたね?折角開始したIFを途中で破棄するのは勿体ないので、次命令までは実行してしまって、その後で分岐すると分岐ハザードを軽減する事が可能です(下図)。

a381_pipe_brdly.png

 分岐命令直後の命令を特にディレイスロットと呼びます。上図の場合、beq命令が分岐成立した場合でも、次のldbiu命令までは実行してから分岐します。ディレイスロットにldbiu命令が入った状態です。
 結果、上図の通り、4段パイプラインにて分岐ペナルティが2サイクル→1サイクルに減って、分岐成立時の実行サイクル数が2サイクルに短縮されました。

※上図でお解りだと思いますが、条件分岐命令の2個後続命令<next instruction>も、破棄されています。さらにパフォーマンスを上げるため、ディレイスロットを2個に設定する考え方もあります。

 ただ、これは命令セットアーキテクチャ(ISA;Instruction Set Architecture)に関わる技術です。ISAで遅延分岐を採用していないNihoniumに於いてこれを採用してしまうと、Moscoviumシリーズ内で互換性を失ってしまいます。
 従って、Nihoniumに於いては、不採用です。

遅延分岐の悲喜こもごも

 遅延分岐に関して言及しておくと、実は使って見ると、すごく使い難いです。そもそも、ディレイスロットに投入できる命令には制限があります。先行する分岐命令の動作に影響しない命令である必要があるからです。

 しかも、条件分岐命令の分岐成立時と不成立時に共通して実行したい命令って、何よ??って事です。

 条件によって異なる処理に分岐したいからこそ、条件分岐命令を使うはずです。なのに、「分岐成立/不成立に関わらず実行する命令を記述できますよ」って言われても、全然嬉しくないのです。

 割り込みを受け付ける機構の検討を始めると、更に重大な問題に直面する事になります。

  例)ディレイスロットの命令を実行中に割り込みを受け付けることができるか?

 仮に割り込みの課題を解決したとしても、中々ディレイスロットを埋める命令が無く、結局nop命令を投入する、なんていう無意味な事になるのが落ちだったりします。理論的に有理でしょ?とか騙されて遅延分岐を採用したところで、ガッカリする事になるかもしれません。よく考えて採否を決めましょう。

ステートマシン方式との比較

 ステートマシン方式のNihoniumに於ける分岐成立時のパイプライン実行図は、以下となっています。

a381_pipe_brfsm.png

 その代わり、IDとEXが混然一体となって1ステージに押し込まれていたため、周波数を高くすることが困難な実装でした。


 ここで、以下の様に定義しておきます。

 この2つの指標は、以下の通り相反する関係にあります。

サイクル性能が高い 1サイクル内の処理が複雑で、
周波数を上げ難い
周波数性能は低い
サイクル性能が低い 1サイクル内の処理が簡素で、
周波数を上げ易い
周波数性能は高い

 原理的に相反する指標なので、一般に、一方を上げると、他方が下がる関係にあります。また、サイクル性能を×2倍にするのと、周波数性能を×2倍にするのとを比べると、結果として同じパフォーマンスとなります。

 分岐成立時、2サイクル→3サイクルとなって、サイクル性能が×2/3倍に低下しますが、その分、周波数性能が×3/2倍に向上できたら、同等性能です。そもそも、サイクル性能が低下するのは分岐命令だけですが、周波数性能が上がると、分岐命令以外のパフォーマンスも向上するので、周波数が×3/2倍に満たない場合でも、全命令を総合(平均)したら性能が向上する場合があります。

 突き詰めると、「どちらの性能がより上げ易いか?」って事になるのです。
 今回のNihoniumでは、どちらが有利か不明ですが、一旦、分岐ペナルティ2サイクルを許容して先へ進めたいと思います(周波数性能を選択)。

衆議院議員選挙(2026/02/08)も、近い未来を決定する取捨選択。

ロシアが始めた侵略戦争に端を発したエネルギ/穀物価格の高騰。
ここに円安が重なって、エネルギも食料品も輸入に頼る日本の消費者に物価高騰の打撃。
政府・与党は物価高を対策する気は、全くない
だって消費税があるから。物価が上がれば、自動的に税収が増える。濡れ手に粟。
だから、選挙用に打ち出した消費減税の公約も、期間限定。選挙対策な事は明白。

与党に騙されてはいけない。今回も、非与党への投票で決まり

レジスタ読み出し(RDステージ)の追加

 レジスタファイルからレジスタ値を読み出す回路も、そこそこ重たい回路であると指摘しました。レジスタ読み出しRDステージを追加した方が、周波数性能を向上できる余地が広がります。
 ところが、このRDステージを追加する場合、EAステージの前段に追加する必要が生じます。ということは、分岐ペナルティを増加させてしまう事に繋がってしまうのです(下図)。

a381_pipe_brrds.png

 ステートマシン方式Nihoniumでのパイプライン実行図も含めて、パイプラインの段数によって分岐ペナルティのサイクル数が変化する事をご理解いただけた事と思います。一般的には、パイプライン段数が増加すると分岐ペナルティも増加する傾向があります。
 前節で解説した通り、サイクル性能と周波数性能のどちらを優先して設計するか?という課題に帰着します。

 今回は、RDステージを不採用としました。既に、分岐ペナルティの1サイクル増加を許容しているので、更にサイクル性能を落とすことは避けたいのが理由です。

※RDステージを追加する場合、レジスタ更新と参照間の競合条件が複雑化する事にも留意。WB更新→RD参照の競合が2命令先で発生、新たにEX更新→RD参照間にも競合条件発生、等。RDを採用する効果は高いが、難易度も高い。

jal命令とrtn命令

 サブルーチンに分岐するjal命令と、そこから復帰してくるrtn命令も、分岐命令の一種です。単に分岐だけすれば良い命令と異なり、一旦分岐した後、元の位置に戻ってくる必要がある命令です。

 ステートマシン方式のNihoniumに於けるjal命令の実行サイクル数は、分岐命令の実行サイクル数+1サイクルでした。増加した+1サイクルは、スタックへの書き込みサイクルです。
 4段パイプライン方式でのパイプライン実行図を下図に示し、解説します。

a381_pipe_jrtn.png

 jal命令は、先にプログラムカウンタpcを更新して、分岐先のフェッチ(IFステージ)と、戻り先アドレス<return addr>のスタック書き込み(MAステージ)を同時に実行できるようになったため、通常の分岐命令と同じ3サイクルで分岐できました。
 rtn命令では、Pcの回復にWBステージの終了時まで要するため、分岐ペナルティが大きく、実行に4サイクル掛かります。


 分岐命令についての検討が終わりました。パイプライン方式で実装すると、分岐ペナルティが増加した分、ステートマシン方式と比べて、実行サイクル数が増加することが判りました。致し方なしです。


btn_arduino.png

btn_prev.png btn_next.png

home