情報画像工学実験II

実験II-6. 論理回路設計

回路シミュレータについて


回路シミュレータについて

HDL 言語で回路設計したとき、実際に回路を製作する前に、まずは、記述した回路が考えていたとおりの動作をするかどうか、シミュレータを用いてコンピュータ上で十分検証する。本実験ではシミュレータ GPL Cver と 波形表示ツール GTKWave を用いて動作検証を行う。具体的に、シミュレータ GPL Cver を用いて verilog記述した回路をシミュレートし、その結果をダンプファイルと呼ばれるファイルに記録する。次に波形表示ツール GTKWave を用いて、得られたダンプファイルから波形情報を抽出、波形をグラフィカルに表示し、回路が期待した通りに動作しているかどうか確認する。ここでは、それぞれのツールの操作法等について説明する。

シミュレータ GPL Cver

まずはテキスト図2に示した半加算器を例にツールの操作法を説明する。サンプルを以下の手順で準備されたい。まずファイルHALF_ADDER.tar をダウンロードされたい。次に GNOME 端末を立ち上げ、ファイルの置かれているディレクトリをカレントディレクトリとし、以下のコマンドを入力されたい。

tar -xf HALF_ADDER.tar

HALF_ADDER というディレクトリが作成され、その下に HALF_ADDER.v と testbench.v の2ファイルが作成されたはずである。HALF_ADDER.v はテキスト図2に示した半加算器である。ただし、一箇所わざと間違えてある。testbench.v はシミュレーション実験を行うためのファイルであり、詳細は後述する。

以下のコマンドを実行されたい。

cver HALF_ADDER.v testbench.v

図1 のように、シミュレータ GPL Cver が起動し、HALF_ADDER.v に含まれている誤りを指摘して終了する。

GPLCVER_2.11a of 07/05/05 (Linux-elf).
Copyright (c) 1991-2005 Pragmatic C Software Corp.
  All Rights reserved.  Licensed under the GNU General Public License (GPL).
  See the 'COPYING' file for details.  NO WARRANTY provided.
Today is XXX XXX XX XX:XX:XX XXXX.
Compiling source file "HALF_ADDER.v"
**HALF_ADDER.v(14) ERROR** [1116] expression terminal expected - <EXPR END> read
Compiling source file "testbench.v"
  Unable to begin simulation.
  There were 1 error(s), 0 warning(s), and 0 inform(s).
End of GPLCVER_2.11a at XXX XXX XX XX:XX:XX XXXX(elapsed 0.0 seconds).

図1. GPL Cver のエラーメッセージ例

指摘に従って誤りを修正し、再度 Cver を実行されたい。図2のように誤りを指摘することなく終了したならシミュレーションは成功である。

GPLCVER_2.11a of 07/05/05 (Linux-elf).
Copyright (c) 1991-2005 Pragmatic C Software Corp.
  All Rights reserved.  Licensed under the GNU General Public License (GPL).
  See the 'COPYING' file for details.  NO WARRANTY provided.
Today is XXX XXX XX XX:XX:XX XXXX.
Compiling source file "HALF_ADDER.v"
Compiling source file "testbench.v"
Highest level modules:
TESTBENCH

Halted at location **testbench.v(17) time 2000 ps from call to $finish.
  There were 0 error(s), 0 warning(s), and 4 inform(s).

図2. シミュレーション成功時のメッセージ

シミュレーションが成功したなら、ダンプファイル HALF_ADDER.vcd が生成されているはずである。確認されたい。

波形表示ツール GTKWave

以下のコマンドを実行されたい。図3のように、波形表示ツール GTKWave が起動する。

gtkwave HALF_ADDER.vcd


図3. GTKWave

次に Search → Signal Search Tree とされたい。図4のように、Signal Search Tree ダイアログが開く。TESTBENCH を選び(青く反転させ)、Append をクリックされたい。


図4. Signal Search Tree

図5のようにシミュレーション結果の波形図が表示される。ただし、このままのズームでは見にくいので Zoom Best Fit ボタン(図5中、赤○で示すボタン)をクリックされたい。図6 のような波形図が表示される。


図5. Signal Search Tree


図6. ズームを調節した後の波形図

