早速、FPGAボード上で動作させてみましょう!といいたいところですが、まずはテストベンチを作成し、シミュレーションを実行します。
以下に4bitフリーランカウンタのテストベンチの記述を示します。
1 module TEST_COUNT4; 2 reg clk, reset; 3 wire [3:0] count; 4 5 parameter CYCLE = 100; 6 7 COUNT4 i1(.RESET(reset), .CLK(clk), .COUNT(count)); 8 9 always #(CYCLE/2) 10 clk = ~clk; 11 12 initial 14 reset = 1'b0; clk = 1'b0; ←時刻0 15 #CYCLE reset = 1'b1; ←時刻100 16 #(20*CYCLE) reset = 1'b0; ←時刻2100 17 #CYCLE reset = 1'b1; ←時刻2200 18 #(20*CYCLE) $finish; ←時刻4200、シミュレーションを終了 19 end 20 21 initial 22 $monitor($time,,"clk=%b reset=%b count=%b", clk, reset, count); 23 24 endmodule
9行目のalways文中の「clk」信号、14〜17行目のinitial文中の「clk」「reset」信号が手続き的代入文の中で使用されているので、それぞれの信号をreg宣言します。
「count」信号が、reg宣言またはwire宣言をしなければならない信号としてまだ残っています。count信号は、bit幅が1bitではないのでwire宣言を省略できません(注)。そのため、4bitのwire宣言を行います。
parameter文で、このシミュレーションにおける1クロックサイクルの長さを指定します。このparameter文の値を変更すれば、クロックの周波数を変更できるので非常に便利です。
クロックのような繰り返し「0」「1」になるパルスを生成する典型的な記述です。この場合には、時刻50ユニットごとにclk信号が反転されます(注)。
reset信号とclk信号の時刻0での値を代入します。特にこのclk信号の初期化は大変重要です。これを忘れてしまうと、うまくclkを生成することができません。
ちなみに、最新のVerilog-HDLの規格では、「reg clk = 1'b0;」のようにreg宣言時に初期値を与えることも可能です(この場合、initial文中での初期化は不要)。
時刻100ユニットでreset信号を「1'b1」にして、時刻2100ユニット(100+2000)でreset信号を「1'b0」にします。さらに、時刻2200ユニット(100+2000+100)でreset信号を再び「1'b1」にして、時刻4200ユニット(100+2000+100+2000)で$finish(シミュレーションを終了)します。
これで、RTLとテストベンチが完成しました。それでは、ModelSimを使ってシミュレーションを実行してみましょう。前回までの記事を参考にコンパイル、シミュレート、実行をして、波形表示で動作を確認してください。
画面1のように動作すれば問題ありません。
画面1では、結果を確認しやすくするためにカウンタの値を整数値で表示しています。この表示を行うには、「wave-default(波形表示のウィンドウ)」の左側リストから表示を変更したい信号を右クリックして[ショートカットメニュー]−[Radix]−[Unsigned]を選択します(画面2)。
これで、シミュレーションでの動作確認が取れました。それでは、RTLをFPGAのボード上で動かしてみましょう。
ここでは、手早く動作を確認するために4bitのカウンタの値を赤色LEDにそのまま出力しています。以下のピンアサインを行って、論理合成、配置配線を実行してください。
I/O Name | Loc |
---|---|
CLK | P39 |
RESET | P17 |
COUNT<0> | P68 |
COUNT<1> | P67 |
COUNT<2> | P66 |
COUNT<3> | P65 |
1 NET "CLK" LOC = "P39" ; 2 NET "RESET" LOC = "P17" ; 3 NET "COUNT<0>" LOC = "P68" ; 4 NET "COUNT<1>" LOC = "P67" ; 5 NET "COUNT<2>" LOC = "P66" ; 6 NET "COUNT<3>" LOC = "P65" ;
特に問題がなければ、ボード上に設計データ(bitファイル)をダウンロードします。
いかがでしょうか?
ボード上で確認してみると、すべての赤色LEDが点灯したような状態になっていると思います。
赤色LEDは、なぜカウント動作をしてくれないのでしょうか?
それは、カウンタが6MHzで動作しているからです。実際は正しくカウント動作をしているのですが、高速過ぎて人間の目には「すべてのLEDが点灯しているだけ」のように見えているのです。
このままでは、ボード(赤色LED)上で正しくカウンタが動作しているかを確認することができません。そこで、カウンタのクロックを遅くする方法を紹介します。
あまり良い方法ではありませんが(その理由は、次回説明します)、今回は6MHzのクロックを分周してカウンタに渡して動作させます。
分周するクロックを入れるために、リスト1を以下のように変更します。
1 module COUNT4(RESET, CLK, COUNT); 2 input RESET, CLK; 3 output [3:0] COUNT; 4 5 reg [22:0] tmp_count; 6 reg [3:0] COUNT; 7 8 always @(posedge CLK or negedge RESET) 9 begin 10 if (RESET == 1'b0) 11 tmp_count <= 23'h000000; 12 else 13 tmp_count <= tmp_count + 23'h1; 14 end 15 16 assign DIVIDE_CLK = tmp_count[22]; 17 18 always @(posedge DIVIDE_CLK or negedge RESET) 19 begin 20 if (RESET == 1'b0) 21 COUNT <= 4'h0; 22 else 23 COUNT <= COUNT + 4'h1; 24 end 25 26 endmodule
変更したポイントは、下記のとおりです。
この変更を行ったら、ISE WebPACKで論理合成、配置配線を行い、設計データをFPGAのボードにダウンロードします。
今回はいかがでしょうか? カウンタの動作を確認できたと思います。ただし、赤色LEDは負論理なのでLEDの動作はカウントダウンしています。
このシミュレーションを行うには、かなりのクロック数が必要となりますので、まともにシミュレーションするのは現実的ではありません(カウントが1つアップするだけでも、気の遠くなるようなクロック数が必要となります)。この課題を克服するためのシミュレーションテクニックに関しては「単相同期回路設計」の解説と併せて次回紹介する予定です。
Copyright © ITmedia, Inc. All Rights Reserved.