VLSI Design - Verilog Einführung

Verilog ist eine HARDWARE-BESCHREIBUNGSSPRACHE (HDL). Es ist eine Sprache, die zur Beschreibung eines digitalen Systems wie eines Netzwerk-Switches oder eines Mikroprozessors oder eines Speichers oder eines Flip-Flops verwendet wird. Mit einem HDL können wir jede digitale Hardware auf jeder Ebene beschreiben. Entwürfe, die in HDL beschrieben werden, sind unabhängig von der Technologie, sehr einfach zu entwerfen und zu debuggen und normalerweise nützlicher als Schaltpläne, insbesondere für große Schaltungen.

Verilog unterstützt ein Design auf vielen Abstraktionsebenen. Die drei wichtigsten sind -

  • Verhaltensstufe
  • Register-Transfer-Level
  • Torebene

Verhaltensstufe

Diese Ebene beschreibt ein System durch gleichzeitige Algorithmen (Behavioral). Jeder Algorithmus ist sequentiell, dh er besteht aus einer Reihe von Anweisungen, die einzeln ausgeführt werden. Funktionen, Aufgaben und Blöcke sind die Hauptelemente. Die strukturelle Realisierung des Entwurfs wird nicht berücksichtigt.

Register - Transfer Level

Entwürfe, die den Registerübertragungspegel verwenden, spezifizieren die Eigenschaften einer Schaltung unter Verwendung von Operationen und der Übertragung von Daten zwischen den Registern. Die moderne Definition eines RTL-Codes lautet "Jeder Code, der synthetisierbar ist, wird als RTL-Code bezeichnet".

Gate Level

Innerhalb der logischen Ebene werden die Eigenschaften eines Systems durch logische Verknüpfungen und ihre Timing-Eigenschaften beschrieben. Alle Signale sind diskrete Signale. Sie können nur bestimmte logische Werte haben ("0", "1", "X", "Z"). Die verwendbaren Operationen sind vordefinierte Logikprimitive (Basisgatter). Die Modellierung auf Gate-Ebene ist möglicherweise keine richtige Idee für das Logikdesign. Gate-Level-Code wird mit Tools wie Synthesewerkzeugen generiert und seine Netzliste wird für die Gate-Level-Simulation und für das Backend verwendet.

Lexikalische Token

Verilog-Sprachquelltextdateien sind ein Strom von lexikalischen Token. Ein Token besteht aus einem oder mehreren Zeichen, und jedes einzelne Zeichen befindet sich in genau einem Token.

Die von Verilog HDL verwendeten lexikalischen Grundtoken ähneln denen in der Programmiersprache C. Verilog unterscheidet zwischen Groß- und Kleinschreibung. Alle Schlüsselwörter sind in Kleinbuchstaben.

Leerraum

Leerzeichen können Zeichen für Leerzeichen, Tabulatoren, neue Zeilen und Formular-Feeds enthalten. Diese Zeichen werden ignoriert, es sei denn, sie dienen zur Trennung von Token.

Leerzeichen sind Leerzeichen, Tabulatoren, Zeilenumbrüche, Neue Zeilen und Formular-Feeds.

Bemerkungen

Es gibt zwei Formen, um die Kommentare darzustellen

  • 1) Einzeilige Kommentare beginnen mit dem Token // und enden mit dem Wagenrücklauf.

Bsp.: // Dies ist eine einzeilige Syntax

  • 2) Mehrzeilige Kommentare beginnen mit dem Token / * und enden mit dem Token * /

Bsp.: / * Dies ist eine mehrzeilige Syntax * /

Zahlen

Sie können eine Zahl im Binär-, Oktal-, Dezimal- oder Hexadezimalformat angeben. Negative Zahlen werden in den Komplimentzahlen von 2 dargestellt. Verilog erlaubt Ganzzahlen, reelle Zahlen und vorzeichenbehaftete und vorzeichenlose Zahlen.

Die Syntax wird durch - <Größe> <Radix> <Wert> angegeben

Größe oder nicht dimensionierte Zahl können in <Größe> definiert werden, und <Radix> definiert, ob es sich um eine Binär-, Oktal-, Hexadezimal- oder Dezimalzahl handelt.

