Very Hard Delight Life

内容はLinux, HW, プログラミング, HaFaBra.

Emacs Verilog-Mode でVerilog HDL をサクサク書く

モチベーション

ハードウェアの記述の大変なところは色々とありますが、テストを書きづらいところも苦労する点の1つだと思います。

そこで、Emacs Verilog-Mode を利用するとある程度の作業をスキップすることができます。 Verilog HDL を書く際の助けになれば幸いです。 SystemVerilog の記法にも対応しており、初心者から玄人まで使いやすいツールです。

以下、Verilog HDL および SystemVerilog を総称してVerilog とします。

使い方

Emacsverilog-mode.el を認識させてEmacs 上でVerilog を記述するのが本来の用途ですが、Emacs を使いづらい環境や使わない環境も多いため、ここはDocker を利用してフィルタ機能のみ抽出します。

手前味噌ですが、自作したDocker image であるstomoki/eda-env_emacs-verilog-mode を利用します。

以下のコマンドを実行することで利用できます。

$ docker run --rm -t -v <path-to-target-dir>:/dat \
    stomoki/eda-env_emacs-verilog-mode:7 \
    emacs --batch /dat/<path-to-target-file-from-target-dir> -f verilog-batch-auto 

オプションごとに解説すると、

--rm : 生成したコンテナを破棄。メモリの節約。
-t : 処理した出力の表示。
-v : ボリュームのマウント。Docker 上でローカルマシンのファイルを参照できるようにする。
stomoki/... : Emacs Verilog-Mode を含むDocker image の指定
emacs ... : 実行されるコマンド

となっています。 なお、各行の末尾の \ は長いコマンドを分割して入力するためのものです。

実際に実行されるコマンドの詳細を解説すると、

--batch : バッチモードでEmacs を実行
/dat/... : Verilog-mode で処理するターゲットのファイル。`-v` で指定したディレクトリをトップとしてファイルのパスを指定。
-f : 実行するファンクション。基本的に `verilog-batch-auto` の指定で十分

となります。

例えば、ローカルマシンの/path/to/hdl をプロジェクトのトップディレクトリとし、src/target.v に対してVerilog-mode の処理を実行する場合、以下のようなコマンドの内容となります。

$ docker run --rm -t -v /path/to/hdl:/dat \
    stomoki/eda-env_emacs-verilog-mode:7 \
    emacs --batch /dat/src/target.v -f verilog-batch-auto

実際に使ってみる

実際に使ってみましょう。 Verilog で記述されたファイルを変更しながら、Emacs Verilog-mode の使い方を見ていきます。

使用する例

定番web ページ ASIC World から拝借します。 ただし、入力 data は未使用なので削除しています。

//-----------------------------------------------------
// Design Name : up_down_counter
// File Name   : up_down_counter.v
// Function    : Up down counter
// Coder       : Deepak Kumar Tala
//-----------------------------------------------------
module up_down_counter    (
    out      ,  // Output of the counter
    up_down  ,  // up_down control for counter
    clk      ,  // clock input
    reset       // reset input
);
//----------Output Ports--------------
output [7:0] out;
//------------Input Ports-------------- 
input [7:0] data;
input up_down, clk, reset;
//------------Internal Variables--------
reg [7:0] out;
//-------------Code Starts Here-------
always @(posedge clk)
if (reset) begin // active high reset
  out <= 8'b0 ;
end else if (up_down) begin
  out <= out + 1;
end else begin
  out <= out - 1;
end

endmodule 

(8-Bit Up-Down Counter より)

このコードに対してVerilog-mode を実行しても何も起きません。

ポート生成を自動化 (AUTOARG)

では、コードを以下のように一部書き換えます。

module up_down_counter    (
    /*AUTOARG*/
);
//----------Output Ports--------------
output [7:0] out;
//------------Input Ports-------------- 
input up_down, clk, reset;
//------------Internal Variables--------
reg [7:0] out;
//-------------Code Starts Here-------
always @(posedge clk)
if (reset) begin // active high reset
  out <= 8'b0 ;
end else if (up_down) begin
  out <= out + 1;
end else begin
  out <= out - 1;
end

endmodule 

ポートリストを削除し、代わりに/*AUTOARG*/ というコメントを挿入しました。

