少しづつですが、なんだか、わかってきましたね (^_^;) 今回は、この問題をやってみます。
4 ビットカウンタをシミュレーションする
4 ビットカウンタは、クロックをカウントして 4 ビットの値を出力する、順序回路です。過去記事で、じっさいにつくりましたね。
図 1 のブロック図、クロック CLK は立ち上がりエッジでカウントするという表示になっています。RES はリセットですが、◯ がついているので、アクティブロー (0 でリセットされる) とします。
回路記述
回路をつくりましょう。
- module counter_4bit(CLK, RES, Q);
- input CLK, RES;
- output [3:0] Q;
- wire CLK, RES;
- reg [3:0] Q;
- always @(posedge CLK) begin
- if(RES == 1'b0)
- Q = 4'd0;
- else
- Q = Q + 4'd1;
- end
- endmodule
9 行目。組み合わせ回路では assign でしたが、順序回路では always を使います。posedge は CLK の立ち上がりエッジを意味します。立ち下がりエッジは negedge です。
7 行目。always を使う場合、出力信号は reg として「変数宣言」します。wire は「ネット宣言」といいます。変数は値を記憶する、ネットは信号を流す、ってことなのかな。
10~13 行目は if 文。1’b0 は定数で、サイズが 1 ビットの 2 進数で 0b0 です。RES が 0 なら、Q を 4’d0、つまりサイズが 4 ビットの 10 進数で 0 にする。つまり、リセットする。esle ならば、Q をカウントアップする。
ちなみに、定数のサイズを指定しないと 32 ビットになります。そうだ、前回、for() 文のループ変数 i を integer で宣言したけど、これも 32 ビットです。
なお、CLK の立ち上がりエッジだけで動作するので、リセットも CLK に同期します。
非同期リセットにするときは、
- always @(posedge CLK, negedge RES) begin
とします。RES の立ち下がりエッジで、非同期リセットされます。
テストベンチ
テストベンチファイルです。
- module counter_4bit_test;
- reg CLK, RES;
- wire [3:0] Q;
- counter_4bit ctr0(CLK, RES, Q);
- always begin
- #5 CLK = ~CLK;
- end
- initial begin
- CLK = 0;
- RES = 0;
- #30 RES = 1;
- #200 RES = 0;
- #30 RES = 1;
- #50 $finish;
- end
- initial begin
- $monitor("CLK = %d RES = %d Q = %d", CLK, RES, Q);
- $dumpfile("counter_4bit.vcd");
- $dumpvars(0, counter_4bit_test);
- end
- endmodule
8~10 行目。クロック CLK を always で発生させます。5 ユニット時間ごとに反転させる、ってことは、周期が 10 ユニット時間のクロックになる。
12~19 行目が、入力信号。RES を 1 にするとカウントスタート、0 にするとリセット。
図 2 が、シミュレーション波形です。
RES が 1 のときに、カウントアップし、0xF までカウントしたら 0 に戻る 16 進カウンタです。RES が 0 になると、CLK に同期して 0 になっています。