Verilog always-blokken begrijpen: Syntaxis & gevoeligheidslijsten
Een always blok is een van de procedurale blokken in Verilog. Statements binnen een always-blok worden sequentieel uitgevoerd.
Syntaxis
always @ (gebeurtenis) [statement]
always @ (gebeurtenis) begin [meerdere statements] endWat is de gevoeligheidslijst?
Een gevoeligheidslijst is de expressie die definieert wanneer het always-blok uitgevoerd moet worden en wordt gespecificeerd na de @ operator binnen haakjes ( ). Deze lijst kan één of een groep signalen bevatten wiens waardeverandering het always-blok triggert.
In de onderstaande code worden alle statements binnen het always blok uitgevoerd wanneer de waarde van signalen a of b verandert.
// Voer always-blok uit wanneer waarde van "a" of "b" verandert
always @ (a or b) begin [statements] endWaarvoor wordt het always-blok gebruikt?
Een always blok kan gebruikt worden om combinatorische of sequentiële elementen te realiseren. Een sequentieel element als flipflop wordt actief wanneer het een klok en reset krijgt. Een combinatorisch blok wordt actief wanneer een van zijn invoerwaarden verandert. Deze hardware-blokken werken allemaal concurrent, onafhankelijk van elkaar. De verbinding tussen elk bepaalt de dataflow. Om dit gedrag te modelleren, wordt een always blok gemaakt als een continu proces dat getriggerd wordt en een actie uitvoert wanneer een signaal in de gevoeligheidslijst actief wordt.
In het volgende voorbeeld worden alle statements binnen het always-blok uitgevoerd bij elke positieve flank van het signaal clk.
// Voer always-blok uit op positieve flank van signaal "clk"
always @ (posedge clk) begin [statements] endWat gebeurt er als er geen gevoeligheidslijst is?
Het always blok herhaalt zich continu gedurende de duur van een simulatie. De gevoeligheidslijst brengt een zekere timing-mechanisme: wanneer elk signaal in de lijst verandert, wordt het always-blok getriggerd. Als er geen timing-control statements binnen een always-blok zijn, zal de simulatie hangen vanwege een zero-delay oneindige lus!
Voorbeeld
Het onderstaande voorbeeld is een always-blok dat probeert de waarde van signaal clk te inverteren. Het statement wordt na elke 0 tijdseenheden uitgevoerd. Daarom voert het zich oneindig uit door de afwezigheid van een vertraging.
// always-blok start op tijd 0
// Maar wanneer moet het herhaald worden?
// Er is geen tijdscontrole, dus het blijft en herhaalt zich op 0 tijdseenheden. Dit loopt in een lus en simulatie hangt!
always clk = ~clk;Zelfs als de gevoeligheidslijst leeg is, moet er een andere vorm van tijdsvertraging zijn. Simulatietijd wordt voortgeschreven door een vertragingsstatement binnen het always construct zoals hieronder. Nu wordt de klokinversie elke 10 tijdseenheden gedaan.
always #10 clk = ~clk;Let op: Expliciete vertragingen zijn niet synthetiseerbaar naar logische gates!
Daarom vereist echte Verilog-ontwerpcode altijd een gevoeligheidslijst.
Sequentieel element ontwerpvoorbeeld
De onderstaande code definieert een module tff die een datainvoer, klok en active-low reset accepteert. De uitvoer wordt geïnverteerd wanneer d 1 is op de positieve flank van de klok. Hier wordt het always blok getriggerd op de positieve flank van clk of de negatieve flank van rstn.
Wat gebeurt er op de positieve flank van de klok?
De volgende gebeurtenissen gebeuren op de positieve flank van de klok en herhalen zich voor alle positieve flanken.
- Eerste
ifblok controleert waarde van active-low resetrstn - Als
rstnnul is, moet uitvoerqgereset worden naar standaardwaarde 0 - Als
rstnéén is, is reset niet toegepast en volgt standaardgedrag - Als vorige stap false is:
- Controleer waarde van
den als het 1 is, inverter waarde vanq - Als
d0 is, behoud waarde vanq
module tff (input d, clk, rstn, output reg q);
always @ (posedge clk or negedge rstn) begin
if (!rstn) q <= 0;
else if (d) q <= ~q;
else q <= q;
end
endmoduleWat gebeurt er op de negatieve flank van reset?
De volgende gebeurtenissen gebeuren op de negatieve flank van rstn en bij al dergelijke gevallen.
- Eerste
ifblok controleert waarde van active-low resetrstn. Op de negatieve flank is de waarde 0. - Als waarde van
rstn0 is, betekent dat reset toegepast is en uitvoer gereset naar 0 - Het geval waar waarde 1 is, wordt niet overwogen omdat de huidige gebeurtenis negatieve flank van
rstnis
Combinatorisch element ontwerpvoorbeeld
Een always blok kan ook gebruikt worden voor combinatorische blokken. Het volgende digitale circuit vertegenwoordigt een combinatie van drie logische gates die een bepaalde uitvoer leveren aan signaal o.
De onderstaande code is een module met vier invoerpoorten en een enkele uitvoerpoort o. Het always blok wordt getriggerd wanneer een van de signalen in de gevoeligheidslijst van waarde verandert. Uitvoersignaal wordt als type reg gedeclareerd in de module-poortlijst omdat het in een proceduraal blok gebruikt wordt. Alle signalen in een proceduraal blok moeten als type reg gedeclareerd zijn.
module combo ( input a, input b, input c, input d, output reg o);
always @ (a or b or c or d) begin
o <= ~((a & b) | (c^d));
end
endmoduleZie dat signaal o 1 wordt wanneer de combinatorische expressie aan de RHS waar wordt. o wordt 0 wanneer RHS false is.
Klik hier voor een slideshow met simulatiefbeeld!
Verilog
- Verilog beheersen: Complete tutorial voor digitale schakelingontwerp
- Verilog concatenatie beheersen: Een praktische gids
- Verilog Essentials: Een beknopt overzicht
- Verilog-toewijzingen begrijpen: types, syntax en best practices
- Verilog Blocking vs. Non-Blocking: belangrijkste verschillen uitgelegd
- Verilog-functies beheersen voor efficiënt RTL-ontwerp
- Verilog Tasks begrijpen: Functions vs Tasks, Syntax en Gebruik
- Verilog Clock Generator: Ontwerp & Implementatie Gids
- Verilog Math Functions beheersen voor efficiënt Hardware-ontwerp
- Verilog $timeformat beheersen: Precisie en Weergave-controle
- Verilog Timescales begrijpen en printen in elke Scope