このコメントはVerilog-mode へ特定の処理を指示するもので、Verilog-mode のキーワードはすべてAUTOで始まります。 このAUTOARGはコード中のディレクション指示の記述からポートリストを自動生成します。 詳細はHelp : verilog-auto-argを参照してください。

Verilog-mode の動作結果は以下の通りとなります。

module up_down_counter    (
  /*AUTOARG*/
   // Outputs
   out,
   // Inputs
   up_down, clk, reset
   );
//----------Output Ports--------------
output [7:0] out;
//------------Input Ports-------------- 
input up_down, clk, reset;
//------------Internal Variables--------
reg [7:0] out;
//-------------Code Starts Here-------
always @(posedge clk)
if (reset) begin // active high reset
  out <= 8'b0 ;
end else if (up_down) begin
  out <= out + 1;
end else begin
  out <= out - 1;
end

endmodule 

このようにポートリストが自動生成されました。

これを利用する利点として、Verilog-1995 の冗長な点であったポートリストとディレクションの指定の重複をスキップできることです。 ディレクションはコード中で明示的に指定する必要があります。

もっとも、Verilog-2001 以降のANSI C 形式の記法ならばAUTOARG は必要ないように思えます。

インスタンスのポート結線を自動化 (AUTOINST)

では、上記のテストベンチを作成してみましょう。

以下のようなテストベンチtb_up_down_counter.v を作成しました。

`timescale 1ns/1ns

module tb_up_down_counter;

localparam CLK_PERIOD = 10;

wire [7:0] out;
reg up_down, clk, reset;

up_down_counter DUT (
  .out(out),
  .up_down(up_down),
  .clk(clk),
  .reset(reset)
);

initial begin: gen_clk
  clk = 1'b0;
  forever #(CLK_PERIOD/2) clk = ~clk;
end

initial begin: test_count_up
  $monitor("[%0t] up_down %b | out %h", $time, up_down, out);
  up_down = 1'b0;
  reset = 1'b1;
  #(CLK_PERIOD) reset = 1'b0;
  up_down = 1'b1; //count-up
  $display("[%0t] start count-up", $time);
  repeat(16) @(posedge clk);
  $finish;
end

endmodule

このテストベンチを以下のようなコマンドを実行してModelSim でシミュレーションします。

$ vlib work
$ vlog up_down_counter.v tb_up_down_counter.v
$ vsim -c work.tb_up_down_counter -do "run -all"

以下のような出力が得られます。

# vsim -c work.tb_up_down_counter -do "run -all" 
# Start time: 11:38:19 on May 17,2020
# Loading work.tb_up_down_counter
# Loading work.up_down_counter
# run -all
# [0] up_down 0 | out xx
# [5] up_down 0 | out 00
# [10] start count-up
# [10] up_down 1 | out 00
# [15] up_down 1 | out 01
# [25] up_down 1 | out 02
# [35] up_down 1 | out 03
# [45] up_down 1 | out 04
# [55] up_down 1 | out 05
# [65] up_down 1 | out 06
# [75] up_down 1 | out 07
# [85] up_down 1 | out 08
# [95] up_down 1 | out 09
# [105] up_down 1 | out 0a
# [115] up_down 1 | out 0b
# [125] up_down 1 | out 0c
# [135] up_down 1 | out 0d
# [145] up_down 1 | out 0e
# [155] up_down 1 | out 0f
# ** Note: $finish    : tb_up_down_counter.v(30)
#    Time: 165 ns  Iteration: 1  Instance: /tb_up_down_counter
# End time: 11:38:20 on May 17,2020, Elapsed time: 0:00:01
# Errors: 0, Warnings: 0

ここまでは通常のシミュレーションです。 ここからVerilog-mode を利用して記述量を削減します。

まず、インスタンスを生成する部分を以下のように置換します。

`timescale 1ns/1ns

module tb_up_down_counter;

localparam CLK_PERIOD = 10;

wire [7:0] out;
reg up_down, clk, reset;

up_down_counter DUT (/*AUTOINST*/);

initial begin: gen_clk
  clk = 1'b0;
  forever #(CLK_PERIOD/2) clk = ~clk;
end

initial begin: test_count_up
  $monitor("[%0t] up_down %b | out %h", $time, up_down, out);
  up_down = 1'b0;
  reset = 1'b1;
  #(CLK_PERIOD) reset = 1'b0;
  up_down = 1'b1; //count-up
  $display("[%0t] start count-up", $time);
  repeat(16) @(posedge clk);
  $finish;