Kennungen

Bezeichner ist der Name, der zum Definieren des Objekts verwendet wird, z. B. eine Funktion, ein Modul oder ein Register. Bezeichner sollten mit alphabetischen Zeichen oder Unterstrichen beginnen. Ex. A_Z, a_z, _

Bezeichner sind eine Kombination aus Buchstaben, Zahlen, Unterstrichen und $ -Zeichen. Sie können bis zu 1024 Zeichen lang sein.

Betreiber

Operatoren sind Sonderzeichen, die zum Setzen von Bedingungen oder zum Bedienen der Variablen verwendet werden. Es gibt ein, zwei und manchmal drei Zeichen, mit denen Operationen an Variablen ausgeführt werden.

Ex. >, +, ~, &! =.

Verilog-Schlüsselwörter

Wörter, die in Verilog eine besondere Bedeutung haben, werden als Verilog-Schlüsselwörter bezeichnet. Weisen Sie beispielsweise case, while, wire, reg und / oder nand und module zu. Sie sollten nicht als Bezeichner verwendet werden. Zu den Verilog-Schlüsselwörtern gehören auch Compiler-Direktiven sowie Systemaufgaben und -funktionen.

Gate Level Modellierung

Verilog verfügt über integrierte Grundelemente wie Logikgatter, Übertragungsgatter und Schalter. Diese werden selten für Entwurfsarbeiten verwendet, aber sie werden in der Welt nach der Synthese zur Modellierung von ASIC / FPGA-Zellen verwendet.

Die Modellierung auf Gate-Ebene weist zwei Eigenschaften auf:

Drive strength- Die Stärke der Ausgangsgatter wird durch die Antriebsstärke definiert. Die Ausgabe ist am stärksten, wenn eine direkte Verbindung zur Quelle besteht. Die Stärke nimmt ab, wenn die Verbindung über einen leitenden Transistor erfolgt, und am wenigsten, wenn die Verbindung über einen Pull-Up / Down-Widerstand erfolgt. Die Antriebsstärke wird normalerweise nicht angegeben. In diesem Fall sind die Stärken standardmäßig strong1 und strong0.

Delays- Wenn keine Verzögerungen angegeben sind, haben die Gates keine Ausbreitungsverzögerungen. Wenn zwei Verzögerungen angegeben sind, repräsentiert die erste die Anstiegsverzögerung und die zweite die Abfallverzögerung. Wenn nur eine Verzögerung angegeben ist, sind sowohl Anstieg als auch Abfall gleich. Verzögerungen können bei der Synthese ignoriert werden.

Torprimitive

Die grundlegenden Logikgatter mit einem Ausgang und vielen Eingängen werden in Verilog verwendet. GATE verwendet eines der Schlüsselwörter - und, nand oder oder noch xor, xnor zur Verwendung in Verilog für N Anzahl von Eingaben und 1 Ausgabe.

Example:  
   Module gate() 
   Wire ot0; 
   Wire ot1; 
   Wire ot2; 
   
   Reg in0,in1,in2,in3; 
   Not U1(ot0,in0); 
   Xor U2(ot1,in1,in2,in3); 
   And U3(ot2, in2,in3,in0)

Transmission Gate Primitive

Übertragungsgatterprimitive umfassen sowohl Puffer als auch Inverter. Sie haben einen einzelnen Eingang und einen oder mehrere Ausgänge. In der unten gezeigten Gate-Instanziierungssyntax steht GATE entweder für das Schlüsselwort buf oder NOT gate.

Beispiel: Nicht, buf, bufif0, bufif1, notif0, notif1

Kein Wechselrichter

Pufferausgangspuffer

Bufifo - Tristate Buffer, Active Low Enable

Bufif1 - Tristate-Puffer, aktive Hochfreigabe

Notifo - Tristate - Wechselrichter, aktive Low - Freigabe

Notif1 - Tristate-Wechselrichter, aktive Hochfreigabe

Example:  
   Module gate() 
   Wire out0; 
   Wire out1; 
   
   Reg in0,in1;
   Not U1(out0,in0); 
   Buf U2(out0,in0);

