Verilatorが内部でどのような方式によりVerilogをC++に変換しているのか興味がある。
色々調べてみると、--debug
オプションを付けるとデータフローグラフを出力してくれるらしい。
verilator --cc --debug simple_ff.sv
とりあえず出てきたdot
ファイルを片っ端から画像に変換する。
for dot in `ls -1 *.dot` do dot -Tjpg -O ${dot} done
--debug
オプションでVerilogがC++に変換されるフローが観察できる。
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.