@Vengineerの戯言 : Twitter
SystemVerilogの世界へようこそ、すべては、SystemC v0.9公開から始まった
はじめに
昨日の「Verilatorの中を調べる(その1)」の続き。
Verilatorの最新版 v4.200 では、その前の v4.110 とちょこっと変わったようです。。。それは、後程。
準備
最新版の v4.200 をインストール。あたしは Windows 10 上の WSL2/Ubuntu 20.04 + Visual Studio を使っています。
インストール先は、/usr/local/verilator/v4.200 です。
SystemCを使うので、v2.3.3 をビルドし、/usr/local/systemc/2.3.3 にインストールしています。
とりあえず、-V オプションにて確認。環境変数 PATH に /usr/local/verilator/v4.200/bin を追加し、SYSTEMC_INCLUDE に /usr/local/systemc/2.3.3/inculde を設定しています。
下記のログから、VERILATOR_ROOT に /usr/local/verilator/v4.200/share/verilator、SYSTMEC_INCLUDE に /usr/local/systemc/2.3.3/inculde が設定されているのがわかります。
$ verilator -V Verilator 4.200 2021-03-12 rev v4.200 Copyright 2003-2021 by Wilson Snyder. Verilator is free software; you can redistribute it and/or modify the Verilator internals under the terms of either the GNU Lesser General Public License Version 3 or the Perl Artistic License Version 2.0. See https://verilator.org for documentation Summary of configuration: Compiled in defaults if not in environment: SYSTEMC = SYSTEMC_ARCH = SYSTEMC_INCLUDE = SYSTEMC_LIBDIR = VERILATOR_ROOT = /usr/local/verilator/v4.200/share/verilator SystemC system-wide = 1 Environment: MAKE = PERL = SYSTEMC = SYSTEMC_ARCH = SYSTEMC_INCLUDE = /usr/local/systemc/2.3.3/include SYSTEMC_LIBDIR = VERILATOR_ROOT = VERILATOR_BIN = Features (based on environment or compiled-in support): SystemC found = 1
examples/make_hello_c
examples/make_hello_c を見てみます。
Verilog HDLコードは、top.v 、テストベンチ側は sim_main.cpp (C++コード)です。あとは、Makefile です。
make コマンドを実行してみましょう。
以下のように、最初に verilator -cc --exe --build -j top.v sim_main.cpp が実行されています。
$ cd examples/make_hello_c $ ls Makefile sim_main.cpp top.v $ make - Verilator hello-world simple example -- VERILATE & BUILD -------- verilator -cc --exe --build -j top.v sim_main.cpp make[1]: Entering directory '/mnt/c/Users/haray/home/verilator/verilator/examples/make_hello_c/obj_dir' g++ -I. -MMD -I/usr/local/verilator/v4.200/share/verilator/include -I/usr/local/verilator/v4.200/share/verilator/include/vltstd -DVM_COVERAGE=0 -DVM_SC=0 -DVM_TRACE=0 -DVM_TRACE_FST=0 -faligned-new -fcf-protection=none -Wno-bool-operation -Wno-sign-compare -Wno-uninitialized -Wno-unused-but-set-variable -Wno-unused-parameter -Wno-unused-variable -Wno-shadow -std=gnu++14 -Os -c -o sim_main.o ../sim_main.cpp g++ -I. -MMD -I/usr/local/verilator/v4.200/share/verilator/include -I/usr/local/verilator/v4.200/share/verilator/include/vltstd -DVM_COVERAGE=0 -DVM_SC=0 -DVM_TRACE=0 -DVM_TRACE_FST=0 -faligned-new -fcf-protection=none -Wno-bool-operation -Wno-sign-compare -Wno-uninitialized -Wno-unused-but-set-variable -Wno-unused-parameter -Wno-unused-variable -Wno-shadow -std=gnu++14 -Os -c -o verilated.o /usr/local/verilator/v4.200/share/verilator/include/verilated.cpp /usr/bin/perl /usr/local/verilator/v4.200/share/verilator/bin/verilator_includer -DVL_INCLUDE_OPT=include Vtop.cpp Vtop__Slow.cpp Vtop__Syms.cpp > Vtop__ALL.cpp g++ -I. -MMD -I/usr/local/verilator/v4.200/share/verilator/include -I/usr/local/verilator/v4.200/share/verilator/include/vltstd -DVM_COVERAGE=0 -DVM_SC=0 -DVM_TRACE=0 -DVM_TRACE_FST=0 -faligned-new -fcf-protection=none -Wno-bool-operation -Wno-sign-compare -Wno-uninitialized -Wno-unused-but-set-variable -Wno-unused-parameter -Wno-unused-variable -Wno-shadow -std=gnu++14 -Os -c -o Vtop__ALL.o Vtop__ALL.cpp Archive ar -cr Vtop__ALL.a Vtop__ALL.o g++ sim_main.o verilated.o Vtop__ALL.a -o Vtop make[1]: Leaving directory '/mnt/c/Users/haray/home/verilator/verilator/examples/make_hello_c/obj_dir' -- RUN --------------------- obj_dir/Vtop Hello World! - top.v:11: Verilog $finish final -- DONE -------------------- Note: Once this example is understood, see examples/make_tracing_c. Note: Also see the EXAMPLE section in the verilator manpage/document.
cc オプションは、テストベンチ側に C++ を使う時に指定します。生成されるものが C++ コードになります。
exe オプションは、実行プログラムを生成します。
build オプションは、コードを生成して、実行プログラムを生成します。
ls コマンドにて生成されたコードを確認してみましょう。obj_dir ディレクトリが生成され、その下にいろいろなファイルが生成されています。
$ ls Makefile obj_dir sim_main.cpp top.v $ ls obj_dir Vtop Vtop.h Vtop__ALL.a Vtop__ALL.d Vtop__Slow.cpp Vtop__Syms.h Vtop__verFiles.dat sim_main.d verilated.d Vtop.cpp Vtop.mk Vtop__ALL.cpp Vtop__ALL.o Vtop__Syms.cpp Vtop__ver.d Vtop_classes.mk sim_main.o verilated.o
obj_dir はデフォルト値で、-Mdir directory_name にて変更できます。
$ make clean $ verilator --c --exe --build -j top.v sim_main.cpp -Mdir xxx $ ls Makefile xxx sim_main.cpp top.v
build オプションを付けないで実行するとどうなるでしょうか?*.d や *.o および、Vtop_ALL.a や Vtop などのオブジェクトは生成されていません。--build オプションをしていすることでこれらオブジェクトを生成していることになります。
$ make clean Makefile sim_main.cpp top.v $ verilator --cc --exe top.v sim_main.cpp $ ls obj_dir Vtop.cpp Vtop.h Vtop.mk Vtop__Slow.cpp Vtop__Syms.cpp Vtop__Syms.h Vtop__ver.d Vtop__verFiles.dat Vtop_classes.mk
最初のログファイルを見てみると、obj_dir ディレクトリ内で、g++ コマンドにて生成されたC++コードをコンパイルしています。
コンパイルしているファイルは、../sim_main.cpp 、 /usr/local/verilator/v4.200/share/verilator/include/verilated.cpp、Vtop__ALL.cpp です。ただし、Vtop_ALL.cpp は、Vtop.cpp,
Vtop_Slow.cpp Vtop__Syms.cpp を リダイレクトしたファイルです。Vtop__ALL.o は、ar コマンドに Vtop_ALL.a にして、最後に、sim_main.o verilated.o Vtop_ALL.a から Vtop を生成しています。
make[1]: Entering directory '/mnt/c/Users/haray/home/verilator/verilator/examples/make_hello_c/obj_dir' g++ -I. -MMD -I/usr/local/verilator/v4.200/share/verilator/include -I/usr/local/verilator/v4.200/share/verilator/include/vltstd -DVM_COVERAGE=0 -DVM_SC=0 -DVM_TRACE=0 -DVM_TRACE_FST=0 -faligned-new -fcf-protection=none -Wno-bool-operation -Wno-sign-compare -Wno-uninitialized -Wno-unused-but-set-variable -Wno-unused-parameter -Wno-unused-variable -Wno-shadow -std=gnu++14 -Os -c -o sim_main.o ../sim_main.cpp g++ -I. -MMD -I/usr/local/verilator/v4.200/share/verilator/include -I/usr/local/verilator/v4.200/share/verilator/include/vltstd -DVM_COVERAGE=0 -DVM_SC=0 -DVM_TRACE=0 -DVM_TRACE_FST=0 -faligned-new -fcf-protection=none -Wno-bool-operation -Wno-sign-compare -Wno-uninitialized -Wno-unused-but-set-variable -Wno-unused-parameter -Wno-unused-variable -Wno-shadow -std=gnu++14 -Os -c -o verilated.o /usr/local/verilator/v4.200/share/verilator/include/verilated.cpp /usr/bin/perl /usr/local/verilator/v4.200/share/verilator/bin/verilator_includer -DVL_INCLUDE_OPT=include Vtop.cpp Vtop__Slow.cpp Vtop__Syms.cpp > Vtop__ALL.cpp g++ -I. -MMD -I/usr/local/verilator/v4.200/share/verilator/include -I/usr/local/verilator/v4.200/share/verilator/include/vltstd -DVM_COVERAGE=0 -DVM_SC=0 -DVM_TRACE=0 -DVM_TRACE_FST=0 -faligned-new -fcf-protection=none -Wno-bool-operation -Wno-sign-compare -Wno-uninitialized -Wno-unused-but-set-variable -Wno-unused-parameter -Wno-unused-variable -Wno-shadow -std=gnu++14 -Os -c -o Vtop__ALL.o Vtop__ALL.cpp Archive ar -cr Vtop__ALL.a Vtop__ALL.o g++ sim_main.o verilated.o Vtop__ALL.a -o Vtop make[1]: Leaving directory '/mnt/c/Users/haray/home/verilator/verilator/examples/make_hello_c/obj_dir'
生成された Vtop.h を見てみる
まずは、top.v の中を見てみます。initial 文内で、$display システムタスクと $finish システムタスクを実行しているだけです。
module top; initial begin $display("Hello World!"); $finish; end endmodule
生成された Vtop.h を見てみましょう。
// Verilated -*- C++ -*- // DESCRIPTION: Verilator output: Primary design header // // This header should be included by all source files instantiating the design. // The class here is then constructed to instantiate the design. // See the Verilator manual for examples. #ifndef VERILATED_VTOP_H_ #define VERILATED_VTOP_H_ // guard #include "verilated_heavy.h" //========== class Vtop__Syms; //---------- VL_MODULE(Vtop) { public: // INTERNAL VARIABLES // Internals; generally not touched by application code Vtop__Syms* __VlSymsp; // Symbol table // CONSTRUCTORS private: VL_UNCOPYABLE(Vtop); ///< Copying not allowed public: /// Construct the model; called by application code /// If contextp is null, then the model will use the default global context /// If name is "", then makes a wrapper with a /// single model invisible with respect to DPI scope names. Vtop(VerilatedContext* contextp, const char* name = "TOP"); Vtop(const char* name = "TOP") : Vtop(nullptr, name) {} /// Destroy the model; called (often implicitly) by application code ~Vtop(); // API METHODS /// Return current simulation context for this model. /// Used to get to e.g. simulation time via contextp()->time() VerilatedContext* contextp(); /// Evaluate the model. Application must call when inputs change. void eval() { eval_step(); } /// Evaluate when calling multiple units/models per time step. void eval_step(); /// Evaluate at end of a timestep for tracing, when using eval_step(). /// Application must call after all eval() and before time changes. void eval_end_step() {} /// Simulation complete, run final blocks. Application must call on completion. void final(); // INTERNAL METHODS static void _eval_initial_loop(Vtop__Syms* __restrict vlSymsp); void __Vconfigure(Vtop__Syms* symsp, bool first); private: static QData _change_request(Vtop__Syms* __restrict vlSymsp); static QData _change_request_1(Vtop__Syms* __restrict vlSymsp); void _ctor_var_reset() VL_ATTR_COLD; public: static void _eval(Vtop__Syms* __restrict vlSymsp); private: #ifdef VL_DEBUG void _eval_debug_assertions(); #endif // VL_DEBUG public: static void _eval_initial(Vtop__Syms* __restrict vlSymsp) VL_ATTR_COLD; static void _eval_settle(Vtop__Syms* __restrict vlSymsp) VL_ATTR_COLD; static void _final_TOP(Vtop__Syms* __restrict vlSymsp) VL_ATTR_COLD; static void _initial__TOP__1(Vtop__Syms* __restrict vlSymsp) VL_ATTR_COLD; } VL_ATTR_ALIGNED(VL_CACHE_LINE_BYTES); //---------- #endif // guard
VL_MODULE(Vtop) というマクロを使ったクラス定義になっています。VL_MODULEは、下記のように、include/verilated.h の中でマクロ定義されています。VerilatedModule クラスを継承した Vtop というクラスになります。
include/verilated.h:#define VL_MODULE(modname) class modname VL_NOT_FINAL : public VerilatedModule
テストベンチの sim_main.cpp を見てみる
テストベンチの sim_main.cpp を見てみます。#include にて、
Vtop* top = new Vtop; で top.v から生成された Vtop クラスのインスタンスを生成しています。生成したインスタンス top のメソッドである eval と final を呼んでいます。
#include <verilated.h> #include "Vtop.h" int main(int argc, char** argv, char** env) { if (false && argc && argv && env) {} Verilated::randReset(1); Vtop* top = new Vtop; while (!Verilated::gotFinish()) { top->eval(); } top->final(); delete top; return 0; }
eval および final メソッド の中を見てみる
eval は、Vtop.hおよびVtop.cpp 、final は Vtop_Slow.cpp の中で以下のようにメソッドが定義されています。
eval メソッドの中で、eval_step メソッドが呼ばれています。eval_step メソッドは、Vtop.cpp の中で下記のように定義されています。__Vchange が 1 の間、do - while loop を実行しています。
void eval() { eval_step(); }
void Vtop::eval_step() { VL_DEBUG_IF(VL_DBG_MSGF("+++++TOP Evaluate Vtop::eval\n"); ); Vtop__Syms* __restrict vlSymsp = this->__VlSymsp; // Setup global symbol table Vtop* const __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp; #ifdef VL_DEBUG // Debug assertions _eval_debug_assertions(); #endif // VL_DEBUG // Initialize if (VL_UNLIKELY(!vlSymsp->__Vm_didInit)) _eval_initial_loop(vlSymsp); // Evaluate till stable int __VclockLoop = 0; QData __Vchange = 1; do { VL_DEBUG_IF(VL_DBG_MSGF("+ Clock loop\n");); _eval(vlSymsp); if (VL_UNLIKELY(++__VclockLoop > 100)) { // About to fail, so enable debug to see what's not settling. // Note you must run make with OPT=-DVL_DEBUG for debug prints. int __Vsaved_debug = Verilated::debug(); Verilated::debug(1); __Vchange = _change_request(vlSymsp); Verilated::debug(__Vsaved_debug); VL_FATAL_MT("top.v", 8, "", "Verilated model didn't converge\n" "- See DIDNOTCONVERGE in the Verilator manual"); } else { __Vchange = _change_request(vlSymsp); } } while (VL_UNLIKELY(__Vchange)); }
一方、final メソッドは、Vtop_Slow.cpp で下記のように定義されています。_final_TOP メソッドが呼び出されています。
void Vtop::final() { VL_DEBUG_IF(VL_DBG_MSGF("+ Vtop::final\n"); ); // Variables Vtop__Syms* __restrict vlSymsp = this->__VlSymsp; Vtop* const __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp; // Body vlTOPp->_final_TOP(vlSymsp); }
_final_TOP メソッドも Vtop_Slow.cpp の中で次のように定義されています。特に何もしていません。
void Vtop::_final_TOP(Vtop__Syms* __restrict vlSymsp) { VL_DEBUG_IF(VL_DBG_MSGF("+ Vtop::_final_TOP\n"); ); // Variables Vtop* const __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp; // Body }
Vtop を実行してみる
生成された Vtop を実行してみましょう。Hello World! は、$display システムタスクの出力、- top.v:11:Verilog $finish は、$finish システムタスクの出力になります。
$ obj_dir/Vtop
Hello World!
- top.v:11: Verilog $finish
make コマンドの最後の部分と同じです。
-- RUN --------------------- obj_dir/Vtop Hello World! - top.v:11: Verilog $finish -- DONE --------------------
Verilog HDL の initial 文はどうなっているのか?
Verilog HDL の initial 文は、生成された Vtop クラスの中でどのように実装されているのでしょうか?
Vtop__Slow.cpp の initial__TOP__1 メソッドが Verilog HDL の initial 文に対応しているようです。下記のように // Body のコメントの後に、VL_WRITE("Hello World!\n"); と VL_FINISH_MT("top.v, 11, ""); が実行されています。これは、obj_dir/Vtop の実行結果に一致します。
void Vtop::_initial__TOP__1(Vtop__Syms* __restrict vlSymsp) { VL_DEBUG_IF(VL_DBG_MSGF("+ Vtop::_initial__TOP__1\n"); ); Vtop* const __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp; // Body VL_WRITEF("Hello World!\n"); VL_FINISH_MT("top.v", 11, ""); }
initial__TOP__1 メソッドは、以下のように、Vtop__Slow.cpp の eval_initial メソッドから呼ばれています。
void Vtop::_eval_initial(Vtop__Syms* __restrict vlSymsp) { VL_DEBUG_IF(VL_DBG_MSGF("+ Vtop::_eval_initial\n"); ); Vtop* const __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp; // Body vlTOPp->_initial__TOP__1(vlSymsp); }
_eval_initial メソッドは、Vtop.cpp の eval_initial_loop メソッドの最初に呼ばれています。
void Vtop::_eval_initial_loop(Vtop__Syms* __restrict vlSymsp) { vlSymsp->__Vm_didInit = true; _eval_initial(vlSymsp); // Evaluate till stable int __VclockLoop = 0; QData __Vchange = 1;
eval_initial_loop メソッドは、Vtop.cpp の eval_step メソッドの最初で呼ばれています。
void Vtop::eval_step() { VL_DEBUG_IF(VL_DBG_MSGF("+++++TOP Evaluate Vtop::eval\n"); ); Vtop__Syms* __restrict vlSymsp = this->__VlSymsp; // Setup global symbol table Vtop* const __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp; #ifdef VL_DEBUG // Debug assertions _eval_debug_assertions(); #endif // VL_DEBUG // Initialize if (VL_UNLIKELY(!vlSymsp->__Vm_didInit)) _eval_initial_loop(vlSymsp); // Evaluate till stable int __VclockLoop = 0; QData __Vchange = 1;
C++モデルの eval と Verilog HDL の initial 文の関係
以上のことからまとめると、
C++モデルの eval => eval_step => _eval_initial_loop => _eval_initial => initial__TOP__1 になり、initial_TOP__1 が Verilog HDL の initial 文に対応することになります。
initial 文を複数書くと?
initial 文を下記のように追加してみました。
module top; initial begin $display("Hello World!"); $finish; end initial begin $display("Hello World!-2"); end endmodule
make コマンドでの実行結果は、下記のようになりました。
-- RUN --------------------- obj_dir/Vtop Hello World! - top.v:11: Verilog $finish Hello World!-2 -- DONE --------------------
書いた順番に、initial 文が実行されているっぽいです。
生成されたコードの initial__TOP__1 メソッドは、下記のようになっています。
void Vtop::_initial__TOP__1(Vtop__Syms* __restrict vlSymsp) { VL_DEBUG_IF(VL_DBG_MSGF("+ Vtop::_initial__TOP__1\n"); ); Vtop* const __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp; // Body VL_WRITEF("Hello World!\n"); VL_FINISH_MT("top.v", 11, ""); VL_WRITEF("Hello World!-2\n"); }
initial 文をもう一つ追加しました。今度は、最初の initial 文の前に追加しました。
module top; initial begin $display("Hello World!-0"); end initial begin $display("Hello World!"); $finish; end initial begin $display("Hello World!-2"); end endmodule
実行結果は以下の通り。
-- RUN --------------------- obj_dir/Vtop Hello World!-0 Hello World! - top.v:14: Verilog $finish Hello World!-2 -- DONE -------------------- * おわりに
生成されたコードは、下記のように、最初の initial 文の Hellow World!-0 と 2番目の Hello World! が 1つの LV_WRITEF 文でまとまっていますね。
void Vtop::_initial__TOP__1(Vtop__Syms* __restrict vlSymsp) { VL_DEBUG_IF(VL_DBG_MSGF("+ Vtop::_initial__TOP__1\n"); ); Vtop* const __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp; // Body VL_WRITEF("Hello World!-0\nHello World!\n"); VL_FINISH_MT("top.v", 14, ""); VL_WRITEF("Hello World!-2\n"); }
final メソッドは何をする?
Vtop クラスの final メソッドは、何をするのだろうか?と思ったのですが、SystemVerilog には、final 文なるものがあります。どうやら、この final 文が final メソッドになるっぽです。
top.v に final 文を追加してみました。
module top; initial begin $display("Hello World!"); $finish; end final begin $display("final"); end endmodule
実行結果の最後に、final が表示されますね。
-- RUN --------------------- obj_dir/Vtop Hello World! - top.v:16: Verilog $finish final -- DONE --------------------
生成されたコードを見てみると、// Body の後に、VL_WRITEF("final\n"); が追加されています。
void Vtop::_final_TOP(Vtop__Syms* __restrict vlSymsp) { VL_DEBUG_IF(VL_DBG_MSGF("+ Vtop::_final_TOP\n"); ); // Variables Vtop* const __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp; // Body VL_WRITEF("final\n"); }
Verilated::gotFinish() メソッドとは?
テストベンチ sim_main.cppの中の Verilated::gotFinish() メソッドって、何だろうか?
while (!Verilated::gotFinish()) { top->eval(); }
Verilated::gotFinishメソッドは、include/verilated.h に以下のように定義されています。Verilated::threadContexp()->gotFinish() の戻り値を返しています。
static bool gotFinish() VL_MT_SAFE { return Verilated::threadContextp()->gotFinish(); }
こっちの gotFinish() は、include/verilated.h に次のように定義されています。m_s.m_gotFinish の値を返しているだけですね。
bool gotFinish() const VL_MT_SAFE { return m_s.m_gotFinish; }
m_s.m_gotFinish は、include/verilated.cpp の中で次のように gotFinish メソッドで設定されています。
void VerilatedContext::gotFinish(bool flag) VL_MT_SAFE { const VerilatedLockGuard lock(m_mutex); m_s.m_gotFinish = flag; }
gotFinish(bool flag) メソッドは、include/verilated.cpp の中の vl_finish、vl_stop、vl_fatal メソッドの中で呼ばれています。
#ifndef VL_USER_FINISH ///< Define this to override this function void vl_finish(const char* filename, int linenum, const char* hier) VL_MT_UNSAFE { if (false && hier) {} VL_PRINTF( // Not VL_PRINTF_MT, already on main thread "- %s:%d: Verilog $finish\n", filename, linenum); if (Verilated::threadContextp()->gotFinish()) { VL_PRINTF( // Not VL_PRINTF_MT, already on main thread "- %s:%d: Second verilog $finish, exiting\n", filename, linenum); Verilated::runFlushCallbacks(); Verilated::runExitCallbacks(); exit(0); } Verilated::threadContextp()->gotFinish(true); } #endif #ifndef VL_USER_STOP ///< Define this to override this function void vl_stop(const char* filename, int linenum, const char* hier) VL_MT_UNSAFE { const char* const msg = "Verilog $stop"; Verilated::threadContextp()->gotError(true); Verilated::threadContextp()->gotFinish(true); if (Verilated::threadContextp()->fatalOnError()) { vl_fatal(filename, linenum, hier, msg); } else { if (filename && filename[0]) { // Not VL_PRINTF_MT, already on main thread VL_PRINTF("%%Error: %s:%d: %s\n", filename, linenum, msg); } else { VL_PRINTF("%%Error: %s\n", msg); } Verilated::runFlushCallbacks(); } } #endif #ifndef VL_USER_FATAL ///< Define this to override this function void vl_fatal(const char* filename, int linenum, const char* hier, const char* msg) VL_MT_UNSAFE { if (false && hier) {} Verilated::threadContextp()->gotError(true); Verilated::threadContextp()->gotFinish(true); if (filename && filename[0]) { // Not VL_PRINTF_MT, already on main thread VL_PRINTF("%%Error: %s:%d: %s\n", filename, linenum, msg); } else { VL_PRINTF("%%Error: %s\n", msg); } Verilated::runFlushCallbacks(); VL_PRINTF("Aborting...\n"); // Not VL_PRINTF_MT, already on main thread // Second flush in case VL_PRINTF does something needing a flush Verilated::runFlushCallbacks(); // Callbacks prior to termination Verilated::runExitCallbacks(); abort(); } #endif
vl_finish、vl_stop、vl_fatal メソッドは、Verilog HDLの $finish、$stop、$fatal(これは、SystemVerilogかな?) システムタスクに対応していて、include/verilated.cpp で次のように定義されています。
void VL_FINISH_MT(const char* filename, int linenum, const char* hier) VL_MT_SAFE {
#ifdef VL_THREADED
VerilatedThreadMsgQueue::post(VerilatedMsg([=]() { //
vl_finish(filename, linenum, hier);
}));
#else
vl_finish(filename, linenum, hier);
#endif
}
void VL_STOP_MT(const char* filename, int linenum, const char* hier, bool maybe) VL_MT_SAFE {
#ifdef VL_THREADED
VerilatedThreadMsgQueue::post(VerilatedMsg([=]() { //
vl_stop_maybe(filename, linenum, hier, maybe);
}));
#else
vl_stop_maybe(filename, linenum, hier, maybe);
#endif
}
void VL_FATAL_MT(const char* filename, int linenum, const char* hier, const char* msg) VL_MT_SAFE {
#ifdef VL_THREADED
VerilatedThreadMsgQueue::post(VerilatedMsg([=]() { //
vl_fatal(filename, linenum, hier, msg);
}));
#else
vl_fatal(filename, linenum, hier, msg);
#endif
}
<< |
ということは、下記のように、$finish; をコメントアウトすると、シミュレーションは終わらないのか?
module top; initial begin $display("Hello World!"); // $finish; end endmodule
はい、終わりませんでした。
$ make
-- RUN ---------------------
obj_dir/Vtop
Hello World!
$stop システムタスクを追加したみたら、どうなるでしょうか?
module top; initial begin $display("Hello World!"); $stop(); // $finish; end endmodule
シミュレーションは終わりますが、%Error および Aborting ... になりますね。
-- RUN --------------------- obj_dir/Vtop Hello World! %Error: top.v:16: Verilog $stop Aborting... make: *** [Makefile:40: default] Aborted
$fatal システムタスクにしたみたら、ちょっと違うメッセージですが、%Error および Aborting ... になりますね。
module top; initial begin $display("Hello World!"); $fatal(); // $finish; end endmodule
-- RUN --------------------- obj_dir/Vtop Hello World! [0] %Error: top.v:16: Assertion failed in TOP.top %Error: top.v:16: Verilog $stop Aborting... make: *** [Makefile:40: default] Aborted
$stop システムタスクの場合は、fatalなエラーが発生した場合(fatalOnError()が0出ない時)は、vl_fatal ($fatalシステムタスクを呼んだ場合と同じ)を呼んでいますね。
#ifndef VL_USER_STOP ///< Define this to override this function void vl_stop(const char* filename, int linenum, const char* hier) VL_MT_UNSAFE { const char* const msg = "Verilog $stop"; Verilated::threadContextp()->gotError(true); Verilated::threadContextp()->gotFinish(true); if (Verilated::threadContextp()->fatalOnError()) { vl_fatal(filename, linenum, hier, msg); } else { if (filename && filename[0]) { // Not VL_PRINTF_MT, already on main thread VL_PRINTF("%%Error: %s:%d: %s\n", filename, linenum, msg); } else { VL_PRINTF("%%Error: %s\n", msg); } Verilated::runFlushCallbacks(); } } #endif
$fatal システムタスクでは、vl_fatal メソッドの最後に abort() 関数を呼んでいますね。
#ifndef VL_USER_FATAL ///< Define this to override this function void vl_fatal(const char* filename, int linenum, const char* hier, const char* msg) VL_MT_UNSAFE { if (false && hier) {} Verilated::threadContextp()->gotError(true); Verilated::threadContextp()->gotFinish(true); if (filename && filename[0]) { // Not VL_PRINTF_MT, already on main thread VL_PRINTF("%%Error: %s:%d: %s\n", filename, linenum, msg); } else { VL_PRINTF("%%Error: %s\n", msg); } Verilated::runFlushCallbacks(); VL_PRINTF("Aborting...\n"); // Not VL_PRINTF_MT, already on main thread // Second flush in case VL_PRINTF does something needing a flush Verilated::runFlushCallbacks(); // Callbacks prior to termination Verilated::runExitCallbacks(); abort(); } #endif
おわりに
Verilatror の中を調べるということで、例題の examples/make_hello_c で生成される C++ コードとその中で呼ばれる メソッドを調べてみました。
make_hello_c の top.v には、initial 文しかないですが、それだけでも、いろいろなことが行われていることがわかって、凄くためになりました。
次回は、examples/make_tracing_c を見てみます。
Verilatorの最新版 v4.200 では、その前の v4.110 とちょこっと変わった部分の例題が examples/make_trace_c にありましたので。
こうご期待。。。