Looking for verilog Keywords? Try Ask4Keywords

verilogErste Schritte mit Verilog


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

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.

  1. 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.
  2. 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.
  3. 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!
>
 

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

  1. Gehe zu http://gtkwave.sourceforge.net/gtkwave.zip und lade es herunter. Diese Version ist normalerweise die neueste.
  2. 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.

Installation des Icarus Verilog Compilers für Mac OSX Sierra

  1. Installieren Sie Xcode aus dem App Store.
  2. Installieren Sie die Xcode-Entwicklerwerkzeuge
> xcode-select --install
 

Dadurch werden grundlegende Befehlszeilen-Tools wie gcc und make gcc

  1. 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.

  1. Installieren Sie icarus mit Mac-Ports
> sudo port install iverilog
 
  1. Ü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.

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.

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.