always を使用したシーケンシャル ロジック
以前の記事では、 always
を使用するさまざまな例を示しました 組み合わせロジックを実装するためのブロック。 always
ブロックは主に シーケンシャル の実装にも使用されます 値を保持できるフリップフロップなどのメモリ要素を持つロジック。
JK フリップフロップ
JK フリップフロップは、値を格納するために使用される多くのタイプのフロップの 1 つであり、リセット rstn 用とクロック clk 用に 1 つずつ、2 つのデータ入力 j と k を備えています。 JK フロップの真理値表を以下に示します。これは通常、NAND ゲートを使用して実装されます。
rstn | j | k | q | コメント |
---|---|---|---|---|
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=1,k=1 の場合、出力は現在の値を切り替えます |
JK フリップフロップのビヘイビア Verilog コードは、次のように記述できます
module jk_ff ( input j, // Input J
input k, // Input K
input rstn, // Active-low async reset
input clk, // Input clk
output reg q); // Output 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
型であることに注意してください アクティブに駆動するデザインの出力に接続されているためです。設計への他のすべての入力は reg
型です。 initial
などの手続き型ブロック内で駆動できるようにするため .
スティミュラスは、最初にデザインへのすべての入力を 0 に初期化し、しばらくしてからリセットをディアサートします。 for
loop は、ランダムな時間に駆動される j と k に異なる値を駆動するために使用されます。ループが完了したら、もう少し待ってからシミュレーションを終了してください。
module tb;
// Declare testbench variables
reg j, k, rstn, clk;
wire q;
integer i;
reg [2:0] dly;
// Start the clock
always #10 clk = ~clk;
// Instantiate the design
jk_ff u0 ( .j(j), .k(k), .clk(clk), .rstn(rstn), .q(q));
// Write the stimulus
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 までカウントし、その後ゼロにロールバックして再びカウントを開始します。通常、このようなカウンターには log2 が必要です カウント値を保持する N フロップ数。以下に示すのは、リセット 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
テストベンチ
テストベンチは最初に、いくつかの値を割り当てて設計入力に駆動できるいくつかの変数を宣言します。その後、カウンタ モジュールがインスタンス化され、テストベンチ信号に接続されます。テストベンチ信号は、後でスティミュラスの値で駆動されます。カウンターもクロックを必要とするため、テストベンチ クロックは always
でモデル化されます。 ブロック。スティミュラスは、時間 0ns でデフォルト値を設定し、10ns 後にリセットをディアサートし、デザインをしばらく実行できるようにします。
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 ビット左シフト レジスタ
以下に示すのは、LSB への入力 d を受け入れる 4 ビットの左シフト レジスタで、他のすべてのビットは左に 1 シフトされます。たとえば、d がゼロに等しく、レジスタの初期値が 0011 の場合、クロック clk の次のエッジ。
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
テストベンチ
テストベンチは、いくつかの変数が宣言され、デザイン モジュールがインスタンス化され、テストベンチ信号に接続される前に示したものと同様のテンプレートに従います。次に、クロックが開始され、initial
を使用してスティミュラスがデザインに駆動されます。 ブロック。このテストベンチの例では、異なる値の d を実行する必要があるため、for
loop を使用して 20 回反復し、ランダムな値をデザインに適用します。
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