For-Schleifen in Verilog meistern: Wiederverwendbare Hardware-Logik erstellen
Eine for-Schleife ist die am häufigsten verwendete Schleife in der Software, wird in Verilog jedoch primär dazu verwendet, Hardware-Logik zu replizieren. Die Idee hinter einer for-Schleife ist es, eine Reihe von Anweisungen innerhalb der Schleife so lange zu iterieren, wie die gegebene Bedingung wahr ist. Dies ist der while-Schleife sehr ähnlich, wird aber häufiger in Kontexten verwendet, in denen ein Iterator verfügbar ist und die Bedingung vom Wert dieses Iterators abhängt.
Syntax
for (<initial_condition>; <condition>; <step_assignment>) begin
// Statements
end
Das Schlüsselwort for spezifiziert diesen Schleifentyp und hat drei Teile:
- Anfangsbedingung zur Spezifikation der Initialwerte von Signalen
- Eine Prüfung, ob die gegebene Bedingung wahr ist
- Aktualisierung der Steuerungsvariable für die nächste Iteration
Die Anfangsbedingung und Aktualisierungen der Steuerungsvariable sind in der for-Schleife enthalten und müssen nicht separat spezifiziert werden, im Gegensatz zur while-Schleife. Eine while-Schleife ist allgemeiner und wird meist nur verwendet, wenn die gegebenen Anweisungen so lange wiederholt werden sollen, wie eine gegebene Bedingung gilt. Die for-Schleife hat typischerweise einen definierten Anfang und ein definiertes Ende, das durch die Schrittvariable gesteuert wird.
Hier ist ein einfaches Beispiel, das die Verwendung einer for-Schleife veranschaulicht.
module my_design;
integer i;
initial begin
// Beachten Sie, dass der ++-Operator in Verilog NICHT existiert!
for (i = 0; i < 10; i = i + 1) begin
$display ("Current loop#%0d ", i);
end
end
endmodule
Simulationslog:
ncsim> run Current loop#0 Current loop#1 Current loop#2 Current loop#3 Current loop#4 Current loop#5 Current loop#6 Current loop#7 Current loop#8 Current loop#9 ncsim: *W,RNQUIE: Simulation is complete.
Design-Beispiel
Sehen wir uns an, wie ein 8-Bit-Links-Schieberegister in Verilog ohne eine for-Schleife implementiert werden kann und vergleichen es dann mit dem Code mit einer for-Schleife, um den Nutzen eines Schleifenkonstrukts zu würdigen.
module lshift_reg (
input clk, // Clock-Eingang
input rstn, // Aktiver Low-Reset
input [7:0] load_val, // Ladewert
input load_en, // Lade-Enable
output reg [7:0] op // Ausgangsregister-Wert
);
// Bei posedge von Clock: Wenn Reset low, Output auf 0 setzen
// Wenn Reset high, neuen Wert in op laden wenn load_en=1
// Wenn Reset high und load_en=0, Schieberegister nach links verschieben
always @ (posedge clk) begin
if (!rstn) begin
op <= 0;
end else begin
if (load_en) begin
op <= load_val;
end else begin
op[0] <= op[7];
op[1] <= op[0];
op[2] <= op[1];
op[3] <= op[2];
op[4] <= op[3];
op[5] <= op[4];
op[6] <= op[5];
op[7] <= op[6];
end
end
end
endmodule
Dasselbe Verhalten kann mit einer for-Schleife implementiert werden, was den Code reduziert und ihn für verschiedene Registerbreiten skalierbar macht. Wenn die Breite des Registers als Verilog-Parameter definiert wird, wird das Design-Modul skalierbar und derselbe Parameter kann innerhalb der for-Schleife verwendet werden.
module lshift_reg (
input clk,
input rstn,
input [7:0] load_val,
input load_en,
output reg [7:0] op
);
integer i;
always @ (posedge clk) begin
if (!rstn) begin
op <= 0;
end else begin
// Wenn load_en 1 ist, Wert in op laden
// sonst bei jedem Takt weiterschieben
if (load_en) begin
op <= load_val;
end else begin
for (i = 0; i < 8; i = i + 1) begin
op[i+1] <= op[i];
end
op[0] <= op[7];
end
end
end
endmodule
Testbench
Der Testbench-Code ist unten gezeigt und instanziiert das Design.
module tb;
reg clk;
reg rstn;
reg [7:0] load_val;
reg load_en;
wire [7:0] op;
// DUT Clock einrichten
always #10 clk = ~clk;
// Design instanziieren
lshift_reg u0 (
.clk(clk),
.rstn(rstn),
.load_val(load_val),
.load_en(load_en),
.op(op)
);
initial begin
// 1. Testbench-Variablen initialisieren
clk <= 0;
rstn <= 0;
load_val <= 8'h01;
load_en <= 0;
// 2. Reset auf Design anwenden
repeat (2) @ (posedge clk);
rstn <= 1;
repeat (5) @ (posedge clk);
// 3. load_en für 1 Takt setzen, damit load_val geladen wird
load_en <= 1;
repeat(1) @ (posedge clk);
load_en <= 0;
// 4. Design 20 Takte laufen lassen und dann beenden
repeat (20) @ (posedge clk);
$finish;
end
endmodule
Verilog
- Verilog Grundlagen: Ihr erstes AND-Gate designen
- C# For-Schleifen meistern: Syntax, Ablauf und praktische Beispiele
- C# foreach Schleifen: Arrays und Collections einfach durchlaufen
- Java-Programm zur Identifikation von Armstrong-Zahlen mit For-Schleife
- Verilog meistern: Komplettes Tutorial für digitales Schaltungsdesign
- Verilog Concatenation meistern: Praktischer Leitfaden
- Verilog Assignments verstehen: Typen, Syntax und Best Practices
- Verilog Blocking vs. Non-Blocking: Wichtige Unterschiede erklärt
- Verilog Functions meistern für effizientes RTL-Design
- Verilog Tasks verstehen: Functions vs. Tasks, Syntax und Verwendung