Verilator は最速の Verilog シミュレータかつ lint ツール。オープンソースのツールであり、機能が優れているため、様々なプロジェクトで利用されている (Welcome to Verilator - Veripool)。
Verilator の大きな特徴として、Verilog を C++ にコンパイルしてからシミュレーションすることが挙げられる。また、設計した回路のテストベンチを C++ で記述できるため、Verilog だけでは困難なシミュレーションを行えるという特徴もある。
Verilator で波形ファイルを出力する方法には以下の2通りの方法がある。
1つ目の方法は他の Verilog シミュレータを利用したことがある人にとっては親しみやすい。2つ目の方法は C++ のみでテストベンチを記述するときに向いている。これらの2通りの方法について、サンプルプロジェクトを例にそれぞれ説明する。
今回は C++ のテストベンチを利用する場合について紹介する。Verilog のファイルだけを使ってシミュレーションする場合は、verilator --binary --trace <verilog_file>
などとし、後述する $dumpfile
や $dumpvars
を追加すれば波形ファイルを出力できる。
一次資料を読みたい方は以下がおすすめ。
- How do I generate waveforms (traces) in C++? - Verilator User's Guide
- verilator/examples/make_tracing_c - GitHub
動作環境
OS release : Ubuntu 22.04.3 LTS Verilator version : Verilator 5.019 devel rev v5.018-75-g39d9bd4d4
サンプルプロジェクト
サンプルプロジェクトのディレクトリ構成は以下のようになっている。
. ├── Makefile ├── sim_main.cpp ├── top.v └── counter.v
sim_main.cpp
が Verilator 用のテストベンチを記述した C++ ファイル、top.v
が Verilog のシミュレーション用の記述をした Verilog ファイル、counter.v
がカウンタ回路を記述した Verilog ファイル。Makefile
はソースコードをビルドして動かすために利用する。それぞれのファイルの内容を以下に示す。
Makefile
#=========================================================== # Sources #----------------------------------------------------------- SRCS += $(wildcard *.v) CXX_SRCS += $(wildcard *.cpp) #=========================================================== # Verilator #----------------------------------------------------------- VERILATOR ?= verilator VL_TOPNAME := Vtop VERILATOR_FLAGS += --cc --exe --build VERILATOR_FLAGS += --prefix $(VL_TOPNAME) VERILATOR_INPUT += $(CXX_SRCS) $(SRCS) #=========================================================== # Build rules #----------------------------------------------------------- .PHONY: default build run clean default: build run build: $(VERILATOR) $(VERILATOR_FLAGS) $(VERILATOR_INPUT) run: obj_dir/$(VL_TOPNAME) clean: rm -rf obj_dir rm -f *.vcd
sim_main.cpp
#include <verilated.h> #include "Vtop.h" int main (int argc, char **argv) { VerilatedContext *contextp = new VerilatedContext; contextp->commandArgs(argc, argv); Vtop *top = new Vtop{contextp}; top->clk_i = 0; top->rst_ni = 0; while (!contextp->gotFinish()) { contextp->timeInc(1); top->clk_i = !top->clk_i; if (!top->clk_i) { if (contextp->time()>5) { top->rst_ni = 1; } } top->eval(); } top->final(); delete top; return 0; }
top.v
module top ( input wire clk_i , input wire rst_ni ); wire [31:0] cntr; counter counter0 ( .clk_i (clk_i ), .rst_ni(rst_ni), .cntr_o(cntr ) ); always @(negedge clk_i) begin $write("%10d\n", cntr); if (cntr==20) begin $finish; end end endmodule
counter.v
module counter ( input wire clk_i , input wire rst_ni, output wire [31:0] cntr_o ); reg [31:0] cntr; assign cntr_o = cntr; always @(posedge clk_i) begin if (!rst_ni) begin cntr <= 0; end else begin cntr <= cntr+1; end end endmodule
1. Verilog ファイルに $dumpfile
や $dumpvars
を追加して波形ファイルを出力する方法
まずは1つ目の方法について説明する。変更を加えるファイルは sim_main.cpp
、top.v
、Makefile
の3つ。
sim_main.cpp
に波形の出力を有効化するための処理を追加する。以下のソースコードにおいて、コメントで <- Added
と記述した行が新たに追加したコード。
// sim_main.cpp #include <verilated.h> #include "Vtop.h" int main (int argc, char **argv) { VerilatedContext *contextp = new VerilatedContext; contextp->commandArgs(argc, argv); contextp->traceEverOn(true); // <- Added
top.v
に $dumpfile
や $dumpvars
を追加する。$dumpfile
は波形ファイルの出力先を指定するものであり、$dumpvars
は波形の出力を行うモジュールの階層を指定するもの。
// top.v module top ( input wire clk_i , input wire rst_ni ); initial begin // <- Added $dumpfile("dump.vcd"); // <- Added $dumpvars(0); // <- Added end // <- Added
Makefile
に波形ファイルを出力するための Verilator オプション --trace
を追加する。--trace
は VCD (Value Change Dump) 形式の波形ファイルを出力するために使用される。
# Makefile VERILATOR_FLAGS += --cc --exe --build VERILATOR_FLAGS += --prefix $(VL_TOPNAME) VERILATOR_FLAGS += --trace # <- Added VERILATOR_INPUT += $(CXX_SRCS) $(SRCS)
あとは make
を実行すればシミュレーションが行われ、波形ファイル dump.vcd
が出力される。波形を見るには gtkwave dump.vcd
を実行すればよい。
2. C++ ファイルから直接波形を出力する方法
次に、2つ目の方法について説明する。変更を加えるファイルは sim_main.cpp
、Makefile
の2つ。
sim_main.cpp
に波形ファイルを出力するために必要なヘッダーファイル、波形の出力を有効化するための処理、波形ファイルのオープン、書き込み、クローズの処理を追加する。
// sim_main.cpp #include <verilated.h> #include <verilated_vcd_c.h> // <- Added #include "Vtop.h" int main (int argc, char **argv) { VerilatedContext *contextp = new VerilatedContext; contextp->commandArgs(argc, argv); contextp->traceEverOn(true); // <- Added Vtop *top = new Vtop{contextp}; top->clk_i = 0; top->rst_ni = 0; VerilatedVcdC *tfp = new VerilatedVcdC; // <- Added top->trace(tfp, 0); // <- Added tfp->open("dump.vcd"); // <- Added while (!contextp->gotFinish()) { contextp->timeInc(1); top->clk_i = !top->clk_i; if (!top->clk_i) { if (contextp->time()>5) { top->rst_ni = 1; } } top->eval(); tfp->dump(contextp->time()); // <- Added } tfp->close(); // <- Added top->final(); delete tfp; // <- Added delete top; return 0; }
Makefile
に波形ファイルを出力するための Verilator オプション --trace
を追加する。
# Makefile VERILATOR_FLAGS += --cc --exe --build VERILATOR_FLAGS += --prefix $(VL_TOPNAME) VERILATOR_FLAGS += --trace # <- Added VERILATOR_INPUT += $(CXX_SRCS) $(SRCS)
あとは1つ目の方法と同様に make
を実行すればシミュレーションが行われ、波形ファイル dump.vcd
が出力される。波形を見るには gtkwave dump.vcd
を実行すればよい。