電気回路/HDL/SystemPerl の導入 の履歴(No.4)
更新SystemPerl を入れてカバレッジ測定をしてみたい†
Verilator と SystemPerl を組み合わせて使うとカバレッジ測定ができるそうです。
カバレッジ解析について >> http://www.altima.jp/products/3rdparty/eda/code_coverage.html
電気回路/HDL/Verilator の導入(C++モード) および 電気回路/HDL/SystemC の導入 の続きです。
SystemPerl の導入†
ここでは cygwin 環境にて、Perl のモジュール管理システムである CPAN を使ってインストールを行いました。
(Linux のディストリビューションにバイナリーパッケージが用意されている場合には、 ディストリビューション固有のパッケージ管理ソフトを使ってインストールした方が よいので、注意してください)
LANG:console $ cpan cpan shell -- CPAN exploration and modules installation (v1.9402) Enter 'h' for help. cpan[1]> i /SystemPerl/ CPAN: Storable loaded ok (v2.20) Going to read '/home/osamu/.cpan/Metadata' Database was generated on Fri, 29 Oct 2010 09:30:12 GMT Distribution id = W/WS/WSNYDER/SystemPerl-1.335.tar.gz CPAN_USERID WSNYDER (Wilson Snyder <wsnyder@wsnyder.org>) CONTAINSMODS SystemC::Coverage SystemC::Coverage::Item SystemC::Coverage::ItemKey SystemC::Netli st SystemC::Netlist::AutoCover SystemC::Netlist::AutoTrace SystemC::Netlist::Cell SystemC::Netlist:: Class SystemC::Netlist::CoverGroup SystemC::Netlist::CoverPoint SystemC::Netlist::File SystemC::Netl ist::Method SystemC::Netlist::Module SystemC::Netlist::Net SystemC::Netlist::Pin SystemC::Netlist::P ort SystemC::Parser SystemC::Template cpan[2]> install W/WS/WSNYDER/SystemPerl-1.335.tar.gz ... Running make for W/WS/WSNYDER/SystemPerl-1.335.tar.gz CPAN.pm: Going to build W/WS/WSNYDER/SystemPerl-1.335.tar.gz Checking if your kit is complete... Looks good Warning: prerequisite Verilog::Getopt 2.211 not found. Warning: prerequisite Verilog::Netlist 3.2 not found. Writing Makefile for SystemC::Parser Writing Makefile for SystemC::Netlist -Info: SystemC isn't in the environment, 'make test' will skip tests ---- Unsatisfied dependencies detected during ---- ---- WSNYDER/SystemPerl-1.335.tar.gz ---- Verilog::Netlist [requires] Verilog::Getopt [requires] Shall I follow them and prepend them to the queue of modules we are processing right now? [yes] yes ... Appending installation info to /usr/lib/perl5/5.10/i686-cygwin/perllocal.pod WSNYDER/SystemPerl-1.335.tar.gz /usr/bin/make install -- OK cpan[5]> q Lockfile removed. $ sp_preproc $ which sp_preproc /usr/local/bin/sp_preproc
導入できました。
Verilator + SystemPerl によるカバレッジ測定†
http://www.veripool.org/projects/verilator/wiki/Manual-verilator#how_do_i_do_coverage_analysis
の How do I do coverage analysis? を参考にしました。
Verilator を SystemPerl モードで起動し、--coverage オプションを付けます。
その際、SYSTEMPERL および SYSTEMPERL_INCLUDE 環境変数が必要になります。
SYSTEMPERL_INCLUDE は、どうするのが正しいのかわからなかったのですが、 どうもヘッダファイル (*.h) はインストール時にどこにもコピーされていないようなので、 しかたなく SystemPerl をビルドしたソースフォルダを指すようにしています。
LANG:console $ export SYSTEMPERL=/usr/lib/perl5/site_perl/5.10/i686-cygwin/SystemC/ $ export SYSTEMPERL_INCLUDE=~/.cpan/build/SystemPerl-1.335-t4zlPN/src/ $ verilator -sp -Wno-lint --top-module bin2bcd bin2bcd.v --exe bin2bcd_sc.cpp --coverage $ cd obj_dir/ $ ls Vbin2bcd.mk Vbin2bcd__Syms.cpp Vbin2bcd__ver.d Vbin2bcd_classes.mk Vbin2bcd.sp Vbin2bcd__Syms.h Vbin2bcd__verFiles.dat $ sp_preproc --preproc *.sp $ ls Vbin2bcd.cpp Vbin2bcd.mk Vbin2bcd__Syms.cpp Vbin2bcd__ver.d Vbin2bcd_classes.mk Vbin2bcd.h Vbin2bcd.sp Vbin2bcd__Syms.h Vbin2bcd__verFiles.dat $ make -j -f Vbin2bcd.mk Vbin2bcd g++ -I. -MMD -I/home/osamu/verilator-3.804/include -I/home/osamu/verilator-3.804/include/vltstd -DV L_PRINTF=printf -DVM_TRACE=0 -DVM_COVERAGE=1 -I/home/osamu/systemc/systemc-2.2.0//include -I/ home/osamu/.cpan/build/SystemPerl-1.335-t4zlPN/src/ -DSYSTEMPERL -c -o bin2bcd_sc.o ../bin2bcd_sc.c pp g++ -I. -MMD -I/home/osamu/verilator-3.804/include -I/home/osamu/verilator-3.804/include/vltstd -DV L_PRINTF=printf -DVM_TRACE=0 -DVM_COVERAGE=1 -I/home/osamu/systemc/systemc-2.2.0//include -I/ home/osamu/.cpan/build/SystemPerl-1.335-t4zlPN/src/ -DSYSTEMPERL -c -o verilated.o /home/osamu/veri lator-3.804/include/verilated.cpp g++ -I. -MMD -I/home/osamu/verilator-3.804/include -I/home/osamu/verilator-3.804/include/vltstd -DV L_PRINTF=printf -DVM_TRACE=0 -DVM_COVERAGE=1 -I/home/osamu/systemc/systemc-2.2.0//include -I/ home/osamu/.cpan/build/SystemPerl-1.335-t4zlPN/src/ -DSYSTEMPERL -c -o Sp.o /home/osamu/.cpan/build /SystemPerl-1.335-t4zlPN/src/Sp.cpp /usr/bin/perl /home/osamu/verilator-3.804/bin/verilator_includer Vbin2bcd.cpp > Vbin2bcd__ALLcls.cpp /usr/bin/perl /home/osamu/verilator-3.804/bin/verilator_includer Vbin2bcd__Syms.cpp > Vbin2bcd__ALLs up.cpp g++ -I. -MMD -I/home/osamu/verilator-3.804/include -I/home/osamu/verilator-3.804/include/vltstd -DV L_PRINTF=printf -DVM_TRACE=0 -DVM_COVERAGE=1 -I/home/osamu/systemc/systemc-2.2.0//include -I/ home/osamu/.cpan/build/SystemPerl-1.335-t4zlPN/src/ -DSYSTEMPERL -c -o Vbin2bcd__ALLsup.o Vbin2bcd_ _ALLsup.cpp g++ -I. -MMD -I/home/osamu/verilator-3.804/include -I/home/osamu/verilator-3.804/include/vltstd -DV L_PRINTF=printf -DVM_TRACE=0 -DVM_COVERAGE=1 -I/home/osamu/systemc/systemc-2.2.0//include -I/ home/osamu/.cpan/build/SystemPerl-1.335-t4zlPN/src/ -DSYSTEMPERL -c -o Vbin2bcd__ALLcls.o Vbin2bcd_ _ALLcls.cpp Archiving Vbin2bcd__ALL.a ... ar r Vbin2bcd__ALL.a Vbin2bcd__ALLcls.o Vbin2bcd__ALLsup.o ar: creating Vbin2bcd__ALL.a ranlib Vbin2bcd__ALL.a g++ -L/home/osamu/systemc/systemc-2.2.0//lib-cygwin bin2bcd_sc.o verilated.o Sp.o Vbin2bcd__ALL. a -o Vbin2bcd -lm -lstdc++ -lsystemc 2>&1 | c++filt $ ls Sp.d Vbin2bcd.mk Vbin2bcd__ALLcls.o Vbin2bcd__Syms.h bin2bcd_sc.o Sp.o Vbin2bcd.sp Vbin2bcd__ALLsup.cpp Vbin2bcd__ver.d verilated.d Vbin2bcd.cpp Vbin2bcd__ALL.a Vbin2bcd__ALLsup.d Vbin2bcd__verFiles.dat verilated.o Vbin2bcd.exe* Vbin2bcd__ALLcls.cpp Vbin2bcd__ALLsup.o Vbin2bcd_classes.mk Vbin2bcd.h Vbin2bcd__ALLcls.d Vbin2bcd__Syms.cpp bin2bcd_sc.d $ ./Vbin2bcd.exe SystemC 2.2.0 --- Oct 29 2010 15:47:29 Copyright (c) 1996-2006 by all Contributors ALL RIGHTS RESERVED done $ ls logs ls: cannot access logs: No such file or directory
あれ?計測結果は logs/coverage.pl というファイルとして保存されるはずなんだけど・・・
/verilator-3.804/test_sp/ をよく見たところ、 カバレッジ測定結果を保存するにはテストベンチに手を加える必要があるようなので、
bin2bcd_sc.cpp の先頭に、
LANG:cpp #ifdef SYSTEMPERL #include "systemperl.h" // SystemC + SystemPerl global header #include "sp_log.h" // Logging cout to files #include "SpTraceVcd.h" #include "SpCoverage.h" #endif
sc_main の最後に、
LANG:cpp #ifdef SYSTEMPERL SpCoverage::write(); // Writes logs/coverage.pl #endif
を加えることにしました。
LANG:console $ make -j -f Vbin2bcd.mk Vbin2bcd g++ -I. -MMD -I/home/osamu/verilator-3.804/include -I/home/osamu/verilator-3.804/include/vltstd -DV L_PRINTF=printf -DVM_TRACE=0 -DVM_COVERAGE=1 -I/home/osamu/systemc/systemc-2.2.0//include -I/ home/osamu/.cpan/build/SystemPerl-1.335-t4zlPN/src/ -DSYSTEMPERL -c -o bin2bcd_sc.o ../bin2bcd_sc.c pp g++ -L/home/osamu/systemc/systemc-2.2.0//lib-cygwin bin2bcd_sc.o verilated.o Sp.o Vbin2bcd__ALL. a -o Vbin2bcd -lm -lstdc++ -lsystemc 2>&1 | c++filt $ ./Vbin2bcd.exe SystemC 2.2.0 --- Oct 29 2010 15:47:29 Copyright (c) 1996-2006 by all Contributors ALL RIGHTS RESERVED done%Error: Can't Write logs/coverage.pl Aborted (core dumped) $ mkdir logs $ ./Vbin2bcd.exe SystemC 2.2.0 --- Oct 29 2010 15:47:29 Copyright (c) 1996-2006 by all Contributors ALL RIGHTS RESERVED done $ ls logs coverage.pl $ vcoverage %Error: No such file or directory bin2bcd.v $ vcoverage --help ... +incdir+*dir* =item -I*dir* Specifies a directory for finding include files. ... $ vcoverage +incdir+.. Total coverage (22/23) 95.65% See lines with '%00' in logs/coverage_source $ less logs/coverage_source/bin2bcd.v
とした結果は、
LANG:verilog(linenumber) // Coverage analysis on Fri Oct 29 21:02:38 2010 // 2進数を BCD に直す回路 // bin に変換元の符号なし整数をセットして start に1を立てる // 次クロックで busy が立つので、降りるまで待って bcd を読む // BITS により、任意ビット数に対応可能 // 計算時間は (BITS-1) * 6 クロック程度 module bin2bcd #( parameter BITS = 32 ) (clk, rst, start, busy, bin, bcd); // log 16 = 1.20412 < 1205/1000 を使って BCD 表現に必要な桁数を求める localparam BCD_DIGITS = BITS * 1205 / 1000 / 4 + 1; localparam BCD_DIGITS_BITS = BCD_DIGITS < 2 ? 1 : BCD_DIGITS < 4 ? 2 : BCD_DIGITS < 8 ? 3 : BCD_DIGITS < 16 ? 4 : BCD_DIGITS < 32 ? 5 : BCD_DIGITS < 64 ? 6 : BCD_DIGITS < 128 ? 7 : 8; 122920 input wire clk; %000002 input wire rst; 002048 input wire start; 002048 output wire busy; 002036 input wire [BITS-1:0] bin; 022924 output wire [BCD_DIGITS*4-1:0] bcd; // 割り算用レジスタ 015406 reg [BITS-1:0] numerator; // 分子 364542 reg [BITS+3-1:0] denominator; // 分母 017099 reg [3:0] quotient; // 商 // 10^n を保持する ROM reg [BITS-1:0] denominators[1:BCD_DIGITS-1]; integer i; initial // ROM の初期化 for (i=1; i<BCD_DIGITS; i=i+1) denominators[i] = 10 ** i; // ステートマシンは state, digit を変数として動作する 110592 reg [2:0] state; 016386 reg [BCD_DIGITS_BITS-1:0] digit; localparam stIdle = 0; localparam stDivide0 = 1; localparam stDivide1 = 2; localparam stDivide2 = 3; localparam stDivide3 = 4; localparam stDivide4 = 5; localparam stNext = 6; // 計算結果を保持するレジスタ 000019 reg [3:0] bcd_internal[2:BCD_DIGITS-1]; always @(posedge clk) 000011 if (rst) begin state <= stIdle; end else 061449 case (state) 006153 stIdle: begin digit <= BCD_DIGITS - 1; 001024 if (start) begin numerator <= bin; state <= stDivide0; end end 009216 stDivide0: begin // 分母に 10^n << 3 を用意する denominator <= denominators[digit] << 3; state <= stDivide1; end 036864 stDivide1, stDivide2, stDivide3, stDivide4: begin // 割り算して商を得る 003038 if (numerator >= denominator) begin quotient <= { quotient, 1'b1 }; numerator <= numerator - denominator; 033826 end else begin quotient <= { quotient, 1'b0 }; end denominator <= denominator >> 1; state <= state + 1; end 009216 stNext: begin // 結果を格納して次へ bcd_internal[digit] <= quotient; 001024 if (digit==1) begin state <= stIdle; 008192 end else begin digit <= digit - 1; state <= stDivide0; end end endcase // 出力に繋ぐ assign busy = state != stIdle; generate genvar j; for (j=2; j<BCD_DIGITS; j=j+1) begin: bcd_connection assign bcd[j*4 +: 4] = bcd_internal[j]; end endgenerate assign bcd[7:4] = quotient; assign bcd[3:0] = numerator[3:0]; endmodule
となって、行頭の数値が恐らく呼び出し回数ですね。
先頭に % が付いている行は「テストが足りないのでは?」 と注意してくれている行になります。
たしかに rst 信号は2回しか変化してないので、注意されても仕方がない???
上記測定結果で
LANG:console Total coverage (22/23) 95.65%
と出ているのは、23 行中 1 行に % がついたので、それを除いた 22 行を全体で割った値のようです。
うまくいっているようですね。
ソースを変更したせいで†
ただ、カバレッジ計測のためにテストベンチのソースをいじらなければならないのは感心しないところです。
上記ソースのまま、--coverage を付けず -sc でコンパイルしようとすると、
LANG:console $ cd .. $ rm -r obj_dir/ $ verilator -sc -Wno-lint bin2bcd.v --exe bin2bcd_sc.cpp $ cd obj_dir/ $ make -j -f Vbin2bcd.mk Vbin2bcd g++ -I. -MMD -I/home/osamu/verilator-3.804/include -I/home/osamu/verilator-3.804/include/vltstd -DV L_PRINTF=printf -DVM_TRACE=0 -DVM_COVERAGE=0 -I/home/osamu/systemc/systemc-2.2.0//include -c -o bin2bcd_sc.o ../bin2bcd_sc.cpp g++ -I. -MMD -I/home/osamu/verilator-3.804/include -I/home/osamu/verilator-3.804/include/vltstd -DV L_PRINTF=printf -DVM_TRACE=0 -DVM_COVERAGE=0 -I/home/osamu/systemc/systemc-2.2.0//include -c -o verilated.o /home/osamu/verilator-3.804/include/verilated.cpp /usr/bin/perl /home/osamu/verilator-3.804/bin/verilator_includer Vbin2bcd.cpp > Vbin2bcd__ALLcls.cpp /usr/bin/perl /home/osamu/verilator-3.804/bin/verilator_includer Vbin2bcd__Syms.cpp > Vbin2bcd__ALLs up.cpp g++ -I. -MMD -I/home/osamu/verilator-3.804/include -I/home/osamu/verilator-3.804/include/vltstd -DV L_PRINTF=printf -DVM_TRACE=0 -DVM_COVERAGE=0 -I/home/osamu/systemc/systemc-2.2.0//include -c -o Vbin2bcd__ALLsup.o Vbin2bcd__ALLsup.cpp g++ -I. -MMD -I/home/osamu/verilator-3.804/include -I/home/osamu/verilator-3.804/include/vltstd -DV L_PRINTF=printf -DVM_TRACE=0 -DVM_COVERAGE=0 -I/home/osamu/systemc/systemc-2.2.0//include -c -o Vbin2bcd__ALLcls.o Vbin2bcd__ALLcls.cpp ../bin2bcd_sc.cpp: In function ‘int sc_main(int, char**)’: ../bin2bcd_sc.cpp:60: error: ‘SpCoverage’ has not been declared make: *** [bin2bcd_sc.o] Error 1 make: *** Waiting for unfinished jobs....
となって止まってしまいます。
#ifdef SYSTEMPERL で囲っても駄目なのはあたりまえなので、
--coverage を付けた時だけ有効になるような定義済みマクロがないか探しているところです。
1つのモジュールを複数のテストベンチで検証する場合の解析方法†
module_A に対して、module_A_sc1.cpp, module_A_sc2.cpp, module_A_sc3.cpp など、複数のテストベンチを作って検証した場合、 単一のテストベンチによるカバレッジを解析しても意味がありません。
全部のテストベンチを動かしたうえで、 それでもカバーされていないコードを見つけられるようにするために、 Verilator のカバレッジ解析では logs/coverage.pl は上書きではなく 追加モードで書き込まれるそうです。
これを利用すれば、あるディレクトリに logs を掘って、 そこで複数のテストベンチを連続して走らせ、 最後に vcoverage で集計することで、 総合のカバレッジ解析ができるわけです。
三項演算子も解析できるか?†
LANG:verilog a <= (b > c) ? b : c;
のような三項演算子 ( ? と : ) は、 もしかするとカバレッジ計測をする上での鬼門かもしれませんね。
どのような解析結果になるのか、後で調べる必要がありそうです。