電気回路/HDL/SystemPerl の導入 のバックアップの現在との差分(No.3)

更新


  • 追加された行はこの色です。
  • 削除された行はこの色です。
[[公開メモ]]

#contents

* SystemPerl を入れてカバレッジ測定をしてみたい [#va28e7a7]

Verilator と SystemPerl を組み合わせて使うとカバレッジ測定ができるそうです。

カバレッジ解析について >> http://www.altima.jp/products/3rdparty/eda/code_coverage.html

[[電気回路/HDL/Verilator の導入(C++モード)]] および [[電気回路/HDL/SystemC の導入]] 
の続きです。

* SystemPerl の導入 [#i55c4e9c]

ここでは 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 によるカバレッジ測定 [#e4e99b79]

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 行を全体で割った値のようです。

うまくいっているようですね。

* ソースを変更したせいで [#da699798]

ただ、カバレッジ計測のためにテストベンチのソースをいじらなければならないのは感心しないところです。

上記ソースのまま、--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つのモジュールを複数のテストベンチで検証する場合の解析方法 [#i6610107]

module_A に対して、module_A_sc1.cpp, module_A_sc2.cpp, module_A_sc3.cpp 
など、複数のテストベンチを作って検証した場合、
単一のテストベンチによるカバレッジを解析しても意味がありません。

全部のテストベンチを動かしたうえで、
それでもカバーされていないコードを見つけられるようにするために、
Verilator のカバレッジ解析では logs/coverage.pl は上書きではなく
追加モードで書き込まれるそうです。

これを利用すれば、あるディレクトリに logs を掘って、
そこで複数のテストベンチを連続して走らせ、
最後に vcoverage で集計することで、
総合のカバレッジ解析ができるわけです。

* 三項演算子も解析できるか? [#n883aab4]

 LANG:verilog
 a <= (b > c) ? b : c;

のような三項演算子 ( ? と : ) は、
もしかするとカバレッジ計測をする上での鬼門かもしれませんね。

どのような解析結果になるのか、後で調べる必要がありそうです。

* 関連記事 [#z846becd]

#ls2(電気回路/HDL/Verilator);
#ls2(電気回路/HDL/System);

* コメント [#r0107ac1]

#article_kcaptcha


Counter: 8524 (from 2010/06/03), today: 1, yesterday: 0