Industriële fabricage
Industrieel internet der dingen | Industriële materialen | Onderhoud en reparatie van apparatuur | Industriële programmering |
home  MfgRobots >> Industriële fabricage >  >> Industrial programming >> Verilog

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 negedge is wanneer er een overgang is van 1 naar X, Z of 0 en van X of Z naar 0
  • Een posedge is 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

  1. Verilog beheersen: Complete tutorial voor digitale schakelingontwerp
  2. Verilog concatenatie beheersen: Een praktische gids
  3. Verilog-toewijzingen begrijpen: types, syntax en best practices
  4. Verilog Blocking vs. Non-Blocking: belangrijkste verschillen uitgelegd
  5. Verilog controlestroom beheersen: IF-ELSE, Case, en meer
  6. Verilog-functies beheersen voor efficiënt RTL-ontwerp
  7. Verilog Tasks begrijpen: Functions vs Tasks, Syntax en Gebruik
  8. Inter- en Intra-Assignment Delays in Verilog begrijpen
  9. Gate Delays in Verilog begrijpen: Accurate timing voor betrouwbare digitale ontwerpen
  10. Verilog Clock Generator: Ontwerp & Implementatie Gids
  11. Verilog Math Functions beheersen voor efficiënt Hardware-ontwerp