Verilog-HDL Simulation環境
2021/05/08
WSL2上でのSimulation環境構築
  • Verilog-HDL Simulation環境を、WSL2(Windows Subsystem for Linux ver.2)ではなく、純粋にWindows上で構築する場合は、このSectionをスキップして"Windows上でのSimulation環境構築"から読んで下さい。(この章は2021/5/8に追加しました。違和感あると思いますがご勘弁下さい)

  • 本SectionではWSL2(Windows Subsystem for Linux ver.2)上にVerilog-HDL Simulation環境を作ります。シミュレータはIcarus Verilog、波形表示はGTKWaveを利用します。

  • ここで波形確認ツールであるGTKWaveはX-Windows上の動作すなわちGUIが必要になります。GUIを含めたWSL2自身の環境構築は"WSL2のGUI環境作成"を参照して下さい。

  • WSL2 GUI環境構築後は、ターミナル上で下記コマンドを実行し、Icarus VerilogとGTKWaveのインストールを行います。
    $ sudo apt install iverilog
    $ sudo apt install gtkwave

  • インストール後は念のためコマンド実行の確認をしてみて下さい。
    $ iverilog -h
    Usage: iverilog [-ESvV] [-B base] [-c cmdfile|-f cmdfile]
                    [-g1995|-g2001|-g2005|-g2005-sv|-g2009|-g2012] [-g]
    ...略...
    
    $ gtkwave -h Usage: gtkwave [OPTION]... [DUMPFILE] [SAVEFILE] [RCFILE] ...略...

  • インストール終了後は、次のSectionをスキップして"サンプルのRTL"から読んで下さい。

Windows上でのSimulation環境構築
  • Verilog-HDLは、Hardware Description Languageの一つです。この言語で回路設計を行うために、まずは環境構築(ツールの準備)から始めたいと思います。Verilog-HDLを扱う際に最低限必要なツールは下記3種です。
      + テキストエディタ
      + シミュレータ
      + 波形表示ツール

  • テキストエディタは、特に説明の必要無いですね。好きなものを使っていただければ良いと思います。次にシミュレータですが、無償かつ複数環境で動かしやすいものとして「Icarus Verilog」を使用します。最後に波形表示ツールですが、シミュレータ同様の理由で「GTKWave」を選びました。

  • では早速Windows版Icarus Verilogの入手から始めます。しかしながらIcarus Verilog本家サイト(iverilog.icarus.com)ではWindows版の配布が止まっており(*1)、別のWindows版Icarus Verilogサイト「bleyer.org/icarus」からダウンロードします。現時点での最新安定版は
      iverilog-0.9.7_setup.exe (latest stable release) [10.5MB]
    です。

  • 尚上記で入手できる「Windows版Icarus Verilog 0.9.7」には「GTKWave」も入っています。なのでIcarus Verilogをインストールすると、GTKWaveも使用できるようになります(*2)。インストールは通常のWindows用ツールと同様なので特に説明しませんが、1点注意があります。メッセージでも出てきますが、インストール先のディレクトリ/フォルダ名にスペースを入れてはいけないという制限です。具体的には
      NG : C:\Program Files\iVerilog
      OK : C:\iVerilog
      OK : C:\Tools\iVerilog
    のように考えて下さい。2byte系文字が入るのも避けたほうが無難でしょう。

  • インストールが終了したら、起動のみ確認してみます。コマンドプロンプトを開いて「iverilog」とコマンド入力して下さい。下記のようにusageが出てくればOKです。
    C:>iverilog ← コマンド入力
    
    iverilog: no source files.
    
    Usage: iverilog [-ESvV] [-B base] [-c cmdfile|-f cmdfile]
                    [-g1995|-g2001|-g2005] [-g]
                    [-D macro[=defn]] [-I includedir] [-M depfile] [-m module]
                    [-N file] [-o filename] [-p flag=value]
                    [-s topmodule] [-t target] [-T min|typ|max]
                    [-W class] [-y dir] [-Y suf] source_file(s)
    

  • 次はGTKWaveですが、これも先と同様にコマンドプロンプトを開いて「gtkwave」とコマンド入力してください。下図のようなGUIが起動すればOKです。尚、Help→Wave Versionを確認すると「GTKWave Analyzer v3.3.48(w)1999-2013 BSI」になっています。