Datentypen

Wert gesetzt

Verilog besteht hauptsächlich aus vier Grundwerten. Alle Verilog-Datentypen, die in Verilog verwendet werden, speichern diese Werte -

0 (logische Null oder falsche Bedingung)

1 (logische Eins oder wahre Bedingung)

x (unbekannter logischer Wert)

z (hochohmiger Zustand)

Die Verwendung von x und z ist für die Synthese sehr begrenzt.

Draht

Ein Draht wird verwendet, um einen physischen Draht in einer Schaltung darzustellen, und er wird zum Verbinden von Gates oder Modulen verwendet. Der Wert eines Drahtes kann nur gelesen und nicht in einer Funktion oder einem Block zugewiesen werden. Ein Draht kann keinen Wert speichern, wird jedoch immer durch eine fortlaufende Zuweisungsanweisung oder durch Verbinden des Drahtes mit dem Ausgang eines Gatters / Moduls gesteuert. Andere spezifische Arten von Drähten sind -

Wand (wired-AND) - Hier hängt der Wert von Wand vom logischen UND aller daran angeschlossenen Gerätetreiber ab.

Wor (wired-OR) - Hier hängt der Wert eines Wor vom logischen ODER aller damit verbundenen Gerätetreiber ab.

Tri (three-state) - Hier müssen alle mit einem Tri verbundenen Treiber z sein, außer nur einem (der den Wert von Tri bestimmt).

Example: 
   Wire [msb:lsb] wire_variable_list; 
   Wirec // simple wire 
   Wand d; 
   
   Assign d = a; // value of d is the logical AND of 
   Assign d = b; // a and b 
   Wire [9:0] A; // a cable (vector) of 10 wires. 
   
   Wand [msb:lsb] wand_variable_list; 
   Wor [msb:lsb] wor_variable_list; 
   Tri [msb:lsb] tri_variable_list;

Registrieren

Ein reg (register) ist ein Datenobjekt, das den Wert von einer prozeduralen Zuordnung zur nächsten enthält und nur in verschiedenen Funktionen und prozeduralen Blöcken verwendet wird. Eine Registrierung ist ein einfaches Verilog-Register vom Variablentyp und kann kein physikalisches Register implizieren. In Mehrbitregistern werden die Daten in Form von vorzeichenlosen Zahlen gespeichert und die Vorzeichenerweiterung wird nicht verwendet.

Beispiel -

reg c; // einzelne 1-Bit-Registervariable

reg [5: 0] gem; // ein 6-Bit-Vektor;

reg [6: 0] d, e; // zwei 7-Bit-Variablen

Eingabe, Ausgabe, Inout

Diese Schlüsselwörter werden verwendet, um Eingabe-, Ausgabe- und bidirektionale Ports einer Aufgabe oder eines Moduls zu deklarieren. Hier sind die Eingangs- und Ausgangsanschlüsse, die vom Drahttyp und vom Ausgangsanschluss sind, so konfiguriert, dass sie vom Draht-, Reg-, Stab-, Wor- oder Tri-Typ sind. Standard ist immer der Drahttyp.

Example

Module sample(a, c, b, d);  
Input c;   // An input where wire is used. 

Output a, b;  // Two outputs where wire is used. 
Output [2:0] d;  /* A three-bit output. One must declare type in a separate statement. */ 
reg [1:0] a;  // The above ‘a’ port is for declaration in reg.

Ganze Zahl

Ganzzahlen werden in Allzweckvariablen verwendet. Sie werden hauptsächlich in Schleifenangaben, Konstanten und Parametern verwendet. Sie sind vom Datentyp 'reg'. Sie speichern Daten als vorzeichenbehaftete Nummern, während explizit deklarierte Reg-Typen sie als vorzeichenlose Daten speichern. Wenn die Ganzzahl zum Zeitpunkt des Kompilierens nicht definiert ist, beträgt die Standardgröße 32 Bit.

Wenn eine Ganzzahl eine Konstante hält, passt der Synthesizer sie auf die zum Zeitpunkt der Kompilierung erforderliche Mindestbreite an.

Example

Integer c;   // single 32-bit integer 
Assign a = 63;  // 63 defaults to a 7-bit variable.