end

endmodule

インスタンスのポートマップをAUTOINST に置換しました。 以下のコマンドでVerilog-mode を実行します。 なお、カレントディレクト/path/to/hdltb_up_down_counter.v および up_down_counter.v があるとします。

$ docker run --rm -t -v /path/to/hdl:/dat \
  stomoki/eda-env_emacs-verilog-mode:7 \
  emacs --batch /dat/tb_up_down_counter.v -f verilog-batch-auto

なお、Bash 系では以下の記法も可能です。

$ docker run --rm -t -v $(pwd):/dat \
  stomoki/eda-env_emacs-verilog-mode:7 \
  emacs --batch /dat/tb_up_down_counter.v -f verilog-batch-auto

上記コマンドを実行したとき、tb_up_down_counter.v の内容は以下の通りとなります。

`timescale 1ns/1ns

module tb_up_down_counter;

localparam CLK_PERIOD = 10;

wire [7:0] out;
reg up_down, clk, reset;

up_down_counter DUT (
  /*AUTOINST*/
             // Outputs
             .out       (out[7:0]),
             // Inputs
             .up_down       (up_down),
             .clk       (clk),
             .reset     (reset));

initial begin: gen_clk
  clk = 1'b0;
  forever #(CLK_PERIOD/2) clk = ~clk;
end

initial begin: test_count_up
  $monitor("[%0t] up_down %b | out %h", $time, up_down, out);
  up_down = 1'b0;
  reset = 1'b1;
  #(CLK_PERIOD) reset = 1'b0;
  up_down = 1'b1; //count-up
  $display("[%0t] start count-up", $time);
  repeat(16) @(posedge clk);
  $finish;
end

endmodule

上記のように、、インスタンスの結線が自動的に生成されました。

この処理はインスタンスの参照先であるup_down_counter.v を参照して実行されています。 srctb といったように、もしデザインとテストベンチが保存されている場合は参照元のファイルの末尾に以下のようなコメントを追加してVerilog-mode へ参照先を指示する必要があります。

// Local Variables:
// verilog-library-directories:("." "../src")
// End:

詳細はHelp: verilog-library-directories を参照してください。

もっとも、SystemVerilog の.* (ドットスター記述)を利用すればこの機能も不要です。 ただし、EDAツールによっては.* を上手く解決できなかったり、.* だと結線されている信号名が分かりづらかったりするため、この機能を使用した方が記述量を削減しつつ可読性を向上できます。

インスタンスの結線用信号の記述を自動化 (AUTOWIRE, AUTOREGINPUT)

AUTOINST を利用することで、インスタンスのポートリストを自動化することができました。 併せて、ポートリストと接続する結線用の信号の宣言を自動化することで、さらに記述量を削減することができます。

以下のようにtb_up_down_counter.v を書き換えます。

`timescale 1ns/1ns

module tb_up_down_counter;

localparam CLK_PERIOD = 10;

/*AUTOWIRE*/
/*AUTOREGINPUT*/

up_down_counter DUT (/*AUTOINST*/);

initial begin: gen_clk
  clk = 1'b0;
  forever #(CLK_PERIOD/2) clk = ~clk;
end

initial begin: test_count_up
  $monitor("[%0t] up_down %b | out %h", $time, up_down, out);
  up_down = 1'b0;
  reset = 1'b1;
  #(CLK_PERIOD) reset = 1'b0;
  up_down = 1'b1; //count-up
  $display("[%0t] start count-up", $time);
  repeat(16) @(posedge clk);
  $finish;
end

endmodule

このコードをVerilog-mode で変換すると、以下のようになります。

