Verilog alwaysブロックで順序論理を実装する
前回の記事では always ブロックで組み合わせ論理を実装する例を示しました。always ブロックは、フリップフロップのような値を保持するメモリ要素を持つ 順序 論理の実装にも主に使用されます。
JKフリップフロップ
JKフリップフロップは値を格納するフロップの一種で、データ入力 j と k、リセット rstn、クロック clk を持ちます。真理値表は以下の通りで、通常NANDゲートで実装されます。
| rstn | j | k | q | コメント |
|---|---|---|---|---|
| 0 | 0 | 0 | 0 | リセットアサート時、出力は常に0 |
| 1 | 0 | 0 | 保持 | j=k=0で出力は前回値を保持 |
| 1 | 0 | 1 | 1 | k=1で出力は1 |
| 1 | 1 | 0 | 0 | k=0で出力は0 |
| 1 | 1 | 1 | トグル | j=k=1で出力が現在値を反転 |
JKフリップフロップの振る舞いVerilogコードは以下の通り:
module jk_ff (input j, k, rstn, clk, output reg q);
always @ (posedge clk or negedge rstn) begin
if (!rstn) begin
q <= 0;
end else begin
q <= (j & ~q) | (~k & q);
end
end
endmodule
テストベンチ
テストベンチで使用する変数を宣言し、シンプルな always ブロックでクロックを生成して設計に駆動します。設計をインスタンス化し、ポートをテストベンチ変数と接続。q は設計の出力に接続され積極的に駆動されるため wire 型、他の入力は initial などの手続きブロックで駆動するため reg 型です。
刺激はまずすべての入力を0で初期化し、しばらくしてリセットを非アサート。for ループで j と k にランダムな値をランダムなタイミングで駆動。ループ終了後、少し待ってシミュレーション終了。
module tb;
reg j, k, rstn, clk;
wire q;
integer i;
reg [2:0] dly;
always #10 clk = ~clk;
jk_ff u0 (.j(j), .k(k), .clk(clk), .rstn(rstn), .q(q));
initial begin
{j, k, rstn, clk} <= 0;
#10 rstn <= 1;
for (i = 0; i < 10; i = i+1) begin
dly = $random;
#(dly) j <= $random;
#(dly) k <= $random;
end
#20 $finish;
end
endmodule
シミュレーション波形から、クロックの立ち上がりエッジで、真理値表通りに入力 j と k の状態に基づいて出力 q が値を変化させることがわかります。
モジュロ10カウンタ
モジュロ(MOD)カウンタは特定の数までカウントアップしてからゼロに戻ります。MOD-Nカウンタは0からN-1までカウントし、ゼロに戻って再びカウントを開始。このようなカウンタには通常 log2N 個のフロップが必要です。以下は、リセット rstn が非アサートされている限り、毎クロック clk でカウントアップし続けるMOD-10カウンタのVerilogコードです。
Verilogパラメータを使えば、よりスケーラブルなMOD-Nカウンタが作れます。
module mod10_counter (input clk, input rstn, output reg[3:0] out);
always @ (posedge clk) begin
if (!rstn) begin
out <= 0;
end else begin
if (out == 10) out <= 0;
else out <= out + 1;
end
end
endmodule
テストベンチ
module tb;
reg clk, rstn;
reg [3:0] out;
mod10_counter u0 (.clk(clk), .rstn(rstn), .out(out));
always #10 clk = ~clk;
initial begin
{clk, rstn} <= 0;
#10 rstn <= 1;
#450 $finish;
end
endmodule
カウンタモジュールが0から9までカウントし、0にロールオーバーして再びカウントを開始することがわかります。
4ビット左シフトレジスタ
以下は4ビット左シフトレジスタで、入力 d をLSBに受け取り、他のすべてのビットを1つ左にシフトします。例えば、d が0でレジスタ初期値が0011なら、次のクロックエッジで0110になります。
module lshift_4b_reg (input d, input clk, input rstn, output reg [3:0] out);
always @ (posedge clk) begin
if (!rstn) begin
out <= 0;
end else begin
out <= {out[2:0], d};
end
end
endmodule
テストベンチ
module tb;
reg clk, rstn, d;
wire [3:0] out;
integer i;
lshift_4b_reg u0 (.d(d), .clk(clk), .rstn(rstn), .out(out));
always #10 clk = ~clk;
initial begin
{clk, rstn, d} <= 0;
#10 rstn <= 1;
for (i = 0; i < 20; i=i+1) begin
@(posedge clk) d <= $random;
end
#10 $finish;
end
endmodule
各ビットが1つ左にシフトし、d の新しい値がLSBに適用されることがわかります。
Verilog
- スイッチ付き回路:基本電気回路の実践ガイド
- 集積回路:デジタル論理ゲートの基礎
- プログラマブルロジックコントローラ(PLC):産業システムのための現代的デジタル制御
- ブール代数の理解:論理基礎からデジタル回路まで
- カルノー図によるロジック簡略化のマスター
- フィードバックを持つデジタルロジック:決定論的ゲートからマルチバイブレータへ
- Okamoto精密研削盤で完璧な仕上げを実現:業界トップクラスの研磨技術
- VHDLとVerilogのマスター:クリーンな組み合わせ・順序ロジックの書き方
- Verilog Mod-Nカウンタ:パラメータ化モジュールとテストベンチ
- Verilogグレイカウンタ:4ビットグレイコード生成モジュール
- 自己抑制負荷搭載の完全CMOS互換4T2R nv-SRAM:STI-RRAM採用でゼロ静止電力・高速動作