verilog Tutorial
Erste Schritte mit Verilog
Suche…
Bemerkungen
Verilog ist eine Hardwarebeschreibungssprache (HDL), mit der digitale Schaltkreise auf Verhaltens- oder Registerübertragungsniveau entworfen, simuliert und überprüft werden können. Es ist bemerkenswert, aus Gründen, die es von "traditionellen" Programmiersprachen unterscheiden:
- Es gibt zwei Arten von Zuweisungen, das Blockieren und das Nicht-Blockieren, und jede hat ihre eigene Verwendung und Semantik.
- Variablen müssen entweder als Einzelbitbreite oder mit einer expliziten Breite deklariert werden.
- Designs sind hierarchisch, mit der Möglichkeit, Module mit einem gewünschten Verhalten zu instanziieren.
- In der Simulation (nicht typischerweise in Synthese),
wire
Variablen in einem von vier Zuständen sein kann: 0, 1, schwimmenden (z
) und spezifiziert (x
).
Versionen
Ausführung | Veröffentlichungsdatum |
---|---|
Verilog IEEE-1364-1995 | 1995-01-01 |
Verilog IEEE-1364-2001 | 2001-09-28 |
Verilog IEEE-1364.1-2002 | 2002-12-18 |
Verilog IEEE-1364-2005 | 2006-04-07 |
SystemVerilog IEEE-1800-2009 | 2009-12-11 |
SystemVerilog IEEE-1800-2012 | 2013-02-21 |
Installation oder Setup
Detaillierte Anweisungen zum Einrichten oder Installieren von Verilog hängen von dem von Ihnen verwendeten Tool ab, da es viele Verilog-Tools gibt.
Einführung
Verilog ist eine Hardwarebeschreibungssprache (HDL), mit der elektronische Systeme modelliert werden. Am häufigsten wird ein elektronisches System auf der Register-Transfer-Ebene (RTL) der Abstraktion beschrieben. Es wird auch bei der Verifizierung von analogen Schaltungen und Mixed-Signal-Schaltungen verwendet. Seine Struktur und Hauptprinzipien (wie unten beschrieben) sollen ein elektronisches System beschreiben und erfolgreich implementieren.
- Steifigkeit
Eine elektronische Schaltung ist eine physikalische Einheit mit fester Struktur, und Verilog ist dafür angepasst. Module (Modul), Ports (Eingang / Ausgang / Eingang), Verbindungen (Drähte), Blöcke (@always), Register (reg) sind alle zur Kompilierzeit festgelegt. Die Anzahl der Entitäten und Verbindungen ändert sich nicht dynamisch. Es gibt immer ein "Modul" auf der obersten Ebene, das die Chipstruktur (für die Synthese) darstellt, und eines auf Systemebene zur Verifizierung. - Parallelität
Die inhärenten gleichzeitigen Operationen im physischen Chip werden in der Sprache durch immer (die meisten Commmon), Anfangs- und Gabel / Join-Blöcke nachgebildet.
module top();
reg r1,r2,r3,r4; // 1-bit registers
initial
begin
r1 <= 0 ;
end
initial
begin
fork
r2 <= 0 ;
r3 <= 0 ;
join
end
always @(r4)
r4 <= 0 ;
endmodule
Alle obigen Anweisungen werden innerhalb derselben Zeiteinheit parallel ausgeführt.
Timing und Synchronisation
Verilog unterstützt verschiedene Konstrukte, um die zeitliche Natur von Schaltungen zu beschreiben. Timings und Verzögerungen in Schaltkreisen können in Verilog implementiert werden, zum Beispiel durch # Delay-Konstrukte. In ähnlicher Weise bietet Verilog auch synchrone und asynchrone Schaltungen und Komponenten wie Flops, Latches und kombinatorische Logik an, die verschiedene Konstrukte verwenden, beispielsweise "Always" -Blöcke. Ein Satz von Blöcken kann auch über ein gemeinsames Taktsignal synchronisiert werden oder ein Block kann basierend auf einem bestimmten Eingangssatz ausgelöst werden.#10 ; // delay for 10 time units always @(posedge clk ) // synchronous always @(sig1 or sig2 ) // combinatorial logic @(posedge event1) // wait for post edge transition of event1 wait (signal == 1) // wait for signal to be 1
Unsicherheit
Verilog unterstützt einige der mit elektronischen Schaltkreisen verbundenen Unsicherheiten. "X" wird verwendet, um den unbekannten Zustand der Schaltung darzustellen. "Z" wird verwendet, um den nicht angetriebenen Zustand der Schaltung darzustellen.reg1 = 1'bx; reg2 = 1'bz;
Abstraktion
Verilog unterstützt das Entwerfen auf verschiedenen Abstraktionsebenen. Die höchste Abstraktionsebene für ein Design ist die Resister Transfer Level (RTL), die nächste ist die Gate-Ebene und die niedrigste Zellebene (User Define Primitives), wobei die RTL-Abstraktion am häufigsten verwendet wird. Verilog unterstützt auch die Abstraktionsebene auf Verhaltensebene ohne Rücksicht auf die strukturelle Umsetzung des Entwurfs, die hauptsächlich zur Verifizierung verwendet wird.
// Example of a D flip flop at RTL abstraction
module dff (
clk , // Clock Input
reset , // Reset input
d , // Data Input
q // Q output
);
//-----------Input Ports---------------
input d, clk, reset ;
//-----------Output Ports---------------
output q;
reg q;
always @ ( posedge clk)
if (~reset) begin
q <= 1'b0;
end else begin
q <= d;
end
endmodule
// And gate model based at Gate level abstraction
module and(input x,input y,output o);
wire w;
// Two instantiations of the module NAND
nand U1(w,x, y);
nand U2(o, w, w);
endmodule
// Gate modeled at Cell-level Abstraction
primitive udp_and(
a, // declare three ports
b,
c
);
output a; // Outputs
input b,c; // Inputs
// UDP function code here
// A = B & C;
table
// B C : A
1 1 : 1;
0 1 : 0;
1 0 : 0;
0 0 : 0;
endtable
endprimitive
Es gibt drei Hauptanwendungsfälle für Verilog. Sie bestimmen die Struktur des Codes und seine Interpretation sowie die verwendeten Werkzeugsätze. Alle drei Anwendungen sind für die erfolgreiche Implementierung eines beliebigen Verilog-Designs erforderlich.
- Physikalisches Design / Backend
Hier wird Verilog verwendet, um den Entwurf primär als Matrix aus Gates zu betrachten, die logisches Design implementieren. RTL / Logik / Design durchläuft verschiedene Schritte von der Synthese -> Platzierung -> Taktbaumkonstruktion -> Routing -> DRC -> LVS -> bis zum Tapeout. Die genauen Schritte und Abläufe variieren je nach Art der Implementierung. - Simulation
In diesem Anwendungsfall besteht das Hauptziel darin, Testvektoren zur Validierung des Designs gemäß der Spezifikation zu generieren. Der in diesem Anwendungsfall geschriebene Code muss nicht synthetisierbar sein und bleibt im Verifikationsbereich. Der Code ähnelt eher generischen Softwarestrukturen wie for / while / do-Schleifen usw. - Design
Beim Design wird die Spezifikation einer Schaltung im Allgemeinen auf RTL-Abstraktionsebene implementiert. Der Verilog-Code wird dann zur Verifizierung und der vollständig verifizierte Code für die physische Implementierung angegeben. Der Code wird nur mit den synthetisierbaren Konstrukten von Verilog geschrieben. Bestimmte RTL-Codierungsstile können zu Simulationen und fehlangepassten Synthesen führen, und dies muss vermieden werden.
Es gibt zwei Hauptimplementierungsflüsse. Sie beeinflussen auch die Art und Weise, wie Verilog-Code geschrieben und implementiert wird. Bestimmte Codierungsstile und bestimmte Strukturen sind in einem Fluss besser geeignet als der andere.
- ASIC Flow (anwendungsspezifische integrierte Schaltung)
- FPGA Flow (Field-Programmable Gate Array) - umfasst FPGA und CPLDs
Hallo Welt
In diesem Beispiel wird der icarus verilog-Compiler verwendet.
Schritt 1: Erstellen Sie eine Datei mit dem Namen hello.v
module myModule();
initial
begin
$display("Hello World!"); // This will display a message
$finish ; // This causes the simulation to end. Without, it would go on..and on.
end
endmodule
Schritt 2. Wir kompilieren die .v-Datei mit icarus:
>iverilog -o hello.vvp hello.v
Die Option -o weist der Ausgabeobjektdatei einen Namen zu. Ohne diesen Schalter würde die Ausgabedatei a.out heißen. Hello.v gibt die zu kompilierende Quelldatei an. Wenn Sie diesen Quellcode kompilieren, sollte praktisch keine Ausgabe erfolgen, es sei denn, es sind Fehler aufgetreten.
Schritt 3. Sie können das Hello World Verilog-Programm simulieren. Um dies zu tun, rufen Sie als solches auf:
>vvp hello.vvp
Hello World!
>
Installation des Icarus Verilog Compilers für Mac OSX Sierra
- Installieren Sie Xcode aus dem App Store.
- Installieren Sie die Xcode-Entwicklerwerkzeuge
> xcode-select --install
Dadurch werden grundlegende Befehlszeilen-Tools wie gcc
und make
gcc
- Installieren Sie die Mac-Ports
https://www.macports.org/install.php
Das OSX Sierra-Installationspaket bietet eine Open-Source-Methode zum Installieren und Aktualisieren zusätzlicher Softwarepakete auf der Mac-Plattform. Denken Sie, yum
oder apt-get
für den Mac.
- Installieren Sie icarus mit Mac-Ports
> sudo port install iverilog
- Überprüfen Sie die Installation über die Befehlszeile
$ iverilog
iverilog: no source files.
Usage: iverilog [-ESvV] [-B base] [-c cmdfile|-f cmdfile]
[-g1995|-g2001|-g2005] [-g<feature>]
[-D macro[=defn]] [-I includedir] [-M depfile] [-m module]
[-N file] [-o filename] [-p flag=value]
[-s topmodule] [-t target] [-T min|typ|max]
[-W class] [-y dir] [-Y suf] source_file(s)
See the man page for details.
$
Sie können jetzt Ihre erste Verilog-Datei auf dem Mac kompilieren und simulieren.
Installieren Sie GTKWave für die grafische Anzeige von Simulationsdaten unter Mac OSx Sierra
GTKWave ist ein grafisches Anzeigepaket mit vollem Funktionsumfang, das mehrere Standards für die grafische Datenspeicherung unterstützt, aber auch VCD, das von vvp
ausgegebene Format. Um GTKWave abzuholen, haben Sie mehrere Möglichkeiten
- Gehe zu http://gtkwave.sourceforge.net/gtkwave.zip und lade es herunter. Diese Version ist normalerweise die neueste.
- Wenn Sie MacPorts installiert haben ( https://www.macports.org/ ), führen Sie einfach
sudo port install gtkwave
. Dies wird wahrscheinlich auf die Abhängigkeiten zu installieren wollen. Beachten Sie, dass Sie mit dieser Methode normalerweise eine ältere Version erhalten. Wenn Sie MacPorts nicht installiert haben, finden Sie auf dieser Seite ein Installations-Setup-Beispiel. Ja! Sie benötigen alle xcode-Entwicklerwerkzeuge, da Sie mit dieser Methode eine GTKWave-Quelle "erstellen".
Nach der Installation werden Sie möglicherweise aufgefordert, eine Python-Version auszuwählen. Ich hatte bereits 2.7.10 installiert, also habe ich nie ein neues "ausgewählt".
An diesem Punkt können Sie gtkwave mit gtkwave von der Befehlszeile aus gtkwave
. Beim Starten werden Sie möglicherweise aufgefordert, XQuarts zu installieren oder zu aktualisieren. Tun Sie dies. In meinem Fall ist XQuarts 2.7.11 installiert.
Hinweis: Ich musste tatsächlich einen Neustart durchführen, um XQuarts korrekt zu erhalten. Dann habe ich gtkwave
einmal gtkwave
eingegeben und die Anwendung erscheint.
Im nächsten Beispiel werde ich zwei unabhängige Dateien erstellen, eine Testbench und ein Modul zum Testen, und wir werden den gtkwave verwenden, um das Design anzuzeigen.
Mit Icarus Verilog und GTKWaves können Sie einen Entwurf grafisch simulieren und anzeigen
In diesem Beispiel werden Icarus und GTKWave verwendet. Installationsanweisungen für diese Tools unter OSx finden Sie an anderer Stelle auf dieser Seite.
Beginnen wir mit dem Moduldesign. Dieses Modul ist eine BCD-Anzeige mit 7 Segmenten. Ich habe das Design auf eine stumpfe Art und Weise codiert, um uns etwas zu geben, das leicht zu brechen ist und wir können irgendwann grafisch reparieren. Wir haben also einen Clock-Reset, einen 4-Daten-Eingang, der einen BCD-Wert darstellt, und einen 7-Bit-Ausgang, der die Anzeige mit sieben Segmenten darstellt. Erstellen Sie eine Datei mit dem Namen bcd_to_7seg.v und platzieren Sie die Quelle darunter.
module bcd_to_7seg (
input clk,
input reset,
input [3:0] bcd,
output [6:0] seven_seg_display
);
parameter TP = 1;
reg seg_a;
reg seg_b;
reg seg_c;
reg seg_d;
reg seg_e;
reg seg_f;
reg seg_g;
always @ (posedge clk or posedge reset)
begin
if (reset)
begin
seg_a <= #TP 1'b0;
seg_b <= #TP 1'b0;
seg_c <= #TP 1'b0;
seg_d <= #TP 1'b0;
seg_e <= #TP 1'b0;
seg_f <= #TP 1'b0;
seg_g <= #TP 1'b0;
end
else
begin
seg_a <= #TP ~(bcd == 4'h1 || bcd == 4'h4);
seg_b <= #TP bcd < 4'h5 || bcd > 6;
seg_c <= #TP bcd != 2;
seg_d <= #TP bcd == 0 || bcd[3:1] == 3'b001 || bcd == 5 || bcd == 6 || bcd == 8;
seg_e <= #TP bcd == 0 || bcd == 2 || bcd == 6 || bcd == 8;
seg_f <= #TP bcd == 0 || bcd == 4 || bcd == 5 || bcd == 6 || bcd > 7;
seg_g <= #TP (bcd > 1 && bcd < 7) || (bcd > 7);
end
end
assign seven_seg_display = {seg_g,seg_f,seg_e,seg_d,seg_c,seg_b,seg_a};
endmodule
Als Nächstes benötigen wir einen Test, um zu prüfen, ob dieses Modul ordnungsgemäß funktioniert. Die Fallaussage in der Testbench ist meiner Meinung nach einfacher zu lesen und klarer, was sie tut. Aber ich wollte nicht dieselbe Aussage im Design UND im Test machen. Das ist eine schlechte Praxis. Vielmehr werden zwei unabhängige Entwürfe zur Validierung eines anderen verwendet.
Mit dem folgenden Code werden Sie zwei Zeilen $dumpfile("testbench.vcd");
und $dumpvars(0,testbench);
. Diese Zeilen erstellen die VCD-Ausgabedatei, die zur grafischen Analyse des Designs verwendet wird. Wenn Sie sie weglassen, wird keine VCD-Datei generiert. Erstellen Sie eine Datei mit dem Namen testbench.v und platzieren Sie die Quelle darunter.
`timescale 1ns/100ps
module testbench;
reg clk;
reg reset;
reg [31:0] ii;
reg [31:0] error_count;
reg [3:0] bcd;
wire [6:0] seven_seg_display;
parameter TP = 1;
parameter CLK_HALF_PERIOD = 5;
// assign clk = #CLK_HALF_PERIOD ~clk; // Create a clock with a period of ten ns
initial
begin
clk = 0;
#5;
forever clk = #( CLK_HALF_PERIOD ) ~clk;
end
initial
begin
$dumpfile("testbench.vcd");
$dumpvars(0,testbench);
// clk = #CLK_HALF_PERIOD ~clk;
$display("%0t, Reseting system", $time);
error_count = 0;
bcd = 4'h0;
reset = #TP 1'b1;
repeat (30) @ (posedge clk);
reset = #TP 1'b0;
repeat (30) @ (posedge clk);
$display("%0t, Begin BCD test", $time); // This displays a message
for (ii = 0; ii < 10; ii = ii + 1)
begin
repeat (1) @ (posedge clk);
bcd = ii[3:0];
repeat (1) @ (posedge clk);
if (seven_seg_display !== seven_seg_prediction(bcd))
begin
$display("%0t, ERROR: For BCD %d, module output 0b%07b does not match prediction logic value of 0b%07b.",$time,bcd, seven_seg_display,seven_seg_prediction(bcd));
error_count = error_count + 1;
end
end
$display("%0t, Test Complete with %d errors", $time, error_count);
$display("%0t, Test %s", $time, ~|error_count ? "pass." : "fail.");
$finish ; // This causes the simulation to end.
end
parameter SEG_A = 7'b0000001;
parameter SEG_B = 7'b0000010;
parameter SEG_C = 7'b0000100;
parameter SEG_D = 7'b0001000;
parameter SEG_E = 7'b0010000;
parameter SEG_F = 7'b0100000;
parameter SEG_G = 7'b1000000;
function [6:0] seven_seg_prediction;
input [3:0] bcd_in;
// +--- A ---+
// | |
// F B
// | |
// +--- G ---+
// | |
// E C
// | |
// +--- D ---+
begin
case (bcd_in)
4'h0: seven_seg_prediction = SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F;
4'h1: seven_seg_prediction = SEG_B | SEG_C;
4'h2: seven_seg_prediction = SEG_A | SEG_B | SEG_G | SEG_E | SEG_D;
4'h3: seven_seg_prediction = SEG_A | SEG_B | SEG_G | SEG_C | SEG_D;
4'h4: seven_seg_prediction = SEG_F | SEG_G | SEG_B | SEG_C;
4'h5: seven_seg_prediction = SEG_A | SEG_F | SEG_G | SEG_C | SEG_D;
4'h6: seven_seg_prediction = SEG_A | SEG_F | SEG_G | SEG_E | SEG_C | SEG_D;
4'h7: seven_seg_prediction = SEG_A | SEG_B | SEG_C;
4'h8: seven_seg_prediction = SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G;
4'h9: seven_seg_prediction = SEG_A | SEG_F | SEG_G | SEG_B | SEG_C;
default: seven_seg_prediction = 7'h0;
endcase
end
endfunction
bcd_to_7seg u0_bcd_to_7seg (
.clk (clk),
.reset (reset),
.bcd (bcd),
.seven_seg_display (seven_seg_display)
);
endmodule
Jetzt, da wir zwei Dateien haben, eine testbench.v und eine bcd_to_7seg.v, müssen wir mit Icarus kompilieren. Um dies zu tun:
$ iverilog -o testbench.vvp testbench.v bcd_to_7seg.v
Als nächstes müssen wir simulieren
$ vvp testbench.vvp
LXT2 info: dumpfile testbench.vcd opened for output.
0, Reseting system
6000, Begin BCD test
8000, Test Complete with 0 errors
8000, Test pass.
Wenn Sie überprüfen möchten, dass die Datei wirklich getestet wird, gehen Sie in die Datei bcd_2_7seg.v, verschieben Sie einen Teil der Logik und wiederholen Sie die ersten beiden Schritte.
Als Beispiel ändere ich die Zeile seg_c <= #TP bcd != 2;
zu seg_c <= #TP bcd != 4;
. Rekompilieren und simulieren führt Folgendes aus:
$ iverilog -o testbench.vvp testbench.v bcd_to_7seg.v
$ vvp testbench.vvp
LXT2 info: dumpfile testbench.vcd opened for output.
0, Reseting system
6000, Begin BCD test
6600, ERROR: For BCD 2, module output 0b1011111 does not match prediction logic value of 0b1011011.
7000, ERROR: For BCD 4, module output 0b1100010 does not match prediction logic value of 0b1100110.
8000, Test Complete with 2 errors
8000, Test fail.
$
Jetzt sehen wir uns die Simulation mit GTKWave an. Geben Sie in der Befehlszeile a ein
gtkwave testbench.vcd &
Wenn das GTKWave-Fenster angezeigt wird, sehen Sie im oberen linken Feld den Modulnamen testbench. Klick es. Dadurch werden die mit dieser Datei verknüpften Untermodule, Aufgaben und Funktionen angezeigt. Drähte und Register werden auch im unteren linken Feld angezeigt.
Ziehen Sie nun clk, bcd, error_count und seven_seg_display in das Signalfeld neben dem Wellenformfenster. Die Signale werden nun aufgezeichnet. Error_count zeigt an, welche BCD-Eingabe die falsche seven_seg_display-Ausgabe erzeugt hat.
Sie können jetzt einen Verilog-Fehler grafisch beheben.