`timescale 1ns/1ns

module tb_up_down_counter;

localparam CLK_PERIOD = 10;

/*AUTOWIRE*/
// Beginning of automatic wires (for undeclared instantiated-module outputs)
wire [7:0]      out;            // From DUT of up_down_counter.v
// End of automatics
/*AUTOREGINPUT*/
// Beginning of automatic reg inputs (for undeclared instantiated-module inputs)
reg           clk;            // To DUT of up_down_counter.v
reg           reset;          // To DUT of up_down_counter.v
reg           up_down;        // To DUT of up_down_counter.v
// End of automatics

up_down_counter DUT (/*AUTOINST*/
             // Outputs
             .out       (out[7:0]),
             // Inputs
             .up_down       (up_down),
             .clk       (clk),
             .reset     (reset));

initial begin: gen_clk
  clk = 1'b0;
  forever #(CLK_PERIOD/2) clk = ~clk;
end

initial begin: test_count_up
  $monitor("[%0t] up_down %b | out %h", $time, up_down, out);
  up_down = 1'b0;
  reset = 1'b1;
  #(CLK_PERIOD) reset = 1'b0;
  up_down = 1'b1; //count-up
  $display("[%0t] start count-up", $time);
  repeat(16) @(posedge clk);
  $finish;
end

endmodule

AUTOWIRE は出力ポートの、AUTOREGINPUT は入力ポートの結線信号を自動生成しました。 前述の通り、AUTOINST だけではSystemVerilog の.* の互換となりますが、AUTOWIRE およびAUTOREGINPUT を利用すれば信号宣言なしにテストベンチのひな形を作成することができます。 さらに言えば、テスト対象回路のポートマップを知らずにテストベンチのひな形を作成することができますので、テストベンチ作成の手間を大幅に減らすことができます。

AUTOREGINPUTAUTOREG の派生です。 AUTOREG はポートマップで指定されていない出力方向のレジスタを内部信号として自動的に生成します。 デザインおよびテストベンチで信号線の宣言を忘れていないかのチェックに有用です。

階層構造の記述を自動化する (AUTOINPUT, AUTOOUTPUT)

前述した結線の自動化は複数のインスタンスが存在するときに大きな効果をもたらします。

例えば、以下のような回路を追加し、カウンタの値をSPIプロトコルのシリアル通信へ変換する、とします。

module count_to_driver (
  input wire clk,
  input wire reset,
  input wire [7:0] out,
  output reg sck,
  output reg cs_n,
  output reg so
);

// control logics are here ...

endmodule

また、up_down_countercount_to_driver を組み合わせ、SPIプロトコルに従ったドライバ回路を設計するとします。 このときのコードは以下のように記載できます。

module driver (
  /*AUTOARG*/
);

/*AUTOINPUT*/ 
/*AUTOOUTPUT*/

/*AUTOWIRE*/
/*AUTOREG*/

up_down_counter counter (/*AUTOINST*/);
count_to_driver cnt2spi (/*AUTOINST*/);

endmodule

初出となるAUTOINPUT および AUTOOUTPUT は、インスタンスの入出力信号でコード上に宣言されていない信号をそのまま参照元モジュールの入出力ととして宣言します。

Verilog-mode で変換した結果は以下の通りとなります。

module driver (
  /*AUTOARG*/
   // Outputs
   so, sck, cs_n,
   // Inputs
   up_down, reset, clk
   );

/*AUTOINPUT*/ 
// Beginning of automatic inputs (from unused autoinst inputs)
input         clk;            // To counter of up_down_counter.v, ...
input         reset;          // To counter of up_down_counter.v, ...
input         up_down;        // To counter of up_down_counter.v
// End of automatics
/*AUTOOUTPUT*/
// Beginning of automatic outputs (from unused autoinst outputs)
output            cs_n;           // From cnt2spi of count_to_driver.v
output            sck;            // From cnt2spi of count_to_driver.v
output            so;         // From cnt2spi of count_to_driver.v
// End of automatics

/*AUTOWIRE*/
// Beginning of automatic wires (for undeclared instantiated-module outputs)
wire [7:0]      out;            // From counter of up_down_counter.v
// End of automatics
/*AUTOREG*/

up_down_counter counter (/*AUTOINST*/
             // Outputs
             .out           (out[7:0]),
             // Inputs
             .up_down       (up_down),
             .clk           (clk),
             .reset         (reset));
count_to_driver cnt2spi (/*AUTOINST*/
              // Outputs
              .sck      (sck),
              .cs_n     (cs_n),
              .so       (so),
              // Inputs
              .clk      (clk),
              .reset        (reset),
              .out      (out[7:0]));

endmodule

このように、すべてのインスタンスの結線が解決され、必要な入出力ポートが宣言され、ポートマップが補完されています。 clkreset といった共通の入力信号も重複なく解決されています。

また、ANSI C 形式でポートマップを宣言するときは以下のように記述します。

module driver (
/*AUTOINPUT*/ 
/*AUTOOUTPUT*/
);

/*AUTOWIRE*/
/*AUTOREG*/

up_down_counter counter (/*AUTOINST*/);
count_to_driver cnt2spi (/*AUTOINST*/);

endmodule

この変換結果は以下のようになります。

module driver (
/*AUTOINPUT*/ 
// Beginning of automatic inputs (from unused autoinst inputs)
input         clk,            // To counter of up_down_counter.v, ...
input         reset,          // To counter of up_down_counter.v, ...
input         up_down,        // To counter of up_down_counter.v
// End of automatics
/*AUTOOUTPUT*/
// Beginning of automatic outputs (from unused autoinst outputs)
output            cs_n,           // From cnt2spi of count_to_driver.v
output            sck,            // From cnt2spi of count_to_driver.v
output            so          // From cnt2spi of count_to_driver.v
// End of automatics
);

/*AUTOWIRE*/
// Beginning of automatic wires (for undeclared instantiated-module outputs)
wire [7:0]      out;            // From counter of up_down_counter.v
// End of automatics
/*AUTOREG*/

up_down_counter counter (/*AUTOINST*/
             // Outputs
             .out           (out[7:0]),
             // Inputs
             .up_down       (up_down),
             .clk           (clk),
             .reset         (reset));
count_to_driver cnt2spi (/*AUTOINST*/
              // Outputs
              .sck      (sck),
              .cs_n     (cs_n),
              .so       (so),
              // Inputs
              .clk      (clk),
              .reset        (reset),
              .out      (out[7:0]));

endmodule

ここで、ポートリストに型宣言が含まれないことに注意すること。

SystemVerilog の場合、AUTOWIRE の代わりにAUTOLOGIC の使用を推奨します。 その場合、ポートリストにlogic として型宣言が含まれるようになります。

テスト用スタブを自動生成する (AUTOINOUTMODULE)

テスト作成時に困るのが外部モジュールのふるまいの記述です。

外部モジュールのふるまいをテストコードに直接記述すると、大抵が複雑化し保守性を低下させる要因となりやすいです。 そのため、ここはモックやスタブとして外部モジュールと同様のインタフェースを持つテスト用モジュールを作成し、必要ならばロジックを増やしていく戦略をとると良いと思います。 このメリットとして、テストコードの行数を減らせることとと作成したテストモジュールを他のテストへ再利用できる点が挙げられます。

上記のdriver のスタブを作成してみましょう。 このスタブはdriver モジュールが完成するまで上位モジュールから参照してもコンパイルが通るようにし、driver モジュールから返答がなくてもよい部分を先に作るために有用です。

Verilog-mode のFAQ を参考にして以下のように記述します。

module stub_driver #(
   /*AUTOINOUTPARAM("driver")*/
)(
  /*AUTOINOUTMODULE("driver")*/
);

/*AUTOWIRE*/
/*AUTOREG*/

/*AUTOTIEOFF*/

wire _unused_ok = &{1'b0,
  /*AUTOUNUSED*/
  1'b0};

endmodule

Verilog-mode で変換すると以下のようになります。

module stub_driver #(
   /*AUTOINOUTPARAM("driver")*/
)(
  /*AUTOINOUTMODULE("driver")*/
  // Beginning of automatic in/out/inouts (from specific module)
  output      cs_n,
  output      sck,
  output      so,
  input           clk,
  input           reset,
  input           up_down
  // End of automatics
);

/*AUTOWIRE*/
/*AUTOREG*/

/*AUTOTIEOFF*/
// Beginning of automatic tieoffs (for this module's unterminated outputs)
wire          cs_n            = 1'h0;
wire          sck         = 1'h0;
wire          so          = 1'h0;
// End of automatics

wire _unused_ok = &{1'b0,
  /*AUTOUNUSED*/
  // Beginning of automatic unused inputs
  clk,
  reset,
  up_down,
  // End of automatics
  1'b0};

endmodule

AUTOINOUTPARAM およびAUTOINOUTMODULE は引数として指定したモジュールのポートリストを参照し、内容を複製します。

AUTOTIEOF は未使用の出力信号を1`b0 へ固定し、不定値となることを防ぎます。