サンプルのRTL
  • ここではIcarus Verilog と GTKWave を用いたSimulationと波形取得について説明します。初めにSimulationで使用するRTLを示します。これは10bitのPRPG(Pseudo Random Pattern Generator)です。微妙(*3)にVerilog HDL 2001の記述方式を混ぜています。
    `timescale 1ns/1ps
    
    module Prpg10
     #( // parameters
        parameter Prpg10_UD = 1          // Unit Delay
      )
      ( // ports
        input  wire        Clk,          // Clock
        input  wire        ResetB,       // Reset
        input  wire        PrpgUpld,     // Seed upload
        input  wire        PrpgStart,    // PRPG start
        input  wire [9:0]  PrpgSeed,     // Seed input
        output wire [9:0]  PrpgOut       // PRPG data output
      );
    
      reg  [9:0]  PrpgReg;
      wire [9:0]  PrpgRegIn;
      reg         PrpgStartReg;
    
      always @(posedge Clk, negedge ResetB) begin
        if (ResetB==1'b0) begin      // Asynronous reset
          PrpgReg      <= #Prpg10_UD 10'b00_0000_0000;
          PrpgStartReg <= #Prpg10_UD 1'b0;
        end
        else begin                   // Function
          PrpgReg      <= #Prpg10_UD PrpgRegIn;
          PrpgStartReg <= #Prpg10_UD PrpgStart;
        end
      end
    
      assign PrpgRegIn =
        (PrpgStartReg)? {PrpgReg[8:0],(PrpgReg[9]^PrpgReg[2])} : // x^10+ x^3 + 1
        (PrpgUpld)?      PrpgSeed :
                         PrpgReg ;
    
      assign PrpgOut = PrpgReg & {10{PrpgStartReg}};
    
    endmodule
    

  • 次は上記リストのRTLを図示しました。prpg_polyの部分には、10bit PRPGのPrimitive Polynomial(x^10 + x^3 + 1)(*4)が入ります。リストの青字部分に相当しています。


  • この回路を動作させる手順ですが、所望のクロック(Clk)が入り続けているとして下記になります。
      [1]ResetBを'0'にして、全Registerを初期化します。
      [2]ResetB解除前に、入力ポートの値を確定します(全て'0'にします)。
      [3]ResetBを解除('1'に)します。
      [4]PrpgSeed[9:0]に乱数発生器のSeed値(All'0'以外の値)をセットします。
      [5]PrpgUpldを1cyc以上'1'にした後'0'に戻します→PrpgReg[9:0]にSeed値が入ります。
      [6]PrpgStartを'1'にすると、次のClkのPositive EdgeからPRPGが動作開始(ランダムパターン出力)します。
      [7]PrpgStartを'0'に戻すと、次のClkのPositive EdgeでPRPGが動作停止します。(PrpgOutはAll'0'出力)

  • この回路は10bitのPRPGなので、All'0'以外の1023種の値をランダムに生成します。Seed値が再度出力されるのはPRPG起動後の1023cyc後です。

サンプルのテストベンチ
  • 回路を動作させるためのテストベンチを示します。各動作のstepがどのステートメントに相当するかコメントを入れてありますので参考にして下さい。またinitial文のすぐ下に、VCDダンプのステートメントも入れてあります。
    `timescale 1ns/1ps
    
    module tb_Prpg10;
      reg        Clk, ResetB, PrpgUpld, PrpgStart;
      reg  [9:0] PrpgSeed;
      wire [9:0] PrpgOut;
    
      parameter CYC = 100;
      always #(CYC/2) Clk = ~Clk;
    
      Prpg10 dut ( // Prpg10のInstance
        .Clk (Clk),
        .ResetB (ResetB),
        .PrpgUpld (PrpgUpld),
        .PrpgStart (PrpgStart),
        .PrpgSeed (PrpgSeed),
        .PrpgOut (PrpgOut)
      );
    
      initial begin
        $dumpfile("tb_Prpg10.vcd"); // vcd file name
        $dumpvars(0,tb_Prpg10);     // dump targetは「全部」
    
        // Initilai value
        #(CYC* 0)   Clk=0; ResetB=1; PrpgUpld=0;
                    PrpgStart=0; PrpgSeed=0;     // step[2]の印加値は最初から入れている
        // Reset
        #(CYC*10)   ResetB=0;                    // step[1]
        #(CYC*10)   ResetB=1;                    // step[3](step[2]は実施済み)
        // Set seed
        #(CYC*10)   PrpgSeed=10'b00_0000_0001;   // step[4]
        #(CYC*10)   PrpgUpld=1;                  // step[5]1にして
        #(CYC* 1)   PrpgUpld=0;                  // step[5]0に戻す
        // Start PRPG
        #(CYC*10)   PrpgStart=1;                 // step[6]
        // Stop PRPG after 1024 cyc
        #(CYC*1024) PrpgStart=0; // (return to start 00_0000_0001) step[7]
        // Stop simulation
        #(CYC*10)   $finish;
      end
      
    endmodule
    

