Verilog 遅延制御
Verilog には 2 種類のタイミング制御があります - delay そしてイベント 式。 遅延 制御は、シミュレーターがステートメントを検出してから実際に実行するまでの間に遅延を追加する方法にすぎません。 イベント式 ネットまたは変数の値の変更などのシミュレーション イベントが発生するまで、ステートメントを遅延させることができます (暗黙的なイベント ) または別の手順でトリガーされる明示的に名前が付けられたイベント。
シミュレーション時間は、次のいずれかの方法で進めることができます。
内部遅延を持つようにモデル化されたゲートとネットも、シミュレーション時間を進めます。
遅延制御
遅延式が不明または高インピーダンス値に評価される場合、ゼロ遅延として解釈されます。負の値に評価される場合、時間変数と同じサイズの 2 の補数の符号なし整数として解釈されます。
`timescale 1ns/1ps
module tb;
reg [3:0] a, b;
initial begin
{a, b} <= 0;
$display ("T=%0t a=%0d b=%0d", $realtime, a, b);
#10;
a <= $random;
$display ("T=%0t a=%0d b=%0d", $realtime, a, b);
#10 b <= $random;
$display ("T=%0t a=%0d b=%0d", $realtime, a, b);
#(a) $display ("T=%0t After a delay of a=%0d units", $realtime, a);
#(a+b) $display ("T=%0t After a delay of a=%0d + b=%0d = %0d units", $realtime, a, b, a+b);
#((a+b)*10ps) $display ("T=%0t After a delay of %0d * 10ps", $realtime, a+b);
#(b-a) $display ("T=%0t Expr evaluates to a negative delay", $realtime);
#('h10) $display ("T=%0t Delay in hex", $realtime);
a = 'hX;
#(a) $display ("T=%0t Delay is unknown, taken as zero a=%h", $realtime, a);
a = 'hZ;
#(a) $display ("T=%0t Delay is in high impedance, taken as zero a=%h", $realtime, a);
#1ps $display ("T=%0t Delay of 10ps", $realtime);
end
endmodule
タイムスケールの精度は 1ps 単位であるため、$realtime
であることに注意してください。 遅延式 (a+b)*10ps を使用してステートメントの精度値を表示する必要があります。
xcelium> run T=0 a=x b=x T=10000 a=0 b=0 T=20000 a=4 b=0 T=24000 After a delay of a=4 units T=29000 After a delay of a=4 + b=1 = 5 units T=29050 After a delay of 5 * 10ps T=42050 Expr evaluates to a negative delay T=58050 Delay in hex T=58050 Delay is unknown, taken as zero a=x T=58050 Delay is in high impedance, taken as zero a=z T=58051 Delay of 10ps xmsim: *W,RNQUIE: Simulation is complete.
イベント コントロール
ネットと変数の値の変更は、他の手続き型ステートメントの実行をトリガーする同期イベントとして使用でき、暗黙的 イベント。イベントは、0 に向かって negedge
になるような変化の方向に基づくこともできます。 1 に向かって変更すると、posedge
になります。 .
- A
negedge
1 から X、Z または 0 へ、および X または Z から 0 への遷移がある場合 - A
posedge
0 から X、Z または 1 へ、および X または Z から 1 への遷移がある場合
同じ状態から同じ状態への遷移は、エッジとは見なされません。 posedge や negedge などのエッジ イベントは、ベクトル信号または変数の LSB でのみ検出できます。式が同じ結果に評価される場合、それはイベントとは見なされません。
module tb;
reg a, b;
initial begin
a <= 0;
#10 a <= 1;
#10 b <= 1;
#10 a <= 0;
#15 a <= 1;
end
// Start another procedural block that waits for an update to
// signals made in the above procedural block
initial begin
@(posedge a);
$display ("T=%0t Posedge of a detected for 0->1", $time);
@(posedge b);
$display ("T=%0t Posedge of b detected for X->1", $time);
end
initial begin
@(posedge (a + b)) $display ("T=%0t Posedge of a+b", $time);
@(a) $display ("T=%0t Change in a found", $time);
end
endmodule
シミュレーションログ ncsim> run T=10 Posedge of a detected for 0->1 T=20 Posedge of b detected for X->1 T=30 Posedge of a+b T=45 Change in a found ncsim: *W,RNQUIE: Simulation is complete.
名前付きイベント
キーワード event
名前付きを宣言するために使用できます 明示的にトリガーできるイベント。 event
データを保持できず、期間がなく、特定の時間に発生させることができます。名前付きイベントは ->
によってトリガーされます 演算子は、名前付きイベント ハンドルの前にプレフィックスとして付けます。 @
を使用して、名前付きイベントを待機できます。
module tb;
event a_event;
event b_event[5];
initial begin
#20 -> a_event;
#30;
->a_event;
#50 ->a_event;
#10 ->b_event[3];
end
always @ (a_event) $display ("T=%0t [always] a_event is triggered", $time);
initial begin
#25;
@(a_event) $display ("T=%0t [initial] a_event is triggered", $time);
#10 @(b_event[3]) $display ("T=%0t [initial] b_event is triggered", $time);
end
endmodule
名前付きイベントを使用して、同時に実行されている 2 つ以上のプロセスを同期できます。たとえば、always
ブロックと 2 番目の initial
ブロックは a_event によって同期されます。イベントは、サイズ 5 の配列である b_event の場合のように配列として宣言でき、インデックス 3 はトリガーと待機の目的で使用されます。
ncsim> run T=20 [always] a_event is triggered T=50 [always] a_event is triggered T=50 [initial] a_event is triggered T=100 [always] a_event is triggered T=110 [initial] b_event is triggered ncsim: *W,RNQUIE: Simulation is complete.
イベントまたは演算子
or
演算子を使用して、リストされたイベントのいずれかが式でトリガーされるまで待機できます。コンマ ,
or
の代わりに使用することもできます
module tb;
reg a, b;
initial begin
$monitor ("T=%0t a=%0d b=%0d", $time, a, b);
{a, b} <= 0;
#10 a <= 1;
#5 b <= 1;
#5 b <= 0;
end
// Use "or" between events
always @ (posedge a or posedge b)
$display ("T=%0t posedge of a or b found", $time);
// Use a comma between
always @ (posedge a, negedge b)
$display ("T=%0t posedge of a or negedge of b found", $time);
always @ (a, b)
$display ("T=%0t Any change on a or b", $time);
endmodule
シミュレーションログ ncsim> run T=0 posedge of a or negedge of b found T=0 Any change on a or b T=0 a=0 b=0 T=10 posedge of a or b found T=10 posedge of a or negedge of b found T=10 Any change on a or b T=10 a=1 b=0 T=15 posedge of a or b found T=15 Any change on a or b T=15 a=1 b=1 T=20 posedge of a or negedge of b found T=20 Any change on a or b T=20 a=1 b=0 ncsim: *W,RNQUIE: Simulation is complete.
暗黙のイベント式リスト
センシティビティ リストまたはイベント式リストは、多くの場合、RTL の多くの機能エラーの一般的な原因です。これは、プロシージャル ブロックに新しいシグナルを導入した後、ユーザーがセンシティビティ リストを更新するのを忘れる可能性があるためです。
module tb;
reg a, b, c, d;
reg x, y;
// Event expr/sensitivity list is formed by all the
// signals inside () after @ operator and in this case
// it is a, b, c or d
always @ (a, b, c, d) begin
x = a | b;
y = c ^ d;
end
initial begin
$monitor ("T=%0t a=%0b b=%0b c=%0b d=%0b x=%0b y=%0b", $time, a, b, c, d, x, y);
{a, b, c, d} <= 0;
#10 {a, b, c, d} <= $random;
#10 {a, b, c, d} <= $random;
#10 {a, b, c, d} <= $random;
end
endmodule
シミュレーションログ ncsim> run T=0 a=0 b=0 c=0 d=0 x=0 y=0 T=10 a=0 b=1 c=0 d=0 x=1 y=0 T=20 a=0 b=0 c=0 d=1 x=0 y=1 T=30 a=1 b=0 c=0 d=1 x=1 y=1 ncsim: *W,RNQUIE: Simulation is complete.
ユーザーが新しいシグナル e を追加し、逆を z にキャプチャすることを決定した場合、e もセンシティビティ リストに追加するように特別な注意を払う必要があります。
module tb;
reg a, b, c, d, e;
reg x, y, z;
// Add "e" also into sensitivity list
always @ (a, b, c, d, e) begin
x = a | b;
y = c ^ d;
z = ~e;
end
initial begin
$monitor ("T=%0t a=%0b b=%0b c=%0b d=%0b e=%0b x=%0b y=%0b z=%0b",
$time, a, b, c, d, e, x, y, z);
{a, b, c, d, e} <= 0;
#10 {a, b, c, d, e} <= $random;
#10 {a, b, c, d, e} <= $random;
#10 {a, b, c, d, e} <= $random;
end
endmodule
シミュレーションログ ncsim> run T=0 a=0 b=0 c=0 d=0 e=0 x=0 y=0 z=1 T=10 a=0 b=0 c=1 d=0 e=0 x=0 y=1 z=1 T=20 a=0 b=0 c=0 d=0 e=1 x=0 y=0 z=0 T=30 a=0 b=1 c=0 d=0 e=1 x=1 y=0 z=0 ncsim: *W,RNQUIE: Simulation is complete.
Verilog では、機密リストを *
に置き換えることができるようになりました これは、以下に示すように、statemnt によって読み取られるすべてのネットと変数を追加することで、これらの問題を解消する便利な省略形です。
module tb;
reg a, b, c, d, e;
reg x, y, z;
// Use @* or @(*)
always @ * begin
x = a | b;
y = c ^ d;
z = ~e;
end
initial begin
$monitor ("T=%0t a=%0b b=%0b c=%0b d=%0b e=%0b x=%0b y=%0b z=%0b",
$time, a, b, c, d, e, x, y, z);
{a, b, c, d, e} <= 0;
#10 {a, b, c, d, e} <= $random;
#10 {a, b, c, d, e} <= $random;
#10 {a, b, c, d, e} <= $random;
end
endmodule
シミュレーションログ ncsim> run T=0 a=0 b=0 c=0 d=0 e=0 x=0 y=0 z=1 T=10 a=0 b=0 c=1 d=0 e=0 x=0 y=1 z=1 T=20 a=0 b=0 c=0 d=0 e=1 x=0 y=0 z=0 T=30 a=0 b=1 c=0 d=0 e=1 x=1 y=0 z=0 ncsim: *W,RNQUIE: Simulation is complete.
レベル センシティブ イベント コントロール
手続き型ステートメントの実行は、条件が真になるまで遅らせることもでき、wait
で達成できます。 キーワードであり、レベルに依存するコントロールです。
待機ステートメントは条件を評価し、それが偽の場合、条件が真になるまで後続の手続きステートメントはブロックされたままになります。
module tb;
reg [3:0] ctr;
reg clk;
initial begin
{ctr, clk} <= 0;
wait (ctr);
$display ("T=%0t Counter reached non-zero value 0x%0h", $time, ctr);
wait (ctr == 4) $display ("T=%0t Counter reached 0x%0h", $time, ctr);
$finish;
end
always #10 clk = ~clk;
always @ (posedge clk)
ctr <= ctr + 1;
endmodule
シミュレーションログ ncsim> run T=10 Counter reached non-zero value 0x1 T=70 Counter reached 0x4 T=90 Counter reached 0x5 T=170 Counter reached 0x9 Simulation complete via $finish(1) at time 170 NS + 1
Verilog