FPGA開発日記

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

Verilatorのコンパイルフローを観察する (3. 内部のデータ変換を追いかける)

Verilatorが内部でどのような方式によりVerilogC++に変換しているのか興味がある。 色々調べてみると、--debugオプションを付けるとデータフローグラフを出力してくれるらしい。

verilator --cc  --debug simple_ff.sv

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

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

--debugオプションでVerilogC++に変換されるフローが観察できる。

  • 001:リンクされるモジュールファイルをParseする。
- V3ParseImp.cpp:320: Lexing simple_assign.sv
- V3LinkCells.cpp:201:Link Module: MODULE 0x7fffe4eca660 <e3#> {c1ai} u4=0x7fffe4eca7f0  simple_assign  L0 [NONE]
dot -Tpdf -o ~/a.pdf obj_dir/Vsimple_assign_001_linkcells.dot
  • 002:デザインの構造を把握する。
- V3Ast.cpp:1124:     Dumping obj_dir/Vsimple_assign_002_cells.tree
Verilator Tree Dump (format 0x3900) from <e0> to <e94>
     NETLIST 0x7fffe4eb4f40 <e1#> {a0aa}  $root [1ps/1ps]
    1: MODULE 0x7fffe4eca660 <e94#> {c1ai}  simple_assign  L0 [1ps]
    1:2: PORT 0x7fffe4ecb3d0 <e19#> {c3az}  in1
    1:2: VAR 0x7fffe4ecb8d0 <e22#> {c3az} @dt=0@  in1 INPUT PORT
    1:2:1: BASICDTYPE 0x7fffe4ecb4b0 <e21#> {c3ak} @dt=this@(nw1)  logic kwd=logic
    1:2:1:1: RANGE 0x7fffe4ec4f50 <e18#> {c3ar}
    1:2:1:1:2: CONST 0x7fffe4ecb590 <e16#> {c3at} @dt=0x7fffe4ecad20@(G/swu32/3)  ?32?sh4
    1:2:1:1:3: CONST 0x7fffe4ecb720 <e17#> {c3aw} @dt=0x7fffe4ecb190@(G/swu32/1)  ?32?sh0
    1:2: PORT 0x7fffe4ecc5e0 <e50#> {c4az}  in2
    1:2: VAR 0x7fffe4eccdf0 <e49#> {c4az} @dt=0@  in2 INPUT PORT
    1:2:1: BASICDTYPE 0x7fffe4ecc6c0 <e48#> {c4ak} @dt=this@(nw1)  logic kwd=logic
    1:2:1:1: RANGE 0x7fffe4ecca50 <e45#> {c4ar}
    1:2:1:1:2: CONST 0x7fffe4eccb10 <e43#> {c4at} @dt=0x7fffe4ecad20@(G/swu32/3)  ?32?sh4
    1:2:1:1:3: CONST 0x7fffe4eccc80 <e44#> {c4aw} @dt=0x7fffe4ecb190@(G/swu32/1)  ?32?sh0
    1:2: PORT 0x7fffe4ecdb00 <e78#> {c5az}  out
    1:2: VAR 0x7fffe4ece0c0 <e77#> {c5az} @dt=0@  out OUTPUT PORT
    1:2:1: BASICDTYPE 0x7fffe4ecdbe0 <e76#> {c5al} @dt=this@(nw1)  logic kwd=logic
    1:2:1:1: RANGE 0x7fffe4ecdcc0 <e73#> {c5ar}
    1:2:1:1:2: CONST 0x7fffe4ecdd80 <e71#> {c5at} @dt=0x7fffe4ecad20@(G/swu32/3)  ?32?sh4
    1:2:1:1:3: CONST 0x7fffe4ecdf10 <e72#> {c5aw} @dt=0x7fffe4ecb190@(G/swu32/1)  ?32?sh0
    1:2: ASSIGNW 0x7fffe4ece860 <e93#> {c8am} @dt=0@
    1:2:1: AND 0x7fffe4ece7a0 <e91#> {c8as} @dt=0@
    1:2:1:1: PARSEREF 0x7fffe4ece540 <e88#> {c8ao}  in1 [TEXT]
    1:2:1:2: PARSEREF 0x7fffe4ece6c0 <e89#> {c8au}  in2 [TEXT]
    1:2:2: PARSEREF 0x7fffe4ece3c0 <e92#> {c8ai}  out [TEXT]
    3: TYPETABLE 0x7fffe4eb55e0 <e2#> {a0aa}
                detailed  ->  BASICDTYPE 0x7fffe4ecb190 <e13#> {c3aw} @dt=this@(G/swu32/1)  logic [GENERIC] kwd=logic range=[31:0]
                detailed  ->  BASICDTYPE 0x7fffe4ecad20 <e8#> {c3at} @dt=this@(G/swu32/3)  logic [GENERIC] kwd=logic range=[31:0]
    3:1: BASICDTYPE 0x7fffe4ecad20 <e8#> {c3at} @dt=this@(G/swu32/3)  logic [GENERIC] kwd=logic range=[31:0]
    3:1: BASICDTYPE 0x7fffe4ecb190 <e13#> {c3aw} @dt=this@(G/swu32/1)  logic [GENERIC] kwd=logic range=[31:0]
  • 007:これはどうも良く分からない。リンク?