グラフの見方を説明する。X軸が時間であり、それぞれ信号名の右隣にあるのが、各時間における、各信号線の値である。高い位置にあるとき、その信号線の値は 1 であり、低い位置にあるとき 0 となる。例えば図6 の場合、信号線 A (TESTBENCH.A) の値は時間 0ps から 1000ps までの間、0 であり、その後 2000ps までの間 1 となる。信号線 B の値は時間 0ps から 500ps までの間、0、その後 1000ps まで 1、1500ps まで 0、 2000ps まで 1 である。加算器の入力信号 A, B の変化に応じて、出力信号 S, CO が変化していることを確認されたい。

検証用モジュール

実際の回路において動作確認を行うためには、対象回路の他に入出力信号を制御観測する検証用の回路を用意する必要がある。同様に、Verilog-HDL でも製作したモジュールとは別に、検証用モジュールを用意する必要がある。ファイル testbench.v には検証用モジュールが記述されている。ファイル testbench.v の内容を図7に示す。

`timescale 10ps / 10ps

module TESTBENCH;
        reg A, B;      // HALF_ADDER の入力信号
        wire S, CO;    // HALF_ADDER の出力信号
        
        HALF_ADDER CUT (.A(A), .B(B), .S(S), .CO(CO));    // 検証対象回路のインスタント宣言        
        
        initial begin
                $dumpfile("HALF_ADDER.vcd");    // ダンプファイル名の指定
                $dumpvars(1, TESTBENCH);
                
                A <= 0;  B <= 0;  #50
                A <= 0;  B <= 1;  #50
                A <= 1;  B <= 0;  #50
                A <= 1;  B <= 1;  #50
                $finish;
        end
endmodule

図7. testbench.v

"module TESTBENCH" で始まり、"endmodule" で終わる記述、すなわちモジュールTESTBENCH が確認できる。このモジュールが検証用モジュールである。検証用モジュールTESTBENCH はそれだけで完結しており、他からの入出力信号を持たない。モジュール名の後に括弧と入出力信号名の列挙が無く、また宣言部には input文も output文も存在しない。

最初の行 "`timescale 10ps / 10ps"はタイムスケールを設定している。他の回路用のファイルでも、とりあえずこの通りに書いておいて欲しい。モジュールTESTBENCH中にある reg文は wire文同様内部信号を宣言するための文である。reg文とwire文の違いについての詳細な説明は省く。ここでは、検査用モジュールにおいては、検査対象回路の入力と同名の信号線を reg文で、出力と同名の信号線を wire文で宣言するものと理解されたい。続く "HALF_ADDER CUT" で始まる文ではインスタンスを宣言している。検証用モジュールは検証対象回路 CUT をインスタンスとして持つ階層構造をしたモジュールである。さて、検証用モジュールにおけるインスタンス宣言は以下のように書けばよい。

テスト対象のモジュール名 CUT (テスト対象モジュールの全入出力信号名);

ただし、入出力信号名は ".信号名(信号名)" という書式で列挙する。

"initial begin" から "end" までの間は、手続きブロックである。ここでは手続きブロックについてシミュレーションに必要な説明のみを以下に行う。$dumpfile では出力するダンプファイル名を指定している。適宜変更されたい。$dumpvars ではダンプ対象モジュール、インスタンスを指定している。他の回路用の検証モジュールでも、とりあえずこの通りに書いて欲しい。手続きブロックの中には続いて以下のような表記が繰り返されている。

A <= 0; B <= 1; #50