AUTOUNUSED は未使用な入力信号を列挙します。 この_unused_ok では全ての未使用な入力信号線をまとめ、全てのビットのANDを生成しています。 _unused_ok は1'b0 とのANDとなっているため、常に1'b0となります。 必要ならばこの信号線をリンタなど他のツールのスコープから除外するのがベターだそうです。

一方で、driver の開発を考えた場合、SPIの接続先が必要となります。 その場合、stub_spi として以下のように記述します。

module stub_spi #(
    /*AUTOINOUTPARAM("driver")*/
) (
    /*AUTOINOUTCOMP("driver", "", "^input.*")*/
);

/*AUTOWIRE*/
/*AUTOREG*/

/*AUTOTIEOFF*/
wire _unused_ok = &{1'b0,
  /*AUTOUNUSED*/
  1'b0};

endmodule

Verilog-mode で変換した結果は以下の通りです。

module stub_spi #(
    /*AUTOINOUTPARAM("driver")*/
) (
    /*AUTOINOUTCOMP("driver", "", "^input.*")*/
    // Beginning of automatic in/out/inouts (from specific module)
    input     cs_n,
    input     sck,
    input     so
    // End of automatics
);

/*AUTOWIRE*/
/*AUTOREG*/

/*AUTOTIEOFF*/
wire _unused_ok = &{1'b0,
  /*AUTOUNUSED*/
  // Beginning of automatic unused inputs
  cs_n,
  sck,
  so,
  // End of automatics
  1'b0};

endmodule

AUTOINOUTCOMPAUTOINOUTMODULE の派生で、指定したモジュールのポートリストを参照して逆方向のポートリストを生成します。 ここで重要なのが2番目の引数と3番目の引数です。 2番目の引数は「正規表現による参照元のポートリストの信号名に対するフィルタリング設定」で、例えば^spi_.* のように指定するとspi_から始まる信号線のみをポートリストの対象とします。 3番目の引数は「正規表現による変換後のポートリストのディレクションおよびデータ型に対するフィルタリング設定」で、この例ではinput から始まるポートのみを出力する設定となります。

そのため、AUTOINOUTCOMP("driver","","^input.*") は、 1. driver モジュールの、 2. すべてのポートに対して、 3. 反対のディレクションへ変換し、 4. input から始まる全てのポートを出力する という指示となります。

今回はSPI通信関係の信号線を抽出したかったこととSPI通信に関わる信号線のみが出力だったため上記のような条件設定となりました。 特定のポートのみ出力したい場合は信号名にspi_ のようなプレフィックスを付け、第2引数で指定するのが良いと思います。

詳細はHelp: verilog-auto-inout-module を参照してください。

上記スタブを使用することで、SPI通信関連の信号を内部で処理することができます。 スタブ中に制御ロジックやタスクを追記することでモックとして作り込むこともできます。

実際にスタブを用いたテストベンチを記述してみましょう。

driver モジュールのテストベンチを以下のように記述します。

module tb_driver;

/*AUTOREGINPUT*/
/*AUTOWIRE*/
/*AUTOREG*/

driver DUT (/*AUTOINST*/);
stub_spi stub_spi(/*AUTOINST*/);

// stimulus are here...

endmodule

verilog-mode で変換すると以下のようになります。

module tb_driver;

/*AUTOREGINPUT*/
// Beginning of automatic reg inputs (for undeclared instantiated-module inputs)
reg           clk;            // To DUT of driver.v
reg           reset;          // To DUT of driver.v
reg           up_down;        // To DUT of driver.v
// End of automatics
/*AUTOWIRE*/
// Beginning of automatic wires (for undeclared instantiated-module outputs)
wire          cs_n;           // From DUT of driver.v
wire          sck;            // From DUT of driver.v
wire          so;         // From DUT of driver.v
// End of automatics
/*AUTOREG*/

driver DUT (/*AUTOINST*/
        // Outputs
        .cs_n           (cs_n),
        .sck            (sck),
        .so             (so),
        // Inputs
        .clk            (clk),
        .reset          (reset),
        .up_down            (up_down));
stub_spi stub_spi(/*AUTOINST*/
          // Inputs
          .cs_n         (cs_n),
          .sck          (sck),
          .so           (so));

// stimulus are here ...

endmodule

上記の通り、スタブおよびテスト対象回路の記述量を削減しつつテストベンチを構築することができます.

まとめ

Emacs Verilog-mode を利用することでテストベンチの記述量を減らし、作成スピードを向上することができます。 どこかのモジュールで変更があった場合、信号名の書き換えがコマンドによって自動的に書き換えられるのが利点です。

よいHDL設計ライフを!