- V3Ast.cpp:1124:     Dumping obj_dir/Vsimple_assign_007_link.tree
// Each module:
//   Look for BEGINs
//      BEGIN(VAR...) -> VAR ... {renamed}
//   FOR -> WHILEs
//
//   Add JumpLabel which branches to after statements within JumpLabel
//      RETURN -> JUMPBLOCK(statements with RETURN changed to JUMPGO, ..., JUMPLABEL)
//      WHILE(... BREAK) -> JUMPBLOCK(WHILE(... statements with BREAK changed to JUMPGO),
//                                    ... JUMPLABEL)
//      WHILE(... CONTINUE) -> WHILE(JUMPBLOCK(... statements with CONTINUE changed to JUMPGO,
//                                    ... JUMPPABEL))
  • 008:linkInc、これも良く分からない。結果は007のリンクと一緒だった。
- V3Ast.cpp:1124:     Dumping obj_dir/Vsimple_assign_008_linkInc.tree- 
// V3LinkInc's Transformations:
//
//      prepost_stmt_visit
//        PREADD/PRESUB
//          Create a temporary __VIncrementX variable, assign the value of
//          the current variable value to it, substitute the current
//          variable with the temporary one in the statement.
//          Increment/decrement the original variable with by the given
//          value.
//        POSTADD/POSTSUB
//          Increment/decrement the current variable by the given value.
//          Create a temporary __VIncrementX variable, assign the value of
//          of the current variable (after the operation) to it. Substitute
//          The original variable with the temporary one in the statement.
//      prepost_non_stmt_visit
//        PREADD/PRESUB/POSTADD/POSTSUB
//          Increment/decrement the current variable by the given value.
//          The order (pre/post) doesn't matter outside statements thus
//          the pre/post operations are treated equally and there is no
//          need for a temporary variable.
  • 010:LinkDot
- V3Ast.cpp:1124:     Dumping obj_dir/Vsimple_assign_010_paramlink.tree
// LinkDot TRANSFORMATIONS:
//      Top-down traversal in LinkDotFindVisitor
//          Cells:
//              Make graph of cell hierarchy
//          Var/Funcs's:
//              Collect all names into symtable under appropriate cell
//      Top-down traversal in LinkDotScopeVisitor
//          Find VarScope versions of signals (well past original link)
//      Top-down traversal in LinkDotParamVisitor
//          Create implicit signals
//      Top-down traversal in LinkDotResolveVisitor
//          VarXRef/Func's:
//              Find appropriate named cell and link to var they reference
  • 012:Width
- V3Ast.cpp:1124:     Dumping obj_dir/Vsimple_assign_012_width.tree
// V3Width's Transformations:
//      Top down traversal:
//          Determine width of sub-expressions
//              width() = # bits upper expression wants, 0 for anything-goes
//              widthUnsized() = # bits for unsized constant, or 0 if it's sized
//              widthMin() = Alternative acceptable width for linting, or width() if sized
//              Determine this subop's width, can be either:
//                  Fixed width X
//                  Unsized, min width X   ('d5 is unsized, min 3 bits.)
//              Pass up:
//                  width() = # bits this expression generates
//                  widthSized() = true if all constants sized, else false
//          Compute size of this expression
//          Lint warn about mismatches
//              If expr size != subop fixed, bad
//              If expr size  < subop unsized minimum, bad
//              If expr size != subop, edit netlist
//                      For == and similar ops, if multibit underneath, add a REDOR
//                      If subop larger, add a EXTRACT
//                      If subop smaller, add a EXTEND
//          Pass size to sub-expressions if required (+/-* etc)
//              FINAL = true.
//              Subexpressions lint and extend as needed
  • 014:Const
- V3Const.cpp:2658:   constifyAllLive:
- V3Ast.cpp:1124:     Dumping obj_dir/Vsimple_assign_014_const.tree
// CONST TRANSFORMATIONS:
//   Call on one node for PARAM values, or netlist for overall constant folding:
//      Bottom up traversal:
//          Attempt to convert operands to constants
//          If operands are constant, replace this node with constant.