FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

Verilatorのコンパイルフローを観察する (2. 順序回路を生成するまで)

クロックデザインをどのように設計しているのか見てみることにした。以下のようなVerilogファイルをコンパイルして生成されるファイルを観察する。

  • simple_ff.sv
module simple_ff
  (
   input logic          clk,
   input logic [ 4: 0]  in,
   output logic [ 4: 0] out
   );

logic [ 4: 0]           tmp_ff;

always_ff @ (posedge clk) begin
  tmp_ff <= in;
  out <= tmp_ff;
end
void Vsimple_ff::_eval(Vsimple_ff__Syms* __restrict vlSymsp) {
    VL_DEBUG_IF(VL_DBG_MSGF("+    Vsimple_ff::_eval\n"); );
    Vsimple_ff* const __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp;
    // Body
    if (((IData)(vlTOPp->clk) & (~ (IData)(vlTOPp->__Vclklast__TOP__clk)))) {
        vlTOPp->_sequent__TOP__1(vlSymsp);
    }
    // Final
    vlTOPp->__Vclklast__TOP__clk = vlTOPp->clk;
}

こんなんでいいのか(笑)。clk信号がタイムスライス中で反転した場合、_sequent__TOP__1が実行される。

VL_INLINE_OPT void Vsimple_ff::_sequent__TOP__1(Vsimple_ff__Syms* __restrict vlSymsp) {
    VL_DEBUG_IF(VL_DBG_MSGF("+    Vsimple_ff::_sequent__TOP__1\n"); );
    Vsimple_ff* const __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp;
    // Body
    vlTOPp->out = vlTOPp->simple_ff__DOT__tmp_ff;
    vlTOPp->simple_ff__DOT__tmp_ff = vlTOPp->in;
}

この論理が少し妙だ。これはoutから順に

  • vlTOPp->simple_ff__DOT__tmp_ffからvlTOPp->out

  • vlTOPp->inからvlTOPp->simple_ff__DOT__tmp_ff

となっているがもしこれが逆に配置されていれば普通に信号が通過してinからoutまで一気通貫で実行されてしまう。これはデータフローを解析して、出力に近い側から評価するようになっているのか?

代入の順番を逆にしてもやはり結果は同じだった。容易に想像できるのは、FFを含むデータフローを作って、出力側から追いかけていき代入するフローを作っていくことだ。ソフトウェアパイプラインのような技法に近い。

色々調べてみると、--debugオプションを付けるとデータフローグラフを出力してくれるらしい。

verilator --cc  --debug simple_ff.sv

とりあえず出てきたdotファイルを片っ端から画像に変換する。

for dot in `ls -1 *.dot`
do
    dot -Tjpg -O ${dot}
done

最終的なグラフは以下のようになった。これではまだ良く分からないなあ...

f:id:msyksphinz:20210330001528j:plain