Verilog Delay Control begrijpen: Timing-technieken en best practices
Er zijn twee typen timing-controls in Verilog: delay en event expressies. De delay-control is een manier om een vertraging toe te voegen tussen het moment dat de simulator de statement tegenkomt en wanneer deze daadwerkelijk uitgevoerd wordt. De event-expressie stelt het statement uit tot de voorkoming van een simulatie-event, wat een waardeverandering op een net of variabele kan zijn (impliciet event) of een expliciet benoemd event dat in een andere procedure getriggerd wordt.
Simulatiettijd kan op een van de volgende manieren vooruitgeschoven worden.
Gates en nets die gemodelleerd zijn met interne vertragingen schuiven de simulatiettijd ook vooruit.
Delay Control
Als de delay-expressie evalueert naar een onbekende of high-impedance waarde, wordt het geïnterpreteerd als nul-vertraging. Als het evalueert naar een negatieve waarde, wordt het geïnterpreteerd als een 2's complement unsigned integer van dezelfde grootte als een time-variabele.
`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 Na een vertraging van a=%0d eenheden", $realtime, a);
#(a+b) $display ("T=%0t Na een vertraging van a=%0d + b=%0d = %0d eenheden", $realtime, a, b, a+b);
#((a+b)*10ps) $display ("T=%0t Na een vertraging van %0d * 10ps", $realtime, a+b);
#(b-a) $display ("T=%0t Expr evalueert naar een negatieve vertraging", $realtime);
#('h10) $display ("T=%0t Vertraging in hex", $realtime);
a = 'hX; #(a) $display ("T=%0t Vertraging is onbekend, genomen als nul a=%h", $realtime, a);
a = 'hZ; #(a) $display ("T=%0t Vertraging is high impedance, genomen als nul a=%h", $realtime, a);
#1ps $display ("T=%0t Vertraging van 10ps", $realtime);
end
endmodule
Let op dat de precisie van timescale in 1ps is en dus $realtime vereist is om de precisiewaarde weer te geven voor de statement met de delay-expressie (a+b)*10ps.
Simulatie-log
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.
Event Control
Waardeveranderingen op nets en variabelen kunnen gebruikt worden als synchronisatie-event om uitvoering van andere procedurale statements te triggeren en is een impliciet event. Het event kan ook gebaseerd zijn op de richting van verandering zoals naar 0 wat het een negedge maakt en een verandering naar 1 maakt het een posedge.
- Een
negedgeis wanneer er een overgang is van 1 naar X, Z of 0 en van X of Z naar 0 - Een
posedgeis wanneer er een overgang is van 0 naar X, Z of 1 en van X of Z naar 1
Een overgang van dezelfde staat naar dezelfde staat wordt niet als een edge beschouwd. Een edge-event zoals posedge of negedge kan alleen gedetecteerd worden op de LSB van een vector-signaal of variabele. Als een expressie evalueert naar hetzelfde resultaat, kan het niet als een event beschouwd worden.
module tb;
reg a, b;
initial begin
a <= 0;
#10 a <= 1;
#10 b <= 1;
#10 a <= 0;
#15 a <= 1;
end
// Start een ander proceduraal blok dat wacht op een update van
// signalen gemaakt in het bovenstaande proceduraal blok
initial begin
@(posedge a); $display ("T=%0t Posedge van a gedetecteerd voor 0->1", $time);
@(posedge b); $display ("T=%0t Posedge van b gedetecteerd voor X->1", $time);
end
initial begin
@(posedge (a + b)) $display ("T=%0t Posedge van a+b", $time);
@(a) $display ("T=%0t Verandering in a gevonden", $time);
end
endmodule
Simulatie-log
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.
Benoemde Events
Het trefwoord event kan gebruikt worden om een benoemd event te declareren dat expliciet getriggerd kan worden. Een event kan geen data vasthouden, heeft geen tijdsduur en kan op elk bepaald moment plaatsvinden. Een benoemd event wordt getriggerd door de -> operator door het voor het benoemde event-handle te prefixen. Een benoemd event kan gewacht worden met de @ operator zoals hierboven beschreven.
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 getriggerd", $time);
initial begin
#25; @(a_event) $display ("T=%0t [initial] a_event is getriggerd", $time);
#10 @(b_event[3]) $display ("T=%0t [initial] b_event is getriggerd", $time);
end
endmodule
Benoemde events kunnen gebruikt worden om twee of meer gelijktijdig draaiende processen te synchroniseren. Bijvoorbeeld, het always-blok en het tweede initial-blok worden gesynchroniseerd door a_event. Events kunnen als arrays gedeclareerd worden zoals in het geval van b_event wat een array van grootte 5 is en index 3 gebruikt voor trigger en wacht-doeleinden.
Simulatie-log
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.
Event or-operator
De or operator kan gebruikt worden om te wachten tot een van de genoemde events getriggerd wordt in een expressie. De komma , kan ook gebruikt worden in plaats van de or operator.
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
// Gebruik "or" tussen events
always @ (posedge a or posedge b) $display ("T=%0t posedge van a of b gevonden", $time);
// Gebruik een komma tussen
always @ (posedge a, negedge b) $display ("T=%0t posedge van a of negedge van b gevonden", $time);
always @ (a, b) $display ("T=%0t Elke verandering op a of b", $time);
endmodule
Simulatie-log
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.
Impliciete Event Expressie Lijst
De gevoeligheidslijst of de event-expressielijst is vaak een veelvoorkomende oorzaak van functionele fouten in de RTL. Dit komt omdat de gebruiker kan vergeten de gevoeligheidslijst bij te werken na het introduceren van een nieuw signaal in het proceduraal blok.
module tb;
reg a, b, c, d;
reg x, y;
// Event expr/gevoeligheidslijst wordt gevormd door alle
// signalen binnen () na @ operator en in dit geval
// is het a, b, c of 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
Simulatie-log
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.
Als de gebruiker besluit een nieuw signaal e toe te voegen en de inverse in z vast te leggen, moet speciale zorg besteed worden om e ook toe te voegen aan de gevoeligheidslijst.
module tb;
reg a, b, c, d, e;
reg x, y, z;
// Voeg "e" ook toe aan gevoeligheidslijst
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
Simulatie-log
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 stelt nu toe de gevoeligheidslijst te vervangen door * wat een handige afkorting is die deze problemen elimineert door alle nets en variabelen die gelezen worden door het statement toe te voegen zoals hieronder getoond.
module tb;
reg a, b, c, d, e;
reg x, y, z;
// Gebruik @* of @(*)
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
Simulatie-log
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.
Level-Sensitive Event Control
Uitvoering van een proceduraal statement kan ook uitgesteld worden tot een conditie true wordt en kan bereikt worden met het wait-trefwoord en is een level-sensitive control.
De wait-statement evalueert een conditie en als deze false is, blijven de proceduraal statements die erop volgen geblokkeerd tot de conditie true wordt.
module tb;
reg [3:0] ctr;
reg clk;
initial begin
{ctr, clk} <= 0;
wait (ctr);
$display ("T=%0t Teller bereikte niet-nul waarde 0x%0h", $time, ctr);
wait (ctr == 4) $display ("T=%0t Teller bereikte 0x%0h", $time, ctr);
$finish;
end
always #10 clk = ~clk;
always @ (posedge clk) ctr <= ctr + 1;
endmodule
Simulatie-log
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
- Verilog beheersen: Complete tutorial voor digitale schakelingontwerp
- Verilog concatenatie beheersen: Een praktische gids
- Verilog-toewijzingen begrijpen: types, syntax en best practices
- Verilog Blocking vs. Non-Blocking: belangrijkste verschillen uitgelegd
- Verilog controlestroom beheersen: IF-ELSE, Case, en meer
- Verilog-functies beheersen voor efficiënt RTL-ontwerp
- Verilog Tasks begrijpen: Functions vs Tasks, Syntax en Gebruik
- Inter- en Intra-Assignment Delays in Verilog begrijpen
- Gate Delays in Verilog begrijpen: Accurate timing voor betrouwbare digitale ontwerpen
- Verilog Clock Generator: Ontwerp & Implementatie Gids
- Verilog Math Functions beheersen voor efficiënt Hardware-ontwerp