これは、「信号線A を 0、 信号線 B を 1 にして、50 だけ時間を進ませる、」という意味である。シミュレーション結果と比較しながら理解されたい。なお、時間の単位は最初の `timescale 文で指定される。この場合は時間1は10psである。シミュレーション実験を終えるために、手続きブロックの最後には $finish; と書く。

階層構造を持つ回路のシミュレーション

次にテキスト図5に示した全加算器を例に、階層構造をもつ回路に対するシミュレーションの実施方法を説明する。

全加算器は半加算器をインスタンスとして持ち、全加算器、検証用モジュールの他に半加算器を用意する必要がある。まずは図5を参考に全加算器を記述する。ファイル名は FULL_ADDER.v とされたい。(ファイル名は何でも良いが、拡張子は必ず .v とする)半加算器は先ほど用いた HALF_ADDER.v をそのまま使い回す。次に、図8を参考に検証用モジュールを記述する。ファイル名は testbench_f.v とされたい。

図8. 全加算器用検証モジュール

検証用モジュールでは直接の検証対象であるモジュール (この場合は FULL_ADDER) に関する記述のみを階層構造を持たない回路の場合と全く同様に行えばよい。HALF_ADDER については触れる必要はない。

次に以下のようにシミュレータ GPL Cver を実行する。シミュレータには全加算器、検証用モジュールに加え、半加算器の記述も与える必要がある。

cver FULL_ADDER.v HALF_ADDER.v testbench_f.v

GPL Cver に複数のファイルを与えたいとき、単にファイル名を列挙すればよい。また、どういう順序で適用しても良い。GPL Cver は与えたモジュールの中から適切に検証用モジュールを選び、シミュレーションを行う。

最後にGTKWave を用いて波形を表示する。半加算器のときと同様に行うことができる。


課題1 の内容はここまでである。以降は必要になったとき読むこと。


入出力信号以外の信号線

デバッグ中には、テキスト図2の半加算器における信号線 C, D のような、入出力信号以外の信号線の値を見たくなることも多々ある。ここでは、それら信号線の波形を表示する方法について説明する。

検証用モジュール中、$dumpvars の引数を (0, TESTBENCH) とする。GPL Cver を実行した後、GTKWave を起動する。Signal Search Tree ダイアログを開く。このとき、CUT (検証対象回路のインスタンス名) の中の信号線も選択可能になっている。図9に半加算器の場合のダイアログを示す。観測したい信号線名を選び Append することにより、それぞれの信号線の波形を出力することができる。全加算器の様に階層構造になっている回路の場合は、さらに階層を掘り下げて信号線を選ぶこともできる。


図9. 半加算器内信号線 C, D の選択画面

バスへの信号値の与え方

検証用モジュールにおいては図10に例示するように、バス中の信号線に信号値をまとめて与えることができる。

`timescale 10ps / 10ps

module TESTBENCH;
        reg [3:0] A, B;    // 検証対象回路の入力信号(バス)
        wire [3:0] S;      // 検証対象回路の出力信号(バス)
        wire CO;           // 検証対象回路の出力信号線
        
        ADDER4 CUT (.A(A), .B(B), .S(S), .CO(CO));
        
        initial begin
                $dumpfile("ADDER4.vcd");
                $dumpvars(1, TESTBENCH);
                
                A <= 4'b0000;  B <= 4'b0000;  #50    // S = 0000, CO = 0        
                A <= 4'b0011;  B <= 4'b0000;  #50    // S = 0011, CO = 0
                ...
                
                $finish;
        end
endmodule

図10. testbench.v

バスに信号値を与えるときは、<= の右辺にバス幅、'b' と与えたい信号値(2進表記)を記述する。例えば、A <= 4'b0101; と書けば、A[3], A[2], A[1], A[0] にはそれぞれ信号値 0, 1, 0, 1 が与えられる。また、<= の右辺に数字のみを記述した場合はその数字を10進表記の数値と見なし、2進表記に読み直した数値が信号値としてバスに与えられる。例えば、3 は2進表記で 0011 であることから、A <= 3; と書けば、A[3], A[2], A[1], A[0] にはそれぞれ信号値 0, 0, 1, 1 が与えられる。

バス出力信号の見方

GTKWave においてバス信号値は、図11 に例示するように波形ではなく、数値によって表示される。

図11. バスの出力信号表示と表記法の変更

例えば "$3" はバス中の信号線がそれぞれ 0, 0, 1, 1 という値になっていることを表している。ここで、$記号は続く数値が16進表示であることを意味する。なお、2進表示は%記号によって表される。表記法を変更したい場合は、バス名を選んでから、"Edit→Data Format→Hex (16進), Decimal (10進), Binary (2進)" と選べばよい。また、"Edit→Expand" を選ぶことにより、バス中の信号線をまとめず別々に表示させることができる。別々にしたバス信号をまとめ直したい場合は、バスを構成している信号線名をすべて選び、"Edit→Combine Down" と選べばよい。


実験II-6トップページに戻る
難波担当実験・演習のページに戻る

難波 一輝 (助教・伊藤・北神・難波研究室)
工学部1号棟4階409号室、内線3255、043-290-3255、namba@ieee.org