Supply0, Supply1

Versorgung0 definiert Drähte, die an Logik 0 (Masse) gebunden sind, und Versorgung1 definiert Drähte, die an Logik 1 (Stromversorgung) gebunden sind.

Example

supply0 logic_0_wires; 
supply0 gnd1;  // equivalent to a wire assigned as 0 

supply1 logic_1_wires; 
supply1 c, s;

Zeit

Zeit ist eine 64-Bit-Größe, die in Verbindung mit der $ time-Systemaufgabe verwendet werden kann, um die Simulationszeit zu speichern. Die Zeit wird für die Synthese nicht unterstützt und daher nur für Simulationszwecke verwendet.

Example

time time_variable_list; 
time c; 
c = $time;   //c = current simulation time

Parameter

Ein Parameter definiert eine Konstante, die festgelegt werden kann, wenn Sie ein Modul verwenden, wodurch das Modul während des Instanziierungsprozesses angepasst werden kann.

Example 
Parameter add = 3’b010, sub = 2’b11; 
Parameter n = 3; 
Parameter [2:0] param2 = 3’b110; 

reg [n-1:0] jam; /* A 3-bit register with length of n or above. */ 
always @(z) 
y = {{(add - sub){z}};  

if (z)
begin 
   state = param2[1];
else
   state = param2[2]; 
end

Betreiber

Rechenzeichen

Diese Operatoren führen arithmetische Operationen aus. Die + und - werden entweder als unäre (x) oder binäre (z - y) Operatoren verwendet.

Die Operatoren, die in der arithmetischen Operation enthalten sind, sind -

+ (Addition), - (Subtraktion), * (Multiplikation), / (Division),% (Modul)

Example - -

parameter v = 5;
reg[3:0] b, d, h, i, count; 
h = b + d; 
i = d - v; 
cnt = (cnt +1)%16; //Can count 0 thru 15.

Vergleichsoperatoren

Diese Operatoren vergleichen zwei Operanden und geben das Ergebnis in einem einzelnen Bit 1 oder 0 zurück.

Wire- und Reg-Variablen sind positiv. Somit ist (–3'd001) = = 3'd111 und (–3b001)> 3b110.

Die Operatoren, die in der relationalen Operation enthalten sind, sind -

  • == (gleich)
  • ! = (ungleich)
  • > (größer als)
  • > = (größer oder gleich)
  • <(weniger als)
  • <= (kleiner oder gleich)

Example

if (z = = y) c = 1; 
   else c = 0; // Compare in 2’s compliment; d>b 
reg [3:0] d,b; 

if (d[3]= = b[3]) d[2:0] > b[2:0]; 
   else b[3]; 
Equivalent Statement 
e = (z == y);

Bitweise Operatoren

Bitweise Operatoren, die einen bitweisen Vergleich zwischen zwei Operanden durchführen.

Die Operatoren, die in der bitweisen Operation enthalten sind, sind -

  • & (bitweises UND)
  • | (bitweise ODER)
  • ~ (bitweise NICHT)
  • ^ (bitweises XOR)
  • ~ ^ oder ^ ~ (bitweises XNOR)

Example

module and2 (d, b, c); 
input [1:0] d, b; 
output [1:0] c; 
assign c = d & b; 
end module

Logische Operatoren

Logische Operatoren sind bitweise Operatoren und werden nur für Einzelbitoperanden verwendet. Sie geben einen einzelnen Bitwert 0 oder 1 zurück. Sie können Ganzzahlen oder Gruppen von Bits und Ausdrücken bearbeiten und alle Werte ungleich Null als 1 behandeln. Logische Operatoren werden im Allgemeinen in bedingten Anweisungen verwendet, da sie mit Ausdrücken arbeiten.

Die Operatoren, die in der logischen Operation enthalten sind, sind -

  • ! (logisch NICHT)
  • && (logisches UND)
  • || (logisches ODER)

Example

wire[7:0] a, b, c; // a, b and c are multibit variables. 
reg x; 

if ((a == b) && (c)) x = 1; //x = 1 if a equals b, and c is nonzero. 
   else x = !a; // x =0 if a is anything but zero.

Reduktionsoperatoren

Reduktionsoperatoren sind die unäre Form der bitweisen Operatoren und arbeiten mit allen Bits eines Operandenvektors. Diese geben auch einen Einzelbitwert zurück.

Die Operatoren, die in der Reduktionsoperation enthalten sind, sind -

  • & (Reduktion UND)
  • | (Reduktion ODER)
  • ~ & (Reduktion NAND)
  • ~ | (Reduktion NOR)
  • ^ (Reduktion XOR)
  • ~ ^ oder ^ ~ (Reduktion XNOR)

Example

Module chk_zero (x, z); 

Input [2:0] x; 
Output z; 
Assign z = & x; // Reduction AND 
End module

Schichtarbeiter

Verschiebungsoperatoren, die den ersten Operanden um die Anzahl der durch den zweiten Operanden in der Syntax angegebenen Bits verschieben. Freie Positionen werden für beide Richtungen, Links- und Rechtsverschiebung, mit Nullen gefüllt (es gibt keine Verwendung der Zeichenerweiterung).

Die Operatoren, die im Schichtbetrieb enthalten sind, sind -

  • << (nach links verschieben)
  • >> (nach rechts verschieben)

Example

Assign z = c << 3; /* z = c shifted left 3 bits;

Freie Stellen werden mit Nullen * / besetzt

Verkettungsoperator

Der Verkettungsoperator kombiniert zwei oder mehr Operanden, um einen größeren Vektor zu bilden.

Der in der Verkettungsoperation enthaltene Operator ist - {} (Verkettung)

Example

wire [1:0] a, h; wire [2:0] x; wire [3;0] y, Z; 
assign x = {1’b0, a}; // x[2] = 0, x[1] = a[1], x[0] = a[0] 
assign b = {a, h}; /* b[3] = a[1], b[2] = a[0], b[1] = h[1], 
b[0] = h[0] */ 
assign {cout, b} = x + Z; // Concatenation of a result

Replikationsoperator

Der Replikationsoperator erstellt mehrere Kopien eines Elements.

Der im Replikationsvorgang verwendete Operator ist - {n {item}} (n-fache Replikation eines Elements)

Example

Wire [1:0] a, f; wire [4:0] x; 
Assign x = {2{1’f0}, a}; // Equivalent to x = {0,0,a } 
Assign y = {2{a}, 3{f}}; //Equivalent to y = {a,a,f,f} 
For synthesis, Synopsis did not like a zero replication.

For example:- 
Parameter l = 5, k = 5; 
Assign x = {(l-k){a}}

Bedingter Operator

Der bedingte Operator synthetisiert zu einem Multiplexer. Es ist die gleiche Art wie in C / C ++ und wertet einen der beiden Ausdrücke basierend auf der Bedingung aus.

Der im bedingten Betrieb verwendete Operator ist -

(Bedingung) ? (Ergebnis, wenn die Bedingung erfüllt ist) -

(Ergebnis wenn Bedingung falsch)

Example

Assign x = (g) ? a : b; 
Assign x = (inc = = 2) ? x+1 : x-1; 
/* if (inc), x = x+1, else x = x-1 */

Operanden

Literale

Literale sind Operanden mit konstantem Wert, die in Verilog-Ausdrücken verwendet werden. Die zwei häufig verwendeten Verilog-Literale sind -

  • String - Ein String-Literal-Operand ist ein eindimensionales Array von Zeichen, die in doppelte Anführungszeichen ("") eingeschlossen sind.

  • Numeric - Ein Operand mit konstanter Zahl wird in Binär-, Oktal-, Dezimal- oder Hexadezimalzahl angegeben.

Example

n - Ganzzahl, die die Anzahl der Bits darstellt

F - eines von vier möglichen Basisformaten -

b für binär, o für oktal, d für dezimal, h für hexadezimal.

“time is”  // string literal 
267        // 32-bit decimal number 
2’b01      // 2-bit binary 
20’hB36F   // 20-bit hexadecimal number 
‘062       // 32-bit octal number

Drähte, Regs und Parameter

Drähte, Register und Parameter sind die Datentypen, die als Operanden in Verilog-Ausdrücken verwendet werden.

Bitauswahl “x [2]” und Teileauswahl “x [4: 2]”

Bitauswahl und Teilauswahl werden verwendet, um ein Bit bzw. mehrere Bits aus einem Draht-, Register- oder Parametervektor unter Verwendung der eckigen Klammern „[]“ auszuwählen. Bitauswahl und Teilauswahl werden ebenso wie ihre Hauptdatenobjekte als Operanden in Ausdrücken verwendet.

Example

reg [7:0] x, y; 
reg [3:0] z; 
reg a; 
a = x[7] & y[7];      // bit-selects 
z = x[7:4] + y[3:0];  // part-selects

Funktionsaufrufe

In den Funktionsaufrufen wird der Rückgabewert einer Funktion direkt in einem Ausdruck verwendet, ohne dass er zuerst einem Register oder einer Leitung zugewiesen werden muss. Es wird lediglich der Funktionsaufruf als einer der Operandentypen platziert. Es ist erforderlich, um sicherzustellen, dass Sie die Bitbreite des Rückgabewerts des Funktionsaufrufs kennen.

Example  
Assign x = y & z & chk_yz(z, y); // chk_yz is a function 

. . ./* Definition of the function */ 
Function chk_yz; // function definition 
Input z,y; 
chk_yz = y^z; 
End function

Module

Moduldeklaration

In Verilog ist ein Modul die Hauptentwurfseinheit. Dies gibt den Namen und die Portliste (Argumente) an. Die nächsten Zeilen geben den Eingabe- / Ausgabetyp (Eingabe, Ausgabe oder Eingang) und die Breite jedes Ports an. Die Standardportbreite beträgt nur 1 Bit. Die Portvariablen müssen per Draht, Stab, deklariert werden. . ., reg. Die Standardportvariable ist wire. Normalerweise sind die Eingänge drahtgebunden, da ihre Daten außerhalb des Moduls zwischengespeichert werden. Die Ausgänge sind vom Reg-Typ, wenn ihre Signale darin gespeichert sind.

Example

module sub_add(add, in1, in2, out); 
input add; // defaults to wire 
input [7:0] in1, in2; wire in1, in2; 

output [7:0] out; reg out; 
... statements ... 
End module

Kontinuierliche Zuordnung

Die fortlaufende Zuweisung in einem Modul wird zum Zuweisen eines Werts zu einem Draht verwendet. Dies ist die normale Zuordnung, die außerhalb von Always- oder Anfangsblöcken verwendet wird. Diese Zuweisung erfolgt mit einer expliziten Zuweisungsanweisung oder um einem Draht während seiner Deklaration einen Wert zuzuweisen. Kontinuierliche Zuordnung wird zum Zeitpunkt der Simulation kontinuierlich ausgeführt. Die Reihenfolge der Zuweisungsanweisungen hat keinen Einfluss darauf. Wenn Sie das Eingangssignal auf der rechten Seite ändern, ändert sich das Ausgangssignal auf der linken Seite.

Example

Wire [1:0] x = 2’y01;   // assigned on declaration 
Assign y = c | d;       // using assign statement 
Assign d = a & b; 
/* the order of the assign statements does not matter. */

Modulinstanziierungen

Moduldeklarationen sind Vorlagen zum Erstellen tatsächlicher Objekte. Module werden in anderen Modulen instanziiert, und bei jeder Instanziierung wird aus dieser Vorlage ein einzelnes Objekt erstellt. Die Ausnahme ist das Modul der obersten Ebene, das eine eigene Instanziierung darstellt. Die Ports des Moduls müssen mit denen übereinstimmen, die in der Vorlage definiert sind. Es ist angegeben -

  • By nameVerwenden Sie dazu den Punkt ".template port name (Name des an den Port angeschlossenen Kabels)". Oder

  • By positionPlatzieren Sie die Ports an derselben Stelle in den Portlisten sowohl der Vorlage als auch der Instanz.

Example

MODULE DEFINITION 
Module and4 (x, y, z); 
Input [3:0] x, y; 
Output [3:0] z; 
Assign z = x | y; 
End module