![]() |
5 |
RISC-Vプロセッサの設計 (32) |
段間データの構造体化
これまでのPCパイプラインでは、段間FIFOを流れるのは Maybe#(int) のPCだけでした。実際のプロセッサでは、段が進むにつれて流す情報が増えます。IFでは命令コード、IDではデコード結果とレジスタ値、EXでは演算結果が加わります。
そこで、段間ごとに構造体を定義し、それをMaybeで包んでFIFOに流します。
typedef Bit#(32) Addr;
typedef Bit#(32) Data;
typedef Bit#(32) Inst;
typedef Bit#(5) RIndx;
typedef struct { Addr pc; Bool epoch; } PC2IF deriving (Bits, Eq);
typedef struct { Addr pc; Bool epoch; Inst inst; } IF2ID deriving (Bits, Eq);
typedef struct { Addr pc; Bool epoch; DecInst dInst;
Data rVal1; Data rVal2; } ID2EX deriving (Bits, Eq);
typedef struct { Addr pc; DecInst dInst; Data result; } EX2MA deriving (Bits, Eq);
typedef struct { Addr pc; Maybe#(RIndx) dst; Data data; } MA2WB deriving (Bits, Eq);
DecInstはデコーダが返す構造体で、別の回で説明します。epochは分岐での取り消し用のタグです。
段間FIFOは次のようになります。
import SpecialFIFOs::*;
FIFO#(Maybe#(PC2IF)) ifs <- mkPipelineFIFO;
FIFO#(Maybe#(IF2ID)) ids <- mkPipelineFIFO;
FIFO#(Maybe#(ID2EX)) exs <- mkPipelineFIFO;
FIFO#(Maybe#(EX2MA)) mas <- mkPipelineFIFO;
FIFO#(Maybe#(MA2WB)) wbs <- mkPipelineFIFO;
EX段の例
waitの扱いはこれまでと同じです。wait中は上流をdeqせずに止め、下流にはinvalid(パイプラインバブル)を流します。
rule ex_stage;
let m = exs.first; // Maybe#(ID2EX)
if (!ex_wait) begin
exs.deq;
Maybe#(EX2MA) out = tagged Invalid;
if (m matches tagged Valid .x)
out = tagged Valid EX2MA { pc: x.pc, dInst: x.dInst,
result: alu(x.dInst.aluOp, x.rVal1, x.rVal2) };
mas.enq(out);
end
else
mas.enq(tagged Invalid);
endrule
上流からinvalidが来た場合は、そのままinvalidを次段へ渡します。
この形にする利点
- 段ごとに型が違うので、段を取り違えた接続はコンパイルエラーになる。
- 項目を足すときは構造体に1行加えるだけで、FIFOの幅は自動で追従する。
- valid bitはMaybeがMSBに1ビット付ける。記事(26)で見た33ビットのMaybe#(int)と同じ構造で、GTKWaveでもMSBを見ればバブルを判別できる。
- 記事(23)で区別したデータパイプラインと制御パイプラインが、1つの型の中に同居する。valid bitが制御パイプライン、構造体の中身がデータパイプラインである。
Invalidのときのデータ部はbscが不定値として扱うので、データ部にはvalidによる選択回路が作られません。bsc 2025.07で生成したVerilogでは、<EX>→<MA>の段間データは次のようになりました。
assign mas_rv$port1__write_1 =
{ 1'd1, // FIFOの内部フラグ
exs_rv[134] && exs_rv[101] == exEpoch, // Maybeのvalid bit
exs_rv[133:102], // pc(素通し)
exs_rv[100:64], // dInst(素通し)
x__h2450 } ; // ALU結果(素通し)
計算されているのはvalid bitの1ビットだけで、pc、dInst、演算結果は上流の値がそのまま入っています。合成ツールの最適化を待たずに、bscの段階で「valid bitだけが制御パイプライン、中身はデータパイプライン」という構造になっています。