コンパイルと実行
  • かなり前置き長くなってしまいましたが、ようやくコンパイルです。現在PRPGの本体である Prpg10.v と テストベンチの tb_Prpg10.v の二つのファイルがあります。これらをIcarus Verilogで下記のようにコンパイルします。
      iverilog Prpg10.v tb_Prpg10.v -o tb_Prpg10.o
  • オプション -o は、コンパイルオブジェクトのファイル名指定です。未指定時は a.out になります。記述ミスがあるとエラーになりますので、まずはここでデバッグをすることになります(*5)。その他にもdefine指定や、Include Path指定などいろいろなオプションがあります。詳しくはインストールディレクトリの iverilog.pdf を参照して下さい。

  • コンパイルが終了したら、次はいよいよSimulation実行です。上記リストのテストベンチは、特にメッセージで判定結果を出さずに「まずは波形を見よう」という感じになっています。Simulationの実行には vvp コマンドを使います。
      vvp tb_Prpg10.o
    ...えっと...これだけです(^^;。今回のサンプルを実行すると「VCD info: dumpfile tb_Prpg10.vcd opened for output.」といったメッセージが出てきます。実際vcdファイル(tb_Prpg10.vcd)が生成されているはずです。

  • vvp コマンドにも、ログファイルの指定などいくつかオプションがあります。詳しくは先と同様にインストールディレクトリのvvp.pdf を参照下さい。

波形の観測
  • 作成したvcdファイルをGTKWaveで観測します。引数にvcdファイル名を指定してgtkwave(*6)を起動します。ちなみにvcdファイルはGTKWave起動後にメニューからロードすることもできます。
      gtkwave tb_Prpg10.vcd
  • GTKWaveはGUIツールなので直感的に使い方はわかると思いますが簡単に説明すると、左上のSST window内で観測したいInstanceを選ぶと、その下にwire/registerの一覧が表示されます。その中から観測したい信号を横のSignals windowにドラッグ&ドロップするか、下部のAppend/Insert/Replaceボタンを使って信号波形を表示させていきます。

  • 実際に実行結果を表示させて見ました。PRPG動作スタートまでの表示になります。クリックすると別Window(又はタブ)に拡大画像を表示します。


  • 作業の流れとしては以上になります。最近ではXilinx, AlteraといったFPGA系ツールでも同様なことができるようになってきていますので、そのあたりもいずれ扱いたいと思います。
Notes
  • 現最新版は0.9台ですが、Windows版が置かれていません。0.8版はありました。以前のようにPermissionの関係でダウンロード不能という程ひどい状態ではないようです。
  • インストールの途中でGTKWaveもインストールするかどうか選択できます。独立でインストールを行いたい方は[GTKwave本体]と[ライブラリ]を別途ダウンロードして下さい。展開後、GTKWave本体のフォルダと、ライブラリのbinをPath環境変数に追加すればOKです。環境変数設定という言葉がピンと来ない場合、無難にIcarus Verilogのセットからインストールを選んだ方が良いでしょう。
  • System Verilogの検証向けとして紹介されている記述は弾かれることも多いです。手堅くいくのであれば、なるべくVerilog HDLの範疇で済ませたほうが今は良さそうです。
  • Paul H. Bardell, "Built-In Test for VLSI: Pseudorandom Techiniques", page 336
  • 今度FreeのLintツールを探してみたいと思います。
  • 以前は winwave がコマンド名でしたね。
2015/09/20: 初版
2021/05/08: WSL2上のインストール方法追加
Copyright(C) 2015 Altmo
本HPについて