@Vengineerの戯言 : Twitter SystemVerilogの世界へようこそ、すべては、SystemC v0.9公開から始まった
はじめに
Dynamic Scheduler版 Verilatorの中を調べる、その3。今回は、wait がどのように実装されているのかをみていきます。
Verilog HDLコード
Verilog HDLコード (examples/wait/wait.v) を以下に示します。wait の中で 変数の比較をやっています。
module t(/*AUTOARG*/); int a = 0; int b = 0; int c = 0; initial begin $write("starting with a == 0, b == 0, c == 0\n"); #2; $write("assigning 1 to b.\n"); b = 1; #1; $write("assigning 2 to a.\n"); a = 2; #1; $write("assigning 3 to c.\n"); c = 3; #1; $write("assigning 4 to c.\n"); c = 4; #1; $write("assigning 5 to b.\n"); b = 5; end initial begin #1; $write("waiting for a > b...\n"); wait(a > b); $write("waited for a > b.\n"); $write("waiting for a + b < c...\n"); wait(a + b < c); $write("waited for a + b < c.\n"); $write("waiting for a < b && b > c...\n"); wait(a < b && b > c); $write("waited for a < b && b > c.\n"); $write("*-* All Finished *-*\n"); $finish; end endmodule
生成されたC++コード
initial 文は、Vtop__Slow.cpp の _initial__TOP__? メソッドです。
_initial__TOP__1, _initial__TOP__2, _initial__TOP__3 メソッドは、Verilog HDLコードの下記の部分に対応します。
int a = 0; int b = 0; int c = 0;
_initia\l__TOP__4 メソッドは、最初の initial 文に、_initial__TOP__5 メソッドは、2番目の initial 文に対応します。最初の initial 文は #遅延のコードなので、(その1)にて説明しましたので、ここでは省略します。wait に対応するコードは、wait_until メソッドの部分です。各wait_until メソッドの部分の return のコードが wait の中の条件を表しています。
2番目の initial 文に対応するC++コードである _initial__TOP__5 メソッドは、次のようになっています。
void Vtop::_initial__TOP__5(Vtop__Syms* __restrict vlSymsp, VerilatedThread* self) { VL_DEBUG_IF(VL_DBG_MSGF("+ Vtop::_initial__TOP__5\n"); ); Vtop* const __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp; // Body self->wait_for_time(vlSymsp, VL_TIME_Q() + 1U); if (self->should_exit()) return; VL_WRITEF("waiting for a > b...\n"); /* [wait statement] */ self->wait_until([](auto&& values) -> bool { return VL_GTS_III(1,32,32, std::get<0>(values), std::get<1>(values)); }, vlTOPp->t__DOT__b, vlTOPp->t__DOT__a); if (self->should_exit()) return; VL_WRITEF("waited for a > b.\nwaiting for a + b < c...\n"); /* [wait statement] */ self->wait_until([](auto&& values) -> bool { return VL_LTS_III(1,32,32, ((IData)(std::get<0>(values)) + (IData)(std::get<1>(values))), std::get<2>(values)); }, vlTOPp->t__DOT__c, vlTOPp->t__DOT__b, vlTOPp->t__DOT__a); if (self->should_exit()) return; VL_WRITEF("waited for a + b < c.\nwaiting for a < b && b > c...\n"); /* [wait statement] */ self->wait_until([](auto&& values) -> bool { return (VL_LTS_III(1,32,32, std::get<0>(values), std::get<1>(values)) & VL_GTS_III(1,32,32, std::get<1>(values), std::get<2>(values))); }, vlTOPp->t__DOT__c, vlTOPp->t__DOT__b, vlTOPp->t__DOT__a); if (self->should_exit()) return; VL_WRITEF("waited for a < b && b > c.\n*-* All Finished *-*\n"); VL_FINISH_MT("/home/vengineer/home/verilator/verilator-dynamic-scheduler-examples/examples/wait/wait.sv", 37, "") ; return; }
- wait( a> b) は、VL_GTS_III(1,32,32, std::get<0>(values), std::get<1>(values))
- wait(a + b < c) は、VL_LTS_III(1,32,32, *1 + (IData)(std::get<1>(values))), std::get<2>(values));
- wait(a < b && b > c ) は、VL_LTS_III(1,32,32, std::get<0>(values), std::get<1>(values)) & VL_GTS_III(1,32,32, std::get<1>(values), std::get<2>(values)));
のようになっています。LV_XXX_IIIマクロを使って、wait のカッコ内の条件を表しています。
おわりに
今回は、wait の実装についてみてみました。wait の実装は、event の @(event) と同じ wait_until メソッドを使っていることがわかりました。
次回は、fork/join について調べてみます。
*1:IData)(std::get<0>(values