Sequentiële logica implementeren met Verilog 'always' blokken
Een vorig artikel toonde voorbeelden van always blokken voor combinatorische logica. Een always blok wordt ook hoofdzakelijk gebruikt voor sequentiële logica met geheugenelementen zoals flipflops die waarden kunnen vasthouden.
JK Flipflop
Een JK-flipflop is een van de veelvoorkomende floptypes om waarden op te slaan en heeft twee datainvoeren j en k, plus een voor reset rstn en een voor klok clk. De waarheidstabel voor een JK-flop is hieronder en wordt typisch geïmplementeerd met NAND-gates.
| rstn | j | k | q | Opmerkingen |
|---|---|---|---|---|
| 0 | 0 | 0 | 0 | Bij geactiveerde reset is uitvoer altijd nul |
| 1 | 0 | 0 | Houd waarde | Bij j=0,k=0 blijft uitvoer hetzelfde |
| 1 | 0 | 1 | 1 | Bij k=1 wordt uitvoer 1 |
| 1 | 1 | 0 | 0 | Bij k=0 wordt uitvoer 0 |
| 1 | 1 | 1 | Toggle waarde | Bij j=1,k=1 toggelt uitvoer huidige waarde |
De behaviorale Verilog-code voor een JK-flipflop:
module jk_ff ( input j, input k, input rstn, input clk, output reg q);
always @ (posedge clk or negedge rstn) begin
if (!rstn) begin q <= 0; end
else begin q <= (j & ~q) | (~k & q); end
end
endmoduleTestbench
Eerst alle testbench-variabelen declareren en een klok starten met een simpel always blok. Vervolgens het ontwerp instantiëren en poorten verbinden met testbench-variabelen. Let op: q is type wire omdat het verbonden is met een uitvoer van het ontwerp die actief zal drijven. Alle andere invoeren zijn reg zodat ze in een proceduraal blok als initial gedreven kunnen worden.
j en k op willekeurige tijden. Na de lus wachten en simulatie beëindigen.module tb;
reg j, k, rstn, clk; wire q; integer i; reg [2:0] dly;
always #10 clk = ~clk;
jk_ff u0 ( .j(j), .k(k), .clk(clk), .rstn(rstn), .q(q));
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 = $random; #(dly) k <= $random;
end
#20 $finish;
end
endmoduleUit de simulatiegolf is te zien dat op de positieve flank van de klok, uitvoer q waarde verandert op basis van de toestand van invoeren j en k zoals in de waarheidstabel.
Modulo-10 teller
Modulus (MOD) tellers tellen tot een bepaald getal voordat ze terugrollen naar nul. Een MOD-N teller telt van 0 tot N-1 en rol dan terug naar nul. Dergelijke tellers vereisen typisch log2N flipflops om de telwaarde vast te houden. Hieronder de Verilog-code voor een MOD-10 teller die optelt bij elke klok clk zolang reset rstn gedeactiveerd is.
Verilog-parameters kunnen gebruikt worden om een MOD-N teller te maken die schaalbaarder is.
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
endmoduleTestbench
De testbench declareert variabelen, instantiateert de teller-module en verbindt met testbench-signalen. Omdat de teller een klok nodig heeft, wordt de testbench-klok gemodelleerd met een always blok. De stimuli stelt standaardwaarden in op 0ns, deactiveert reset na 10ns en laat het ontwerp draaien.
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
endmoduleDe teller telt van nul tot 9, rolt over naar nul en begint opnieuw te tellen.
4-bit Links Schuifregister
Hieronder een 4-bit linksschuifregister dat een invoer d in de LSB accepteert en alle andere bits 1 positie naar links schuift. Als d nul is en de initiële waarde van het register 0011 is, wordt het 0110 op de volgende klokflank.
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
endmoduleTestbench
De testbench volgt een vergelijkbaar sjabloon: variabelen declareren, module instantiëren, klok starten, stimuli drijven. In dit voorbeeld moeten verschillende waarden van d getest worden, dus een for lus herhaalt 20 keer en past willekeurige waarden toe.
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
endmoduleElk bit verschuift 1 positie naar links en de nieuwe waarde van d wordt op de LSB toegepast.
Verilog
- Circuit met een schakelaar: Praktische gids voor basis elektrische circuits
- Geïntegreerde Schakelingen: Fundamenten van Digitale Logische Poorten
- Programmeerbare Logische Controllers (PLC's): Moderne Digitale Besturing voor Industriële Systemen
- Booleaanse Algebra Begrijpen: Van Logica Fundamenten tot Digitale Schakelingen
- Logica Vereenvoudiging Beheersen met Karnaugh-kaarten
- Digitale Logica met Terugkoppeling: Van Deterministische Poorten tot Multivibrators
- Perfecte afwerkingen behalen met Okamoto's precisieslijpmachines
- VHDL & Verilog Meesteren: Schone Combinatoire en Sequentiele Logica Schrijven
- Verilog Mod-N Teller Ontwerp: Geparametriseerde Module & Testbench
- Verilog Gray-code Teller Module – 4-bit Gray Code Generator
- Volledig CMOS‑Compatibele 4T2R nv‑SRAM met STI‑RRAM en Self‑Inhibit Load – Nul Statische Vermogen en Hoge Snelheid