Verilog-HDL 文法(5):シミュレーション記述(1) 2015/09/27 |
[CategoryTop] [Prev] [Next] |
[目次]・シミュレーション記述概要 + テストベンチの構成 + テストベンチ用moduleの構成 ・テストベンチの記述例 + モチーフ回路 + モチーフ回路のテストベンチ ●シミュレーション記述概要 ◆テストベンチの構成 ・テストベンチとは、自分が作成した回路(module)に、シミュレーション上で信号を 印加/観察するためのデータ構造を指します。 ・Verilog-HDLではテストベンチもmodule構造を持っています。以下にテストベンチの 構成を示します。module myrtlが観測対象の回路という想定です。 [Fig.1 テストベンチの構成] ┌─────────────────────────────────────┐ +-- module myrtl_tb ------------------------------+ | | | +--module myrtl--+ | | | | | | [reg clk;]o---+ clk | | | | | | | [reg in1;]o---+ in1 out1+---o wire out1; | | : : : : | | [reg inN;]o---+ inN outM+---o wire outM; | | | | | | +----------------+ | | | +-------------------------------------------------+ └─────────────────────────────────────┘ ・Fig.1のように、テストベンチのmoduleは外部のポートを持っていません。信号を印 加するためのregと、出力観測用のwireのみです。 ・「わかりやすさ」の点から考えれば、テストベンチmoduleのreg, wire名は、観測 moduleの入出力ポート名と同じにすることがほとんどです。 reg 信号 <===> 入力ポート wire信号 <===> 出力ポート ◆テストベンチ用moduleの構成 ・テストベンチ用module記述の雛型はList1のようになります。 [List.1 テストベンチの構成(最もシンプルな例)] ┌─────────────────────────────────────┐ `timescale Sim.単位/精度 module テストベンチ名; reg 入力信号名_1; // ---+ : // +--- (1)信号入力reg定義 reg 入力信号名_N; // ---+ wire 出力信号名_1; // ---+ : // +--- (2)出力観測wire定義 wire 出力信号名_M; // ---+ 観測module名 観測moduleインスタンス( // --+ .入力信号名_1(入力信号名_1), // | : // | .入力信号名_N(入力信号名_N), // +--- (3)観測対象moduleの .出力信号名_1(出力信号名_1), // | インスタンス定義 : // | .出力信号名_M(出力信号名_M) // | ); // --+ initial begin // --+ // | #0 初期値設定; // +--- (4)信号印加記述 #(CYCLE) 印加記述; // | : // | : // | end // --+ initial $monitor(出力記述); // (5)信号出力記述 endmodule └─────────────────────────────────────┘ ・テストベンチではシミュレーションの時間設定が必要です。それが冒頭の `timescale Sim.単位/精度 です。これはシミュレータへの指示子になっています。 ・List1で示したように、テストベンチ用moduleは大まかに5個のブロックで構成され ます。 (1)信号入力reg定義 (2)出力観測wire定義 (3)観測対象moduleのインスタンス定義 (4)信号印加記述 (5)信号出力記述 ・これら5ブロックの記述方法ですが、テストベンチの記述は論理合成を意識していな いので、Verilog-HDLの文法を全て適用することができます。可能な記述については これから順次説明していきます。 ・とりあえず今回はテストベンチのサンプルを見て、基本ステートメントを把握して 下さい。 ●テストベンチの記述例 ◆モチーフ回路 ・テストベンチを作る前に、観測対象とするモチーフ回路を記述してみます。今回は ちょっと変りネタの回路です。3bitのPRPG(Pseudo Random Pattern Generator)を作 成してみます。(*1) [Fig.2 モチーフ回路 : PRPG -- 疑似ランダムパターン発生器] ┌─────────────────────────────────────┐ ![]() └─────────────────────────────────────┘ ・モチーフ回路はLFSR(Linear Feedback Shift Register)を利用したランダムパター ン発生器です。 ・動きですが、最初にInit信号を立ててから、初期値Seed[2:0](必ず何かのbitが1)を 設定し、Clkを1回入れることで各FFに初期値を格納します(同期動作)。 ・その後、Initを下げてClkを叩くと、FeedBackループのデータ演算結果に伴い、 Rdata[2:0]から3bitの値がランダムに出力されるという回路です。全bit0以外の値 が発生されるので、3bitの場合は(2^3-1 = 7)種類の値を取ります。 ・このモチーフ回路のRTL(*2)はList2になります。 [List.2 モチーフ回路 : prpg_3 RTL] ┌─────────────────────────────────────┐ module prpg_3 ( Clk, Init, Seed, Rdata ); input Clk; input Init; input [2:0] Seed; output [2:0] Rdata; reg [2:0] Rdata; always @ ( posedge Clk ) begin if ( Init ) // Seed In (Sync Clk) begin Rdata <= Seed; end else // LFSR Loop begin Rdata[2] <= Rdata[1]; Rdata[1] <= Rdata[0] ^ Rdata[2]; Rdata[0] <= Rdata[2]; end end endmodule └─────────────────────────────────────┘ ◆モチーフ回路のテストベンチ ・それではモチーフ回路のテストベンチ及び、想定信号波形をList3に示します。 [List.3 テストベンチ : prpg_3_tb] ┌─────────────────────────────────────┐ ![]() テストベンチで想定している信号波形 ───────────────────────────────────── `timescale 1ns/1ns module prpg_3_tb; reg Clk; reg Init; reg [2:0] Seed; wire [2:0] Rdata; parameter RATE = 100; // Cycle Rate = 100ns(10MHz) prpg_3 prpg_3 ( // Instanciation .Clk ( Clk ), .Init ( Init ), .Seed ( Seed ), .Rdata ( Rdata ) ); always #(RATE/2) Clk = ~Clk; // Clock Generation initial begin #0 Clk = 0; // Initialize Init = 1'b0; Seed = 3'b000; #(RATE) Init = 1'b1; // Seed Set Seed = 3'b010; #(RATE) Init = 1'b0; // Generation Start Seed = 3'b000; #(RATE * 10) // Random Output 10 Cycle $finish; end initial $monitor ( $stime, " Clk=%b Init=%b Seed=%3b Rdata=%3b", Clk, Init, Seed, Rdata ); endmodule └─────────────────────────────────────┘ ・記述内容を説明します。1行目の `timescale 1ns/1ns はSimulationの実行単位と精度の指定です。スラッシュ(/)を挟んで前が実行単位、 後ろが精度の指定になっています。通常、同じ単位を指定すれば問題ありません。 ・19行目の always #(RATE/2) Clk = ~Clk; はクロック波形の生成です。alwaysはシミュレーション開始後、文字通り「常に」 動作する信号を記述します。この場合、時間がRATE(100ns)の半分進んだら、Clkを 反転させるという記述です。 ・21行目のinitialは「開始時に1度だけ実行されるステートメント」です。このテス トベンチではinitial文が2ヶ所あります。21行目の信号印加ブロック。そして36行 目はシステムタスクである$monitorを起動しています。 ・#0 はディレイ指定ですが、ここで初期値を設定しています。Clkを0にし、この後は alwaysの設定に従い、ディレイ(RATE/2)によって変化します。 ・その後は規定のディレイで信号設定を順次記述しているだけです。 ・37行目の$monitorは引数の信号に変化がある場合値を出力します。引数の中にある $stimeはシミュレーションの時間を示すシステムタスクです。 ・このテストベンチで実行したSimulation結果をList4に示します。 [List.4 シミュレーション結果] ┌─────────────────────────────────────┐ 0 Clk=0 Init=0 Seed=000 Rdata=xxx 50 Clk=1 Init=0 Seed=000 Rdata=xxx 100 Clk=0 Init=1 Seed=010 Rdata=xxx 150 Clk=1 Init=1 Seed=010 Rdata=010 ---- : 010 (初期値) 200 Clk=0 Init=0 Seed=000 Rdata=010 ↑ 250 Clk=1 Init=0 Seed=000 Rdata=100 | : 100 300 Clk=0 Init=0 Seed=000 Rdata=100 | 350 Clk=1 Init=0 Seed=000 Rdata=011 | : 011 400 Clk=0 Init=0 Seed=000 Rdata=011 | 450 Clk=1 Init=0 Seed=000 Rdata=110 | : 110 500 Clk=0 Init=0 Seed=000 Rdata=110 | 550 Clk=1 Init=0 Seed=000 Rdata=111 | : 111 600 Clk=0 Init=0 Seed=000 Rdata=111 | 650 Clk=1 Init=0 Seed=000 Rdata=101 | : 101 700 Clk=0 Init=0 Seed=000 Rdata=101 | 750 Clk=1 Init=0 Seed=000 Rdata=001 | : 001 800 Clk=0 Init=0 Seed=000 Rdata=001 ↓ 850 Clk=1 Init=0 Seed=000 Rdata=010 ---- : 010 (初期値へ戻る) 900 Clk=0 Init=0 Seed=000 Rdata=010 950 Clk=1 Init=0 Seed=000 Rdata=100 1000 Clk=0 Init=0 Seed=000 Rdata=100 以後、繰り返し 1050 Clk=1 Init=0 Seed=000 Rdata=011 1100 Clk=0 Init=0 Seed=000 Rdata=011 1150 Clk=1 Init=0 Seed=000 Rdata=110 └─────────────────────────────────────┘ ・List4の結果を見ればわかるように、初期値010設定後、Rdata[2:0]の値はランダム に変化しています。 ・データ発生を変えたい場合、Seed[2:0]の値を変えます。尚、all0を出力したい場合 はSeed[2:0]をall0にします。ただし、この場合はClkを入れてもRdataはall0固定に なります。 ・尚、この結果を波形で確認したい場合、vcdファイルに格納する方法があります。テ ストベンチに少しだけ追加記述を行いますが、それは「Verilog-HDLのフリー環境」 を参照して下さい。iverilogによる実行も本レポートに書いています。 ・最も基本的なテストベンチの構成については以上になります。次回からはテストベ ンチで可能な様々な記述を見ていくことにします。 (*1)最近のLogic向けDFTでは、よく記述/利用されるタイプの回路です。 (*2)RTLはRegister Transfer Levelの略です。Clkに伴うレジスタ間のデータ転送レベルで 記述したVerilog-HDLデータを指します。 [Revision Table] |Revision |Date |Comments |----------|-----------|----------------------------------------------------- |1.00 |2003-11-24 |初版 |1.01 |2005-11-20 |リンク更新 (2年振りの追加です) [end] Copyright(C) 2015 Altmo
|